2008-10-13 03:47:33 +01:00
|
|
|
/*
|
|
|
|
|
* librm: a library for interfacing to real-mode code
|
|
|
|
|
*
|
|
|
|
|
* Michael Brown <mbrown@fensystems.co.uk>
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2009-05-01 15:41:06 +01:00
|
|
|
FILE_LICENCE ( GPL2_OR_LATER );
|
|
|
|
|
|
2008-10-13 03:47:33 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <realmode.h>
|
2014-04-28 20:17:15 +01:00
|
|
|
#include <pic8259.h>
|
2008-10-13 03:47:33 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file provides functions for managing librm.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2014-04-28 20:17:15 +01:00
|
|
|
/** The interrupt wrapper */
|
|
|
|
|
extern char interrupt_wrapper[];
|
|
|
|
|
|
|
|
|
|
/** The interrupt vectors */
|
|
|
|
|
static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ];
|
|
|
|
|
|
|
|
|
|
/** The interrupt descriptor table */
|
|
|
|
|
struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
|
|
|
|
|
|
|
|
|
|
/** The interrupt descriptor table register */
|
2014-05-02 13:18:55 +01:00
|
|
|
struct idtr idtr = {
|
2014-04-28 20:17:15 +01:00
|
|
|
.limit = ( sizeof ( idt ) - 1 ),
|
|
|
|
|
};
|
|
|
|
|
|
2008-10-13 03:47:33 +01:00
|
|
|
/**
|
|
|
|
|
* Allocate space on the real-mode stack and copy data there from a
|
|
|
|
|
* user buffer
|
|
|
|
|
*
|
2014-04-28 20:17:15 +01:00
|
|
|
* @v data User buffer
|
|
|
|
|
* @v size Size of stack data
|
|
|
|
|
* @ret sp New value of real-mode stack pointer
|
2008-10-13 03:47:33 +01:00
|
|
|
*/
|
|
|
|
|
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.
|
|
|
|
|
*
|
2014-04-28 20:17:15 +01:00
|
|
|
* @v data User buffer
|
|
|
|
|
* @v size Size of stack data
|
2008-10-13 03:47:33 +01:00
|
|
|
*/
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-28 20:17:15 +01:00
|
|
|
/**
|
|
|
|
|
* 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 = ( ( ( uint32_t ) vector ) & 0xffff );
|
|
|
|
|
idte->high = ( ( ( uint32_t ) vector ) >> 16 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialise interrupt descriptor table
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
void init_idt ( void ) {
|
|
|
|
|
struct interrupt_vector *vec;
|
|
|
|
|
unsigned int irq;
|
|
|
|
|
unsigned int intr;
|
|
|
|
|
|
|
|
|
|
/* Initialise the interrupt descriptor table and interrupt vectors */
|
|
|
|
|
for ( irq = 0 ; irq <= IRQ_MAX ; irq++ ) {
|
|
|
|
|
intr = IRQ_INT ( irq );
|
|
|
|
|
vec = &intr_vec[irq];
|
|
|
|
|
vec->pushal = PUSHAL_INSN;
|
|
|
|
|
vec->movb = MOVB_INSN;
|
|
|
|
|
vec->intr = intr;
|
|
|
|
|
vec->jmp = JMP_INSN;
|
|
|
|
|
vec->offset = ( ( uint32_t ) interrupt_wrapper -
|
|
|
|
|
( uint32_t ) vec->next );
|
|
|
|
|
set_interrupt_vector ( intr, vec );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialise the interrupt descriptor table register */
|
|
|
|
|
idtr.base = virt_to_phys ( idt );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Interrupt handler
|
|
|
|
|
*
|
|
|
|
|
* @v irq Interrupt number
|
|
|
|
|
*/
|
|
|
|
|
void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int irq ) {
|
|
|
|
|
uint32_t discard_eax;
|
|
|
|
|
|
|
|
|
|
/* Reissue interrupt in real mode */
|
|
|
|
|
__asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
|
|
|
|
|
"\n1:\n\t"
|
|
|
|
|
"int $0x00\n\t" )
|
|
|
|
|
: "=a" ( discard_eax ) : "0" ( irq ) );
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-13 03:47:33 +01:00
|
|
|
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 );
|