mirror of
https://github.com/ipxe/ipxe
synced 2025-12-27 10:02:42 +03:00
Merged mcb30-realmode-redesign back to HEAD
This commit is contained in:
10
src/arch/i386/include/bios.h
Normal file
10
src/arch/i386/include/bios.h
Normal 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 */
|
||||
27
src/arch/i386/include/bochs.h
Normal file
27
src/arch/i386/include/bochs.h
Normal 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 */
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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.
|
||||
|
||||
18
src/arch/i386/include/kir.h
Normal file
18
src/arch/i386/include/kir.h
Normal 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 */
|
||||
184
src/arch/i386/include/libkir.h
Normal file
184
src/arch/i386/include/libkir.h
Normal 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 */
|
||||
186
src/arch/i386/include/librm.h
Normal file
186
src/arch/i386/include/librm.h
Normal 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 */
|
||||
34
src/arch/i386/include/memsizes.h
Normal file
34
src/arch/i386/include/memsizes.h
Normal 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 */
|
||||
@@ -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 */
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#define PXE_CALLBACKS_H
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "segoff.h"
|
||||
#include "pxe.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
93
src/arch/i386/include/registers.h
Normal file
93
src/arch/i386/include/registers.h
Normal 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 */
|
||||
@@ -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 */
|
||||
85
src/arch/i386/include/virtaddr.h
Normal file
85
src/arch/i386/include/virtaddr.h
Normal 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 */
|
||||
Reference in New Issue
Block a user