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 /**
68  * Call C function from real-mode code
69  *
70  * @v function C function
71  */
72 #define VIRT_CALL( function ) \
73  "pushl $( " _S2 ( VIRTUAL ( function ) ) " )\n\t" \
74  "call virt_call\n\t"
75 
76 /******************************************************************************
77  *
78  * Access to variables in .data16 and .text16
79  *
80  */
81 
82 extern char * const data16;
83 extern char * const text16;
84 
85 #define __data16( variable ) \
86  __attribute__ (( section ( ".data16" ) )) \
87  _data16_ ## variable __asm__ ( #variable )
88 
89 #define __data16_array( variable, array ) \
90  __attribute__ (( section ( ".data16" ) )) \
91  _data16_ ## variable array __asm__ ( #variable )
92 
93 #define __bss16( variable ) \
94  __attribute__ (( section ( ".bss16" ) )) \
95  _data16_ ## variable __asm__ ( #variable )
96 
97 #define __bss16_array( variable, array ) \
98  __attribute__ (( section ( ".bss16" ) )) \
99  _data16_ ## variable array __asm__ ( #variable )
100 
101 #define __text16( variable ) \
102  __attribute__ (( section ( ".text16.data" ) )) \
103  _text16_ ## variable __asm__ ( #variable )
104 
105 #define __text16_array( variable, array ) \
106  __attribute__ (( section ( ".text16.data" ) )) \
107  _text16_ ## variable array __asm__ ( #variable )
108 
109 #define __use_data16( variable ) \
110  ( * ( ( typeof ( _data16_ ## variable ) * ) \
111  & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
112 
113 #define __use_text16( variable ) \
114  ( * ( ( typeof ( _text16_ ## variable ) * ) \
115  & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
116 
117 #define __from_data16( pointer ) \
118  ( ( unsigned int ) \
119  ( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
120 
121 #define __from_text16( pointer ) \
122  ( ( unsigned int ) \
123  ( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
124 
125 /* Variables in librm.S, present in the normal data segment */
126 extern uint16_t rm_sp;
127 extern uint16_t rm_ss;
128 extern const uint16_t __text16 ( rm_cs );
129 #define rm_cs __use_text16 ( rm_cs )
130 extern const uint16_t __text16 ( rm_ds );
131 #define rm_ds __use_text16 ( rm_ds )
132 
133 extern uint16_t copy_to_rm_stack ( const void *data, size_t size );
134 extern void remove_from_rm_stack ( void *data, size_t size );
136 /* CODE_DEFAULT: restore default .code32/.code64 directive */
137 #ifdef __x86_64__
138 #define CODE_DEFAULT ".code64"
139 #define STACK_DEFAULT "q"
140 #else
141 #define CODE_DEFAULT ".code32"
142 #define STACK_DEFAULT "l"
143 #endif
145 /* LINE_SYMBOL: declare a symbol for the current source code line */
146 #define LINE_SYMBOL _S2 ( OBJECT ) "__line_" _S2 ( __LINE__ ) "__%=:"
148 /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
149 #define TEXT16_CODE( asm_code_str ) \
150  ".section \".text16\", \"ax\", @progbits\n\t" \
151  "\n" LINE_SYMBOL "\n\t" \
152  ".code16\n\t" \
153  asm_code_str "\n\t" \
154  CODE_DEFAULT "\n\t" \
155  ".previous\n\t"
156 
157 /* REAL_CODE: declare a fragment of code that executes in real mode */
158 #define REAL_CODE( asm_code_str ) \
159  "push" STACK_DEFAULT " $1f\n\t" \
160  "call real_call\n\t" \
161  TEXT16_CODE ( "\n1:\n\t" \
162  asm_code_str \
163  "\n\t" \
164  "ret\n\t" )
165 
166 /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
167 #define PHYS_CODE( asm_code_str ) \
168  "push" STACK_DEFAULT " $1f\n\t" \
169  "call phys_call\n\t" \
170  ".section \".text.phys\", \"ax\", @progbits\n\t"\
171  "\n" LINE_SYMBOL "\n\t" \
172  ".code32\n\t" \
173  "\n1:\n\t" \
174  asm_code_str \
175  "\n\t" \
176  "ret\n\t" \
177  CODE_DEFAULT "\n\t" \
178  ".previous\n\t"
179 
180 /** Number of interrupts */
181 #define NUM_INT 256
182 
183 /** A 32-bit interrupt descriptor table register */
184 struct idtr32 {
185  /** Limit */
187  /** Base */
189 } __attribute__ (( packed ));
190 
191 /** A 64-bit interrupt descriptor table register */
192 struct idtr64 {
193  /** Limit */
195  /** Base */
197 } __attribute__ (( packed ));
198 
199 /** A 32-bit interrupt descriptor table entry */
201  /** Low 16 bits of address */
203  /** Code segment */
205  /** Unused */
207  /** Type and attributes */
209  /** High 16 bits of address */
211 } __attribute__ (( packed ));
212 
213 /** A 64-bit interrupt descriptor table entry */
215  /** Low 16 bits of address */
217  /** Code segment */
219  /** Unused */
221  /** Type and attributes */
223  /** Middle 16 bits of address */
225  /** High 32 bits of address */
227  /** Reserved */
229 } __attribute__ (( packed ));
230 
231 /** Interrupt descriptor is present */
232 #define IDTE_PRESENT 0x80
233 
234 /** Interrupt descriptor 32-bit interrupt gate type */
235 #define IDTE_TYPE_IRQ32 0x0e
236 
237 /** Interrupt descriptor 64-bit interrupt gate type */
238 #define IDTE_TYPE_IRQ64 0x0e
239 
240 /** An interrupt vector
241  *
242  * Each interrupt vector comprises an eight-byte fragment of code:
243  *
244  * 50 pushl %eax (or pushq %rax in long mode)
245  * b0 xx movb $INT, %al
246  * e9 xx xx xx xx jmp interrupt_wrapper
247  */
249  /** "push" instruction */
251  /** "movb" instruction */
253  /** Interrupt number */
255  /** "jmp" instruction */
257  /** Interrupt wrapper address offset */
259  /** Next instruction after jump */
261 } __attribute__ (( packed ));
262 
263 /** "push %eax" instruction */
264 #define PUSH_INSN 0x50
265 
266 /** "movb" instruction */
267 #define MOVB_INSN 0xb0
268 
269 /** "jmp" instruction */
270 #define JMP_INSN 0xe9
271 
272 /** 32-bit interrupt wrapper stack frame */
290 } __attribute__ (( packed ));
291 
292 /** 64-bit interrupt wrapper stack frame */
314 } __attribute__ (( packed ));
315 
316 extern void set_interrupt_vector ( unsigned int intr, void *vector );
317 
318 /** A page table */
319 struct page_table {
320  /** Page address and flags */
322 };
323 
324 /** Page flags */
326  /** Page is present */
327  PAGE_P = 0x01,
328  /** Page is writable */
329  PAGE_RW = 0x02,
330  /** Page is accessible by user code */
331  PAGE_US = 0x04,
332  /** Page-level write-through */
333  PAGE_PWT = 0x08,
334  /** Page-level cache disable */
335  PAGE_PCD = 0x10,
336  /** Page is a large page */
337  PAGE_PS = 0x80,
338  /** Page is the last page in an allocation
339  *
340  * This bit is ignored by the hardware. We use it to track
341  * the size of allocations made by ioremap().
342  */
343  PAGE_LAST = 0x800,
344 };
345 
346 /** The I/O space page table */
347 extern struct page_table io_pages;
348 
349 /** Maximum number of I/O pages */
350 #define IO_PAGE_COUNT \
351  ( sizeof ( io_pages.page ) / sizeof ( io_pages.page[0] ) )
352 
353 /** I/O page size
354  *
355  * We choose to use 2MB pages for I/O space, to minimise the number of
356  * page table entries required.
357  */
358 #define IO_PAGE_SIZE 0x200000UL
359 
360 /** I/O page base address
361  *
362  * We choose to place I/O space immediately above the identity-mapped
363  * 32-bit address space.
364  */
365 #define IO_BASE ( ( void * ) 0x100000000ULL )
366 
367 /** Startup IPI real-mode handler */
368 extern char __text16_array ( sipi, [] );
369 #define sipi __use_text16 ( sipi )
370 
371 /** Length of startup IPI real-mode handler */
372 extern size_t ABS_SYMBOL ( sipi_len );
373 #define sipi_len ABS_VALUE ( sipi_len )
374 
375 /** Startup IPI real-mode handler copy of real-mode data segment */
376 extern uint16_t __text16 ( sipi_ds );
377 #define sipi_ds __use_text16 ( sipi_ds )
378 
379 /** Startup IPI protected-mode handler (physical address) */
380 extern uint32_t sipi_handler;
381 
382 /** Startup IPI register state */
383 extern struct i386_regs sipi_regs;
384 
385 extern void setup_sipi ( unsigned int vector, uint32_t handler,
386  struct i386_regs *regs );
387 
388 #endif /* ASSEMBLY */
389 
390 #endif /* LIBRM_H */
uint32_t cs
Definition: librm.h:288
uint64_t rsp
Definition: librm.h:312
unsigned short uint16_t
Definition: stdint.h:11
void remove_from_rm_stack(void *data, size_t size)
Deallocate space on the real-mode stack, optionally copying back data.
Definition: librm_mgmt.c:82
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define __text16_array(variable, array)
Definition: librm.h:105
uint64_t r14
Definition: librm.h:295
uint16_t mid
Middle 16 bits of address.
Definition: librm.h:224
uint8_t next[0]
Next instruction after jump.
Definition: librm.h:260
char *const data16
Definition: ib_mad.h:19
uint64_t r12
Definition: librm.h:297
uint32_t vector
MSI-X vector.
Definition: ena.h:20
uint8_t intr
Interrupt number.
Definition: librm.h:254
uint32_t sipi_handler
Startup IPI protected-mode handler (physical address)
uint32_t es
Definition: librm.h:278
uint64_t rsi
Definition: librm.h:304
uint16_t high
High 16 bits of address.
Definition: librm.h:210
Page-level write-through.
Definition: librm.h:333
uint16_t size
Buffer size.
Definition: dwmac.h:14
#define sipi_ds
Definition: librm.h:377
uint8_t attr
Type and attributes.
Definition: librm.h:208
#define sipi_len
Definition: librm.h:373
unsigned long long uint64_t
Definition: stdint.h:13
uint16_t copy_to_rm_stack(const void *data, size_t size)
Allocate space on the real-mode stack and copy data there.
Definition: librm_mgmt.c:67
uint64_t r10
Definition: librm.h:299
uint32_t eax
Definition: librm.h:286
uint32_t high
High 32 bits of address.
Definition: librm.h:226
Page-level cache disable.
Definition: librm.h:335
page_flags
Page flags.
Definition: librm.h:325
uint64_t r13
Definition: librm.h:296
uint64_t ss
Definition: librm.h:313
uint64_t rcx
Definition: librm.h:306
char *const text16
uint32_t ds
Definition: librm.h:279
struct i386_regs sipi_regs
Startup IPI register state.
Definition: librm_mgmt.c:49
uint64_t r8
Definition: librm.h:301
A 32-bit interrupt descriptor table entry.
Definition: librm.h:200
uint32_t edx
Definition: librm.h:283
uint8_t intr
Interrupt number.
Definition: librm.h:140
uint64_t rax
Definition: librm.h:308
uint8_t unused
Unused.
Definition: librm.h:206
size_t ABS_SYMBOL(sipi_len)
Length of startup IPI real-mode handler.
uint32_t fs
Definition: librm.h:277
#define rm_ds
Definition: librm.h:131
uint64_t r9
Definition: librm.h:300
uint8_t movb
"movb" instruction
Definition: librm.h:252
Page is the last page in an allocation.
Definition: librm.h:343
uint32_t ecx
Definition: librm.h:284
uint32_t eip
Definition: librm.h:287
Page is a large page.
Definition: librm.h:337
uint32_t edi
Definition: librm.h:281
uint8_t unused
Unused.
Definition: librm.h:220
uint16_t low
Low 16 bits of address.
Definition: librm.h:202
uint32_t esp
Definition: librm.h:274
uint64_t rdx
Definition: librm.h:305
uint64_t r15
Definition: librm.h:294
struct page_table __attribute__
uint16_t limit
Limit.
Definition: librm.h:186
uint16_t rm_ss
An interrupt vector.
Definition: librm.h:248
uint32_t ebp
Definition: librm.h:280
uint32_t eflags
Definition: librm.h:289
A 32-bit interrupt descriptor table register.
Definition: librm.h:184
unsigned char uint8_t
Definition: stdint.h:10
uint8_t push
"push" instruction
Definition: librm.h:250
uint16_t low
Low 16 bits of address.
Definition: librm.h:216
void set_interrupt_vector(unsigned int intr, void *vector)
Set interrupt vector.
Definition: librm_mgmt.c:98
unsigned int uint32_t
Definition: stdint.h:12
A 64-bit interrupt descriptor table entry.
Definition: librm.h:214
struct i386_regs regs
Definition: registers.h:15
uint64_t rbp
Definition: librm.h:302
A 32-bit general register dump.
Definition: registers.h:62
uint32_t ss
Definition: librm.h:275
void setup_sipi(unsigned int vector, uint32_t handler, struct i386_regs *regs)
Set up startup IPI handler.
Definition: librm_mgmt.c:417
uint64_t rflags
Definition: librm.h:311
A page table.
Definition: librm.h:319
32-bit interrupt wrapper stack frame
Definition: librm.h:273
uint32_t esi
Definition: librm.h:282
uint64_t base
Base.
Definition: librm.h:196
uint32_t reserved
Reserved.
Definition: librm.h:228
uint32_t gs
Definition: librm.h:276
uint32_t ebx
Definition: librm.h:285
uint64_t cs
Definition: librm.h:310
uint16_t segment
Code segment.
Definition: librm.h:218
uint16_t limit
Limit.
Definition: librm.h:194
#define __text16(variable)
Definition: librm.h:101
struct page_table io_pages
The I/O space page table.
Page is writable.
Definition: librm.h:329
uint64_t rbx
Definition: librm.h:307
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint32_t base
Base.
Definition: librm.h:188
uint16_t rm_sp
uint32_t offset
Interrupt wrapper address offset.
Definition: librm.h:258
Page is accessible by user code.
Definition: librm.h:331
#define sipi
Definition: librm.h:369
uint64_t page[512]
Page address and flags.
Definition: librm.h:321
uint64_t rip
Definition: librm.h:309
uint8_t jmp
"jmp" instruction
Definition: librm.h:256
uint64_t r11
Definition: librm.h:298
uint8_t attr
Type and attributes.
Definition: librm.h:222
64-bit interrupt wrapper stack frame
Definition: librm.h:293
A 64-bit interrupt descriptor table register.
Definition: librm.h:192
uint64_t rdi
Definition: librm.h:303
uint16_t segment
Code segment.
Definition: librm.h:204
#define rm_cs
Definition: librm.h:129
Page is present.
Definition: librm.h:327