The Place to Start for Operating System Developers
http://forum.osdev.org/
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-----
In theory, it doesn't work, because you can't easily deal with these cases:b.zaar wrote:I'm not playing in long mode yet, but I was thinking could you fake a vm86 mode using 16bit pmode segments. I think 16 bit selectors are legal in long mode (compatibility mode). This is just a theory and I haven't tried it so it could all be BS.
using ldt entries cs = 0x00 ds = 0x08 es = 0x10 fs = 0x18 gs = 0x20 ss = 0x28
(for gdt entries just start with cs = 0x08 instead)
whenever a real mode program (BIOS interrupt) program faults by using an invalid segment then set the allocated selector to the base with a limit of 64K and reload it back into the selector. Because the real mode IVT goes up to 0x0400 most programs wont request anything below this as a segment except maybe 0x00 which will trigger a fault because to use selector 0x00 it would need to be loaded as 0x07 for ring3/ldt flags.
This is basically a normal vm86 monitor to handle protected instruction but also it sets the selectors whenever an invalid read/write happens. You can still set the v86 bit in the eflags for long mode to detect whether you need to set selectors.
Just curious if this is a viable option.
Usually an OS won't call any BIOS calls, it's very-very rare. Maybe at boottime and switching video modes, that's all, so it not worth the candle imho.b.zaar wrote:I'm not playing in long mode yet, but I was thinking could you fake a vm86 mode using 16bit pmode segments. I think 16 bit selectors are legal in long mode (compatibility mode).