iPXE
librm.h
Go to the documentation of this file.
00001 #ifndef LIBRM_H
00002 #define LIBRM_H
00003 
00004 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00005 
00006 /* Segment selectors as used in our protected-mode GDTs.
00007  *
00008  * Don't change these unless you really know what you're doing.
00009  */
00010 #define VIRTUAL_CS 0x08
00011 #define VIRTUAL_DS 0x10
00012 #define PHYSICAL_CS 0x18
00013 #define PHYSICAL_DS 0x20
00014 #define REAL_CS 0x28
00015 #define REAL_DS 0x30
00016 #define P2R_DS 0x38
00017 #define LONG_CS 0x40
00018 
00019 /* Calculate symbol address within VIRTUAL_CS or VIRTUAL_DS
00020  *
00021  * In a 64-bit build, we set the bases of VIRTUAL_CS and VIRTUAL_DS
00022  * such that truncating a .textdata symbol value to 32 bits gives a
00023  * valid 32-bit virtual address.
00024  *
00025  * The C code is compiled with -mcmodel=kernel and so we must place
00026  * all .textdata symbols within the negative 2GB of the 64-bit address
00027  * space.  Consequently, all .textdata symbols will have the MSB set
00028  * after truncation to 32 bits.  This means that a straightforward
00029  * R_X86_64_32 relocation record for the symbol will fail, since the
00030  * truncated symbol value will not correctly zero-extend to the
00031  * original 64-bit value.
00032  *
00033  * Using an R_X86_64_32S relocation record would work, but there is no
00034  * (sensible) way to generate these relocation records within 32-bit
00035  * or 16-bit code.
00036  *
00037  * The simplest solution is to generate an R_X86_64_32 relocation
00038  * record with an addend of (-0xffffffff00000000).  Since all
00039  * .textdata symbols are within the negative 2GB of the 64-bit address
00040  * space, this addend acts to effectively truncate the symbol to 32
00041  * bits, thereby matching the semantics of the R_X86_64_32 relocation
00042  * records generated for 32-bit and 16-bit code.
00043  *
00044  * In a 32-bit build, this problem does not exist, and we can just use
00045  * the .textdata symbol values directly.
00046  */
00047 #ifdef __x86_64__
00048 #define VIRTUAL(address) ( (address) - 0xffffffff00000000 )
00049 #else
00050 #define VIRTUAL(address) (address)
00051 #endif
00052 
00053 #ifdef ASSEMBLY
00054 
00055 /**
00056  * Call C function from real-mode code
00057  *
00058  * @v function          C function
00059  */
00060 .macro virtcall function
00061         pushl   $VIRTUAL(\function)
00062         call    virt_call
00063 .endm
00064 
00065 #else /* ASSEMBLY */
00066 
00067 #ifdef UACCESS_LIBRM
00068 #define UACCESS_PREFIX_librm
00069 #else
00070 #define UACCESS_PREFIX_librm __librm_
00071 #endif
00072 
00073 /**
00074  * Call C function from real-mode code
00075  *
00076  * @v function          C function
00077  */
00078 #define VIRT_CALL( function )                                           \
00079         "pushl $( " _S2 ( VIRTUAL ( function ) ) " )\n\t"               \
00080         "call virt_call\n\t"
00081 
00082 /* Variables in librm.S */
00083 extern const unsigned long virt_offset;
00084 
00085 /**
00086  * Convert physical address to user pointer
00087  *
00088  * @v phys_addr         Physical address
00089  * @ret userptr         User pointer
00090  */
00091 static inline __always_inline userptr_t
00092 UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
00093 
00094         /* In a 64-bit build, any valid physical address is directly
00095          * usable as a virtual address, since the low 4GB is
00096          * identity-mapped.
00097          */
00098         if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
00099                 return phys_addr;
00100 
00101         /* In a 32-bit build, subtract virt_offset */
00102         return ( phys_addr - virt_offset );
00103 }
00104 
00105 /**
00106  * Convert user buffer to physical address
00107  *
00108  * @v userptr           User pointer
00109  * @v offset            Offset from user pointer
00110  * @ret phys_addr       Physical address
00111  */
00112 static inline __always_inline unsigned long
00113 UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
00114         unsigned long addr = ( userptr + offset );
00115 
00116         /* In a 64-bit build, any virtual address in the low 4GB is
00117          * directly usable as a physical address, since the low 4GB is
00118          * identity-mapped.
00119          */
00120         if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) &&
00121              ( addr <= 0xffffffffUL ) )
00122                 return addr;
00123 
00124         /* In a 32-bit build or in a 64-bit build with a virtual
00125          * address above 4GB: add virt_offset
00126          */
00127         return ( addr + virt_offset );
00128 }
00129 
00130 static inline __always_inline userptr_t
00131 UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
00132         return trivial_virt_to_user ( addr );
00133 }
00134 
00135 static inline __always_inline void *
00136 UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
00137         return trivial_user_to_virt ( userptr, offset );
00138 }
00139 
00140 static inline __always_inline userptr_t
00141 UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
00142         return trivial_userptr_add ( userptr, offset );
00143 }
00144 
00145 static inline __always_inline off_t
00146 UACCESS_INLINE ( librm, userptr_sub ) ( userptr_t userptr,
00147                                         userptr_t subtrahend ) {
00148         return trivial_userptr_sub ( userptr, subtrahend );
00149 }
00150 
00151 static inline __always_inline void
00152 UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
00153                                         userptr_t src, off_t src_off,
00154                                         size_t len ) {
00155         trivial_memcpy_user ( dest, dest_off, src, src_off, len );
00156 }
00157 
00158 static inline __always_inline void
00159 UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
00160                                          userptr_t src, off_t src_off,
00161                                          size_t len ) {
00162         trivial_memmove_user ( dest, dest_off, src, src_off, len );
00163 }
00164 
00165 static inline __always_inline int
00166 UACCESS_INLINE ( librm, memcmp_user ) ( userptr_t first, off_t first_off,
00167                                         userptr_t second, off_t second_off,
00168                                         size_t len ) {
00169         return trivial_memcmp_user ( first, first_off, second, second_off, len);
00170 }
00171 
00172 static inline __always_inline void
00173 UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
00174                                         int c, size_t len ) {
00175         trivial_memset_user ( buffer, offset, c, len );
00176 }
00177 
00178 static inline __always_inline size_t
00179 UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
00180         return trivial_strlen_user ( buffer, offset );
00181 }
00182 
00183 static inline __always_inline off_t
00184 UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
00185                                         int c, size_t len ) {
00186         return trivial_memchr_user ( buffer, offset, c, len );
00187 }
00188 
00189 
00190 /******************************************************************************
00191  *
00192  * Access to variables in .data16 and .text16
00193  *
00194  */
00195 
00196 extern char * const data16;
00197 extern char * const text16;
00198 
00199 #define __data16( variable )                                            \
00200         __attribute__ (( section ( ".data16" ) ))                       \
00201         _data16_ ## variable __asm__ ( #variable )
00202 
00203 #define __data16_array( variable, array )                               \
00204         __attribute__ (( section ( ".data16" ) ))                       \
00205         _data16_ ## variable array __asm__ ( #variable )
00206 
00207 #define __bss16( variable )                                             \
00208         __attribute__ (( section ( ".bss16" ) ))                        \
00209         _data16_ ## variable __asm__ ( #variable )
00210 
00211 #define __bss16_array( variable, array )                                \
00212         __attribute__ (( section ( ".bss16" ) ))                        \
00213         _data16_ ## variable array __asm__ ( #variable )
00214 
00215 #define __text16( variable )                                            \
00216         __attribute__ (( section ( ".text16.data" ) ))                  \
00217         _text16_ ## variable __asm__ ( #variable )
00218 
00219 #define __text16_array( variable, array )                               \
00220         __attribute__ (( section ( ".text16.data" ) ))                  \
00221         _text16_ ## variable array __asm__ ( #variable )
00222 
00223 #define __use_data16( variable )                                        \
00224         ( * ( ( typeof ( _data16_ ## variable ) * )                     \
00225               & ( data16 [ ( size_t ) & ( _data16_ ## variable ) ] ) ) )
00226 
00227 #define __use_text16( variable )                                        \
00228         ( * ( ( typeof ( _text16_ ## variable ) * )                     \
00229               & ( text16 [ ( size_t ) & ( _text16_ ## variable ) ] ) ) )
00230 
00231 #define __from_data16( pointer )                                        \
00232         ( ( unsigned int )                                              \
00233           ( ( ( void * ) (pointer) ) - ( ( void * ) data16 ) ) )
00234 
00235 #define __from_text16( pointer )                                        \
00236         ( ( unsigned int )                                              \
00237           ( ( ( void * ) (pointer) ) - ( ( void * ) text16 ) ) )
00238 
00239 /* Variables in librm.S, present in the normal data segment */
00240 extern uint16_t rm_sp;
00241 extern uint16_t rm_ss;
00242 extern const uint16_t __text16 ( rm_cs );
00243 #define rm_cs __use_text16 ( rm_cs )
00244 extern const uint16_t __text16 ( rm_ds );
00245 #define rm_ds __use_text16 ( rm_ds )
00246 
00247 extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
00248 extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
00249 
00250 /* CODE_DEFAULT: restore default .code32/.code64 directive */
00251 #ifdef __x86_64__
00252 #define CODE_DEFAULT ".code64"
00253 #else
00254 #define CODE_DEFAULT ".code32"
00255 #endif
00256 
00257 /* LINE_SYMBOL: declare a symbol for the current source code line */
00258 #define LINE_SYMBOL _S2 ( OBJECT ) "__line_" _S2 ( __LINE__ ) "__%=:"
00259 
00260 /* TEXT16_CODE: declare a fragment of code that resides in .text16 */
00261 #define TEXT16_CODE( asm_code_str )                     \
00262         ".section \".text16\", \"ax\", @progbits\n\t"   \
00263         "\n" LINE_SYMBOL "\n\t"                         \
00264         ".code16\n\t"                                   \
00265         asm_code_str "\n\t"                             \
00266         CODE_DEFAULT "\n\t"                             \
00267         ".previous\n\t"
00268 
00269 /* REAL_CODE: declare a fragment of code that executes in real mode */
00270 #define REAL_CODE( asm_code_str )                       \
00271         "push $1f\n\t"                                  \
00272         "call real_call\n\t"                            \
00273         TEXT16_CODE ( "\n1:\n\t"                        \
00274                       asm_code_str                      \
00275                       "\n\t"                            \
00276                       "ret\n\t" )
00277 
00278 /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
00279 #define PHYS_CODE( asm_code_str )                       \
00280         "push $1f\n\t"                                  \
00281         "call phys_call\n\t"                            \
00282         ".section \".text.phys\", \"ax\", @progbits\n\t"\
00283         "\n" LINE_SYMBOL "\n\t"                         \
00284         ".code32\n\t"                                   \
00285         "\n1:\n\t"                                      \
00286         asm_code_str                                    \
00287         "\n\t"                                          \
00288         "ret\n\t"                                       \
00289         CODE_DEFAULT "\n\t"                             \
00290         ".previous\n\t"
00291 
00292 /** Number of interrupts */
00293 #define NUM_INT 256
00294 
00295 /** A 32-bit interrupt descriptor table register */
00296 struct idtr32 {
00297         /** Limit */
00298         uint16_t limit;
00299         /** Base */
00300         uint32_t base;
00301 } __attribute__ (( packed ));
00302 
00303 /** A 64-bit interrupt descriptor table register */
00304 struct idtr64 {
00305         /** Limit */
00306         uint16_t limit;
00307         /** Base */
00308         uint64_t base;
00309 } __attribute__ (( packed ));
00310 
00311 /** A 32-bit interrupt descriptor table entry */
00312 struct interrupt32_descriptor {
00313         /** Low 16 bits of address */
00314         uint16_t low;
00315         /** Code segment */
00316         uint16_t segment;
00317         /** Unused */
00318         uint8_t unused;
00319         /** Type and attributes */
00320         uint8_t attr;
00321         /** High 16 bits of address */
00322         uint16_t high;
00323 } __attribute__ (( packed ));
00324 
00325 /** A 64-bit interrupt descriptor table entry */
00326 struct interrupt64_descriptor {
00327         /** Low 16 bits of address */
00328         uint16_t low;
00329         /** Code segment */
00330         uint16_t segment;
00331         /** Unused */
00332         uint8_t unused;
00333         /** Type and attributes */
00334         uint8_t attr;
00335         /** Middle 16 bits of address */
00336         uint16_t mid;
00337         /** High 32 bits of address */
00338         uint32_t high;
00339         /** Reserved */
00340         uint32_t reserved;
00341 } __attribute__ (( packed ));
00342 
00343 /** Interrupt descriptor is present */
00344 #define IDTE_PRESENT 0x80
00345 
00346 /** Interrupt descriptor 32-bit interrupt gate type */
00347 #define IDTE_TYPE_IRQ32 0x0e
00348 
00349 /** Interrupt descriptor 64-bit interrupt gate type */
00350 #define IDTE_TYPE_IRQ64 0x0e
00351 
00352 /** An interrupt vector
00353  *
00354  * Each interrupt vector comprises an eight-byte fragment of code:
00355  *
00356  *   50                 pushl %eax (or pushq %rax in long mode)
00357  *   b0 xx              movb $INT, %al
00358  *   e9 xx xx xx xx     jmp interrupt_wrapper
00359  */
00360 struct interrupt_vector {
00361         /** "push" instruction */
00362         uint8_t push;
00363         /** "movb" instruction */
00364         uint8_t movb;
00365         /** Interrupt number */
00366         uint8_t intr;
00367         /** "jmp" instruction */
00368         uint8_t jmp;
00369         /** Interrupt wrapper address offset */
00370         uint32_t offset;
00371         /** Next instruction after jump */
00372         uint8_t next[0];
00373 } __attribute__ (( packed ));
00374 
00375 /** "push %eax" instruction */
00376 #define PUSH_INSN 0x50
00377 
00378 /** "movb" instruction */
00379 #define MOVB_INSN 0xb0
00380 
00381 /** "jmp" instruction */
00382 #define JMP_INSN 0xe9
00383 
00384 /** 32-bit interrupt wrapper stack frame */
00385 struct interrupt_frame32 {
00386         uint32_t esp;
00387         uint32_t ss;
00388         uint32_t gs;
00389         uint32_t fs;
00390         uint32_t es;
00391         uint32_t ds;
00392         uint32_t ebp;
00393         uint32_t edi;
00394         uint32_t esi;
00395         uint32_t edx;
00396         uint32_t ecx;
00397         uint32_t ebx;
00398         uint32_t eax;
00399         uint32_t eip;
00400         uint32_t cs;
00401         uint32_t eflags;
00402 } __attribute__ (( packed ));
00403 
00404 /** 64-bit interrupt wrapper stack frame */
00405 struct interrupt_frame64 {
00406         uint64_t r15;
00407         uint64_t r14;
00408         uint64_t r13;
00409         uint64_t r12;
00410         uint64_t r11;
00411         uint64_t r10;
00412         uint64_t r9;
00413         uint64_t r8;
00414         uint64_t rbp;
00415         uint64_t rdi;
00416         uint64_t rsi;
00417         uint64_t rdx;
00418         uint64_t rcx;
00419         uint64_t rbx;
00420         uint64_t rax;
00421         uint64_t rip;
00422         uint64_t cs;
00423         uint64_t rflags;
00424         uint64_t rsp;
00425         uint64_t ss;
00426 } __attribute__ (( packed ));
00427 
00428 extern void set_interrupt_vector ( unsigned int intr, void *vector );
00429 
00430 /** A page table */
00431 struct page_table {
00432         /** Page address and flags */
00433         uint64_t page[512];
00434 };
00435 
00436 /** Page flags */
00437 enum page_flags {
00438         /** Page is present */
00439         PAGE_P = 0x01,
00440         /** Page is writable */
00441         PAGE_RW = 0x02,
00442         /** Page is accessible by user code */
00443         PAGE_US = 0x04,
00444         /** Page-level write-through */
00445         PAGE_PWT = 0x08,
00446         /** Page-level cache disable */
00447         PAGE_PCD = 0x10,
00448         /** Page is a large page */
00449         PAGE_PS = 0x80,
00450         /** Page is the last page in an allocation
00451          *
00452          * This bit is ignored by the hardware.  We use it to track
00453          * the size of allocations made by ioremap().
00454          */
00455         PAGE_LAST = 0x800,
00456 };
00457 
00458 /** The I/O space page table */
00459 extern struct page_table io_pages;
00460 
00461 /** I/O page size
00462  *
00463  * We choose to use 2MB pages for I/O space, to minimise the number of
00464  * page table entries required.
00465  */
00466 #define IO_PAGE_SIZE 0x200000UL
00467 
00468 /** I/O page base address
00469  *
00470  * We choose to place I/O space immediately above the identity-mapped
00471  * 32-bit address space.
00472  */
00473 #define IO_BASE ( ( void * ) 0x100000000ULL )
00474 
00475 #endif /* ASSEMBLY */
00476 
00477 #endif /* LIBRM_H */