NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: nobody on December 01, 2008, 12:57:11 PM
-
I am looking for code which switches from real to protected mode as part of a BIOS initialisation routine. I've found code to do this in redboot, Coreboot (LinuxBIOS), and several other places, but they are all using the GNU assembler, and they all hand-craft the jump instructions.
The Nasm documentation seems to suggest it's possible to mix 16 and 32-bit instructions, and this should allow me to write this code without 'tricks', however my code always triple-faults when performing the jmp just after setting up GDT and enabling pmode.
Is this possible?
Many thanks,
Simon.
-
Perhaps I should make it a bit clearer what I'm doing. I've written the following code
and run it in qemu on Linux.
I know that this will never work on a real machine - it's just a learning exercise for myself. If I don't choose the correct value to load into the data selectors I get a triple fault, however I don't understand where this number comes from.
Can anyone explain how this works?
thanks.
<----cut here ----->|<----cut here ----->|<----cut here ----->|<----cut here ----->
; Compile with:
; nasm -o bios.bin bios.S
; Run Qemu with:
; qemu -cpu 486 -L ./ -hda /dev/zero -serial stdio -m 16 -nographic
;
ORG 0xffff0000 ; 64k BIOS
BITS 16
rom_start:
cli
lgdt [gdtDesc]
mov eax,cr0 ; protected mode
or ax,1
mov cr0,eax
jmp word pm_start
pm_start:
; Signal we are in PM via COM1, output a byte on serial port.
mov dx, 0x3f8
mov al, 'P'
out dx, al
; Load data selectors
mov eax, 0x2
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
; Signal we are done via COM1
mov dx, 0x3f8
mov al, 'F'
out dx, al
jmp $
ALIGN 4
gdtDesc:
dw (gdtEnd - gdt)
dw gdt
ALIGN 4
gdt:
dd 0,0 ; null.
dw 0xffff, 0x0000
db 0x00, 10011010b, 11001111b, 0x00 ; code
dw 0xffff, 0x0000
db 0x00, 10010010b, 11001111b, 0x00 ; data
gdtEnd:
TIMES 0xfff0-($-$$) DB 0xff
reset_entry: ; power on
jmp rom_start
TIMES 0x10000-($-$$) DB 0xff
<----cut here ----->|<----cut here ----->|<----cut here ----->|<----cut here ----->
-
I'm over my head here - no experience with bios code (and I'll have to review the unit on "decrypting descriptors")...
But I think you'll want a far jump after the "mov cr0, eax"...
jmp 8:pm_start
(8 would be the offset of your code descriptor) If the descriptor says 32-bit code, you'll want a "bits 32" directive in there too. Then, 16 (0x10) would be the correct value to load into the segment registers (cs is loaded by the far jump) - it's a byte offset into the descriptor table, not a "descriptor number"...
That should help, but may not be enough to do it. If you've got some "working" Gas code, we can probably help you "translate" that. Good luck!
Best,
Frank
-
Thanks Frank.
The working Gas code is here:
http://cvs.cens.ucla.edu/viewcvs/viewcvs.cgi/stargate/ecos/packages/hal/i386/pc/current/src/romboot.S?rev=HEAD&content-type=text/vnd.viewcvs-markup (http://cvs.cens.ucla.edu/viewcvs/viewcvs.cgi/stargate/ecos/packages/hal/i386/pc/current/src/romboot.S?rev=HEAD&content-type=text/vnd.viewcvs-markup)
I don't understand why that code copies the descriptor to DRAM. Surely it should be possible to make this work directly from flash memory at 0xffff0000? Or is there some fundamental limit on the gdt registers that means their descriptors have to be in the lowest 1MB?
I tried your suggestions but they don't work. The JMP you suggested doesn't seem to work - triple fault on the jmp instruction. I tried various combinations of BITS32 before and after the jump, but not joy.
I am a total Nasm beginner, I'm afraid, and this is probably not the best project to start with, but if I could get the Gas code converted that would be something!
regards,
Simon.