[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.
|
||||
*/
|
||||
|
||||
#include <virtaddr.h>
|
||||
#include <librm.h>
|
||||
|
||||
#define SIZEOF_I386_REGS 32
|
||||
#define SIZEOF_I386_FLAGS 4
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <virtaddr.h>
|
||||
#include <gpxe/uaccess.h>
|
||||
#include <gpxe/gdbstub.h>
|
||||
#include <gdbmach.h>
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <gpxe/io.h>
|
||||
#include <pic8259.h>
|
||||
|
||||
/** @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
|
||||
.text
|
||||
|
@ -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 );
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <biosint.h>
|
||||
#include <pnpbios.h>
|
||||
#include <basemem_packet.h>
|
||||
#include <gpxe/io.h>
|
||||
#include <gpxe/iobuf.h>
|
||||
#include <gpxe/netdevice.h>
|
||||
#include <gpxe/if_ether.h>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <realmode.h>
|
||||
#include <bios.h>
|
||||
#include <gpxe/io.h>
|
||||
#include <gpxe/timer.h>
|
||||
|
||||
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef _BITS_UACCESS_H
|
||||
#define _BITS_UACCESS_H
|
||||
|
||||
#include <realmode.h>
|
||||
/** @file
|
||||
*
|
||||
* i386-specific user access API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
#endif /* _BITS_UACCESS_H */
|
||||
|
@ -15,8 +15,6 @@
|
||||
* into a machine with such an old CPU anyway.
|
||||
*/
|
||||
|
||||
#include <virtaddr.h>
|
||||
|
||||
#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 *
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gpxe/list.h>
|
||||
#include <realmode.h>
|
||||
|
||||
struct block_device;
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
#define REALMODE_H
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
|
||||
#include "stdint.h"
|
||||
#include "registers.h"
|
||||
#include <gpxe/io.h>
|
||||
#include <stdint.h>
|
||||
#include <registers.h>
|
||||
#include <gpxe/uaccess.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
@ -10,8 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "compiler.h" /* for doxygen */
|
||||
#include "stdint.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
@ -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
|
||||
*
|
||||
* Michael Brown <mbrown@fensystems.co.uk>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <librm.h>
|
||||
|
||||
/*
|
||||
* 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 <mbrown@fensystems.co.uk>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <realmode.h>
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define UACCESS_LIBRM
|
||||
#define IOAPI_X86
|
||||
#define PCIAPI_PCBIOS
|
||||
#define TIMER_PCBIOS
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <stdint.h>
|
||||
#include <gpxe/api.h>
|
||||
#include <config/ioapi.h>
|
||||
#include <gpxe/uaccess.h>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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 */
|
||||
#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 */
|
||||
|
@ -7,9 +7,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdint.h"
|
||||
#include "pxe_addr.h" /* Architecture-specific PXE definitions */
|
||||
#include "errno.h" /* PXE status codes */
|
||||
#include <stdint.h>
|
||||
#include <errno.h> /* PXE status codes */
|
||||
|
||||
/** @addtogroup pxe Preboot eXecution Environment (PXE) API
|
||||
* @{
|
||||
|
Reference in New Issue
Block a user