Use BIOS funcions from long mode
Posted: Tue Feb 08, 2011 2:55 pm
Before any of you write "no, you cannot do that", I have a working solution I want to share.
Prerequirements:
1. I assume you have set up long mode properly
2. Your kernel is _not_ in the first 64k, so you have to alter CS for real mode. This example code use 1000h, but change it to your needs (kinda homework).
3. The original IVT is untouched
The code uses fasm syntax.
Not so ugly as it first seems Hope that would be useful.
Prerequirements:
1. I assume you have set up long mode properly
2. Your kernel is _not_ in the first 64k, so you have to alter CS for real mode. This example code use 1000h, but change it to your needs (kinda homework).
3. The original IVT is untouched
The code uses fasm syntax.
Code: Select all
;this code is placed somewhere after 10000h
;-----we're in LONG MODE-----
mov qword [.stckptr], rsp ;first of all save stack
sgdt [.gdtv64] ;save your gdt pointer
lgdt [.gdtv16] ;load a new one
sidt [.idt64] ;save your idt pointer
lidt [.idt16] ;load real mode idt
;far jump in long mode is not possible, do a trick
push DESC_REAL
push @f-10000h ;this is CS*10h, modify if needed!
retfq
.stckptr:
dq 0
align 16
.gdtv64:
dw 0
dq 0
align 16
.gdtv16:
dw .gdtend-.gdt-1
dd .gdt,0
align 16
.gdt:
dd 0,0 ;null descriptor
DESC_DATA=8 ;descriptor in YOUR GDT (modify)
DESC_LONG=$-.gdt
dd 00000000h,00209800h ;64 bit long mode cs
DESC_REAL=$-.gdt
dd 0000FFFFh,00009801h ;16 bit real mode cs (modify base if needed!)
.gdtend:
align 16
.idt64:
dw 0
dq 0
align 16
.idt16:
dw 3FFh
dq 0
USE16
;-----we're in COMPATIBLITY MODE-----
;disable paging and protmode at once
@@: mov eax, cr0
and eax, 7FFFFFFEh
mov cr0, eax
;set up real mode segment registers and stack
mov esp, realmode_stack_top ;modify it to your needs!
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;convert long mode rip to real mode cs:ip
;jmp CS:(longmode address)-CS*10h
jmp 1000h:@f-10000h ;modify if needed!
;-----we're in REAL MODE-----
@@: ;***********call some BIOS interrupt here**********
mov ax, 3
int 10h
;switch back to long mode
mov eax, cr0
or eax, 80000001h
mov cr0, eax ;enable protmode and paging
;jmp DESC_LONG:@f
db 66h
db 0EAh
dd @f
dw DESC_LONG
USE64
;-----we're in COMPATIBILITY MODE-----
@@: lgdt [cs:.gdtv64] ;restore gdt
mov ax, DESC_DATA ;read YOUR DATA descriptor to selectors
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
lidt [.idt64] ;restore idt
mov rsp, qword [.stckptr] ;restore stack
;must be a non rip-relative jump
mov rax, @f
jmp rax
@@:
;-----we're in LONG MODE again-----