Merged mcb30-realmode-redesign back to HEAD

This commit is contained in:
Michael Brown
2005-04-08 15:01:17 +00:00
parent de5d935135
commit 0ff80b477d
100 changed files with 4877 additions and 4263 deletions

View File

@@ -0,0 +1,10 @@
#ifndef BIOS_H
#define BIOS_H
extern unsigned long currticks ( void );
extern void cpu_nap ( void );
extern void disk_init ( void );
extern unsigned int pcbios_disk_read ( int drive, int cylinder, int head,
int sector, char *fixme_buf );
#endif /* BIOS_H */

View File

@@ -0,0 +1,27 @@
#ifndef BOCHS_H
#define BOCHS_H
/*
* This file defines "bochsbp", the magic breakpoint instruction that
* is incredibly useful when debugging under bochs.
*
*/
#ifdef ASSEMBLY
/* Breakpoint for when debugging under bochs */
#define bochsbp xchgw %bx, %bx
#define BOCHSBP bochsbp
#else /* ASSEMBLY */
/* Breakpoint for when debugging under bochs */
static inline void bochsbp ( void ) {
__asm__ __volatile__ ( "xchgw %bx, %bx" );
}
#endif /* ASSEMBLY */
#warning "bochs.h should not be included into production code"
#endif /* BOCHS_H */

View File

@@ -1,7 +1,7 @@
#ifndef HIDEMEM_H
#define HIDEMEM_H
#include "segoff.h"
#include "realmode.h"
extern int install_e820mangler ( void *new_mangler );
extern int hide_etherboot ( void );

View File

@@ -1,9 +1,14 @@
#ifndef ETHERBOOT_I386_HOOKS_H
#define ETHERBOOT_I386_HOOKS_H
#ifndef HOOKS_H
#define HOOKS_H
void arch_main(in_call_data_t *data, va_list params);
void arch_on_exit(int status);
#define arch_relocate_to(addr)
void arch_relocated_from ( uint32_t old_addr );
/* in hooks.o */
extern void arch_initialise ( struct i386_all_regs *regs,
void (*retaddr) (void) );
extern void arch_main ( struct i386_all_regs *regs );
#endif /* ETHERBOOT_I386_HOOKS_H */
/* in hooks_rm.o */
extern void arch_rm_initialise ( struct i386_all_regs *regs,
void (*retaddr) (void) );
extern void arch_rm_main ( struct i386_all_regs *regs );
#endif /* HOOKS_H */

View File

@@ -1,22 +1,8 @@
#ifndef ETHERBOOT_IO_H
#define ETHERBOOT_IO_H
/* Amount of relocation etherboot is experiencing */
extern unsigned long virt_offset;
/* Don't require identity mapped physical memory,
* osloader.c is the only valid user at the moment.
*/
static inline unsigned long virt_to_phys(volatile const void *virt_addr)
{
return ((unsigned long)virt_addr) + virt_offset;
}
static inline void *phys_to_virt(unsigned long phys_addr)
{
return (void *)(phys_addr - virt_offset);
}
#include "compiler.h"
#include "virtaddr.h"
/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
* into a memory access cards can use.

View File

@@ -0,0 +1,18 @@
#ifndef KIR_H
#define KIR_H
#ifndef KEEP_IT_REAL
#error "kir.h can be used only with -DKEEP_IT_REAL"
#endif
#ifdef ASSEMBLY
#define code32 code16gcc
#else /* ASSEMBLY */
__asm__ ( ".code16gcc" );
#endif /* ASSEMBLY */
#endif /* KIR_H */

View File

@@ -0,0 +1,184 @@
#ifndef LIBKIR_H
#define LIBKIR_H
#include "realmode.h"
#ifndef ASSEMBLY
/*
* Full API documentation for these functions is in realmode.h.
*
*/
/* Copy to/from base memory */
static inline void copy_to_real_libkir ( uint16_t dest_seg, uint16_t dest_off,
void *src, size_t n ) {
__asm__ ( "movw %4, %%es\n\t"
"cld\n\t"
"rep movsb\n\t"
"pushw %%ds\n\t" /* restore %es */
"popw %%es\n\t"
: "=S" ( src ), "=D" ( dest_off ), "=c" ( n ) /* clobbered */
: "S" ( src ), "r" ( dest_seg ), "D" ( dest_off ), "c" ( n )
: "memory"
);
}
static inline void copy_from_real_libkir ( void *dest,
uint16_t src_seg, uint16_t src_off,
size_t n ) {
__asm__ ( "movw %%ax, %%ds\n\t"
"cld\n\t"
"rep movsb\n\t"
"pushw %%es\n\t" /* restore %ds */
"popw %%ds\n\t"
: "=S" ( src_off ), "=D" ( dest ), "=c" ( n ) /* clobbered */
: "a" ( src_seg ), "S" ( src_off ), "D" ( dest ), "c" ( n )
: "memory"
);
}
#define copy_to_real copy_to_real_libkir
#define copy_from_real copy_from_real_libkir
/*
* Transfer individual values to/from base memory. There may well be
* a neater way to do this. We have two versions: one for constant
* offsets (where the mov instruction must be of the form "mov
* %es:123, %xx") and one for non-constant offsets (where the mov
* instruction must be of the form "mov %es:(%xx), %yx". If it's
* possible to incorporate both forms into one __asm__ instruction, I
* don't know how to do it.
*
* Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant
* to expand to either "b", "w" or "l" depending on the size of
* operand 0. This would remove the (minor) ambiguity in the mov
* instruction. However, gcc on at least my system barfs with an
* "internal compiler error" when confronted with %z0.
*
*/
#define put_real_kir_const_off( var, seg, off ) \
__asm__ ( "movw %w1, %%es\n\t" \
"mov %0, %%es:%c2\n\t" \
"pushw %%ds\n\t" /* restore %es */ \
"popw %%es\n\t" \
: \
: "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \
)
#define put_real_kir_nonconst_off( var, seg, off ) \
__asm__ ( "movw %w1, %%es\n\t" \
"mov %0, %%es:(%2)\n\t" \
"pushw %%ds\n\t" /* restore %es */ \
"popw %%es\n\t" \
: \
: "r" ( var ), "rm" ( seg ), "r" ( off ) \
)
#define put_real_kir( var, seg, off ) \
do { \
if ( __builtin_constant_p ( off ) ) \
put_real_kir_const_off ( var, seg, off ); \
else \
put_real_kir_nonconst_off ( var, seg, off ); \
} while ( 0 )
#define get_real_kir_const_off( var, seg, off ) \
__asm__ ( "movw %w1, %%es\n\t" \
"mov %%es:%c2, %0\n\t" \
"pushw %%ds\n\t" /* restore %es */ \
"popw %%es\n\t" \
: "=r,r" ( var ) \
: "rm,rm" ( seg ), "i,!r" ( off ) \
)
#define get_real_kir_nonconst_off( var, seg, off ) \
__asm__ ( "movw %w1, %%es\n\t" \
"mov %%es:(%2), %0\n\t" \
"pushw %%ds\n\t" /* restore %es */ \
"popw %%es\n\t" \
: "=r" ( var ) \
: "rm" ( seg ), "r" ( off ) \
)
#define get_real_kir( var, seg, off ) \
do { \
if ( __builtin_constant_p ( off ) ) \
get_real_kir_const_off ( var, seg, off ); \
else \
get_real_kir_nonconst_off ( var, seg, off ); \
} while ( 0 )
#define put_real put_real_kir
#define get_real get_real_kir
/* Place/remove parameter on real-mode stack in a way that's
* compatible with libkir
*/
#define BASEMEM_PARAMETER_INIT_LIBKIR( param ) \
( ( uint16_t ) ( ( uint32_t ) & ( param ) ) )
#define BASEMEM_PARAMETER_DONE_LIBKIR( param )
#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBKIR
#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBKIR
/* REAL_CALL: call an external real-mode routine */
#define OUT_CONSTRAINTS(...) __VA_ARGS__
#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
#define CLOBBER(...) __VA_ARGS__
#define REAL_CALL( routine, num_out_constraints, out_constraints, \
in_constraints, clobber ) \
do { \
segoff_t __routine = routine; \
__asm__ __volatile__ ( \
"pushl %" #num_out_constraints "\n\t" \
".code16\n\t" \
"pushw %%gs\n\t" /* preserve segs */ \
"pushw %%fs\n\t" \
"pushw %%es\n\t" \
"pushw %%ds\n\t" \
"pushw %%cs\n\t" /* lcall to routine */ \
"call 1f\n\t" \
"jmp 2f\n\t" \
"\n1:\n\t" \
"addr32 pushl 12(%%esp)\n\t" \
"lret\n\t" \
"\n2:\n\t" \
"popw %%ds\n\t" /* restore segs */ \
"popw %%es\n\t" \
"popw %%fs\n\t" \
"popw %%gs\n\t" \
"addw $4, %%sp\n\t" \
".code16gcc\n\t" \
: out_constraints : in_constraints : clobber \
); \
} while ( 0 )
/* REAL_EXEC: execute some inline assembly code in a way that matches
* the interface of librm
*/
#define IN_CONSTRAINTS_NO_ROUTINE( routine, ... ) __VA_ARGS__
#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
in_constraints, clobber ) \
__asm__ __volatile__ ( \
".code16\n\t" \
"pushw %%gs\n\t" \
"pushw %%fs\n\t" \
"pushw %%es\n\t" \
"pushw %%ds\n\t" \
"\n" #name ":\n\t" \
asm_code_str \
"popw %%ds\n\t" \
"popw %%es\n\t" \
"popw %%fs\n\t" \
"popw %%gs\n\t" \
".code16gcc\n\t" \
: out_constraints \
: IN_CONSTRAINTS_NO_ROUTINE ( in_constraints ) \
: clobber \
);
#endif /* ASSEMBLY */
#endif /* LIBKIR_H */

View File

@@ -0,0 +1,186 @@
#ifndef LIBRM_H
#define LIBRM_H
/* Drag in protected-mode segment selector values */
#include "virtaddr.h"
#include "realmode.h"
#ifndef ASSEMBLY
#include "stddef.h"
#include "string.h"
/*
* Data structures and type definitions
*
*/
/* Real-mode call parameter block, as passed to real_call */
struct real_call_params {
struct i386_seg_regs;
struct i386_regs;
segoff_t rm_code;
segoff_t reserved;
} PACKED;
/* Current location of librm in base memory */
extern char *installed_librm;
/* Start and size of our source copy of librm (i.e. the one that we
* can install by copying it to base memory and setting
* installed_librm)
*/
extern char librm[];
extern size_t _librm_size[];
/* Linker symbols for offsets within librm. Other symbols should
* almost certainly not be referred to from C code.
*/
extern void (*_real_to_prot[]) ( void );
extern void (*_prot_to_real[]) ( void );
extern void (*_prot_call[]) ( void );
extern void (*_real_call[]) ( void );
extern segoff_t _rm_stack[];
extern uint32_t _pm_stack[];
extern char _librm_ref_count[];
/* Symbols within current installation of librm */
#define LIBRM_VAR( sym ) \
( * ( ( typeof ( * _ ## sym ) * ) \
& ( installed_librm [ (int) _ ## sym ] ) ) )
#define LIBRM_FN( sym ) \
( ( typeof ( * _ ## sym ) ) \
& ( installed_librm [ (int) _ ## sym ] ) )
#define LIBRM_CONSTANT( sym ) \
( ( typeof ( * _ ## sym ) ) ( _ ## sym ) )
#define inst_real_to_prot LIBRM_FN ( real_to_prot )
#define inst_prot_to_real LIBRM_FN ( prot_to_real )
#define inst_prot_call LIBRM_FN ( prot_call )
#define inst_real_call LIBRM_FN ( real_call )
#define inst_rm_stack LIBRM_VAR ( rm_stack )
#define inst_pm_stack LIBRM_VAR ( pm_stack )
#define inst_librm_ref_count LIBRM_VAR ( librm_ref_count )
#define librm_size LIBRM_CONSTANT ( librm_size )
/* Functions that librm expects to be able to link to. Included here
* so that the compiler will catch prototype mismatches.
*/
extern void _phys_to_virt ( void );
extern void _virt_to_phys ( 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 void copy_to_real_librm ( uint16_t dest_seg, uint16_t dest_off,
void *src, size_t n ) {
memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
}
static inline void copy_from_real_librm ( void *dest,
uint16_t src_seg, uint16_t 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
/* Copy to/from real-mode stack */
extern uint16_t copy_to_rm_stack ( void *data, size_t size );
extern void remove_from_rm_stack ( void *data, size_t size );
/* Place/remove parameter on real-mode stack in a way that's
* compatible with libkir
*/
#define BASEMEM_PARAMETER_INIT_LIBRM( param ) \
copy_to_rm_stack ( & ( param ), sizeof ( param ) )
#define BASEMEM_PARAMETER_DONE_LIBRM( param ) \
remove_from_rm_stack ( & ( param ), sizeof ( param ) )
#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM
#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM
/* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */
#define REAL_FRAGMENT( name, asm_code_str ) \
extern void name ( void ); \
extern char name ## _size[]; \
__asm__ __volatile__ ( \
".section \".text16\"\n\t" \
".code16\n\t" \
".arch i386\n\t" \
#name ":\n\t" \
asm_code_str "\n\t" \
"lret\n\t" \
#name "_end:\n\t" \
".equ " #name "_size, " #name "_end - " #name "\n\t" \
".code32\n\t" \
".previous\n\t" \
: : \
)
#define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size )
/* REAL_CALL: call a real-mode routine via librm */
#define OUT_CONSTRAINTS(...) __VA_ARGS__
#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__
#define CLOBBER(...) __VA_ARGS__
#define REAL_CALL( routine, num_out_constraints, out_constraints, \
in_constraints, clobber ) \
do { \
segoff_t __routine = routine; \
__asm__ __volatile__ ( \
"pushl %" #num_out_constraints "\n\t" \
"call 1f\n\t" \
"jmp 2f\n\t" \
"\n1:\n\t" \
"pushl installed_librm\n\t" \
"addl $_real_call, 0(%%esp)\n\t" \
"ret\n\t" \
"\n2:\n\t" \
"addl $4, %%esp\n\t" \
: out_constraints \
: in_constraints \
: clobber \
); \
} while ( 0 )
/* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */
#define PASSTHRU(...) __VA_ARGS__
#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \
in_constraints, clobber ) \
do { \
segoff_t fragment; \
\
REAL_FRAGMENT ( name, asm_code_str ); \
\
fragment.segment = inst_rm_stack.segment; \
fragment.offset = \
copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) ); \
\
REAL_CALL ( fragment, num_out_constraints, \
PASSTHRU ( out_constraints ), \
PASSTHRU ( in_constraints ), \
PASSTHRU ( clobber ) ); \
\
remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) ); \
} while ( 0 )
#endif /* ASSEMBLY */
#endif /* LIBRM_H */

View File

@@ -0,0 +1,34 @@
#ifndef MEMSIZES_H
#define MEMSIZES_H
/*
* These structures seem to be very i386 (and, in fact, PCBIOS)
* specific, so I've moved them out of etherboot.h.
*
*/
struct e820entry {
uint64_t addr;
uint64_t size;
uint32_t type;
#define E820_RAM 1
#define E820_RESERVED 2
#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
#define E820_NVS 4
} __attribute__ (( packed ));
#define E820ENTRY_SIZE 20
#define E820MAX 32
struct meminfo {
uint16_t basememsize;
uint16_t pad;
uint32_t memsize;
uint32_t map_count;
struct e820entry map[E820MAX];
} __attribute__ (( packed ));
extern struct meminfo meminfo;
extern void get_memsizes ( void );
#endif /* MEMSIZES_H */

View File

@@ -8,7 +8,7 @@
#define PIC8259_H
/* For segoff_t */
#include "segoff.h"
#include "realmode.h"
#define IRQ_PIC_CUTOFF (8)
@@ -90,7 +90,7 @@ void dump_irq_status ( void );
* handler code, so we put prototypes and the size macro here.
*/
extern void _trivial_irq_handler ( void );
extern void _trivial_irq_handler_end ( void );
extern char _trivial_irq_handler_size[];
#define TRIVIAL_IRQ_HANDLER_SIZE FRAGMENT_SIZE(_trivial_irq_handler)
#endif /* PIC8259_H */

View File

@@ -5,7 +5,6 @@
#define PXE_CALLBACKS_H
#include "etherboot.h"
#include "segoff.h"
#include "pxe.h"
typedef struct {

View File

@@ -10,7 +10,7 @@
/* SEGOFF16_t defined in separate header
*/
#include "segoff.h"
#include "realmode.h"
typedef segoff_t I386_SEGOFF16_t;
#define SEGOFF16_t I386_SEGOFF16_t

View File

@@ -1,124 +1,124 @@
/* Real-mode interface
*/
#ifndef REALMODE_H
#define REALMODE_H
#ifndef ASSEMBLY
#include "etherboot.h"
#include "segoff.h"
#include "stdint.h"
#include "compiler.h"
#include "registers.h"
#include "io.h"
typedef union {
struct {
union {
uint8_t l;
uint8_t byte;
};
uint8_t h;
} PACKED;
uint16_t word;
} PACKED reg16_t;
typedef union {
reg16_t w;
uint32_t dword;
} PACKED reg32_t;
/* Macros to help with defining inline real-mode trampoline fragments.
/*
* Data structures and type definitions
*
*/
#define RM_XSTR(x) #x /* Macro hackery needed to stringify */
/* All i386 registers, as passed in by prot_call or kir_call */
struct real_mode_regs {
struct i386_all_regs;
} PACKED;
/* Segment:offset structure. Note that the order within the structure
* is offset:segment.
*/
typedef struct {
uint16_t offset;
uint16_t segment;
} segoff_t PACKED;
/* Macro hackery needed to stringify bits of inline assembly */
#define RM_XSTR(x) #x
#define RM_STR(x) RM_XSTR(x)
#define RM_FRAGMENT(name, asm_code_str) \
extern void name ( void ); \
extern void name ## _end (void); \
__asm__( \
".section \".text16\"\n\t" \
".code16\n\t" \
".arch i386\n\t" \
".globl " #name " \n\t" \
#name ":\n\t" \
asm_code_str "\n\t" \
".globl " #name "_end\n\t" \
#name "_end:\n\t" \
".code32\n\t" \
".previous\n\t" \
)
#define FRAGMENT_SIZE(fragment) ( (size_t) ( ( (void*) fragment ## _end )\
- ( (void*) (fragment) ) ) )
/* Data structures in _prot_to_real and _real_to_prot. These
* structures are accessed by assembly code as well as C code.
*/
typedef struct {
uint32_t esp;
uint16_t cs;
uint16_t ss;
uint32_t r2p_params;
} PACKED prot_to_real_params_t;
typedef struct {
uint32_t ret_addr;
uint32_t esp;
uint32_t ebx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t out_stack;
uint32_t out_stack_len;
} PACKED real_to_prot_params_t;
/* Function prototypes: realmode.c
*/
#define real_call( fragment, in_stack, out_stack ) \
_real_call ( fragment, FRAGMENT_SIZE(fragment), \
(void*)(in_stack), \
( (in_stack) == NULL ? 0 : sizeof(*(in_stack)) ), \
(void*)(out_stack), \
( (out_stack) == NULL ? 0 : sizeof(*(out_stack)) ) )
extern uint16_t _real_call ( void *fragment, int fragment_len,
void *in_stack, int in_stack_len,
void *out_stack, int out_stack_len );
/* Function prototypes: realmode_asm.S
*/
extern void rm_callback_interface;
extern uint16_t rm_callback_interface_size;
extern uint32_t rm_etherboot_location;
extern void _rm_in_call ( void );
extern void _rm_in_call_far ( void );
extern void _prot_to_real_prefix ( void );
extern void _prot_to_real_prefix_end ( void );
extern uint16_t prot_to_real_prefix_size;
extern void _real_to_prot_suffix ( void );
extern void _real_to_prot_suffix_end ( void );
extern uint16_t real_to_prot_suffix_size;
/* PXE assembler bits */
extern void pxe_callback_interface;
extern uint16_t pxe_callback_interface_size;
extern void _pxe_in_call_far ( void );
extern void _pxenv_in_call_far ( void );
extern void _pxe_intercept_int1a ( void );
extern segoff_t _pxe_intercepted_int1a;
extern segoff_t _pxe_pxenv_location;
/* Global variables
*/
extern uint32_t real_mode_stack;
extern size_t real_mode_stack_size;
extern int lock_real_mode_stack;
/* Function prototypes from basemem.c
*/
#ifdef LINUXBIOS
/* A silly hard code that let's the code compile and work.
* When this becomes a problem feel free to implement
* something better.
*/
static inline void allot_real_mode_stack(void) { real_mode_stack = 0x7c00; }
/* Drag in the selected real-mode transition library header */
#ifdef KEEP_IT_REAL
#include "libkir.h"
#else
void allot_real_mode_stack(void);
#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.
*
*/
/*
* 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 )
*
* These functions can be used to copy data to and from arbitrary
* locations in base memory.
*/
/*
* put_real ( variable, uint16_t dest_seg, uint16_t dest_off )
* get_real ( variable, uint16_t src_seg, uint16_t src_off )
*
* 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.
*/
/*
* REAL_CALL ( routine, num_out_constraints, out_constraints,
* in_constraints, clobber )
* REAL_EXEC ( name, asm_code_str, num_out_constraints, out_constraints,
* in_constraints, clobber )
*
* If you have a pre-existing real-mode routine that you want to make
* a far call to, use REAL_CALL. If you have a code fragment that you
* want to copy down to base memory, execute, and then remove, use
* REAL_EXEC.
*
* out_constraints must be of the form OUT_CONSTRAINTS(constraints),
* and in_constraints must be of the form IN_CONSTRAINTS(constraints),
* where "constraints" is a constraints list as would be used in an
* inline __asm__()
*
* clobber must be of the form CLOBBER ( clobber_list ), where
* "clobber_list" is a clobber list as would be used in an inline
* __asm__().
*
* These are best illustrated by example. To write a character to the
* console using INT 10, you would do something like:
*
* REAL_EXEC ( rm_test_librm,
* "int $0x10",
* 1,
* OUT_CONSTRAINTS ( "=a" ( discard ) ),
* IN_CONSTRAINTS ( "a" ( 0x0e00 + character ),
* "b" ( 1 ) ),
* CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
*
* IMPORTANT: gcc does not automatically assume that input operands
* get clobbered. The only way to specify that an input operand may
* be modified is to also specify it as an output operand; hence the
* "(discard)" in the above code.
*/
#warning "realmode.h contains placeholders for obsolete macros"
/* Just for now */
#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
/* To make basemem.c compile */
extern int lock_real_mode_stack;
extern char *real_mode_stack;
extern char real_mode_stack_size[];
#define RM_FRAGMENT(name,asm) \
void name ( void ) {} \
extern char name ## _size[];
#endif /* ASSEMBLY */
#endif /* REALMODE_H */

View File

@@ -0,0 +1,93 @@
#ifndef REGISTERS_H
#define REGISTERS_H
#include "stdint.h"
#include "compiler.h"
/* Basic 16-bit and 32-bit register types */
typedef union {
struct {
union {
uint8_t l;
uint8_t byte;
};
uint8_t h;
} PACKED;
uint16_t word;
} PACKED reg16_t;
typedef union {
reg16_t;
uint32_t dword;
} PACKED reg32_t;
/* As created by pushal / read by popal */
struct i386_regs {
union {
uint16_t di;
uint32_t edi;
};
union {
uint16_t si;
uint32_t esi;
};
union {
uint16_t bp;
uint32_t ebp;
};
union {
uint16_t sp;
uint32_t esp;
};
union {
struct {
uint8_t bl;
uint8_t bh;
} PACKED;
uint16_t bx;
uint32_t ebx;
};
union {
struct {
uint8_t dl;
uint8_t dh;
} PACKED;
uint16_t dx;
uint32_t edx;
};
union {
struct {
uint8_t cl;
uint8_t ch;
} PACKED;
uint16_t cx;
uint32_t ecx;
};
union {
struct {
uint8_t al;
uint8_t ah;
} PACKED;
uint16_t ax;
uint32_t eax;
};
} PACKED;
/* Our pushal/popal equivalent for segment registers */
struct i386_seg_regs {
uint16_t cs;
uint16_t ss;
uint16_t ds;
uint16_t es;
uint16_t fs;
uint16_t gs;
} PACKED;
/* All i386 registers, as passed in by prot_call or kir_call */
struct i386_all_regs {
struct i386_seg_regs;
struct i386_regs;
uint32_t i386_flags;
} PACKED;
#endif /* REGISTERS_H */

View File

@@ -1,41 +0,0 @@
/*
* Segment:offset types and macros
*
* Initially written by Michael Brown (mcb30).
*/
#ifndef SEGOFF_H
#define SEGOFF_H
#include <stdint.h>
#include <osdep.h>
#include <io.h>
/* Segment:offset structure. Note that the order within the structure
* is offset:segment.
*/
typedef struct {
uint16_t offset;
uint16_t segment;
} segoff_t;
/* Macros for converting from virtual to segment:offset addresses,
* when we don't actually care which of the many isomorphic results we
* get.
*/
#ifdef DEBUG_SEGMENT
uint16_t SEGMENT ( const void * const ptr ) {
uint32_t phys = virt_to_phys ( ptr );
if ( phys > 0xfffff ) {
printf ( "FATAL ERROR: segment address out of range\n" );
}
return phys >> 4;
}
#else
#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
#endif
#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
#endif /* SEGOFF_H */

View File

@@ -0,0 +1,85 @@
#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 PHYSICAL_CS 0x08
#define PHYSICAL_DS 0x10
#define VIRTUAL_CS 0x18
#define VIRTUAL_DS 0x20
#define LONG_CS 0x28
#define LONG_DS 0x30
#ifndef ASSEMBLY
#include "stdint.h"
#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.
*
*/
/* C-callable function prototypes */
extern void relocate_to ( uint32_t new_phys_addr );
/* Variables in virtaddr.S */
extern unsigned long virt_offset;
/*
* Convert between virtual and physical addresses
*
*/
static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
return ( ( unsigned long ) virt_addr ) + virt_offset;
}
static inline void * phys_to_virt ( unsigned long phys_addr ) {
return ( void * ) ( phys_addr - virt_offset );
}
#else /* KEEP_IT_REAL */
/*
* 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 */