diff --git a/src/arch/i386/core/gdbidt.S b/src/arch/i386/core/gdbidt.S index 860f7b01..64c29e4b 100644 --- a/src/arch/i386/core/gdbidt.S +++ b/src/arch/i386/core/gdbidt.S @@ -2,7 +2,7 @@ * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub. */ -#include +#include #define SIZEOF_I386_REGS 32 #define SIZEOF_I386_FLAGS 4 diff --git a/src/arch/i386/core/gdbmach.c b/src/arch/i386/core/gdbmach.c index 5e72e4d0..d07663c4 100644 --- a/src/arch/i386/core/gdbmach.c +++ b/src/arch/i386/core/gdbmach.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/arch/i386/core/pic8259.c b/src/arch/i386/core/pic8259.c index defe2e7d..8a0433dd 100644 --- a/src/arch/i386/core/pic8259.c +++ b/src/arch/i386/core/pic8259.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include /** @file diff --git a/src/arch/i386/core/start32.S b/src/arch/i386/core/start32.S deleted file mode 100644 index 37ef5eb9..00000000 --- a/src/arch/i386/core/start32.S +++ /dev/null @@ -1,325 +0,0 @@ -#include "virtaddr.h" - - .equ MSR_K6_EFER, 0xC0000080 - .equ EFER_LME, 0x00000100 - .equ X86_CR4_PAE, 0x00000020 - .equ CR0_PG, 0x80000000 - -#ifdef GAS291 -#define DATA32 data32; -#define ADDR32 addr32; -#define LJMPI(x) ljmp x -#else -#define DATA32 data32 -#define ADDR32 addr32 -/* newer GAS295 require #define LJMPI(x) ljmp *x */ -#define LJMPI(x) ljmp x -#endif - -/* - * NOTE: if you write a subroutine that is called from C code (gcc/egcs), - * then you only have to take care of %ebx, %esi, %edi and %ebp. These - * registers must not be altered under any circumstance. All other registers - * may be clobbered without any negative side effects. If you don't follow - * this rule then you'll run into strange effects that only occur on some - * gcc versions (because the register allocator may use different registers). - * - * All the data32 prefixes for the ljmp instructions are necessary, because - * the assembler emits code with a relocation address of 0. This means that - * all destinations are initially negative, which the assembler doesn't grok, - * because for some reason negative numbers don't fit into 16 bits. The addr32 - * prefixes are there for the same reasons, because otherwise the memory - * references are only 16 bit wide. Theoretically they are all superfluous. - * One last note about prefixes: the data32 prefixes on all call _real_to_prot - * instructions could be removed if the _real_to_prot function is changed to - * deal correctly with 16 bit return addresses. I tried it, but failed. - */ - - .text - .arch i386 - .code32 - - /* This is a struct os_entry_regs */ - .globl os_regs -os_regs: .space 56 - -/************************************************************************** -XSTART32 - Transfer control to the kernel just loaded -**************************************************************************/ - .globl xstart32 -xstart32: - /* Save the callee save registers */ - movl %ebp, os_regs + 32 - movl %esi, os_regs + 36 - movl %edi, os_regs + 40 - movl %ebx, os_regs + 44 - - /* save the return address */ - popl %eax - movl %eax, os_regs + 48 - - /* save the stack pointer */ - movl %esp, os_regs + 52 - - /* Get the new destination address */ - popl %ecx - - /* Store the physical address of xend on the stack */ - movl $xend32, %ebx - addl virt_offset, %ebx - pushl %ebx - - /* Store the destination address on the stack */ - pushl $PHYSICAL_CS - pushl %ecx - - /* Cache virt_offset */ - movl virt_offset, %ebp - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Save the target stack pointer */ - movl %esp, os_regs + 12(%ebp) - leal os_regs(%ebp), %esp - - /* Store the pointer to os_regs */ - movl %esp, os_regs_ptr(%ebp) - - /* Load my new registers */ - popal - movl (-32 + 12)(%esp), %esp - - /* Jump to the new kernel - * The lret switches to a flat code segment - */ - lret - - .balign 4 - .globl xend32 -xend32: - /* Fixup %eflags */ - nop - cli - cld - - /* Load %esp with &os_regs + virt_offset */ - .byte 0xbc /* movl $0, %esp */ -os_regs_ptr: - .long 0 - - /* Save the result registers */ - addl $32, %esp - pushal - - /* Compute virt_offset */ - movl %esp, %ebp - subl $os_regs, %ebp - - /* Load the stack pointer and convert it to physical address */ - movl 52(%esp), %esp - addl %ebp, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - movl os_regs + 32, %ebp - movl os_regs + 36, %esi - movl os_regs + 40, %edi - movl os_regs + 44, %ebx - movl os_regs + 48, %edx - movl os_regs + 52, %esp - - /* Get the C return value */ - movl os_regs + 28, %eax - - jmpl *%edx - -#ifdef CONFIG_X86_64 - .arch sledgehammer -/************************************************************************** -XSTART_lm - Transfer control to the kernel just loaded in long mode -**************************************************************************/ - .globl xstart_lm -xstart_lm: - /* Save the callee save registers */ - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - - /* Cache virt_offset && (virt_offset & 0xfffff000) */ - movl virt_offset, %ebp - movl %ebp, %ebx - andl $0xfffff000, %ebx - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Initialize the page tables */ - /* Level 4 */ - leal 0x23 + pgt_level3(%ebx), %eax - leal pgt_level4(%ebx), %edi - movl %eax, (%edi) - - /* Level 3 */ - leal 0x23 + pgt_level2(%ebx), %eax - leal pgt_level3(%ebx), %edi - movl %eax, 0x00(%edi) - addl $4096, %eax - movl %eax, 0x08(%edi) - addl $4096, %eax - movl %eax, 0x10(%edi) - addl $4096, %eax - movl %eax, 0x18(%edi) - - /* Level 2 */ - movl $0xe3, %eax - leal pgt_level2(%ebx), %edi - leal 16384(%edi), %esi -pgt_level2_loop: - movl %eax, (%edi) - addl $8, %edi - addl $0x200000, %eax - cmp %esi, %edi - jne pgt_level2_loop - - /* Point at the x86_64 page tables */ - leal pgt_level4(%ebx), %edi - movl %edi, %cr3 - - - /* Setup for the return from 64bit mode */ - /* 64bit align the stack */ - movl %esp, %ebx /* original stack pointer + 16 */ - andl $0xfffffff8, %esp - - /* Save original stack pointer + 16 */ - pushl %ebx - - /* Save virt_offset */ - pushl %ebp - - /* Setup for the jmp to 64bit long mode */ - leal start_lm(%ebp), %eax - movl %eax, 0x00 + start_lm_addr(%ebp) - movl $LM_CODE_SEG, %eax - movl %eax, 0x04 + start_lm_addr(%ebp) - - /* Setup for the jump out of 64bit long mode */ - leal end_lm(%ebp), %eax - movl %eax, 0x00 + end_lm_addr(%ebp) - movl $FLAT_CODE_SEG, %eax - movl %eax, 0x04 + end_lm_addr(%ebp) - - /* Enable PAE mode */ - movl %cr4, %eax - orl $X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Enable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Start paging, entering 32bit compatiblity mode */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Enter 64bit long mode */ - ljmp *start_lm_addr(%ebp) - .code64 -start_lm: - /* Load 64bit data segments */ - movl $LM_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - andq $0xffffffff, %rbx - /* Get the address to jump to */ - movl 20(%rbx), %edx - andq $0xffffffff, %rdx - - /* Get the argument pointer */ - movl 24(%rbx), %ebx - andq $0xffffffff, %rbx - - /* Jump to the 64bit code */ - call *%rdx - - /* Preserve the result */ - movl %eax, %edx - - /* Fixup %eflags */ - cli - cld - - /* Switch to 32bit compatibility mode */ - ljmp *end_lm_addr(%rip) - - .code32 -end_lm: - /* Disable paging */ - movl %cr0, %eax - andl $~CR0_PG, %eax - movl %eax, %cr0 - - /* Disable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - andl $~EFER_LME, %eax - wrmsr - - /* Disable PAE */ - movl %cr4, %eax - andl $~X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Compute virt_offset */ - popl %ebp - - /* Compute the original stack pointer + 16 */ - popl %ebx - movl %ebx, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - popl %ebx - popl %esi - popl %edi - popl %ebp - - /* Get the C return value */ - movl %edx, %eax - - /* Return */ - ret - - .arch i386 -#endif /* CONFIG_X86_64 */ - -#ifdef CONFIG_X86_64 - .section ".bss" - .p2align 12 - /* Include a dummy space in case we are loaded badly aligned */ - .space 4096 - /* Reserve enough space for a page table convering 4GB with 2MB pages */ -pgt_level4: - .space 4096 -pgt_level3: - .space 4096 -pgt_level2: - .space 16384 -start_lm_addr: - .space 8 -end_lm_addr: - .space 8 -#endif diff --git a/src/arch/i386/core/virtaddr.S b/src/arch/i386/core/virtaddr.S index 5d762375..cf6da4f6 100644 --- a/src/arch/i386/core/virtaddr.S +++ b/src/arch/i386/core/virtaddr.S @@ -4,7 +4,7 @@ * */ -#include "virtaddr.h" +#include "librm.h" .arch i386 .text diff --git a/src/arch/i386/core/x86_io.c b/src/arch/i386/core/x86_io.c index 1aab6c96..424a96cc 100644 --- a/src/arch/i386/core/x86_io.c +++ b/src/arch/i386/core/x86_io.c @@ -65,10 +65,8 @@ static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) { : : "A" ( data ), "r" ( io_addr ) ); } -PROVIDE_IOAPI_INLINE ( x86, virt_to_phys ); -PROVIDE_IOAPI_INLINE ( x86, phys_to_virt ); -PROVIDE_IOAPI_INLINE ( x86, virt_to_bus ); -PROVIDE_IOAPI_INLINE ( x86, bus_to_virt ); +PROVIDE_IOAPI_INLINE ( x86, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, bus_to_phys ); PROVIDE_IOAPI_INLINE ( x86, ioremap ); PROVIDE_IOAPI_INLINE ( x86, iounmap ); PROVIDE_IOAPI_INLINE ( x86, io_to_bus ); diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index 12b954c0..229fde02 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/arch/i386/firmware/pcbios/gateA20.c b/src/arch/i386/firmware/pcbios/gateA20.c index 91135247..34e3ac52 100644 --- a/src/arch/i386/firmware/pcbios/gateA20.c +++ b/src/arch/i386/firmware/pcbios/gateA20.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ diff --git a/src/arch/i386/include/bits/uaccess.h b/src/arch/i386/include/bits/uaccess.h index 9c6d0c21..0ecc5028 100644 --- a/src/arch/i386/include/bits/uaccess.h +++ b/src/arch/i386/include/bits/uaccess.h @@ -1,6 +1,12 @@ #ifndef _BITS_UACCESS_H #define _BITS_UACCESS_H -#include +/** @file + * + * i386-specific user access API implementations + * + */ + +#include #endif /* _BITS_UACCESS_H */ diff --git a/src/arch/i386/include/gpxe/x86_io.h b/src/arch/i386/include/gpxe/x86_io.h index 8b9942e6..0ecedfef 100644 --- a/src/arch/i386/include/gpxe/x86_io.h +++ b/src/arch/i386/include/gpxe/x86_io.h @@ -15,8 +15,6 @@ * into a machine with such an old CPU anyway. */ -#include - #ifdef IOAPI_X86 #define IOAPI_PREFIX_x86 #else @@ -28,24 +26,19 @@ * */ -static inline __always_inline unsigned long -IOAPI_INLINE ( x86, virt_to_phys ) ( volatile const void *addr ) { - return ( ( ( unsigned long ) addr ) + virt_offset ); -} +/* + * Physical<->Bus and Bus<->I/O address mappings + * + */ -static inline __always_inline void * -IOAPI_INLINE ( x86, phys_to_virt ) ( unsigned long phys_addr ) { - return ( ( void * ) ( phys_addr - virt_offset ) ); +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; } static inline __always_inline unsigned long -IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) { - return virt_to_phys ( addr ); -} - -static inline __always_inline void * -IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) { - return phys_to_virt ( bus_addr ); +IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; } static inline __always_inline void * diff --git a/src/arch/i386/include/int13.h b/src/arch/i386/include/int13.h index 72ca97d7..bf6d0318 100644 --- a/src/arch/i386/include/int13.h +++ b/src/arch/i386/include/int13.h @@ -9,6 +9,7 @@ #include #include +#include struct block_device; diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h index 07a85c59..9eb2767a 100755 --- a/src/arch/i386/include/librm.h +++ b/src/arch/i386/include/librm.h @@ -1,21 +1,109 @@ #ifndef LIBRM_H #define LIBRM_H -/* Drag in protected-mode segment selector values */ -#include "virtaddr.h" -#include "realmode.h" +/* Segment selectors as used in our protected-mode GDTs. + * + * Don't change these unless you really know what you're doing. + */ + +#define VIRTUAL_CS 0x08 +#define VIRTUAL_DS 0x10 +#define PHYSICAL_CS 0x18 +#define PHYSICAL_DS 0x20 +#define REAL_CS 0x28 +#define REAL_DS 0x30 +#if 0 +#define LONG_CS 0x38 +#define LONG_DS 0x40 +#endif #ifndef ASSEMBLY -#include "stddef.h" -#include "string.h" +#ifdef UACCESS_LIBRM +#define UACCESS_PREFIX_librm +#else +#define UACCESS_PREFIX_librm __librm_ +#endif -/* - * Data structures and type definitions +/* Variables in librm.S */ +extern unsigned long virt_offset; + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) { + return ( phys_addr - virt_offset ); +} + +/** + * Convert user buffer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) { + return ( userptr + offset + virt_offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) { + return trivial_virt_to_user ( addr ); +} + +static inline __always_inline void * +UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) { + return trivial_user_to_virt ( userptr, offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) { + return trivial_userptr_add ( userptr, offset ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memcpy_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memmove_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + trivial_memset_user ( buffer, offset, c, len ); +} + +static inline __always_inline size_t +UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) { + return trivial_strlen_user ( buffer, offset ); +} + +static inline __always_inline off_t +UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + return trivial_memchr_user ( buffer, offset, c, len ); +} + + +/****************************************************************************** + * + * Access to variables in .data16 and .text16 * */ -/* Access to variables in .data16 and .text16 */ extern char *data16; extern char *text16; @@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds ); */ extern void gateA20_set ( void ); -/* - * librm_mgmt: functions for manipulating base memory and executing - * real-mode code. - * - * Full API documentation for these functions is in realmode.h. - * - */ - -/* Macro for obtaining a physical address from a segment:offset pair. */ -#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) ) - -/* Copy to/from base memory */ -static inline __attribute__ (( always_inline )) void -copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off, - void *src, size_t n ) { - memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n ); -} -static inline __attribute__ (( always_inline )) void -copy_from_real_librm ( void *dest, unsigned int src_seg, - unsigned int src_off, size_t n ) { - memcpy ( dest, VIRTUAL ( src_seg, src_off ), n ); -} -#define put_real_librm( var, dest_seg, dest_off ) \ - do { \ - * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \ - } while ( 0 ) -#define get_real_librm( var, src_seg, src_off ) \ - do { \ - var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \ - } while ( 0 ) -#define copy_to_real copy_to_real_librm -#define copy_from_real copy_from_real_librm -#define put_real put_real_librm -#define get_real get_real_librm - -/** - * A pointer to a user buffer - * - * Even though we could just use a void *, we use an intptr_t so that - * attempts to use normal pointers show up as compiler warnings. Such - * code is actually valid for librm, but not for libkir (i.e. under - * KEEP_IT_REAL), so it's good to have the warnings even under librm. - */ -typedef intptr_t userptr_t; - -/** - * Add offset to user pointer - * - * @v ptr User pointer - * @v offset Offset - * @ret new_ptr New pointer value - */ -static inline __attribute__ (( always_inline )) userptr_t -userptr_add ( userptr_t ptr, off_t offset ) { - return ( ptr + offset ); -} - -/** - * Copy data to user buffer - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @v src Source - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) { - memcpy ( ( ( void * ) buffer + offset ), src, len ); -} - -/** - * Copy data from user buffer - * - * @v dest Destination - * @v buffer User buffer - * @v offset Offset within user buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) { - memcpy ( dest, ( ( void * ) buffer + offset ), len ); -} - -/** - * Copy data between user buffers - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Copy data between user buffers, allowing for overlap - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Fill user buffer with a constant byte - * - * @v buffer User buffer - * @v offset Offset within buffer - * @v c Constant byte with which to fill - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - memset ( ( ( void * ) buffer + offset ), c, len ); -} - -/** - * Find length of NUL-terminated string in user buffer - * - * @v buffer User buffer - * @v offset Offset within buffer - * @ret len Length of string (excluding NUL) - */ -static inline __attribute__ (( always_inline )) size_t -strlen_user ( userptr_t buffer, off_t offset ) { - return strlen ( ( void * ) buffer + offset ); -} - -/** - * Find character in user buffer - * - * @v buffer User buffer - * @v offset Starting offset within buffer - * @v c Character to search for - * @v len Length of user buffer - * @ret offset Offset of character, or <0 if not found - */ -static inline __attribute__ (( always_inline )) off_t -memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - void *found; - - found = memchr ( ( ( void * ) buffer + offset ), c, len ); - return ( found ? ( found - ( void * ) buffer ) : -1 ); -} - -/** - * Convert virtual address to user buffer - * - * @v virtual Virtual address - * @ret buffer User buffer - * - * This constructs a user buffer from an ordinary pointer. Use it - * when you need to pass a pointer to an internal buffer to a function - * that expects a @c userptr_t. - */ -static inline __attribute__ (( always_inline )) userptr_t -virt_to_user ( void * virtual ) { - return ( ( intptr_t ) virtual ); -} - /** * Convert segment:offset address to user buffer * @@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) { * @v offset Real-mode offset * @ret buffer User buffer */ -static inline __attribute__ (( always_inline )) userptr_t +static inline __always_inline userptr_t real_to_user ( unsigned int segment, unsigned int offset ) { - return virt_to_user ( VIRTUAL ( segment, offset ) ); -} - -/** - * Convert physical address to user buffer - * - * @v physical Physical address - * @ret buffer User buffer - */ -static inline __attribute__ (( always_inline )) userptr_t -phys_to_user ( physaddr_t physical ) { - return virt_to_user ( phys_to_virt ( physical ) ); -} - -/** - * Convert user buffer to physical address - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @ret physical Physical address - */ -static inline __attribute__ (( always_inline )) physaddr_t -user_to_phys ( userptr_t buffer, off_t offset ) { - return virt_to_phys ( ( void * ) buffer + offset ); + return ( phys_to_user ( ( segment << 4 ) + offset ) ); } extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ); diff --git a/src/arch/i386/include/pxe_addr.h b/src/arch/i386/include/pxe_addr.h deleted file mode 100644 index 954551e8..00000000 --- a/src/arch/i386/include/pxe_addr.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Architecture-specific portion of pxe.h for Etherboot - * - * This file has to define the types SEGOFF16_t, SEGDESC_t and - * SEGSEL_t for use in other PXE structures. See pxe.h for details. - */ - -#ifndef PXE_ADDR_H -#define PXE_ADDR_H - -#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) ) -#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) ) -#define PTR_TO_SEGOFF16(ptr,segoff16) \ - (segoff16).segment = SEGMENT(ptr); \ - (segoff16).offset = OFFSET(ptr); - -#endif /* PXE_ADDR_H */ diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h index ea4192ed..26e6dd77 100644 --- a/src/arch/i386/include/realmode.h +++ b/src/arch/i386/include/realmode.h @@ -1,45 +1,15 @@ #ifndef REALMODE_H #define REALMODE_H -#ifndef ASSEMBLY - -#include "stdint.h" -#include "registers.h" -#include +#include +#include +#include /* * Data structures and type definitions * */ -/* Segment:offset structure. Note that the order within the structure - * is offset:segment. - */ -struct segoff { - uint16_t offset; - uint16_t segment; -} __attribute__ (( packed )); - -typedef struct segoff segoff_t; - -/* Macro hackery needed to stringify bits of inline assembly */ -#define RM_XSTR(x) #x -#define RM_STR(x) RM_XSTR(x) - -/* Drag in the selected real-mode transition library header */ -#ifdef KEEP_IT_REAL -#include "libkir.h" -#else -#include "librm.h" -#endif - -/* - * The API to some functions is identical between librm and libkir, so - * they are documented here, even though the prototypes are in librm.h - * and libkir.h. - * - */ - /* * Declaration of variables in .data16 * @@ -92,24 +62,53 @@ typedef struct segoff segoff_t; * assembler output to make sure that it's doing the right thing. */ -/* - * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off, - * void *src, size_t n ) - * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off, - * size_t n ) +/** + * Copy data to base memory * - * These functions can be used to copy data to and from arbitrary - * locations in base memory. + * @v dest_seg Destination segment + * @v dest_off Destination offset + * @v src Source + * @v len Length */ +static inline __always_inline void +copy_to_real ( unsigned int dest_seg, unsigned int dest_off, + void *src, size_t n ) { + copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n ); +} -/* - * put_real ( variable, uint16_t dest_seg, uint16_t dest_off ) - * get_real ( variable, uint16_t src_seg, uint16_t src_off ) +/** + * Copy data to base memory * - * These macros can be used to read or write single variables to and - * from arbitrary locations in base memory. "variable" must be a - * variable of either 1, 2 or 4 bytes in length. + * @v dest Destination + * @v src_seg Source segment + * @v src_off Source offset + * @v len Length */ +static inline __always_inline void +copy_from_real ( void *dest, unsigned int src_seg, + unsigned int src_off, size_t n ) { + copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n ); +} + +/** + * Write a single variable to base memory + * + * @v var Variable to write + * @v dest_seg Destination segment + * @v dest_off Destination offset + */ +#define put_real( var, dest_seg, dest_off ) \ + copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) ) + +/** + * Read a single variable from base memory + * + * @v var Variable to read + * @v src_seg Source segment + * @v src_off Source offset + */ +#define get_real( var, src_seg, src_off ) \ + copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) ) /* * REAL_CODE ( asm_code_str ) @@ -123,6 +122,4 @@ typedef struct segoff segoff_t; * */ -#endif /* ASSEMBLY */ - #endif /* REALMODE_H */ diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h index 2b9b2b43..e68fa85a 100644 --- a/src/arch/i386/include/registers.h +++ b/src/arch/i386/include/registers.h @@ -10,8 +10,7 @@ * */ -#include "compiler.h" /* for doxygen */ -#include "stdint.h" +#include /** * A 16-bit general register. @@ -184,4 +183,14 @@ struct i386_all_regs { #define SF ( 1 << 7 ) #define OF ( 1 << 11 ) +/* Segment:offset structure. Note that the order within the structure + * is offset:segment. + */ +struct segoff { + uint16_t offset; + uint16_t segment; +} PACKED; + +typedef struct segoff segoff_t; + #endif /* REGISTERS_H */ diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h deleted file mode 100644 index e7bb2cce..00000000 --- a/src/arch/i386/include/virtaddr.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef VIRTADDR_H -#define VIRTADDR_H - -/* Segment selectors as used in our protected-mode GDTs. - * - * Don't change these unless you really know what you're doing. - */ - -#define VIRTUAL_CS 0x08 -#define VIRTUAL_DS 0x10 -#define PHYSICAL_CS 0x18 -#define PHYSICAL_DS 0x20 -#define REAL_CS 0x28 -#define REAL_DS 0x30 -#if 0 -#define LONG_CS 0x38 -#define LONG_DS 0x40 -#endif - -#ifndef ASSEMBLY - -#ifndef KEEP_IT_REAL - -/* - * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a - * fixed link address but an unknown physical start address. Our GDT - * sets up code and data segments with an offset of virt_offset, so - * that link-time addresses can still work. - * - */ - -/* Variables in virtaddr.S */ -extern unsigned long virt_offset; - -#else /* KEEP_IT_REAL */ - -#include - -/* - * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link - * addresses and a segmented memory model. We have separate code and - * data segments. - * - * Because we may be called in 16-bit protected mode (damn PXE spec), - * we cannot simply assume that physical = segment * 16 + offset. - * Instead, we have to look up the physical start address of the - * segment in the !PXE structure. We have to assume that - * virt_to_phys() is called only on pointers within the data segment, - * because nothing passes segment information to us. - * - * We don't implement phys_to_virt at all, because there will be many - * addresses that simply cannot be reached via a virtual address when - * the virtual address space is limited to 64kB! - */ - -static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) { - /* Cheat: just for now, do the segment*16+offset calculation */ - uint16_t ds; - - __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : ); - return ( 16 * ds + ( ( unsigned long ) virt_addr ) ); -} - -/* Define it as a deprecated function so that we get compile-time - * warnings, rather than just the link-time errors. - */ -extern void * phys_to_virt ( unsigned long phys_addr ) - __attribute__ ((deprecated)); - -#endif /* KEEP_IT_REAL */ - -#endif /* ASSEMBLY */ - -#endif /* VIRTADDR_H */ diff --git a/src/arch/i386/transitions/librm_mgmt.c b/src/arch/i386/transitions/librm_mgmt.c index 59b2eabc..50569f8e 100755 --- a/src/arch/i386/transitions/librm_mgmt.c +++ b/src/arch/i386/transitions/librm_mgmt.c @@ -1,45 +1,56 @@ -/* - * librm: a library for interfacing to real-mode code - * - * Michael Brown - * - */ - -#include -#include - -/* - * This file provides functions for managing librm. - * - */ - -/** - * Allocate space on the real-mode stack and copy data there from a - * user buffer - * - * @v data User buffer - * @v size Size of stack data - * @ret sp New value of real-mode stack pointer - */ -uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { - userptr_t rm_stack; - rm_sp -= size; - rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - return rm_sp; -}; - -/** - * Deallocate space on the real-mode stack, optionally copying back - * data to a user buffer. - * - * @v data User buffer - * @v size Size of stack data - */ -void remove_user_from_rm_stack ( userptr_t data, size_t size ) { - if ( data ) { - userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); - } - rm_sp += size; -}; +/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown + * + */ + +#include +#include + +/* + * This file provides functions for managing librm. + * + */ + +/** + * Allocate space on the real-mode stack and copy data there from a + * user buffer + * + * @v data User buffer + * @v size Size of stack data + * @ret sp New value of real-mode stack pointer + */ +uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { + userptr_t rm_stack; + rm_sp -= size; + rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + return rm_sp; +}; + +/** + * Deallocate space on the real-mode stack, optionally copying back + * data to a user buffer. + * + * @v data User buffer + * @v size Size of stack data + */ +void remove_user_from_rm_stack ( userptr_t data, size_t size ) { + if ( data ) { + userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + } + rm_sp += size; +}; + +PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); +PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); +PROVIDE_UACCESS_INLINE ( librm, userptr_add ); +PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); +PROVIDE_UACCESS_INLINE ( librm, memmove_user ); +PROVIDE_UACCESS_INLINE ( librm, memset_user ); +PROVIDE_UACCESS_INLINE ( librm, strlen_user ); +PROVIDE_UACCESS_INLINE ( librm, memchr_user ); diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index a670e7a6..211f28cf 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -7,6 +7,7 @@ * */ +#define UACCESS_LIBRM #define IOAPI_X86 #define PCIAPI_PCBIOS #define TIMER_PCBIOS diff --git a/src/include/gpxe/io.h b/src/include/gpxe/io.h index 24cc180f..0fc7c74e 100644 --- a/src/include/gpxe/io.h +++ b/src/include/gpxe/io.h @@ -19,6 +19,7 @@ #include #include #include +#include /** * Calculate static inline I/O API function name @@ -149,24 +150,20 @@ } while ( 0 ) /** - * Convert virtual address to a physical address + * Convert physical address to a bus address * - * @v addr Virtual address - * @ret phys_addr Physical address + * @v phys_addr Physical address + * @ret bus_addr Bus address */ -unsigned long virt_to_phys ( volatile const void *addr ); +unsigned long phys_to_bus ( unsigned long phys_addr ); /** - * Convert physical address to a virtual address + * Convert bus address to a physical address * - * @v addr Virtual address + * @v bus_addr Bus address * @ret phys_addr Physical address - * - * This operation isn't actually valid within our memory model, and is - * impossible to achieve under -DKEEP_IT_REAL. Some drivers haven't - * been updated to avoid it yet, though. */ -void * phys_to_virt ( unsigned long phys_addr ); +unsigned long bus_to_phys ( unsigned long bus_addr ); /** * Convert virtual address to a bus address @@ -174,7 +171,10 @@ void * phys_to_virt ( unsigned long phys_addr ); * @v addr Virtual address * @ret bus_addr Bus address */ -unsigned long virt_to_bus ( volatile const void *addr ); +static inline __always_inline unsigned long +virt_to_bus ( volatile const void *addr ) { + return phys_to_bus ( virt_to_phys ( addr ) ); +} /** * Convert bus address to a virtual address @@ -182,11 +182,11 @@ unsigned long virt_to_bus ( volatile const void *addr ); * @v bus_addr Bus address * @ret addr Virtual address * - * This operation isn't actually valid within our memory model, and is - * impossible to achieve under -DKEEP_IT_REAL. Some drivers haven't - * been updated to avoid it yet, though. + * This operation is not available under all memory models. */ -void * bus_to_virt ( unsigned long bus_addr ); +static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) { + return phys_to_virt ( bus_to_phys ( bus_addr ) ); +} /** * Map bus address as an I/O address diff --git a/src/include/gpxe/uaccess.h b/src/include/gpxe/uaccess.h index 05f89e03..f677b7fd 100644 --- a/src/include/gpxe/uaccess.h +++ b/src/include/gpxe/uaccess.h @@ -19,9 +19,323 @@ * */ -#include +#include +#include +#include +#include + +/** + * A pointer to a user buffer + * + */ +typedef unsigned long userptr_t; /** Equivalent of NULL for user pointers */ #define UNULL ( ( userptr_t ) 0 ) +/** + * @defgroup uaccess_trivial Trivial user access API implementations + * + * User access API implementations that can be used by environments in + * which virtual addresses allow access to all of memory. + * + * @{ + * + */ + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +trivial_virt_to_user ( volatile const void *addr ) { + return ( ( userptr_t ) addr ); +} + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * +trivial_user_to_virt ( userptr_t userptr, off_t offset ) { + return ( ( void * ) userptr + offset ); +} + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +static inline __always_inline userptr_t +trivial_userptr_add ( userptr_t userptr, off_t offset ) { + return ( userptr + offset ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memcpy ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memmove ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Fill user buffer with a constant byte + * + * @v buffer User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +static inline __always_inline void +trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + memset ( ( ( void * ) buffer + offset ), c, len ); +} + +/** + * Find length of NUL-terminated string in user buffer + * + * @v buffer User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +static inline __always_inline size_t +trivial_strlen_user ( userptr_t buffer, off_t offset ) { + return strlen ( ( void * ) buffer + offset ); +} + +/** + * Find character in user buffer + * + * @v buffer User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +static inline __always_inline off_t +trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + void *found; + + found = memchr ( ( ( void * ) buffer + offset ), c, len ); + return ( found ? ( found - ( void * ) buffer ) : -1 ); +} + +/** @} */ + +/** + * Calculate static inline user access API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define UACCESS_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent user access API headers */ + +/* Include all architecture-dependent user access API headers */ +#include + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +userptr_t phys_to_user ( unsigned long phys_addr ); + +/** + * Convert user pointer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +unsigned long user_to_phys ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +userptr_t virt_to_user ( volatile const void *addr ); + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +void * user_to_virt ( userptr_t userptr, off_t offset ); + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +userptr_t userptr_add ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to a physical address + * + * @v addr Virtual address + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +virt_to_phys ( volatile const void *addr ) { + return user_to_phys ( virt_to_user ( addr ), 0 ); +} + +/** + * Convert physical address to a virtual address + * + * @v addr Virtual address + * @ret phys_addr Physical address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) { + return user_to_virt ( phys_to_user ( phys_addr ), 0 ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Copy data to user buffer + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v len Length + */ +static inline __always_inline void +copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { + memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len ); +} + +/** + * Copy data from user buffer + * + * @v dest Destination + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) { + memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Fill user buffer with a constant byte + * + * @v userptr User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +void memset_user ( userptr_t userptr, off_t offset, int c, size_t len ); + +/** + * Find length of NUL-terminated string in user buffer + * + * @v userptr User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +size_t strlen_user ( userptr_t userptr, off_t offset ); + +/** + * Find character in user buffer + * + * @v userptr User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len ); + #endif /* _GPXE_UACCESS_H */ diff --git a/src/include/pxe_types.h b/src/include/pxe_types.h index e31af062..dd9092ef 100644 --- a/src/include/pxe_types.h +++ b/src/include/pxe_types.h @@ -7,9 +7,8 @@ * */ -#include "stdint.h" -#include "pxe_addr.h" /* Architecture-specific PXE definitions */ -#include "errno.h" /* PXE status codes */ +#include +#include /* PXE status codes */ /** @addtogroup pxe Preboot eXecution Environment (PXE) API * @{