summaryrefslogtreecommitdiffstats
path: root/src/arch/x86/transitions/librm_mgmt.c
diff options
context:
space:
mode:
authorMichael Brown2016-02-16 16:19:01 +0100
committerMichael Brown2016-02-16 20:32:32 +0100
commitf468f12b1eca15e703aa2a79f1c82969c04c2322 (patch)
treef1868e6cb7debaeb7aca59e4488b603fcc6481d7 /src/arch/x86/transitions/librm_mgmt.c
parent[bios] Move isolinux definitions to Makefile.pcbios (diff)
downloadipxe-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.c158
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 );