[uaccess] Formalise the uaccess API
The userptr_t is now the fundamental type that gets used for conversions. For example, virt_to_phys() is implemented in terms of virt_to_user() and user_to_phys().
This commit is contained in:
parent
667819becc
commit
6554b79ff9
@ -2,7 +2,7 @@
|
|||||||
* Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
|
* Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <virtaddr.h>
|
#include <librm.h>
|
||||||
|
|
||||||
#define SIZEOF_I386_REGS 32
|
#define SIZEOF_I386_REGS 32
|
||||||
#define SIZEOF_I386_FLAGS 4
|
#define SIZEOF_I386_FLAGS 4
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <virtaddr.h>
|
#include <gpxe/uaccess.h>
|
||||||
#include <gpxe/gdbstub.h>
|
#include <gpxe/gdbstub.h>
|
||||||
#include <gdbmach.h>
|
#include <gdbmach.h>
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <gpxe/io.h>
|
||||||
#include <pic8259.h>
|
#include <pic8259.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
@ -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
|
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "virtaddr.h"
|
#include "librm.h"
|
||||||
|
|
||||||
.arch i386
|
.arch i386
|
||||||
.text
|
.text
|
||||||
|
@ -65,10 +65,8 @@ static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
|
|||||||
: : "A" ( data ), "r" ( io_addr ) );
|
: : "A" ( data ), "r" ( io_addr ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
PROVIDE_IOAPI_INLINE ( x86, virt_to_phys );
|
PROVIDE_IOAPI_INLINE ( x86, phys_to_bus );
|
||||||
PROVIDE_IOAPI_INLINE ( x86, phys_to_virt );
|
PROVIDE_IOAPI_INLINE ( x86, bus_to_phys );
|
||||||
PROVIDE_IOAPI_INLINE ( x86, virt_to_bus );
|
|
||||||
PROVIDE_IOAPI_INLINE ( x86, bus_to_virt );
|
|
||||||
PROVIDE_IOAPI_INLINE ( x86, ioremap );
|
PROVIDE_IOAPI_INLINE ( x86, ioremap );
|
||||||
PROVIDE_IOAPI_INLINE ( x86, iounmap );
|
PROVIDE_IOAPI_INLINE ( x86, iounmap );
|
||||||
PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
|
PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <biosint.h>
|
#include <biosint.h>
|
||||||
#include <pnpbios.h>
|
#include <pnpbios.h>
|
||||||
#include <basemem_packet.h>
|
#include <basemem_packet.h>
|
||||||
|
#include <gpxe/io.h>
|
||||||
#include <gpxe/iobuf.h>
|
#include <gpxe/iobuf.h>
|
||||||
#include <gpxe/netdevice.h>
|
#include <gpxe/netdevice.h>
|
||||||
#include <gpxe/if_ether.h>
|
#include <gpxe/if_ether.h>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <realmode.h>
|
#include <realmode.h>
|
||||||
#include <bios.h>
|
#include <bios.h>
|
||||||
|
#include <gpxe/io.h>
|
||||||
#include <gpxe/timer.h>
|
#include <gpxe/timer.h>
|
||||||
|
|
||||||
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
|
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
#ifndef _BITS_UACCESS_H
|
#ifndef _BITS_UACCESS_H
|
||||||
#define _BITS_UACCESS_H
|
#define _BITS_UACCESS_H
|
||||||
|
|
||||||
#include <realmode.h>
|
/** @file
|
||||||
|
*
|
||||||
|
* i386-specific user access API implementations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <librm.h>
|
||||||
|
|
||||||
#endif /* _BITS_UACCESS_H */
|
#endif /* _BITS_UACCESS_H */
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
* into a machine with such an old CPU anyway.
|
* into a machine with such an old CPU anyway.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <virtaddr.h>
|
|
||||||
|
|
||||||
#ifdef IOAPI_X86
|
#ifdef IOAPI_X86
|
||||||
#define IOAPI_PREFIX_x86
|
#define IOAPI_PREFIX_x86
|
||||||
#else
|
#else
|
||||||
@ -28,24 +26,19 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline __always_inline unsigned long
|
/*
|
||||||
IOAPI_INLINE ( x86, virt_to_phys ) ( volatile const void *addr ) {
|
* Physical<->Bus and Bus<->I/O address mappings
|
||||||
return ( ( ( unsigned long ) addr ) + virt_offset );
|
*
|
||||||
}
|
*/
|
||||||
|
|
||||||
static inline __always_inline void *
|
static inline __always_inline unsigned long
|
||||||
IOAPI_INLINE ( x86, phys_to_virt ) ( unsigned long phys_addr ) {
|
IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
|
||||||
return ( ( void * ) ( phys_addr - virt_offset ) );
|
return phys_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __always_inline unsigned long
|
static inline __always_inline unsigned long
|
||||||
IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) {
|
IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
|
||||||
return virt_to_phys ( addr );
|
return bus_addr;
|
||||||
}
|
|
||||||
|
|
||||||
static inline __always_inline void *
|
|
||||||
IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) {
|
|
||||||
return phys_to_virt ( bus_addr );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __always_inline void *
|
static inline __always_inline void *
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <gpxe/list.h>
|
#include <gpxe/list.h>
|
||||||
|
#include <realmode.h>
|
||||||
|
|
||||||
struct block_device;
|
struct block_device;
|
||||||
|
|
||||||
|
@ -1,21 +1,109 @@
|
|||||||
#ifndef LIBRM_H
|
#ifndef LIBRM_H
|
||||||
#define LIBRM_H
|
#define LIBRM_H
|
||||||
|
|
||||||
/* Drag in protected-mode segment selector values */
|
/* Segment selectors as used in our protected-mode GDTs.
|
||||||
#include "virtaddr.h"
|
*
|
||||||
#include "realmode.h"
|
* 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 ASSEMBLY
|
||||||
|
|
||||||
#include "stddef.h"
|
#ifdef UACCESS_LIBRM
|
||||||
#include "string.h"
|
#define UACCESS_PREFIX_librm
|
||||||
|
#else
|
||||||
|
#define UACCESS_PREFIX_librm __librm_
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/* Variables in librm.S */
|
||||||
* Data structures and type definitions
|
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 *data16;
|
||||||
extern char *text16;
|
extern char *text16;
|
||||||
|
|
||||||
@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds );
|
|||||||
*/
|
*/
|
||||||
extern void gateA20_set ( void );
|
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
|
* Convert segment:offset address to user buffer
|
||||||
*
|
*
|
||||||
@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) {
|
|||||||
* @v offset Real-mode offset
|
* @v offset Real-mode offset
|
||||||
* @ret buffer User buffer
|
* @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 ) {
|
real_to_user ( unsigned int segment, unsigned int offset ) {
|
||||||
return virt_to_user ( VIRTUAL ( segment, offset ) );
|
return ( phys_to_user ( ( segment << 4 ) + 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
|
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
|
||||||
|
@ -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 */
|
|
@ -1,45 +1,15 @@
|
|||||||
#ifndef REALMODE_H
|
#ifndef REALMODE_H
|
||||||
#define REALMODE_H
|
#define REALMODE_H
|
||||||
|
|
||||||
#ifndef ASSEMBLY
|
#include <stdint.h>
|
||||||
|
#include <registers.h>
|
||||||
#include "stdint.h"
|
#include <gpxe/uaccess.h>
|
||||||
#include "registers.h"
|
|
||||||
#include <gpxe/io.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data structures and type definitions
|
* 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
|
* 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.
|
* assembler output to make sure that it's doing the right thing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* void copy_to_real ( uint16_t dest_seg, uint16_t dest_off,
|
* Copy data to base memory
|
||||||
* void *src, size_t n )
|
|
||||||
* void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off,
|
|
||||||
* size_t n )
|
|
||||||
*
|
*
|
||||||
* These functions can be used to copy data to and from arbitrary
|
* @v dest_seg Destination segment
|
||||||
* locations in base memory.
|
* @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 )
|
* Copy data to base memory
|
||||||
* get_real ( variable, uint16_t src_seg, uint16_t src_off )
|
|
||||||
*
|
*
|
||||||
* These macros can be used to read or write single variables to and
|
* @v dest Destination
|
||||||
* from arbitrary locations in base memory. "variable" must be a
|
* @v src_seg Source segment
|
||||||
* variable of either 1, 2 or 4 bytes in length.
|
* @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 )
|
* REAL_CODE ( asm_code_str )
|
||||||
@ -123,6 +122,4 @@ typedef struct segoff segoff_t;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#endif /* ASSEMBLY */
|
|
||||||
|
|
||||||
#endif /* REALMODE_H */
|
#endif /* REALMODE_H */
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compiler.h" /* for doxygen */
|
#include <stdint.h>
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 16-bit general register.
|
* A 16-bit general register.
|
||||||
@ -184,4 +183,14 @@ struct i386_all_regs {
|
|||||||
#define SF ( 1 << 7 )
|
#define SF ( 1 << 7 )
|
||||||
#define OF ( 1 << 11 )
|
#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 */
|
#endif /* REGISTERS_H */
|
||||||
|
@ -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 <stdint.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
|
@ -1,45 +1,56 @@
|
|||||||
/*
|
/*
|
||||||
* librm: a library for interfacing to real-mode code
|
* librm: a library for interfacing to real-mode code
|
||||||
*
|
*
|
||||||
* Michael Brown <mbrown@fensystems.co.uk>
|
* Michael Brown <mbrown@fensystems.co.uk>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <librm.h>
|
#include <realmode.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file provides functions for managing librm.
|
* This file provides functions for managing librm.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate space on the real-mode stack and copy data there from a
|
* Allocate space on the real-mode stack and copy data there from a
|
||||||
* user buffer
|
* user buffer
|
||||||
*
|
*
|
||||||
* @v data User buffer
|
* @v data User buffer
|
||||||
* @v size Size of stack data
|
* @v size Size of stack data
|
||||||
* @ret sp New value of real-mode stack pointer
|
* @ret sp New value of real-mode stack pointer
|
||||||
*/
|
*/
|
||||||
uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
|
uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
|
||||||
userptr_t rm_stack;
|
userptr_t rm_stack;
|
||||||
rm_sp -= size;
|
rm_sp -= size;
|
||||||
rm_stack = real_to_user ( rm_ss, rm_sp );
|
rm_stack = real_to_user ( rm_ss, rm_sp );
|
||||||
memcpy_user ( rm_stack, 0, data, 0, size );
|
memcpy_user ( rm_stack, 0, data, 0, size );
|
||||||
return rm_sp;
|
return rm_sp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocate space on the real-mode stack, optionally copying back
|
* Deallocate space on the real-mode stack, optionally copying back
|
||||||
* data to a user buffer.
|
* data to a user buffer.
|
||||||
*
|
*
|
||||||
* @v data User buffer
|
* @v data User buffer
|
||||||
* @v size Size of stack data
|
* @v size Size of stack data
|
||||||
*/
|
*/
|
||||||
void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
|
void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
|
||||||
if ( data ) {
|
if ( data ) {
|
||||||
userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
|
userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
|
||||||
memcpy_user ( rm_stack, 0, data, 0, size );
|
memcpy_user ( rm_stack, 0, data, 0, size );
|
||||||
}
|
}
|
||||||
rm_sp += 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 );
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define UACCESS_LIBRM
|
||||||
#define IOAPI_X86
|
#define IOAPI_X86
|
||||||
#define PCIAPI_PCBIOS
|
#define PCIAPI_PCBIOS
|
||||||
#define TIMER_PCBIOS
|
#define TIMER_PCBIOS
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <gpxe/api.h>
|
#include <gpxe/api.h>
|
||||||
#include <config/ioapi.h>
|
#include <config/ioapi.h>
|
||||||
|
#include <gpxe/uaccess.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate static inline I/O API function name
|
* Calculate static inline I/O API function name
|
||||||
@ -149,24 +150,20 @@
|
|||||||
} while ( 0 )
|
} while ( 0 )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert virtual address to a physical address
|
* Convert physical address to a bus address
|
||||||
*
|
*
|
||||||
* @v addr Virtual address
|
* @v phys_addr Physical address
|
||||||
* @ret 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
|
* @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
|
* Convert virtual address to a bus address
|
||||||
@ -174,7 +171,10 @@ void * phys_to_virt ( unsigned long phys_addr );
|
|||||||
* @v addr Virtual address
|
* @v addr Virtual address
|
||||||
* @ret bus_addr Bus 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
|
* 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
|
* @v bus_addr Bus address
|
||||||
* @ret addr Virtual address
|
* @ret addr Virtual address
|
||||||
*
|
*
|
||||||
* This operation isn't actually valid within our memory model, and is
|
* This operation is not available under all memory models.
|
||||||
* impossible to achieve under -DKEEP_IT_REAL. Some drivers haven't
|
|
||||||
* been updated to avoid it yet, though.
|
|
||||||
*/
|
*/
|
||||||
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
|
* Map bus address as an I/O address
|
||||||
|
@ -19,9 +19,323 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <bits/uaccess.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <gpxe/api.h>
|
||||||
|
#include <config/ioapi.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pointer to a user buffer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef unsigned long userptr_t;
|
||||||
|
|
||||||
/** Equivalent of NULL for user pointers */
|
/** Equivalent of NULL for user pointers */
|
||||||
#define UNULL ( ( userptr_t ) 0 )
|
#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 <bits/uaccess.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
#endif /* _GPXE_UACCESS_H */
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
#include "pxe_addr.h" /* Architecture-specific PXE definitions */
|
#include <errno.h> /* PXE status codes */
|
||||||
#include "errno.h" /* PXE status codes */
|
|
||||||
|
|
||||||
/** @addtogroup pxe Preboot eXecution Environment (PXE) API
|
/** @addtogroup pxe Preboot eXecution Environment (PXE) API
|
||||||
* @{
|
* @{
|
||||||
|
Reference in New Issue
Block a user