stage1: add bios call hook
This commit is contained in:
parent
ce19f70440
commit
2ec426677f
2 changed files with 110 additions and 0 deletions
61
stage1/src/asm/int.s
Normal file
61
stage1/src/asm/int.s
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
.text
|
||||||
|
.code32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This has got to be one of the most cursed routines within stage1.
|
||||||
|
* Temporarily returns to Real Mode, does a BIOS interrupt, and then
|
||||||
|
* goes back to Protected Mode again. Furthermore, the interrupt
|
||||||
|
* number is written ahead of time by the callee.
|
||||||
|
*/
|
||||||
|
GLOBL __do_bios_int
|
||||||
|
push %ebp /* '1 v */
|
||||||
|
mov %esp, %ebp
|
||||||
|
pushal /* '2 v */
|
||||||
|
|
||||||
|
mov 8(%ebp), %ebp
|
||||||
|
mov (%ebp), %ax
|
||||||
|
mov 2(%ebp), %cx
|
||||||
|
mov 4(%ebp), %dx
|
||||||
|
mov 6(%ebp), %bx
|
||||||
|
mov 8(%ebp), %si
|
||||||
|
mov 10(%ebp), %di
|
||||||
|
|
||||||
|
push %ebp /* '3 v */
|
||||||
|
|
||||||
|
push %eax /* '4 v */
|
||||||
|
push %edx /* '5 v */
|
||||||
|
call prot_to_real
|
||||||
|
.code16
|
||||||
|
pop %edx /* '5 ^ */
|
||||||
|
pop %eax /* '4 ^ */
|
||||||
|
|
||||||
|
/* call that polymorphism! */
|
||||||
|
.byte 0xcd /* opcode for `int imm8` */
|
||||||
|
GLOBL __bios_int_number, object
|
||||||
|
.byte 0x18 /* this is the imm8 */
|
||||||
|
|
||||||
|
push %eax /* '4 v */
|
||||||
|
push %edx /* '5 v */
|
||||||
|
pushfl /* '6 v */
|
||||||
|
call real_to_prot
|
||||||
|
.code32
|
||||||
|
popfl /* '6 ^ */
|
||||||
|
pop %edx /* '5 ^ */
|
||||||
|
pop %eax /* '4 ^ */
|
||||||
|
|
||||||
|
pop %ebp /* '3 ^ */
|
||||||
|
|
||||||
|
mov %ax, (%ebp)
|
||||||
|
mov %cx, 2(%ebp)
|
||||||
|
mov %dx, 4(%ebp)
|
||||||
|
mov %bx, 6(%ebp)
|
||||||
|
mov %si, 8(%ebp)
|
||||||
|
mov %di, 10(%ebp)
|
||||||
|
mov %al, 12(%ebp)
|
||||||
|
|
||||||
|
popal /* '2 ^ */
|
||||||
|
setc %al
|
||||||
|
movzbl %al, %eax
|
||||||
|
pop %ebx /* '1 ^ */
|
||||||
|
ret
|
||||||
|
END __do_bios_int
|
|
@ -23,3 +23,52 @@ extern "C" {
|
||||||
include_asm!("boot.s");
|
include_asm!("boot.s");
|
||||||
|
|
||||||
include_asm!("pmode.s");
|
include_asm!("pmode.s");
|
||||||
|
|
||||||
|
include_asm!("int.s");
|
||||||
|
extern "C" {
|
||||||
|
/// Temporarily return to Real Mode and do a BIOS interrupt with the
|
||||||
|
/// specified register values. Returns the value of the carry flag
|
||||||
|
/// (`true` if CF=1, `false` if CF=0).
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// This is horrendously unsafe and there is nothing you can do about it.
|
||||||
|
/// Before calling, you MUST set [`__bios_int_number`] to the interrupt
|
||||||
|
/// number you wish to invoke. Cache shouldn't be an issue because going
|
||||||
|
/// from protected to real mode flushes the pipeline and prefetch cache
|
||||||
|
/// anyway, but don't quote me on that.
|
||||||
|
fn __do_bios_int(regs: &mut BiosIntRegs) -> u8;
|
||||||
|
|
||||||
|
/// This is located within [`__do_bios_int`] and writing to it modifies
|
||||||
|
/// the interrupt number that is invoked when calling the function.
|
||||||
|
static mut __bios_int_number: u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub struct BiosIntRegs {
|
||||||
|
pub ax: u16,
|
||||||
|
pub cx: u16,
|
||||||
|
pub dx: u16,
|
||||||
|
pub bx: u16,
|
||||||
|
pub si: u16,
|
||||||
|
pub di: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BiosResult = Result<BiosIntRegs, BiosIntRegs>;
|
||||||
|
|
||||||
|
/// Temporarily return to Real Mode and do a BIOS interrupt with the
|
||||||
|
/// specified register values. Returns `Ok` if the carry flag was
|
||||||
|
/// clear after the interrupt, and `Err` if it was set. In either
|
||||||
|
/// case, the wrapped value contains the state of the registers after
|
||||||
|
/// the interrupt.
|
||||||
|
pub unsafe fn do_bios_int(number: u8, mut regs: BiosIntRegs) -> BiosResult {
|
||||||
|
// this might be mildly unsafe
|
||||||
|
__bios_int_number = number;
|
||||||
|
let cf = __do_bios_int(&mut regs);
|
||||||
|
if cf == 0 {
|
||||||
|
Ok(regs)
|
||||||
|
} else {
|
||||||
|
Err(regs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue