Reputation: 2884
I have the following assembly code. I'm trying to create a small bootloader to go into 32-bit protected mode. Once in protected mode, I need to print to VGA text mode video memory (0xb8000) for testing purposes. My code doesn't work. I found code from various resources around the web and learned that most have similar code which works properly, like this example: Printing characters to screen ASM in protected mode . My code that doesn't work:
bits 16
mov ah, 0x00 ;Set up video mode
mov al, 0x03
int 0x10
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdtr:
dw 24
dd gdt_start
lgdt [gdtr]
cli
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x08:protectedMode
bits 32
protectedMode:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov word [0xb8000], 0x0769
times 510 - ($-$$) db 0
dw 0xaa55
I compile the code with:
nasm -fbin boot.asm -oboot.bin
and run the result with:
qemu-system-x86_64 -fda boot.bin
It doesn't do anything.
When I disassemble the code with:
ndisasm boot.bin
it outputs the following result:
Why is the instruction before appending the zeroes
mov dword [di], 0xb8000
while it should be
mov word [0xb8000], 0x0769
Upvotes: 3
Views: 986
Reputation: 5265
When you have this block of data:
gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdtr:
dw 24
dd gdt_start
it's located in the path of execution. This data will be executed as code by the processor as the next instructions after int 0x10
. Move this lower, after mov word [0xb8000], 0x0769
.
You also need to add an infinite loop after executing that instruction to prevent execution from falling down to whatever garbage follows (GDT table if you put it there).
Always keep in mind that assembly is very low-level. Whatever you stick in your code, whether actual meaningful instructions or not, will be treated as code if the processor ever gets to it. It won't skip data, and it won't stop after the last instruction you write.
As to why the instruction disassembly is wrong, the disassembler doesn't know when to switch to 32-bit mode. It's just a disassembler, not a simulator, so it can't see the effect of the far jmp that gets the CPU to execute that part in 32-bit mode.
You can disassemble the whole thing in 32-bit mode, and then (after some mess before disassembly happens to get back in sync with actual instruction boundaries) it disassembles to what you intended with this:
ndisasm -b 32 boot.bin
... ;; some earlier mess of 16-bit code disassembled as 32
0000003B 8ED8 mov ds,eax
0000003D 8EC0 mov es,eax
0000003F 8EE0 mov fs,eax
00000041 8EE8 mov gs,eax
00000043 8ED0 mov ss,eax
00000045 66C70500800B0069 mov word [dword 0xb8000],0x769 ; correct disassembly
-07
0000004E 0000 add [eax],al
00000050 0000 add [eax],al
Upvotes: 3