1package asm
2
3//go:generate stringer -output load_store_string.go -type=Mode,Size
4
5// Mode for load and store operations
6//
7//    msb      lsb
8//    +---+--+---+
9//    |MDE|sz|cls|
10//    +---+--+---+
11type Mode uint8
12
13const modeMask OpCode = 0xe0
14
15const (
16	// InvalidMode is returned by getters when invoked
17	// on non load / store OpCodes
18	InvalidMode Mode = 0xff
19	// ImmMode - immediate value
20	ImmMode Mode = 0x00
21	// AbsMode - immediate value + offset
22	AbsMode Mode = 0x20
23	// IndMode - indirect (imm+src)
24	IndMode Mode = 0x40
25	// MemMode - load from memory
26	MemMode Mode = 0x60
27	// XAddMode - add atomically across processors.
28	XAddMode Mode = 0xc0
29)
30
31// Size of load and store operations
32//
33//    msb      lsb
34//    +---+--+---+
35//    |mde|SZ|cls|
36//    +---+--+---+
37type Size uint8
38
39const sizeMask OpCode = 0x18
40
41const (
42	// InvalidSize is returned by getters when invoked
43	// on non load / store OpCodes
44	InvalidSize Size = 0xff
45	// DWord - double word; 64 bits
46	DWord Size = 0x18
47	// Word - word; 32 bits
48	Word Size = 0x00
49	// Half - half-word; 16 bits
50	Half Size = 0x08
51	// Byte - byte; 8 bits
52	Byte Size = 0x10
53)
54
55// Sizeof returns the size in bytes.
56func (s Size) Sizeof() int {
57	switch s {
58	case DWord:
59		return 8
60	case Word:
61		return 4
62	case Half:
63		return 2
64	case Byte:
65		return 1
66	default:
67		return -1
68	}
69}
70
71// LoadMemOp returns the OpCode to load a value of given size from memory.
72func LoadMemOp(size Size) OpCode {
73	return OpCode(LdXClass).SetMode(MemMode).SetSize(size)
74}
75
76// LoadMem emits `dst = *(size *)(src + offset)`.
77func LoadMem(dst, src Register, offset int16, size Size) Instruction {
78	return Instruction{
79		OpCode: LoadMemOp(size),
80		Dst:    dst,
81		Src:    src,
82		Offset: offset,
83	}
84}
85
86// LoadImmOp returns the OpCode to load an immediate of given size.
87//
88// As of kernel 4.20, only DWord size is accepted.
89func LoadImmOp(size Size) OpCode {
90	return OpCode(LdClass).SetMode(ImmMode).SetSize(size)
91}
92
93// LoadImm emits `dst = (size)value`.
94//
95// As of kernel 4.20, only DWord size is accepted.
96func LoadImm(dst Register, value int64, size Size) Instruction {
97	return Instruction{
98		OpCode:   LoadImmOp(size),
99		Dst:      dst,
100		Constant: value,
101	}
102}
103
104// LoadMapPtr stores a pointer to a map in dst.
105func LoadMapPtr(dst Register, fd int) Instruction {
106	if fd < 0 {
107		return Instruction{OpCode: InvalidOpCode}
108	}
109
110	return Instruction{
111		OpCode:   LoadImmOp(DWord),
112		Dst:      dst,
113		Src:      PseudoMapFD,
114		Constant: int64(fd),
115	}
116}
117
118// LoadMapValue stores a pointer to the value at a certain offset of a map.
119func LoadMapValue(dst Register, fd int, offset uint32) Instruction {
120	if fd < 0 {
121		return Instruction{OpCode: InvalidOpCode}
122	}
123
124	fdAndOffset := (uint64(offset) << 32) | uint64(uint32(fd))
125	return Instruction{
126		OpCode:   LoadImmOp(DWord),
127		Dst:      dst,
128		Src:      PseudoMapValue,
129		Constant: int64(fdAndOffset),
130	}
131}
132
133// LoadIndOp returns the OpCode for loading a value of given size from an sk_buff.
134func LoadIndOp(size Size) OpCode {
135	return OpCode(LdClass).SetMode(IndMode).SetSize(size)
136}
137
138// LoadInd emits `dst = ntoh(*(size *)(((sk_buff *)R6)->data + src + offset))`.
139func LoadInd(dst, src Register, offset int32, size Size) Instruction {
140	return Instruction{
141		OpCode:   LoadIndOp(size),
142		Dst:      dst,
143		Src:      src,
144		Constant: int64(offset),
145	}
146}
147
148// LoadAbsOp returns the OpCode for loading a value of given size from an sk_buff.
149func LoadAbsOp(size Size) OpCode {
150	return OpCode(LdClass).SetMode(AbsMode).SetSize(size)
151}
152
153// LoadAbs emits `r0 = ntoh(*(size *)(((sk_buff *)R6)->data + offset))`.
154func LoadAbs(offset int32, size Size) Instruction {
155	return Instruction{
156		OpCode:   LoadAbsOp(size),
157		Dst:      R0,
158		Constant: int64(offset),
159	}
160}
161
162// StoreMemOp returns the OpCode for storing a register of given size in memory.
163func StoreMemOp(size Size) OpCode {
164	return OpCode(StXClass).SetMode(MemMode).SetSize(size)
165}
166
167// StoreMem emits `*(size *)(dst + offset) = src`
168func StoreMem(dst Register, offset int16, src Register, size Size) Instruction {
169	return Instruction{
170		OpCode: StoreMemOp(size),
171		Dst:    dst,
172		Src:    src,
173		Offset: offset,
174	}
175}
176
177// StoreImmOp returns the OpCode for storing an immediate of given size in memory.
178func StoreImmOp(size Size) OpCode {
179	return OpCode(StClass).SetMode(MemMode).SetSize(size)
180}
181
182// StoreImm emits `*(size *)(dst + offset) = value`.
183func StoreImm(dst Register, offset int16, value int64, size Size) Instruction {
184	return Instruction{
185		OpCode:   StoreImmOp(size),
186		Dst:      dst,
187		Offset:   offset,
188		Constant: value,
189	}
190}
191
192// StoreXAddOp returns the OpCode to atomically add a register to a value in memory.
193func StoreXAddOp(size Size) OpCode {
194	return OpCode(StXClass).SetMode(XAddMode).SetSize(size)
195}
196
197// StoreXAdd atomically adds src to *dst.
198func StoreXAdd(dst, src Register, size Size) Instruction {
199	return Instruction{
200		OpCode: StoreXAddOp(size),
201		Dst:    dst,
202		Src:    src,
203	}
204}
205