I am trying to develop my own OS (for learning purpose), everything is fine in qemu, it work well.
nasm -f bin os.s -o os
qemu-system-x86_64 -drive file=os,format=raw
So I decided to try it on real hardware and I encounter two issue : The first is that when I boot my pc with my usb key containing my OS (dd bs=4M if=os of=/dev/sdc), it start by printing "Invalid partition table!". But then, if i press any key it execute correctly the code and it start booting my os by printing "VOK" on the screen and it stop there.
Does anyone know from where the "Invalid partition table!" could come from ?
second question: at the end, I try to perform a far jump to exit the 16bits mode and enter 32bits mode. As you can see I currently stop the program just before with a infinity loop (jmp $). when I pass the loop just after the far jump, in the init_32 label, its working fine with qemu but doesn't work with my laptop (he reboot again and again meaning the code crashed). I have no idea why this is happening, some help would be helpful!
[org 0x7c00]
SECTOR_READ equ 0x08
; memory offset where our kernel is located
KERNEL_OFFSET equ 0x7e00
; this is the boot loader which will be present on the MBR
; sector 1, 512 bytes
mov ah, 0x0e ; tty mode
mov bp, 0x9000 ; this is an address far away from 0x7c00 so that we don't get overwritten
mov sp, bp ; if the stack is empty then sp points to bp
mov al, 'V'
int 0x10
; let's load our OS loader
; load 'dh' sectors from drive 'dl' into ES:BX
mov bx, KERNEL_OFFSET;
mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
mov al, SECTOR_READ ; al <- number of sectors to read (0x01 .. 0x80)
mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
; 0x01 is our boot sector, 0x02 is the first 'available' sector
mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
; DONT TOUCH
; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
; [es:bx] <- pointer to buffer where the data will be stored
int 0x13 ; BIOS interrupt
jc error ; if error (stored in the carry bit)
cmp al, SECTOR_READ ; BIOS also sets 'al' to the # of sectors read. Compare it.
jne error
mov ah, 0x0e ; tty mode
mov al, 'O'
int 0x10
mov al, 'K'
int 0x10
mov al, 0x0a ; newline char
int 0x10
mov al, 0x0d ; carriage return
int 0x10
jmp switch_64bits
error:
mov ah, 0x0e ; tty mode
mov al, 'K'
int 0x10
mov al, 'O'
int 0x10
mov al, 0x0a ; newline char
int 0x10
mov al, 0x0d ; carriage return
int 0x10
jmp $
gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
; the GDT starts with a null 8-byte
dd 0x0 ; 4 byte
dd 0x0 ; 4 byte
; GDT for code segment. base = 0x00000000, length = 0xfffff
; for flags, refer to os-dev.pdf document, page 36
gdt_code:
dw 0xffff ; segment length, bits 0-15
dw 0x0 ; segment base, bits 0-15
db 0x0 ; segment base, bits 16-23
db 10011010b ; flags (8 bits)
db 11001111b ; flags (4 bits) + segment length, bits 16-19
db 0x0 ; segment base, bits 24-31
; GDT for data segment. base and length identical to code segment
; some flags changed, again, refer to os-dev.pdf
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
; GDT descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
dd gdt_start ; address (32 bit)
; define some constants for later use
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
[bits 16]
switch_64bits: ; load 32 bit first, then 64 bits
; clear all interrupts
cli
; load our Global Descriptor Table
lgdt [gdt_descriptor]
; switch to protected mode
; set PE (Protection Enable) bit in CR0
; CR0 is a Control Register 0
mov eax, cr0
or al, 0x1
mov cr0, eax
; far jump to 32 bit instructions
; so we can be sure processor has done
; all other operations before switch
; at this moment we can say bye to 16-bit Real Mode
jmp $
jmp CODE_SEG:init_32
[bits 32]
init_32:
; padding and magic number
times 510 - ($-$$) db 0
; Magic number
dw 0xaa55
times 256 dw 0x0202 ; sector 2 = 512 bytes 0x7e00
times 256 dw 0x0303 ; sector 3 = 512 bytes 0x8000
times 256 dw 0x0404 ; sector 4 = 512 bytes 0x8200
times 256 dw 0x0505 ; sector 5 = 512 bytes 0x8400
times 256 dw 0x0606 ; sector 6 = 512 bytes 0x8600
times 256 dw 0x0707 ; sector 7 = 512 bytes 0x8800
times 256 dw 0x0808 ; sector 8 = 512 bytes 0x8a00
times 256 dw 0x0909 ; sector 9 = 512 bytes 0x8c00