How do I multiboot to real-mode?
Posted: Tue Feb 17, 2015 1:40 am
I'm wanting to roll my own bootloader, but also make it multiboot compatible. To do this, my plan is to create 2 raw binaries; the ipl loaded at 0x7C00 and the spl loaded at 0x7E00. The spl begins with a 16-bit jump followed by the multiboot header and whatnot.
The multiboot stuff is working fine, but I'm having trouble trying to figure out how to return to real mode. Here is what I'm currently doing:
One thing that is rather suspicious is that if the emulator crashes before entering real mode, the IDTR's base and limit are already 0x0000 and 0x03FF. I seriously hope this doesn't mean that multiboot loaders overwrite the real-mode idt...
The most suspicious thing is that jump. The 'correct' mnemonic for that should be 'jmp dword' or 'jmp far'. GAS doesn't support either of those, but I had read somewhere that ljmp was an older name for it. Anyhow, the CS register doesn't appear to be changing, so I really think the problem is there.
Can anyone tell me what mistake I'm making here?
The multiboot stuff is working fine, but I'm having trouble trying to figure out how to return to real mode. Here is what I'm currently doing:
Code: Select all
# Link this file with "--oformat binary -Ttext 0x00007E00".
.set MAGIC, 0x1BADB002
.set AOUT_KLUDGE, 0x00010000
.set FLAGS, AOUT_KLUDGE
.set CHECKSUM, -(MAGIC + FLAGS)
.set newidt, 0x0632
.intel_syntax noprefix
.section .text
.code32
.global _start # _start declared global so the linker doesn't complain
_start: # This label is here so a 32-bit address is used
.code16
jmp real16
.align 4
.code32
multiboot_header:
.long MAGIC # magic
.long FLAGS # flags
.long CHECKSUM # checksum
.long multiboot_header # header address
.long _start # load address
.long 0x00000000 # load end address
.long 0x00000000 # bss end address
.long multiboot_entry # entry address
multiboot_entry:
cli # disable interrupts
mov eax, cr0
and eax, 0x7FFFFFFE # disable paging and protected mode
mov cr0, eax
xor eax, eax
mov cr3, eax # reset address of page directory
ljmp 0x00:real16 # far jump to real mode
.code16
real16:
cli
mov sp, 0x7C00 # set up stack
xor ax, ax # initialize segment registers
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ax, 0x03FF # limit of the idt
mov [newidt], ax
xor ax, ax # base of the idt
mov [newidt + 2], ax
mov [newidt + 4], ax
lidt [newidt] # load new idt
sti # enable interrupts
mov si, message
print:
lodsb
or al, al
jz hang
mov ah, 0x0E
int 0x10
jmp print
hang:
jmp hang
message:
.ascii "Hello World!"
.att_syntax prefix
The most suspicious thing is that jump. The 'correct' mnemonic for that should be 'jmp dword' or 'jmp far'. GAS doesn't support either of those, but I had read somewhere that ljmp was an older name for it. Anyhow, the CS register doesn't appear to be changing, so I really think the problem is there.
Can anyone tell me what mistake I'm making here?