Back to real mode [SOLVED]
Posted: Tue Apr 19, 2011 10:39 am
Hi I need to switch back to real mode in order to perform some software interrupt operations and run old code. In order to do this I wrote a routine which should
- Store the current status of machine
- Load the old real mode data saved before this function
- Go back in real mode, perform the operation
- Enable again protected mode and jump back to my C++ code.
In order to do this, I saved the first 0x400 bytes of memory at start
&I saved the old pic masks
Than, I disabled the interrupts with cli, I also remapped the pic and loaded the old bios values
Finally I performed some memory copies to save the current first 0x400 bytes and to load the old ones.
And than a call
The code of p_int86 is this
The code ends before I return in protected mode because it isn't important. All the operation after sti should be the code to perform in real mode. But it doesn't work well
On my old computer it works but I need to make a cli very early or it restarts. This happens only if I remap the pic, otherwise it works good.
In my new computer It doesn't restart, it doesn't work (the interrupts I mean because I tried simple code to emit a beep in real mode code and it works).
Have I missed anything? What could be wrong? Perhaps I forgot to set up something?
Oh yes this is my gdt
- Store the current status of machine
- Load the old real mode data saved before this function
- Go back in real mode, perform the operation
- Enable again protected mode and jump back to my C++ code.
In order to do this, I saved the first 0x400 bytes of memory at start
Code: Select all
memcpy((void*)0x40000, (void*)0x0, 0x400);
Code: Select all
bios_mask[0]= inportb(0x21);
bios_mask[1] = inportb(0xa1);
Than, I disabled the interrupts with cli, I also remapped the pic and loaded the old bios values
Code: Select all
irq_remap(0x08,0x70);
outportb(0x21, bios_mask[0]);
outportb(0xA1, bios_mask[1]);
Code: Select all
memcpy((void*)0x40400, (void*)0x0, 0x400);
memcpy((void*)0x0, (void*)0x40000, 0x400);
Code: Select all
p_int86(&gp);
Code: Select all
org 0x0
; It is loaded in 0x40000
[bits 32]
TIMES 0x800 db 0
mov eax, cr0
mov [savcr0+0x40000], eax ; save pmode CR0
cli ; Disable interrupts.
lidt [idt_real+0x40000]
jmp dword 0x18:(start+0x40000)
idt_real:
dw 0x3ff ; 256 entries, 4b each = 1K
dd 0 ; Real Mode IVT @ 0x0000
savcr0:
dd 0 ; Storage location for pmode CR0.
start:
; We are already in 16-bit mode here!
[bits 16]
; Need 16-bit Protected Mode GDT entries!
mov eax, 0x20 ; 16-bit Protected Mode data selector.
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
; Disable paging (we need everything to be 1:1 mapped).
mov eax, cr0
and eax, 0x7FFFFFFe ; Disable paging bit & enable rmode.
mov cr0, eax
jmp 0x4000:GoRMode ; Perform Far jump to set CS.
GoRMode:
mov ax, 0x4000 ; Reset segment registers to 0x4000.
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
and eax,0xf0000
shr eax,4
mov ss, ax
mov eax, esp
and eax, 0xffff
mov sp, ax
sti
mov ebx,0
mov eax,0
mov ah,0x0
mov al,0
int 0x10
mov ah,0xe
mov al, '4'
mov bh,0
mov bl, 42
int 10h
hlt
On my old computer it works but I need to make a cli very early or it restarts. This happens only if I remap the pic, otherwise it works good.
In my new computer It doesn't restart, it doesn't work (the interrupts I mean because I tried simple code to emit a beep in real mode code and it works).
Have I missed anything? What could be wrong? Perhaps I forgot to set up something?
Oh yes this is my gdt
Code: Select all
gdt_set_gate(0, 0, 0, 0, 0);
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
gdt_set_gate(3, 0, 0xFFFFF, 0x9a, 0x00); //16bit code
gdt_set_gate(4, 0, 0xFFFFF, 0x92, 0x00); //16bit data