diff options
Diffstat (limited to 'src/arch/i386/include')
-rw-r--r-- | src/arch/i386/include/bios.h | 10 | ||||
-rw-r--r-- | src/arch/i386/include/bochs.h | 27 | ||||
-rw-r--r-- | src/arch/i386/include/hidemem.h | 2 | ||||
-rw-r--r-- | src/arch/i386/include/hooks.h | 19 | ||||
-rw-r--r-- | src/arch/i386/include/io.h | 18 | ||||
-rw-r--r-- | src/arch/i386/include/kir.h | 18 | ||||
-rw-r--r-- | src/arch/i386/include/libkir.h | 184 | ||||
-rw-r--r-- | src/arch/i386/include/librm.h | 186 | ||||
-rw-r--r-- | src/arch/i386/include/memsizes.h | 34 | ||||
-rw-r--r-- | src/arch/i386/include/pic8259.h | 4 | ||||
-rw-r--r-- | src/arch/i386/include/pxe_callbacks.h | 1 | ||||
-rw-r--r-- | src/arch/i386/include/pxe_types.h | 2 | ||||
-rw-r--r-- | src/arch/i386/include/realmode.h | 218 | ||||
-rw-r--r-- | src/arch/i386/include/registers.h | 93 | ||||
-rw-r--r-- | src/arch/i386/include/segoff.h | 41 | ||||
-rw-r--r-- | src/arch/i386/include/virtaddr.h | 85 |
16 files changed, 764 insertions, 178 deletions
diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h new file mode 100644 index 000000000..afc648bae --- /dev/null +++ b/src/arch/i386/include/bios.h @@ -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 */ diff --git a/src/arch/i386/include/bochs.h b/src/arch/i386/include/bochs.h new file mode 100644 index 000000000..73f43c364 --- /dev/null +++ b/src/arch/i386/include/bochs.h @@ -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 */ diff --git a/src/arch/i386/include/hidemem.h b/src/arch/i386/include/hidemem.h index 600a86923..71b0905ff 100644 --- a/src/arch/i386/include/hidemem.h +++ b/src/arch/i386/include/hidemem.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 ); diff --git a/src/arch/i386/include/hooks.h b/src/arch/i386/include/hooks.h index 0764edafa..a4e4b397e 100644 --- a/src/arch/i386/include/hooks.h +++ b/src/arch/i386/include/hooks.h @@ -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 */ diff --git a/src/arch/i386/include/io.h b/src/arch/i386/include/io.h index e351a0c10..5b6a62435 100644 --- a/src/arch/i386/include/io.h +++ b/src/arch/i386/include/io.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. diff --git a/src/arch/i386/include/kir.h b/src/arch/i386/include/kir.h new file mode 100644 index 000000000..84633d26f --- /dev/null +++ b/src/arch/i386/include/kir.h @@ -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 */ diff --git a/src/arch/i386/include/libkir.h b/src/arch/i386/include/libkir.h new file mode 100644 index 000000000..5bac42d88 --- /dev/null +++ b/src/arch/i386/include/libkir.h @@ -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 */ diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h new file mode 100644 index 000000000..16bfc0891 --- /dev/null +++ b/src/arch/i386/include/librm.h @@ -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 */ diff --git a/src/arch/i386/include/memsizes.h b/src/arch/i386/include/memsizes.h new file mode 100644 index 000000000..a5bb3f2df --- /dev/null +++ b/src/arch/i386/include/memsizes.h @@ -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 */ diff --git a/src/arch/i386/include/pic8259.h b/src/arch/i386/include/pic8259.h index 694e9d137..d3f9b8792 100644 --- a/src/arch/i386/include/pic8259.h +++ b/src/arch/i386/include/pic8259.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 */ diff --git a/src/arch/i386/include/pxe_callbacks.h b/src/arch/i386/include/pxe_callbacks.h index 9b941931f..cf5a7a878 100644 --- a/src/arch/i386/include/pxe_callbacks.h +++ b/src/arch/i386/include/pxe_callbacks.h @@ -5,7 +5,6 @@ #define PXE_CALLBACKS_H #include "etherboot.h" -#include "segoff.h" #include "pxe.h" typedef struct { diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h index 7b093e6a5..45736a2bf 100644 --- a/src/arch/i386/include/pxe_types.h +++ b/src/arch/i386/include/pxe_types.h @@ -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 diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h index eca92b9b5..d641869f8 100644 --- a/src/arch/i386/include/realmode.h +++ b/src/arch/i386/include/realmode.h @@ -1,124 +1,124 @@ -/* Real-mode interface - */ +#ifndef REALMODE_H +#define REALMODE_H #ifndef ASSEMBLY -#include "etherboot.h" -#include "segoff.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. +#include "stdint.h" +#include "compiler.h" +#include "registers.h" +#include "io.h" + +/* + * Data structures and type definitions + * */ -#define RM_XSTR(x) #x /* Macro hackery needed to stringify */ -#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. + +/* 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 { - uint32_t esp; - uint16_t cs; - uint16_t ss; - uint32_t r2p_params; -} PACKED prot_to_real_params_t; + uint16_t offset; + uint16_t segment; +} segoff_t PACKED; -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 +/* 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. + * */ -#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 + +/* + * 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. */ -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 + +/* + * 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. */ -extern uint32_t real_mode_stack; -extern size_t real_mode_stack_size; + +/* + * 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[]; -/* 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; } -#else -void allot_real_mode_stack(void); -#endif #endif /* ASSEMBLY */ + +#endif /* REALMODE_H */ diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h new file mode 100644 index 000000000..2e78d418d --- /dev/null +++ b/src/arch/i386/include/registers.h @@ -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 */ diff --git a/src/arch/i386/include/segoff.h b/src/arch/i386/include/segoff.h deleted file mode 100644 index 822ddd332..000000000 --- a/src/arch/i386/include/segoff.h +++ /dev/null @@ -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 */ diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h new file mode 100644 index 000000000..15fad1ccd --- /dev/null +++ b/src/arch/i386/include/virtaddr.h @@ -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 */ |