iPXE
librm.h
Go to the documentation of this file.
1 #ifndef LIBRM_H
2 #define LIBRM_H
3 
4 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
5 
6 /* Segment selectors as used in our protected-mode GDTs.
7  *
8  * Don't change these unless you really know what you're doing.
9  */
10 #define VIRTUAL_CS 0x08
11 #define VIRTUAL_DS 0x10
12 #define PHYSICAL_CS 0x18
13 #define PHYSICAL_DS 0x20
14 #define REAL_CS 0x28
15 #define REAL_DS 0x30
16 #define P2R_DS 0x38
17 #define LONG_CS 0x40
18 
19 /* Calculate symbol address within VIRTUAL_CS or VIRTUAL_DS
20  *
21  * In a 64-bit build, we set the bases of VIRTUAL_CS and VIRTUAL_DS
22  * such that truncating a .textdata symbol value to 32 bits gives a
23  * valid 32-bit virtual address.
24  *
25  * The C code is compiled with -mcmodel=kernel and so we must place
26  * all .textdata symbols within the negative 2GB of the 64-bit address
27  * space. Consequently, all .textdata symbols will have the MSB set
28  * after truncation to 32 bits. This means that a straightforward
29  * R_X86_64_32 relocation record for the symbol will fail, since the
30  * truncated symbol value will not correctly zero-extend to the
31  * original 64-bit value.
32  *
33  * Using an R_X86_64_32S relocation record would work, but there is no
34  * (sensible) way to generate these relocation records within 32-bit
35  * or 16-bit code.
36  *
37  * The simplest solution is to generate an R_X86_64_32 relocation
38  * record with an addend of (-0xffffffff00000000). Since all
39  * .textdata symbols are within the negative 2GB of the 64-bit address
40  * space, this addend acts to effectively truncate the symbol to 32
41  * bits, thereby matching the semantics of the R_X86_64_32 relocation
42  * records generated for 32-bit and 16-bit code.
43  *
44  * In a 32-bit build, this problem does not exist, and we can just use
45  * the .textdata symbol values directly.
46  */
47 #ifdef __x86_64__
48 #define VIRTUAL(address) ( (address) - 0xffffffff00000000 )
49 #else
50 #define VIRTUAL(address) (address)
51 #endif
52 
53 #ifdef ASSEMBLY
54 
55 /**
56  * Call C function from real-mode code
57  *
58  * @v function C function
59  */
60 .macro virtcall function
61  pushl $VIRTUAL(\function)
62  call virt_call
63 .endm
64 
65 #else /* ASSEMBLY */
66 
67 #ifdef UACCESS_LIBRM
68 #define UACCESS_PREFIX_librm
69 #else
70 #define UACCESS_PREFIX_librm __librm_
71 #endif
72 
73 /**
74  * Call C function from real-mode code
75  *
76  * @v function C function
77  */
78 #define VIRT_CALL( function ) \
79  "pushl $( " _S2 ( VIRTUAL ( function ) ) " )\n\t" \
80  "call virt_call\n\t"
81 
82 /* Variables in librm.S */
83 extern const unsigned long virt_offset;
84 
85 /**
86  * Convert physical address to user pointer
87  *
88  * @v phys_addr Physical address
89  * @ret userptr User pointer
90  */
91 static inline __always_inline userptr_t
92 UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
93 
94  /* In a 64-bit build, any valid physical address is directly
95  * usable as a virtual address, since the low 4GB is
96  * identity-mapped.
97  */
98  if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
99  return phys_addr;
100 
101  /* In a 32-bit build, subtract virt_offset */
102  return ( phys_addr - virt_offset );
103 }
104 
105 /**
106  * Convert user buffer to physical address
107  *
108  * @v userptr User pointer
109  * @v offset Offset from user pointer
110  * @ret phys_addr Physical address
111  */
112 static inline __always_inline unsigned long
114  unsigned long addr = ( userptr + offset );
115 
116  /* In a 64-bit build, any virtual address in the low 4GB is
117  * directly usable as a physical address, since the low 4GB is
118  * identity-mapped.
119  */
120  if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
121  ( addr <= 0xffffffffUL ) )
122  return addr;
123 
124  /* In a 32-bit build or in a 64-bit build with a virtual
125  * address above 4GB: add virt_offset
126  */
127  return ( addr + virt_offset );
128 }
129 
130 static inline __always_inline userptr_t
131 UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
132  return trivial_virt_to_user ( addr );
133 }
134 
135 static inline __always_inline void *
136 UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
137  return trivial_user_to_virt ( userptr, offset );
138 }
139 
140 static inline __always_inline userptr_t
141 UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
142  return trivial_userptr_add ( userptr, offset );
143 }
144 
145 static inline __always_inline off_t
146 UACCESS_INLINE ( librm, userptr_sub ) ( userptr_t userptr,
148  return trivial_userptr_sub ( userptr, subtrahend );
149 }
150 
151 static inline __always_inline void
154  size_t len ) {
156 }
157 
158 static inline __always_inline void
161  size_t len ) {
163 }
164 
165 static inline __always_inline int
168  size_t len ) {
170 }
171 
172 static inline __always_inline void
174  int c, size_t len ) {
176 }
177 
178 static inline __always_inline size_t
180  return trivial_strlen_user ( buffer, offset );
181 }
182 
183 static inline __always_inline off_t
185  int c, size_t len ) {
186  return trivial_memchr_user ( buffer, offset, c, len );
187 }
188 
189 
190 /******************************************************************************
191  *
192  * Access to variables in .data16 and .text16
193  *
194  */
195 
196 extern char * const data16;
197 extern char * const text16;
198 
199 #define __data16( variable ) \
200  __attribute__ (( section ( ".data16" ) )) \
201  _data16_ ## variable __asm__ ( #variable )
202 
203 #define __data16_array( variable, array ) \
204  __attribute__ (( section ( ".data16" ) )) \
205  _data16_ ## variable array __asm__ ( #variable )
206 
207 #define __bss16( variable ) \
208  __attribute__ (( section ( ".bss16" ) )) \
209  _data16_ ## variable __asm__ ( #variable )
210 
211 #define __bss16_array( variable, array ) \
212  __attribute__ (( section ( ".bss16" ) )) \
213  _data16_ ## variable array __asm__ ( #variable )
214 
215 #define __text16( variable ) \
216  __attribute__ (( section ( ".text16.data" ) )) \
217  _text16_ ## variable __asm__ ( #variable )
218 
219 #define __text16_array( variable, array ) \
220  __attribute__ (( section ( ".text16.data" ) )) \
221  _text16_ ## variable array __asm__ ( #variable )
222 
223 #define __use_data16( variable ) \
224  ( * ( ( typeof ( _data16_ ## variable ) * ) \
225  & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
226 
227 #define __use_text16( variable ) \
228  ( * ( ( typeof ( _text16_ ## variable ) * ) \
229  & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
230 
231 #define __from_data16( pointer ) \
232  ( ( unsigned int ) \
233  ( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
234 
235 #define __from_text16( pointer ) \
236  ( ( unsigned int ) \
237  ( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
238 
239 /* Variables in librm.S, present in the normal data segment */
240 extern uint16_t rm_sp;
241 extern uint16_t rm_ss;
242 extern const uint16_t __text16 ( rm_cs );
243 #define rm_cs __use_text16 ( rm_cs )
244 extern const uint16_t __text16 ( rm_ds );
245 #define rm_ds __use_text16 ( rm_ds )
246 
248 extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
250 /* CODE_DEFAULT: restore default .code32/.code64 directive */
251 #ifdef __x86_64__
252 #define CODE_DEFAULT ".code64"
253 #else
254 #define CODE_DEFAULT ".code32"
255 #endif
257 /* LINE_SYMBOL: declare a symbol for the current source code line */
258 #define LINE_SYMBOL _S2 ( OBJECT ) "__line_" _S2 ( __LINE__ ) "__%=:"
260 /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
261 #define TEXT16_CODE( asm_code_str ) \
262  ".section \".text16\", \"ax\", @progbits\n\t" \
263  "\n" LINE_SYMBOL "\n\t" \
264  ".code16\n\t" \
265  asm_code_str "\n\t" \
266  CODE_DEFAULT "\n\t" \
267  ".previous\n\t"
268 
269 /* REAL_CODE: declare a fragment of code that executes in real mode */
270 #define REAL_CODE( asm_code_str ) \
271  "push $1f\n\t" \
272  "call real_call\n\t" \
273  TEXT16_CODE ( "\n1:\n\t" \
274  asm_code_str \
275  "\n\t" \
276  "ret\n\t" )
277 
278 /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
279 #define PHYS_CODE( asm_code_str ) \
280  "push $1f\n\t" \
281  "call phys_call\n\t" \
282  ".section \".text.phys\", \"ax\", @progbits\n\t"\
283  "\n" LINE_SYMBOL "\n\t" \
284  ".code32\n\t" \
285  "\n1:\n\t" \
286  asm_code_str \
287  "\n\t" \
288  "ret\n\t" \
289  CODE_DEFAULT "\n\t" \
290  ".previous\n\t"
291 
292 /** Number of interrupts */
293 #define NUM_INT 256
294 
295 /** A 32-bit interrupt descriptor table register */
296 struct idtr32 {
297  /** Limit */
299  /** Base */
301 } __attribute__ (( packed ));
302 
303 /** A 64-bit interrupt descriptor table register */
304 struct idtr64 {
305  /** Limit */
307  /** Base */
309 } __attribute__ (( packed ));
310 
311 /** A 32-bit interrupt descriptor table entry */
313  /** Low 16 bits of address */
315  /** Code segment */
317  /** Unused */
319  /** Type and attributes */
321  /** High 16 bits of address */
323 } __attribute__ (( packed ));
324 
325 /** A 64-bit interrupt descriptor table entry */
327  /** Low 16 bits of address */
329  /** Code segment */
331  /** Unused */
333  /** Type and attributes */
335  /** Middle 16 bits of address */
337  /** High 32 bits of address */
339  /** Reserved */
341 } __attribute__ (( packed ));
342 
343 /** Interrupt descriptor is present */
344 #define IDTE_PRESENT 0x80
345 
346 /** Interrupt descriptor 32-bit interrupt gate type */
347 #define IDTE_TYPE_IRQ32 0x0e
348 
349 /** Interrupt descriptor 64-bit interrupt gate type */
350 #define IDTE_TYPE_IRQ64 0x0e
351 
352 /** An interrupt vector
353  *
354  * Each interrupt vector comprises an eight-byte fragment of code:
355  *
356  * 50 pushl %eax (or pushq %rax in long mode)
357  * b0 xx movb $INT, %al
358  * e9 xx xx xx xx jmp interrupt_wrapper
359  */
361  /** "push" instruction */
363  /** "movb" instruction */
365  /** Interrupt number */
367  /** "jmp" instruction */
369  /** Interrupt wrapper address offset */
371  /** Next instruction after jump */
373 } __attribute__ (( packed ));
374 
375 /** "push %eax" instruction */
376 #define PUSH_INSN 0x50
377 
378 /** "movb" instruction */
379 #define MOVB_INSN 0xb0
380 
381 /** "jmp" instruction */
382 #define JMP_INSN 0xe9
383 
384 /** 32-bit interrupt wrapper stack frame */
402 } __attribute__ (( packed ));
403 
404 /** 64-bit interrupt wrapper stack frame */
426 } __attribute__ (( packed ));
427 
428 extern void set_interrupt_vector ( unsigned int intr, void *vector );
429 
430 /** A page table */
431 struct page_table {
432  /** Page address and flags */
434 };
435 
436 /** Page flags */
438  /** Page is present */
439  PAGE_P = 0x01,
440  /** Page is writable */
441  PAGE_RW = 0x02,
442  /** Page is accessible by user code */
443  PAGE_US = 0x04,
444  /** Page-level write-through */
445  PAGE_PWT = 0x08,
446  /** Page-level cache disable */
447  PAGE_PCD = 0x10,
448  /** Page is a large page */
449  PAGE_PS = 0x80,
450  /** Page is the last page in an allocation
451  *
452  * This bit is ignored by the hardware. We use it to track
453  * the size of allocations made by ioremap().
454  */
455  PAGE_LAST = 0x800,
456 };
457 
458 /** The I/O space page table */
459 extern struct page_table io_pages;
460 
461 /** I/O page size
462  *
463  * We choose to use 2MB pages for I/O space, to minimise the number of
464  * page table entries required.
465  */
466 #define IO_PAGE_SIZE 0x200000UL
467 
468 /** I/O page base address
469  *
470  * We choose to place I/O space immediately above the identity-mapped
471  * 32-bit address space.
472  */
473 #define IO_BASE ( ( void * ) 0x100000000ULL )
474 
475 #endif /* ASSEMBLY */
476 
477 #endif /* LIBRM_H */
uint32_t cs
Definition: librm.h:400
static __always_inline int off_t userptr_t off_t second_off
Definition: librm.h:166
uint64_t rsp
Definition: librm.h:424
unsigned short uint16_t
Definition: stdint.h:11
static __always_inline size_t trivial_strlen_user(userptr_t buffer, off_t offset)
Find length of NUL-terminated string in user buffer.
Definition: uaccess.h:167
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
uint64_t r14
Definition: librm.h:407
uint16_t mid
Middle 16 bits of address.
Definition: librm.h:336
static __always_inline int trivial_memcmp_user(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len)
Compare data between user buffers.
Definition: uaccess.h:140
uint8_t next[0]
Next instruction after jump.
Definition: librm.h:372
char *const data16
Definition: ib_mad.h:19
uint64_t r12
Definition: librm.h:409
uint32_t vector
MSI-X vector.
Definition: ena.h:20
static __always_inline void * trivial_user_to_virt(userptr_t userptr, off_t offset)
Convert user pointer to virtual address.
Definition: uaccess.h:69
uint8_t intr
Interrupt number.
Definition: librm.h:366
off_t memchr_user(userptr_t userptr, off_t offset, int c, size_t len)
Find character in user buffer.
uint32_t es
Definition: librm.h:390
uint64_t rsi
Definition: librm.h:416
uint16_t high
High 16 bits of address.
Definition: librm.h:322
Page-level write-through.
Definition: librm.h:445
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
static __always_inline int off_t first_off
Definition: librm.h:166
static __always_inline void off_t dest_off
Definition: librm.h:152
uint8_t attr
Type and attributes.
Definition: librm.h:320
static __always_inline userptr_t trivial_userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
Definition: uaccess.h:81
unsigned long long uint64_t
Definition: stdint.h:13
userptr_t phys_to_user(unsigned long phys_addr)
Convert physical address to user pointer.
static __always_inline void trivial_memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
Definition: uaccess.h:123
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition: netvsc.h:16
uint64_t r10
Definition: librm.h:411
uint32_t eax
Definition: librm.h:398
static __always_inline userptr_t UACCESS_INLINE(librm, phys_to_user)(unsigned long phys_addr)
Convert physical address to user pointer.
Definition: librm.h:92
uint32_t high
High 32 bits of address.
Definition: librm.h:338
Page-level cache disable.
Definition: librm.h:447
static __always_inline off_t trivial_memchr_user(userptr_t buffer, off_t offset, int c, size_t len)
Find character in user buffer.
Definition: uaccess.h:181
page_flags
Page flags.
Definition: librm.h:437
uint64_t r13
Definition: librm.h:408
uint64_t ss
Definition: librm.h:425
off_t userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
uint64_t rcx
Definition: librm.h:418
char *const text16
uint32_t ds
Definition: librm.h:391
uint64_t r8
Definition: librm.h:413
A 32-bit interrupt descriptor table entry.
Definition: librm.h:312
void memset_user(userptr_t userptr, off_t offset, int c, size_t len)
Fill user buffer with a constant byte.
static __always_inline void off_t userptr_t off_t size_t len
Definition: librm.h:154
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
uint32_t edx
Definition: librm.h:395
uint8_t intr
Interrupt number.
Definition: librm.h:254
uint64_t rax
Definition: librm.h:420
uint8_t unused
Unused.
Definition: librm.h:318
uint32_t fs
Definition: librm.h:389
#define rm_ds
Definition: librm.h:245
uint64_t r9
Definition: librm.h:412
static __always_inline void off_t userptr_t off_t src_off
Definition: librm.h:152
uint8_t movb
"movb" instruction
Definition: librm.h:364
Page is the last page in an allocation.
Definition: librm.h:455
uint32_t ecx
Definition: librm.h:396
uint32_t eip
Definition: librm.h:399
Page is a large page.
Definition: librm.h:449
uint32_t edi
Definition: librm.h:393
static void * dest
Definition: strings.h:176
uint8_t unused
Unused.
Definition: librm.h:332
uint16_t low
Low 16 bits of address.
Definition: librm.h:314
uint32_t esp
Definition: librm.h:386
uint64_t rdx
Definition: librm.h:417
uint64_t r15
Definition: librm.h:406
struct page_table __attribute__
uint16_t limit
Limit.
Definition: librm.h:298
uint16_t rm_ss
#define __always_inline
Declare a function to be always inline.
Definition: compiler.h:611
An interrupt vector.
Definition: librm.h:360
uint32_t ebp
Definition: librm.h:392
uint32_t eflags
Definition: librm.h:401
A 32-bit interrupt descriptor table register.
Definition: librm.h:296
u32 addr
Definition: sky2.h:8
unsigned char uint8_t
Definition: stdint.h:10
static __always_inline void off_t userptr_t src
Definition: librm.h:152
uint8_t push
"push" instruction
Definition: librm.h:362
uint16_t low
Low 16 bits of address.
Definition: librm.h:328
uint16_t copy_user_to_rm_stack(userptr_t data, size_t size)
Allocate space on the real-mode stack and copy data there from a user buffer.
Definition: librm_mgmt.c:64
void set_interrupt_vector(unsigned int intr, void *vector)
Set interrupt vector.
Definition: librm_mgmt.c:93
unsigned int uint32_t
Definition: stdint.h:12
A 64-bit interrupt descriptor table entry.
Definition: librm.h:326
uint64_t rbp
Definition: librm.h:414
uint32_t ss
Definition: librm.h:387
unsigned long physaddr_t
Definition: stdint.h:20
static __always_inline off_t trivial_userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
Definition: uaccess.h:93
size_t strlen_user(userptr_t userptr, off_t offset)
Find length of NUL-terminated string in user buffer.
uint64_t rflags
Definition: librm.h:423
signed long off_t
Definition: stdint.h:8
A page table.
Definition: librm.h:431
32-bit interrupt wrapper stack frame
Definition: librm.h:385
uint32_t esi
Definition: librm.h:394
uint64_t base
Base.
Definition: librm.h:308
uint32_t reserved
Reserved.
Definition: librm.h:340
uint32_t gs
Definition: librm.h:388
uint32_t ebx
Definition: librm.h:397
int memcmp_user(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len)
Compare data between user buffers.
uint64_t cs
Definition: librm.h:422
uint16_t segment
Code segment.
Definition: librm.h:330
uint16_t limit
Limit.
Definition: librm.h:306
static __always_inline void trivial_memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.
Definition: uaccess.h:107
userptr_t virt_to_user(volatile const void *addr)
Convert virtual address to user pointer.
#define __text16(variable)
Definition: librm.h:215
struct page_table io_pages
The I/O space page table.
Page is writable.
Definition: librm.h:441
void * user_to_virt(userptr_t userptr, off_t offset)
Convert user pointer to virtual address.
uint64_t rbx
Definition: librm.h:419
uint8_t size
Entry size (in 32-bit words)
Definition: ena.h:16
uint32_t base
Base.
Definition: librm.h:300
uint16_t rm_sp
const unsigned long virt_offset
uint32_t offset
Interrupt wrapper address offset.
Definition: librm.h:370
void memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
void remove_user_from_rm_stack(userptr_t data, size_t size)
Deallocate space on the real-mode stack, optionally copying back data to a user buffer.
Definition: librm_mgmt.c:79
Page is accessible by user code.
Definition: librm.h:443
uint64_t page[512]
Page address and flags.
Definition: librm.h:433
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint64_t rip
Definition: librm.h:421
static __always_inline off_t userptr_t subtrahend
Definition: librm.h:147
uint8_t jmp
"jmp" instruction
Definition: librm.h:368
static __always_inline unsigned long off_t offset
Interrupt wrapper address offset.
Definition: librm.h:113
static __always_inline userptr_t trivial_virt_to_user(volatile const void *addr)
Convert virtual address to user pointer.
Definition: uaccess.h:55
uint64_t r11
Definition: librm.h:410
static __always_inline int off_t userptr_t second
Definition: librm.h:166
uint8_t attr
Type and attributes.
Definition: librm.h:334
64-bit interrupt wrapper stack frame
Definition: librm.h:405
uint32_t first
Length to skip in first segment.
Definition: pccrc.h:23
A 64-bit interrupt descriptor table register.
Definition: librm.h:304
static __always_inline void off_t int c
Definition: librm.h:173
uint64_t rdi
Definition: librm.h:415
void memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33
uint16_t segment
Code segment.
Definition: librm.h:316
static __always_inline void trivial_memset_user(userptr_t buffer, off_t offset, int c, size_t len)
Fill user buffer with a constant byte.
Definition: uaccess.h:155
#define rm_cs
Definition: librm.h:243
Page is present.
Definition: librm.h:439