1*2e8aa19cSIngo Weinhold/* 2*2e8aa19cSIngo Weinhold * Copyright 2004-2010, Axel Dörfler, axeld@pinc-software.de. 3*2e8aa19cSIngo Weinhold * Distributed under the terms of the MIT License. 4*2e8aa19cSIngo Weinhold */ 5*2e8aa19cSIngo Weinhold 6*2e8aa19cSIngo Weinhold 7*2e8aa19cSIngo Weinhold/*! This file contains code to call BIOS functions out of a protected 8*2e8aa19cSIngo Weinhold mode environment. It doesn't use the virtual86 mode - it switches 9*2e8aa19cSIngo Weinhold to real mode, make the BIOS call, and switch back to protected 10*2e8aa19cSIngo Weinhold mode again. It's meant to be used in a single-threaded boot loader, 11*2e8aa19cSIngo Weinhold not in a multi-tasking operating system. 12*2e8aa19cSIngo Weinhold It relies on the real mode segment descriptors found in shell.S. 13*2e8aa19cSIngo Weinhold*/ 14*2e8aa19cSIngo Weinhold 15*2e8aa19cSIngo Weinhold 16*2e8aa19cSIngo Weinhold#define FUNCTION(x) .globl x ; x ## : 17*2e8aa19cSIngo Weinhold 18*2e8aa19cSIngo Weinhold#define REAL_MODE_STACK 0x9000 19*2e8aa19cSIngo Weinhold // the location of the stack in real mode 20*2e8aa19cSIngo Weinhold 21*2e8aa19cSIngo Weinhold#define SAVED_ESP 0x10000 22*2e8aa19cSIngo Weinhold#define SAVED_CR3 0x10004 23*2e8aa19cSIngo Weinhold#define SAVED_EAX 0x10008 24*2e8aa19cSIngo Weinhold#define SAVED_ES 0x1000c 25*2e8aa19cSIngo Weinhold#define SAVED_FLAGS 0x10010 26*2e8aa19cSIngo Weinhold#define SAVED_EBP 0x10014 27*2e8aa19cSIngo Weinhold // we're overwriting the start of our boot loader to hold some 28*2e8aa19cSIngo Weinhold // temporary values - the first 1024 bytes of it are used at 29*2e8aa19cSIngo Weinhold // startup only, and we avoid some linking issues this way 30*2e8aa19cSIngo Weinhold 31*2e8aa19cSIngo Weinhold 32*2e8aa19cSIngo Weinhold.text 33*2e8aa19cSIngo Weinhold.code32 34*2e8aa19cSIngo Weinhold 35*2e8aa19cSIngo Weinhold 36*2e8aa19cSIngo Weinhold/*! This function brings you back to protected mode after you've 37*2e8aa19cSIngo Weinhold switched to it using switch_to_real_mode(). 38*2e8aa19cSIngo Weinhold Should restore the whole environment to what it looked like 39*2e8aa19cSIngo Weinhold before. Clobbers %eax. 40*2e8aa19cSIngo Weinhold*/ 41*2e8aa19cSIngo WeinholdFUNCTION(switch_to_protected_mode) 42*2e8aa19cSIngo Weinhold cli // turn off interrupts 43*2e8aa19cSIngo Weinhold 44*2e8aa19cSIngo Weinhold .code16 45*2e8aa19cSIngo Weinhold movl %cr0, %eax // set the PE bit (0) to switch to protected mode 46*2e8aa19cSIngo Weinhold orb $0x1, %al 47*2e8aa19cSIngo Weinhold movl %eax, %cr0 48*2e8aa19cSIngo Weinhold 49*2e8aa19cSIngo Weinhold .code32 50*2e8aa19cSIngo Weinhold .byte 0x66 // jump to the protected mode segment 51*2e8aa19cSIngo Weinhold ljmp $0x8, $_protected_code_segment 52*2e8aa19cSIngo Weinhold_protected_code_segment: 53*2e8aa19cSIngo Weinhold movw $0x10, %ax // setup data and stack selectors 54*2e8aa19cSIngo Weinhold movw %ax, %ds 55*2e8aa19cSIngo Weinhold movw %ax, %es 56*2e8aa19cSIngo Weinhold movw %ax, %fs 57*2e8aa19cSIngo Weinhold movw %ax, %gs 58*2e8aa19cSIngo Weinhold movw %ax, %ss 59*2e8aa19cSIngo Weinhold 60*2e8aa19cSIngo Weinhold // turn on paging again 61*2e8aa19cSIngo Weinhold movl SAVED_CR3, %eax // restore the saved page directory 62*2e8aa19cSIngo Weinhold orl %eax, %eax // is there a paging directory at all? 63*2e8aa19cSIngo Weinhold jz _no_paging; 64*2e8aa19cSIngo Weinhold 65*2e8aa19cSIngo Weinhold movl %eax, %cr3 66*2e8aa19cSIngo Weinhold 67*2e8aa19cSIngo Weinhold movl %cr0, %eax // set the PG bit (31) to enable paging 68*2e8aa19cSIngo Weinhold orl $0x80000000, %eax 69*2e8aa19cSIngo Weinhold movl %eax, %cr0 70*2e8aa19cSIngo Weinhold 71*2e8aa19cSIngo Weinhold_no_paging: 72*2e8aa19cSIngo Weinhold // save the return address so that we can pick it up again later 73*2e8aa19cSIngo Weinhold movl (%esp), %eax 74*2e8aa19cSIngo Weinhold movl %eax, REAL_MODE_STACK 75*2e8aa19cSIngo Weinhold 76*2e8aa19cSIngo Weinhold // setup protected stack frame again 77*2e8aa19cSIngo Weinhold movl SAVED_ESP, %eax 78*2e8aa19cSIngo Weinhold movl %eax, %esp 79*2e8aa19cSIngo Weinhold movl SAVED_EBP, %ebp 80*2e8aa19cSIngo Weinhold 81*2e8aa19cSIngo Weinhold // copy the return address to the current stack 82*2e8aa19cSIngo Weinhold movl REAL_MODE_STACK, %eax 83*2e8aa19cSIngo Weinhold movl %eax, (%esp) 84*2e8aa19cSIngo Weinhold 85*2e8aa19cSIngo Weinhold ret 86*2e8aa19cSIngo Weinhold 87*2e8aa19cSIngo Weinhold//-------------------------------------------------------------- 88*2e8aa19cSIngo Weinhold 89*2e8aa19cSIngo Weinhold 90*2e8aa19cSIngo Weinhold/*! Switches from protected mode back to real mode. 91*2e8aa19cSIngo Weinhold It will disable paging and set the real mode segment selectors to 0x1000, 92*2e8aa19cSIngo Weinhold except for the stack selector, which will be 0x0 (the stack is at 0x9000 93*2e8aa19cSIngo Weinhold which is where the BFS boot loader puts it as well). 94*2e8aa19cSIngo Weinhold Clobbers %eax. 95*2e8aa19cSIngo Weinhold*/ 96*2e8aa19cSIngo WeinholdFUNCTION(switch_to_real_mode) 97*2e8aa19cSIngo Weinhold // save the %esp register 98*2e8aa19cSIngo Weinhold movl %esp, %eax 99*2e8aa19cSIngo Weinhold movl %eax, SAVED_ESP 100*2e8aa19cSIngo Weinhold 101*2e8aa19cSIngo Weinhold movl %ebp, SAVED_EBP 102*2e8aa19cSIngo Weinhold 103*2e8aa19cSIngo Weinhold // put the return address on the real mode stack 104*2e8aa19cSIngo Weinhold movl (%esp), %eax 105*2e8aa19cSIngo Weinhold movl %eax, REAL_MODE_STACK 106*2e8aa19cSIngo Weinhold 107*2e8aa19cSIngo Weinhold // disable paging 108*2e8aa19cSIngo Weinhold movl %cr3, %eax // save the page directory address 109*2e8aa19cSIngo Weinhold movl %eax, SAVED_CR3 110*2e8aa19cSIngo Weinhold 111*2e8aa19cSIngo Weinhold movl %cr0, %eax 112*2e8aa19cSIngo Weinhold andl $0x7fffffff, %eax // clear PG bit (31) 113*2e8aa19cSIngo Weinhold movl %eax, %cr0 114*2e8aa19cSIngo Weinhold 115*2e8aa19cSIngo Weinhold xor %eax, %eax // clear page directory to flush TLBs 116*2e8aa19cSIngo Weinhold movl %eax, %cr3 117*2e8aa19cSIngo Weinhold 118*2e8aa19cSIngo Weinhold // setup real mode stack 119*2e8aa19cSIngo Weinhold movl $REAL_MODE_STACK, %eax 120*2e8aa19cSIngo Weinhold movl %eax, %esp 121*2e8aa19cSIngo Weinhold movl %eax, %ebp 122*2e8aa19cSIngo Weinhold 123*2e8aa19cSIngo Weinhold // setup selectors to point to our 16 bit segments 124*2e8aa19cSIngo Weinhold movw $0x20, %ax 125*2e8aa19cSIngo Weinhold movw %ax, %ds 126*2e8aa19cSIngo Weinhold movw %ax, %es 127*2e8aa19cSIngo Weinhold movw %ax, %fs 128*2e8aa19cSIngo Weinhold movw %ax, %gs 129*2e8aa19cSIngo Weinhold movw $0x28, %ax 130*2e8aa19cSIngo Weinhold movw %ax, %ss 131*2e8aa19cSIngo Weinhold 132*2e8aa19cSIngo Weinhold ljmp $0x18, $(_almost_real_code_segment - 0x10000) 133*2e8aa19cSIngo Weinhold 134*2e8aa19cSIngo Weinhold_almost_real_code_segment: 135*2e8aa19cSIngo Weinhold movl %cr0, %eax // switch to real mode 136*2e8aa19cSIngo Weinhold andb $0xfe, %al // clear PE bit (0) 137*2e8aa19cSIngo Weinhold movl %eax, %cr0 138*2e8aa19cSIngo Weinhold 139*2e8aa19cSIngo Weinhold .byte 0x66 140*2e8aa19cSIngo Weinhold ljmp $0x1000, $(_real_code_segment - 0x10000) 141*2e8aa19cSIngo Weinhold 142*2e8aa19cSIngo Weinhold_real_code_segment: 143*2e8aa19cSIngo Weinhold .code16 144*2e8aa19cSIngo Weinhold movw $0x1000, %ax // setup data & stack segments 145*2e8aa19cSIngo Weinhold movw %ax, %ds // data in segment 0x1000, 146*2e8aa19cSIngo Weinhold movw %ax, %es 147*2e8aa19cSIngo Weinhold movw %ax, %fs 148*2e8aa19cSIngo Weinhold movw %ax, %gs 149*2e8aa19cSIngo Weinhold 150*2e8aa19cSIngo Weinhold xor %ax, %ax // stack in segment 0x0 151*2e8aa19cSIngo Weinhold movw %ax, %ss 152*2e8aa19cSIngo Weinhold 153*2e8aa19cSIngo Weinhold sti // turn on interrupts again 154*2e8aa19cSIngo Weinhold ret 155*2e8aa19cSIngo Weinhold 156*2e8aa19cSIngo Weinhold .code32 157*2e8aa19cSIngo Weinhold 158*2e8aa19cSIngo Weinhold//-------------------------------------------------------------- 159*2e8aa19cSIngo Weinhold 160*2e8aa19cSIngo Weinhold 161*2e8aa19cSIngo Weinhold/*! void call_bios_internal(uint8 num, struct bios_regs *regs) 162*2e8aa19cSIngo Weinhold Does a BIOS call by triggering a software interrupt in real 163*2e8aa19cSIngo Weinhold mode. 164*2e8aa19cSIngo Weinhold*/ 165*2e8aa19cSIngo WeinholdFUNCTION(call_bios_internal) 166*2e8aa19cSIngo Weinhold pushal 167*2e8aa19cSIngo Weinhold pushfl 168*2e8aa19cSIngo Weinhold 169*2e8aa19cSIngo Weinhold // make sure the correct IDT is in place 170*2e8aa19cSIngo Weinhold lidt idt_descriptor 171*2e8aa19cSIngo Weinhold 172*2e8aa19cSIngo Weinhold // get the interrupt vector and patch the instruction at the target address 173*2e8aa19cSIngo Weinhold movl 40(%esp), %eax 174*2e8aa19cSIngo Weinhold mov %al, int_number 175*2e8aa19cSIngo Weinhold 176*2e8aa19cSIngo Weinhold // Fills registers from the passed in structure 177*2e8aa19cSIngo Weinhold // Since switch_to_real_mode() clobbers %eax, we have to handle 178*2e8aa19cSIngo Weinhold // it specially here (by temporarily storing it to an arbitrary 179*2e8aa19cSIngo Weinhold // memory location, SAVED_EAX) 180*2e8aa19cSIngo Weinhold movl 44(%esp), %ebp 181*2e8aa19cSIngo Weinhold 182*2e8aa19cSIngo Weinhold movl (%ebp), %eax 183*2e8aa19cSIngo Weinhold movl %eax, SAVED_EAX 184*2e8aa19cSIngo Weinhold movl 4(%ebp), %ebx 185*2e8aa19cSIngo Weinhold movl 8(%ebp), %ecx 186*2e8aa19cSIngo Weinhold movl 12(%ebp), %edx 187*2e8aa19cSIngo Weinhold movl 16(%ebp), %esi 188*2e8aa19cSIngo Weinhold movl 20(%ebp), %edi 189*2e8aa19cSIngo Weinhold movw 24(%ebp), %ax 190*2e8aa19cSIngo Weinhold movw %ax, SAVED_ES 191*2e8aa19cSIngo Weinhold 192*2e8aa19cSIngo Weinhold call switch_to_real_mode 193*2e8aa19cSIngo Weinhold 194*2e8aa19cSIngo Weinhold .code16 195*2e8aa19cSIngo Weinhold 196*2e8aa19cSIngo Weinhold // restore %eax and %es from saved location 197*2e8aa19cSIngo Weinhold movl (SAVED_EAX - 0x10000), %eax 198*2e8aa19cSIngo Weinhold movw (SAVED_ES - 0x10000), %es 199*2e8aa19cSIngo Weinhold 200*2e8aa19cSIngo Weinhold // call the interrupt (will be dynamically changed above) 201*2e8aa19cSIngo Weinhold .byte 0xcd 202*2e8aa19cSIngo Weinholdint_number: 203*2e8aa19cSIngo Weinhold .byte 0 204*2e8aa19cSIngo Weinhold 205*2e8aa19cSIngo Weinhold // we're interested in the flags state as well 206*2e8aa19cSIngo Weinhold pushf 207*2e8aa19cSIngo Weinhold 208*2e8aa19cSIngo Weinhold // save %eax from the call 209*2e8aa19cSIngo Weinhold movl %eax, (SAVED_EAX - 0x10000) 210*2e8aa19cSIngo Weinhold 211*2e8aa19cSIngo Weinhold // save flags from the call 212*2e8aa19cSIngo Weinhold pop %ax 213*2e8aa19cSIngo Weinhold movw %ax, (SAVED_FLAGS - 0x10000) 214*2e8aa19cSIngo Weinhold 215*2e8aa19cSIngo Weinhold // back to protected mode 216*2e8aa19cSIngo Weinhold call switch_to_protected_mode 217*2e8aa19cSIngo Weinhold .code32 218*2e8aa19cSIngo Weinhold 219*2e8aa19cSIngo Weinhold // store the register state into the structure that has been passed in 220*2e8aa19cSIngo Weinhold movl 44(%esp), %eax 221*2e8aa19cSIngo Weinhold 222*2e8aa19cSIngo Weinhold movl %ebx, 4(%eax) 223*2e8aa19cSIngo Weinhold movl %ecx, 8(%eax) 224*2e8aa19cSIngo Weinhold movl %edx, 12(%eax) 225*2e8aa19cSIngo Weinhold movl %esi, 16(%eax) 226*2e8aa19cSIngo Weinhold movl %edi, 20(%eax) 227*2e8aa19cSIngo Weinhold movl SAVED_EAX, %ecx // special handling for %eax and flags 228*2e8aa19cSIngo Weinhold movl %ecx, (%eax) 229*2e8aa19cSIngo Weinhold movw SAVED_FLAGS, %cx 230*2e8aa19cSIngo Weinhold movw %cx, 26(%eax) 231*2e8aa19cSIngo Weinhold 232*2e8aa19cSIngo Weinhold popfl 233*2e8aa19cSIngo Weinhold popal 234*2e8aa19cSIngo Weinhold 235*2e8aa19cSIngo Weinhold ret 236*2e8aa19cSIngo Weinhold 237*2e8aa19cSIngo Weinhold//-------------------------------------------------------------- 238*2e8aa19cSIngo Weinhold 239*2e8aa19cSIngo Weinhold 240*2e8aa19cSIngo Weinhold/*! uint32 boot_key_in_keyboard_buffer() 241*2e8aa19cSIngo Weinhold Search keyboard buffer for the keycodes for space in the first run, and, 242*2e8aa19cSIngo Weinhold if not found - for the escape key at the last two positions of this buffer 243*2e8aa19cSIngo Weinhold*/ 244*2e8aa19cSIngo WeinholdFUNCTION(boot_key_in_keyboard_buffer) 245*2e8aa19cSIngo Weinhold pushal 246*2e8aa19cSIngo Weinhold pushfl 247*2e8aa19cSIngo Weinhold 248*2e8aa19cSIngo Weinhold // make sure the correct IDT is in place 249*2e8aa19cSIngo Weinhold lidt idt_descriptor 250*2e8aa19cSIngo Weinhold 251*2e8aa19cSIngo Weinhold call switch_to_real_mode 252*2e8aa19cSIngo Weinhold .code16 253*2e8aa19cSIngo Weinhold 254*2e8aa19cSIngo Weinhold cld 255*2e8aa19cSIngo Weinhold push %ds 256*2e8aa19cSIngo Weinhold xorl %eax, %eax 257*2e8aa19cSIngo Weinhold mov %ax, %ds 258*2e8aa19cSIngo Weinhold mov $0x41E, %si // BIOS kbd buffer 259*2e8aa19cSIngo Weinholdsearch_cycle1: 260*2e8aa19cSIngo Weinhold lodsw 261*2e8aa19cSIngo Weinhold cmp $0x3920, %ax // test space key 262*2e8aa19cSIngo Weinhold jz to_ret 263*2e8aa19cSIngo Weinhold cmp $0x440, %si 264*2e8aa19cSIngo Weinhold jnz search_cycle1 265*2e8aa19cSIngo Weinhold 266*2e8aa19cSIngo Weinhold addw 0x41C, %si 267*2e8aa19cSIngo Weinhold movw -0x42(%si), %ax 268*2e8aa19cSIngo Weinhold cmp $0x011B, %ax // test ESC key 269*2e8aa19cSIngo Weinhold jz to_ret 270*2e8aa19cSIngo Weinhold movw -0x44(%si), %ax 271*2e8aa19cSIngo Weinhold cmp $0x011B, %ax // test ESC key 272*2e8aa19cSIngo Weinholdto_ret: 273*2e8aa19cSIngo Weinhold pop %ds 274*2e8aa19cSIngo Weinhold 275*2e8aa19cSIngo Weinhold // save %eax 276*2e8aa19cSIngo Weinhold movl %eax, (SAVED_EAX - 0x10000) 277*2e8aa19cSIngo Weinhold 278*2e8aa19cSIngo Weinhold call switch_to_protected_mode 279*2e8aa19cSIngo Weinhold .code32 280*2e8aa19cSIngo Weinhold 281*2e8aa19cSIngo Weinhold popfl 282*2e8aa19cSIngo Weinhold popal 283*2e8aa19cSIngo Weinhold 284*2e8aa19cSIngo Weinhold // restore %eax 285*2e8aa19cSIngo Weinhold movl SAVED_EAX, %eax 286*2e8aa19cSIngo Weinhold 287*2e8aa19cSIngo Weinhold ret 288*2e8aa19cSIngo Weinhold 289*2e8aa19cSIngo Weinhold//-------------------------------------------------------------- 290*2e8aa19cSIngo Weinhold 291*2e8aa19cSIngo Weinhold 292*2e8aa19cSIngo Weinhold.globl idt_descriptor 293*2e8aa19cSIngo Weinholdidt_descriptor: 294*2e8aa19cSIngo Weinhold .short 0x7ff // IDT at 0x0, default real mode location 295*2e8aa19cSIngo Weinhold .long 0x0 296