diff options
author | Michael Brown | 2016-02-16 16:19:01 +0100 |
---|---|---|
committer | Michael Brown | 2016-02-16 20:32:32 +0100 |
commit | f468f12b1eca15e703aa2a79f1c82969c04c2322 (patch) | |
tree | f1868e6cb7debaeb7aca59e4488b603fcc6481d7 /src/arch/x86/transitions/librm_mgmt.c | |
parent | [bios] Move isolinux definitions to Makefile.pcbios (diff) | |
download | ipxe-f468f12b1eca15e703aa2a79f1c82969c04c2322.tar.gz ipxe-f468f12b1eca15e703aa2a79f1c82969c04c2322.tar.xz ipxe-f468f12b1eca15e703aa2a79f1c82969c04c2322.zip |
[bios] Add bin-x86_64-pcbios build platform
Move most arch/i386 files to arch/x86, and adjust the contents of the
Makefiles and the include/bits/*.h headers to reflect the new
locations.
This patch makes no substantive code changes, as can be seen using a
rename-aware diff (e.g. "git show -M5").
This patch does not make the pcbios platform functional for x86_64; it
merely allows it to compile without errors.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/x86/transitions/librm_mgmt.c')
-rw-r--r-- | src/arch/x86/transitions/librm_mgmt.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/arch/x86/transitions/librm_mgmt.c b/src/arch/x86/transitions/librm_mgmt.c new file mode 100644 index 00000000..32695ae0 --- /dev/null +++ b/src/arch/x86/transitions/librm_mgmt.c @@ -0,0 +1,158 @@ +/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown <mbrown@fensystems.co.uk> + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <ipxe/profile.h> +#include <realmode.h> +#include <pic8259.h> + +/* + * This file provides functions for managing librm. + * + */ + +/** The interrupt wrapper */ +extern char interrupt_wrapper[]; + +/** The interrupt vectors */ +static struct interrupt_vector intr_vec[NUM_INT]; + +/** The interrupt descriptor table */ +struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) )); + +/** The interrupt descriptor table register */ +struct idtr idtr = { + .limit = ( sizeof ( idt ) - 1 ), +}; + +/** Timer interrupt profiler */ +static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" }; + +/** Other interrupt profiler */ +static struct profiler other_irq_profiler __profiler = { .name = "irq.other" }; + +/** + * Allocate space on the real-mode stack and copy data there from a + * user buffer + * + * @v data User buffer + * @v size Size of stack data + * @ret sp New value of real-mode stack pointer + */ +uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { + userptr_t rm_stack; + rm_sp -= size; + rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + return rm_sp; +}; + +/** + * Deallocate space on the real-mode stack, optionally copying back + * data to a user buffer. + * + * @v data User buffer + * @v size Size of stack data + */ +void remove_user_from_rm_stack ( userptr_t data, size_t size ) { + if ( data ) { + userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + } + rm_sp += size; +}; + +/** + * Set interrupt vector + * + * @v intr Interrupt number + * @v vector Interrupt vector, or NULL to disable + */ +void set_interrupt_vector ( unsigned int intr, void *vector ) { + struct interrupt_descriptor *idte; + + idte = &idt[intr]; + idte->segment = VIRTUAL_CS; + idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 ); + idte->low = ( ( ( intptr_t ) vector ) & 0xffff ); + idte->high = ( ( ( intptr_t ) vector ) >> 16 ); +} + +/** + * Initialise interrupt descriptor table + * + */ +void init_idt ( void ) { + struct interrupt_vector *vec; + unsigned int intr; + + /* Initialise the interrupt descriptor table and interrupt vectors */ + for ( intr = 0 ; intr < NUM_INT ; intr++ ) { + vec = &intr_vec[intr]; + vec->pushal = PUSHAL_INSN; + vec->movb = MOVB_INSN; + vec->intr = intr; + vec->jmp = JMP_INSN; + vec->offset = ( ( intptr_t ) interrupt_wrapper - + ( intptr_t ) vec->next ); + set_interrupt_vector ( intr, vec ); + } + DBGC ( &intr_vec[0], "INTn vector at %p+%zxn (phys %#lx+%zxn)\n", + intr_vec, sizeof ( intr_vec[0] ), + virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) ); + + /* Initialise the interrupt descriptor table register */ + idtr.base = virt_to_phys ( idt ); +} + +/** + * Determine interrupt profiler (for debugging) + * + * @v intr Interrupt number + * @ret profiler Profiler + */ +static struct profiler * interrupt_profiler ( int intr ) { + + switch ( intr ) { + case IRQ_INT ( 0 ) : + return &timer_irq_profiler; + default: + return &other_irq_profiler; + } +} + +/** + * Interrupt handler + * + * @v intr Interrupt number + */ +void __attribute__ (( regparm ( 1 ) )) interrupt ( int intr ) { + struct profiler *profiler = interrupt_profiler ( intr ); + uint32_t discard_eax; + + /* Reissue interrupt in real mode */ + profile_start ( profiler ); + __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t" + "\n1:\n\t" + "int $0x00\n\t" ) + : "=a" ( discard_eax ) : "0" ( intr ) ); + profile_stop ( profiler ); + profile_exclude ( profiler ); +} + +PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); +PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); +PROVIDE_UACCESS_INLINE ( librm, userptr_add ); +PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); +PROVIDE_UACCESS_INLINE ( librm, memmove_user ); +PROVIDE_UACCESS_INLINE ( librm, memset_user ); +PROVIDE_UACCESS_INLINE ( librm, strlen_user ); +PROVIDE_UACCESS_INLINE ( librm, memchr_user ); |