Implemented call_bios() function that is called from protected mode.
It switches to real mode for execution of the BIOS interrupt; it's really only intended for the boot loader. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7233 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
1e56fb4aeb
commit
46df41d103
229
src/kernel/boot/platform/bios_ia32/bios.S
Normal file
229
src/kernel/boot/platform/bios_ia32/bios.S
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
/** This file contains code to call BIOS functions out of a protected
|
||||
* mode environment. It doesn't use the virtual86 mode - it switches
|
||||
* to real mode, make the BIOS call, and switch back to protected
|
||||
* mode again. It's meant to be used in a single-threaded boot loader,
|
||||
* not in a multi-tasking operating system.
|
||||
* It relies on the real mode segment descriptors found in shell.S.
|
||||
*/
|
||||
|
||||
#define FUNCTION(x) .globl x ; x ## :
|
||||
|
||||
#define REAL_MODE_STACK 0x9000
|
||||
// the location of the stack in real mode
|
||||
#define SAVED_ESP 0x10000
|
||||
#define SAVED_CR3 0x10004
|
||||
#define SAVED_EAX 0x10008
|
||||
#define SAVED_FLAGS 0x1000c
|
||||
// we're overwriting the start of our boot loader to hold some
|
||||
// temporary values - the first 1024 bytes of it are used at
|
||||
// startup only, and we avoid some linking issues this way
|
||||
|
||||
|
||||
.text
|
||||
.code32
|
||||
|
||||
/** This function brings you back to protected mode after you've
|
||||
* switched to it using switch_to_real_mode().
|
||||
* Should restore the whole environment to what it looked like
|
||||
* before. Clobbers %eax.
|
||||
*/
|
||||
|
||||
FUNCTION(switch_to_protected_mode)
|
||||
cli // turn off interrupts
|
||||
|
||||
.code16
|
||||
movl %cr0, %eax // set the PE bit (0) to switch to protected mode
|
||||
orb $0x1, %al
|
||||
movl %eax, %cr0
|
||||
|
||||
.code32
|
||||
.byte 0x66 // jump to the protected mode segment
|
||||
ljmp $0x8, $_protected_code_segment
|
||||
_protected_code_segment:
|
||||
movw $0x10, %ax // setup data and stack selectors
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
|
||||
// turn on paging again
|
||||
movl SAVED_CR3, %eax // restore the saved page directory
|
||||
movl %eax, %cr3
|
||||
|
||||
movl %cr0, %eax // set the PG bit (31) to enable paging
|
||||
orl $0x80000000, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
// save the return address so that we can pick it up again later
|
||||
movl (%esp), %eax
|
||||
movl %eax, REAL_MODE_STACK
|
||||
|
||||
// setup protected stack frame again
|
||||
movl SAVED_ESP, %eax
|
||||
movl %eax, %esp
|
||||
movl %eax, %ebp
|
||||
|
||||
// copy the return address to the current stack
|
||||
movl REAL_MODE_STACK, %eax
|
||||
movl %eax, (%esp)
|
||||
|
||||
ret
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/** Switches from protected mode back to real mode.
|
||||
* It will disable paging and set the real mode segment selectors to 0x1000,
|
||||
* except for the stack selector, which will be 0x0 (the stack is at 0x9000
|
||||
* which is where the BFS boot loader puts it as well).
|
||||
* Clobbers %eax.
|
||||
*/
|
||||
|
||||
FUNCTION(switch_to_real_mode)
|
||||
// save the %esp register
|
||||
movl %esp, %eax
|
||||
movl %eax, SAVED_ESP
|
||||
|
||||
// put the return address on the real mode stack
|
||||
movl (%esp), %eax
|
||||
movl %eax, REAL_MODE_STACK
|
||||
|
||||
// disable paging
|
||||
movl %cr3, %eax // save the page directory address
|
||||
movl %eax, SAVED_CR3
|
||||
|
||||
movl %cr0, %eax
|
||||
andl $0x7fffffff, %eax // clear PG bit (31)
|
||||
movl %eax, %cr0
|
||||
|
||||
xor %eax, %eax // clear page directory to flush TLBs
|
||||
movl %eax, %cr3
|
||||
|
||||
// setup real mode stack
|
||||
movl $REAL_MODE_STACK, %eax
|
||||
movl %eax, %esp
|
||||
movl %eax, %ebp
|
||||
|
||||
// setup selectors to point to our 16 bit segments
|
||||
movw $0x20, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw $0x28, %ax
|
||||
movw %ax, %ss
|
||||
|
||||
ljmp $0x18, $(_almost_real_code_segment - 0x10000)
|
||||
|
||||
_almost_real_code_segment:
|
||||
movl %cr0, %eax // switch to real mode
|
||||
andb $0xfe, %al // clear PE bit (0)
|
||||
movl %eax, %cr0
|
||||
|
||||
.byte 0x66
|
||||
ljmp $0x1000, $(_real_code_segment - 0x10000)
|
||||
|
||||
_real_code_segment:
|
||||
.code16
|
||||
movw $0x1000, %ax // setup data & stack segments
|
||||
movw %ax, %ds // data in segment 0x1000,
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
xor %ax, %ax // stack in segment 0x0
|
||||
movw %ax, %ss
|
||||
|
||||
sti // turn on interrupts again
|
||||
ret
|
||||
|
||||
.code32
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/** void call_bios(uint8 num, struct bios_regs *regs)
|
||||
* Does a BIOS call by triggering a software interrupt in real
|
||||
* mode.
|
||||
*/
|
||||
|
||||
FUNCTION(call_bios)
|
||||
pushal
|
||||
pushfl
|
||||
|
||||
// make sure the correct IDT is in place
|
||||
lidt idt_descriptor
|
||||
|
||||
// get the interrupt vector and patch the instruction at the target address
|
||||
movl 40(%esp), %eax
|
||||
mov %al, int_number
|
||||
|
||||
// Fills registers from the passed in structure
|
||||
// Since switch_to_real_mode() clobbers %eax, we have to handle
|
||||
// it specially here (by temporarily storing it to an arbitrary
|
||||
// memory location, SAVED_EAX)
|
||||
movl 44(%esp), %ebp
|
||||
|
||||
movl (%ebp), %eax
|
||||
movl %eax, SAVED_EAX
|
||||
movl 4(%ebp), %ebx
|
||||
movl 8(%ebp), %ecx
|
||||
movl 12(%ebp), %edx
|
||||
movl 16(%ebp), %esi
|
||||
movl 20(%ebp), %edi
|
||||
mov 24(%ebp), %es
|
||||
|
||||
call switch_to_real_mode
|
||||
|
||||
.code16
|
||||
|
||||
// restore %eax from saved location
|
||||
movl (SAVED_EAX - 0x10000), %eax
|
||||
|
||||
// call the interrupt (will be dynamically changed above)
|
||||
.byte 0xcd
|
||||
int_number:
|
||||
.byte 0
|
||||
|
||||
// we're interested in the flags state as well
|
||||
pushf
|
||||
|
||||
// save %eax from the call
|
||||
movl %eax, (SAVED_EAX - 0x10000)
|
||||
|
||||
// save flags from the call
|
||||
pop %ax
|
||||
movw %ax, (SAVED_FLAGS - 0x10000)
|
||||
|
||||
// back to protected mode
|
||||
call switch_to_protected_mode
|
||||
.code32
|
||||
|
||||
// store the register state into the structure that has been passed in
|
||||
movl 44(%esp), %eax
|
||||
|
||||
movl %ebx, 4(%eax)
|
||||
movl %ecx, 8(%eax)
|
||||
movl %edx, 12(%eax)
|
||||
movl %esi, 16(%eax)
|
||||
movl %edi, 20(%eax)
|
||||
movl SAVED_EAX, %ecx // special handling for %eax and flags
|
||||
movl %ecx, (%eax)
|
||||
movw SAVED_FLAGS, %cx
|
||||
movw %cx, 26(%eax)
|
||||
|
||||
popfl
|
||||
popal
|
||||
|
||||
ret
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
idt_descriptor:
|
||||
.short 0x7ff // IDT at 0x0, default real mode location
|
||||
.long 0x0
|
32
src/kernel/boot/platform/bios_ia32/bios.h
Normal file
32
src/kernel/boot/platform/bios_ia32/bios.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
#ifndef BIOS_H
|
||||
#define BIOS_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
// The values in this structure are passed to the BIOS call, and
|
||||
// are updated to the register contents after that call.
|
||||
|
||||
struct bios_regs {
|
||||
uint32 eax;
|
||||
uint32 ebx;
|
||||
uint32 ecx;
|
||||
uint32 edx;
|
||||
uint32 esi;
|
||||
uint32 edi;
|
||||
uint16 es;
|
||||
uint16 flags;
|
||||
};
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
void call_bios(uint8 num, struct bios_regs *regs);
|
||||
|
||||
#endif /* BIOS_H */
|
Loading…
Reference in New Issue
Block a user