Adrian
Adrian

Reputation: 2001

Why do I get this Guru meditation while using int 13h?

I am building a hobby operating system, but at some point it didn't work (Got a black screen not showing anything), and while trying to know why I tried to make the smallest kernel possible that worked inappropriately, which led instead to a guru medidation error, which I suspect have something to do with int 13h

This is the code that produces guru meditation error:

VGA_MEMORY equ 0xB8000

org 0x7C00
bits 16

mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x07E0
mov ss, ax
mov esp, 0xFFF0
mov ax, 0
mov ds, ax

; Disable the annoying cursor
mov ah, 0x01
mov ch, 001_11111b
int 0x10

reset_disk_hdd:
    mov ah, 0x00  ; reset function
    int 0x13      ; disk int
    jc reset_disk_hdd

mov ax, 00h
mov ds, ax
mov si, disk_address_packet

read_disk_hdd:
    mov ah, 42h   ; read function
    int 0x13      ; disk int
    jc read_disk_hdd

jmp $

disk_address_packet:
db 10h          ; size of DAP (set this to 10h)
db 00h          ; unused, should be zero
dw 44h          ; number of sectors to be read
dd 0x0000_7E00  ; segment:offset pointer to the memory buffer to which sectors will be transferred
dq 01h          ; absolute number of the start of the sectors to be read

times 510-($-$$) db 0

dw 0xAA55
dw 'H'

The original code I started working with read a double word located in the second sector of the hard disk, which was basically a color for the foreground, a color for the background and a character to print in screen, and then moved that double word to 0xB8000 to have it printed on the screen. But when I got this black screen showing nothing I started to reduce the code as much as possible to keep getting this error, but instead got a Guru Meditation error. Notice, for instance, that I am reading exactly 44h sectors from disk. This is the lowest number that keep giving me the error.

Those are the commands I use to turn on the virtual machine with this code:

mkdir vbox ; \
VBoxManage controlvm "X" poweroff ; \
sleep 1 ; \
VBoxManage unregistervm "e0b08add-d834-4af5-89e8-05abec11aa78" ; \
rm -r vbox/X ; \
rm kernel  ; \
rm kernel.raw ; \
rm kernel.vdi ; \
VBoxManage createvm \
     --name "X" \
     --ostype "Other" \
     --register \
     --basefolder "$(pwd)/vbox" \
     --uuid "e0b08add-d834-4af5-89e8-05abec11aa78" \
     --default ; \
VBoxManage modifyvm "e0b08add-d834-4af5-89e8-05abec11aa78" \
     --usbxhci on \
     --memory 8 ; \
nasm -l kernel.lst kernel.asm ; \
dd if=/dev/zero of=kernel.raw bs=1024 count=2048 ; \
dd if=kernel of=kernel.raw conv=notrunc ; \
VBoxManage convertfromraw kernel.raw kernel.vdi --format VDI ; \
VBoxManage storageattach "X" \
     --storagectl "IDE" \
     --port 0 \
     --device 0 \
     --type hdd \
     --medium "$(pwd)"/kernel.vdi ; \
VBoxManage startvm "X"; \

I am using Virtualbox 6.1.0

These are my operating system specs, which I add just in case because I don't know if you might find it useful:

What I really want to know is whether I am missing something (and if so, what) or it's an actual bug of the virtual machine.

EDIT

Michael Petch commented:

There is a rule for BIOS that you should never cross a 64KiB boundary because of DMA (direct memory address). I don't know if virtualbox enforces it but I could see that if the address you load at (0x7e00) + (the number of sectors * bytes per sector)> 0x10000 (0x10000=64KiB) a problem may occur . In theory though if that were the problem I'd expect potential problems to be with anything > 0x41 sectors (0x42 * 512 + 0x7e00) = 0x10200. If you load 0x44 sectors starting at 0x1000:0x0000 rather than 0x0000:0x7e00 does it fail?

I changed the assembly code to set the buffer address at 0x10000, but the program still doesn't work. However, the problem now is different: instead of getting a guru meditation, I only get a black screen not printing anything. This happens when I load as little as 3Fh sectors, but when I load any number of sectors below 3Fh the program correctly prints the 'H' character:

VGA_MEMORY equ 0xB8000

GREEN         equ 0x2
RED           equ 0x4

org 0x7C00
bits 16

mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x07E0
mov ss, ax
mov esp, 0xFFF0
mov ax, 0
mov ds, ax

; Disable the annoying cursor
mov ah, 0x01
mov ch, 001_11111b
int 0x10

reset_disk_hdd:
    mov ah, 0x00  ; reset function
    int 0x13      ; disk int
    jc reset_disk_hdd

mov ax, 00h
mov ds, ax
mov si, disk_address_packet

read_disk_hdd:
    mov ah, 42h   ; read function
    int 0x13      ; disk int
    jc read_disk_hdd

mov ax, VGA_MEMORY >> 4
mov es, ax
mov ax, 0x1000
mov ds, ax
mov ax, [ds:0x0000]
mov [es:0x00], ax

jmp $

disk_address_packet:
db 10h          ; size of DAP (set this to 10h)
db 00h          ; unused, should be zero
dw 3Fh          ; number of sectors to be read
dd 0x1000_0000  ; segment:offset pointer to the memory buffer to which sectors will be transferred
dq 01h          ; absolute number of the start of the sectors to be read

times 510-($-$$) db 0

dw 0xAA55
dw (RED << 4 | GREEN) << 8 | 'H'

Upvotes: 1

Views: 399

Answers (1)

Adrian
Adrian

Reputation: 2001

To make sure int 13h ah=02h or ah=42h works as it should check the following:

  • Wherever you load the bytes from disk to memory, make sure it doesn't overlap the stack
  • Don't load more than 0x7f sectors as some ancient BIOSes do not support reading a number of sectors >= 0x80
  • The buffer shouldn't cross the 64KiB boundary
  • You are not touching the interrupt vector table, BDA, EBDA, the BIOS or any other memory location forbidden or not free for use. See Memory map and Upper memory map.

Upvotes: 3

Related Questions