Assembly enter protected mode and jump back to real mode
Asked Answered
R

1

6

I am developing a toy OS in assembly and I have a problem when switching from protected mode back to real mode. I have successfully switched to protected mode, called the kernel that writes text to [0xb8000] video memory, returned to the caller and (probably) switched back to real mode. I am trying to use bios interrupts from real mode so I don't have to write my own device drivers.

Interrupts however don't seem to be executed after switching back to real mode. They don't crash the system as they would in protected mode so I guess I am in real mode.

minrep.asm (bootloader)

boot.header:
[BITS 16]
[ORG 0x7c00]
mov ax, cs
mov ds, ax
xor ax, ax
mov ds, ax
cli
mov ss, ax
mov sp, 0x7c00
sti
call main
jmp $
disk.read_sectors:
reset:
xor ax,ax
int 0x13
jc reset
floppy:
xor bx,bx
mov ah,0x2
mov al, [esp+6]
mov cx,[esp+4]
mov dh,0x0
mov dl, 0x80
mov bx, ds
mov es, bx
mov bx, [esp+2]
int 0x13
jc error
mov ax, 0
ret
error:
mov ax, 1
ret
main:
push word 16 ; 16 sectors for stage2
push word 2 ; starts at sector 2
push word 0x1000 ; into 0x1000 memory buffer
call disk.read_sectors
pop bx
pop bx
pop bx
jmp 0000:0x1000
mov ax, 0
ret
footer:
times 510-($-boot.header) db 0
dw 0xAA55

minrep_st2.asm (stage2, enter prot and back to real)

[BITS 16]
[ORG 0x1000]

stage2.header:

mov ax, cs
mov ds, ax
jmp stage2.main

stage2.main:

mov al, 'B'
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10

call switch_to_protected
switch_to_protected:


            [ bits 16 ]

            cli

            switch_to_pm:

                lgdt [ gdt_descriptor ]
                mov eax , cr0
                or eax , 0x1
                mov cr0 , eax
                jmp CODE_SEG:init_pm

            [ bits 32 ]

            init_pm:

                   mov ax, DATA_SEG
                mov ds, ax
                mov ss, ax
                mov es, ax
                mov fs, ax
                mov gs, ax
                mov ebp , 0x90000
                mov esp , ebp

                sti






[BITS 32]
switch_to_real:


mov [0xb8000], byte 'D'

[BITS 32]
cli

mov eax, cr0
and eax, 0x7FFFFFFF    ; clear PG bit
mov cr0, eax

xor     eax,eax         ; A convenient zero
mov     cr3,eax         ; Flush the TLB

mov eax, cr0
and eax, 0xFFFFFFFE    ; clear PE bit
mov cr0, eax

lidt [idtr]

jmp 0:continue

[BITS 16]

continue:

sti

mov al, 'C'
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10

hlt


GDT:


            idtr:
            dw 0x3ff
            dd 0

            gdt_start:

                gdt_null:
                    dd 0x0 ;
                    dd 0x0

                gdt_code:
                    dw 0xffff
                    dw 0x0
                    db 0x0
                    db 10011010b ; 1 st flags , type flags
                    db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
                    db 0x0

                gdt_data:
                    dw 0xffff
                    dw 0x0
                    db 0x0
                    db 10010010b ; 1 st flags , type flags
                    db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
                    db 0x0

                gdt_end:

                gdt_descriptor:
                    dw gdt_end - gdt_start - 1
                    dd gdt_start

            CODE_SEG equ gdt_code - gdt_start
            DATA_SEG equ gdt_data - gdt_start

stage2.footer:
times 8192-($-stage2.header) db 0

how to compile:

nasm.bat minrep.asm -o disk_p1.bin
nasm minrep_st2.asm -o disk_p2.bin
copy /b disk_pt1.bin + disk_pt2.bin disk.img
call qemu disk.img

EDIT:

if i only do this to go protected, then movin to 0xb800 in real mode does clear the first character but doesn't print it correctly (blank char instead of byte 'Z')

        [ bits 16 ]

    cli

    switch_to_pm:

        lgdt [ gdt_descriptor ]
        mov eax , cr0
        or eax , 0x1
        mov cr0 , eax
        jmp CODE_SEG:init_pm

    [ bits 32 ]

    init_pm:

the print char 'Z' after sti in continue:

mov ax, 0xb800; 
mov es, ax; 
mov [es:0000], byte 'Z'
Religion answered 24/2, 2020 at 15:12 Comment(1)
Comments are not for extended discussion; this conversation has been moved to chat.Soccer
D
0

If anyone is interested after all this time, on your return to real mode you enable interrupts, print your "c", then use hlt. With interrupts enabled, execution will continue after the hlt on the first interrupt called which would likely be the timer (irq0/int8) but there is no code there so anything could happen

Dudleyduds answered 10/2, 2022 at 18:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.