mirror of
https://github.com/ipxe/ipxe
synced 2025-12-28 18:42:53 +03:00
[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:
@@ -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 */
|
||||
Reference in New Issue
Block a user