[fixed]VGA BIOS Interrupts After Switching Back to Real Mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
quantumdude
Posts: 4
Joined: Fri Jun 28, 2013 7:55 am

[fixed]VGA BIOS Interrupts After Switching Back to Real Mode

Post by quantumdude »

Hello all,

I'm currently working on a basic OS, and one of the features I want is a sort-of fatal error handler (akin to Windows BSoD or Linux kernel panic).

Right now, I have the error handler switch to 16-bit real mode in order to use VGA BIOS interrupts. However, as soon as I invoke BIOS int 10h, it seems to enter an infinite loop in the BIOS code. I tried this both in QEMU and on real hardware (Dell Latitude E6400), but they both experience the same issue.

I've double-checked the mode-switch code, and I correctly restore the real-mode IVT and re-enable interrupts, and all of my segment registers are properly set. I've also made sure that none of my code touches the BDA.

Could the issue be caused by booting from syslinux with mboot.c32? Could it possibly modify any BDA/EBDA structures? Or is there something else I need to (re)set before I can use VGA BIOS interrupts again?

I can provide more details if needed.
Last edited by quantumdude on Wed Aug 07, 2013 7:27 am, edited 1 time in total.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by egos »

Yes, show the code. I use such technique and all works fine.
If you have seen bad English in my words, tell me what's wrong, please.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by bluemoon »

I would like to point out that, even without any fatal error, switching back to real-mode is a total mess - to some extend it may generate more trouble than you can imagine.

There are a lot of discussion about switching back to real mode, due to the huge amount of work for "properly" switching back, and the high risk for being test pilot (since it is about the least things to be QA'ed) even when the OS runs fine, so I would not recommend doing that when things already goes wrong.
quantumdude
Posts: 4
Joined: Fri Jun 28, 2013 7:55 am

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by quantumdude »

Code to jump to 16-bit segment:

Code: Select all

    jmp SEG_CODE16:0x0000
SEG_CODE16 refers to a 16-bit code selector with base 0x00010000, which is where the 16-bit error handler has been relocated to.

Actual 16-bit code (starts off in protected mode, switches to real mode):

Code: Select all

; 16-bit fatal error handler

FATAL_SEG equ 0x1000

bits 16
org 0x0000 ; relative to segmant 0x1000 

fatal16:
    ; disable protected mode and paging
    mov     eax, cr0
    and     eax, 0x7ffffffe
    mov     cr0, eax
    xor     eax, eax
    mov     cr3, eax

    ; setup data segments
    mov     ax, FATAL_SEG
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
    mov     ss, ax
    ; setup small stack
    mov     sp, stack

    ; fix code segment (so interrupts can properly return)
    jmp     FATAL_SEG:.csFix
.csFix:

    ; restore real-mode IVT and enable interrupts
    lidt    [idtr]
    sti

    ; TODO: figure out why VGA BIOS interrupts aren't working

    ; switch to VGA 80x25
    mov     ax, 0x0002
    int     0x10
    ; reset cursor
    mov     ax, 0x0002
    xor     bh, bh
    xor     dx, dx
    int     0x10
    ; clear screen (to a nice white-on-red color)
    mov     ax, 0xb800
    mov     es, ax
    xor     di, di
    mov     ax, 0xcf00
    mov     cx, 80 * 25
    rep     stosw

    ; TODO: display something
    mov     si, msg
    mov     cx, msg.len
.loop:
    mov     ah, 0x0e
    mov     bx, 0xf400
    lodsb
    int     0x10
    loop    .loop

    jmp     $

align 4
idtr:
    dw 0x03ff
    dd 0x00000000
msg:
    db "UH OH, SPAGHETTI-O'S"
.len equ $ - msg

    times 1024 - ($ - $$) db 0
stack:
GDT:

Code: Select all

section .data
    
    align 4
gdt:
    ; null entry - re-use space for GDT pointer
gdtp:
    dw gdt.size - 1
    dd gdt  
    ; pad to 8 bytes
    dw 0    
    
SEL_CODE32 equ $ - gdt
    ; 32-bit code
    dw 0xffff
    dw 0x0000
    db 0x00 
    db 0x9a 
    db 0xcf 
    db 0x00
    
SEL_DATA32 equ $ - gdt
    ; 32-bit data
    dw 0xffff
    dw 0x0000
    db 0x00 
    db 0x92
    db 0xcf 
    db 0x00 

SEL_CODE16 equ $ - gdt
    ; 16-bit code, base 0x00010000
    dw 0xffff
    dw 0x0000
    db 0x01
    db 0x9a
    db 0x00
    db 0x00
gdt.size equ $ - gdt
(on an unrelated note, is there a way to "hide" all that code? I.e. something like [spoiler]code[/spoiler]?)
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by Combuster »

; switch to VGA 80x25
mov ax, 0x0002
int 0x10
Shouldn't that be mode 3h?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
quantumdude
Posts: 4
Joined: Fri Jun 28, 2013 7:55 am

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by quantumdude »

Combuster wrote:
; switch to VGA 80x25
mov ax, 0x0002
int 0x10
Shouldn't that be mode 3h?
Yeah probably, I just took a quick glance at RBIL. But even if I don't do the mode switch at all, it still hangs at the next interrupt.

Also, I just realized that the second interrupt call should start

Code: Select all

mov ah,0x02
and the string print loop should have

Code: Select all

mov bx, 0x00f4
but even still, the interrupts hang.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by egos »

bluemoon, in general I agree, but I was telling about switching to RM right after getting control from Multiboot-compliant boot loader.

quantumdude, I don't see that you load "16-bit data selector". And is recommended to load cs first:
- jmp CODE16_SEL:x;
- set data seg regs with DATA16_SEL;
- clear PE flag;
- jmp CODESEG:x;
- set data seg regs with DATASEG.

Code: Select all

    ; setup small stack
    mov     sp, stack
Maybe too small :wink:

Code: Select all

    mov     cx, msg.len
.loop:
    mov     ah, 0x0e
    mov     bx, 0x00f4 ; fixed
    lodsb
    int     0x10
    loop    .loop
Try to save/restore cx value (or to use null-terminated string).
If you have seen bad English in my words, tell me what's wrong, please.
quantumdude
Posts: 4
Joined: Fri Jun 28, 2013 7:55 am

Re: VGA BIOS Interrupts After Switching Back to Real Mode

Post by quantumdude »

I found the issue.

When I set up the small stack:

Code: Select all

    mov     sp, stack
I forgot that the upper-16 bits of esp are still set, which seems to break BIOS. When I clear out esp first:

Code: Select all

    xor     esp, esp
    mov     sp, stack
Everything works fine. I did, however, make the changes you suggested, egos, so hopefully it'll be more robust.
Post Reply