Reputation:
I'm trying to print the character "C" after switching to the Protected Mode, but it isn't working, and I don't know why. I'm using Assembly AT&T/GAS syntax
Here is the code:
.code16
.global _start
_start:
cli
gdt_start:
.quad 0x0
gdt_data:
.short 0xffff
.short 0x0
.byte 0x0
.byte 0b10010010
.byte 0b11001111
.byte 0x0
gdt_code:
.short 0xffff
.short 0x0
.byte 0x0
.byte 0b10011010
.byte 0b11001111
.byte 0x0
gdt_end:
DATASEG = gdt_data-gdt_start
CODESEG = gdt_code-gdt_start
gdt_pointer:
.short gdt_end - gdt_start - 1
.long gdt_start
lgdt (gdt_pointer)
mov %cr0, %eax
or $1, %eax
mov %eax, %cr0
ljmp $CODESEG, $protected_mode
.code32
protected_mode:
mov $'C', %al
mov 0x0f, %ah
mov %ax, (0xb8000)
jmp .
.fill 510-(.-_start), 1, 0
.word 0xaa55
The Makefile options:
as main.s -o boot.o
ld -Ttext 0x7c00 -o boot.bin --oformat binary boot.o
I think the problem is my GDT table or the far jump, but I don't know where. Anyway, I tried searching for other people's code, but didn't find anything.
Upvotes: 1
Views: 67
Reputation: 39166
I think the problem is my GDT table or the far jump,
.fill
directive, so after your infinite loop jmp .
.lgdt (gdt_pointer)
and mov %ax, (0xb8000)
instructions depend on the DS segment register. You must make sure you set it up correctly. Because you are using an origin of 0x7C00
that would be DS=0 in the first case, and DS=DATASEG with a segment base of 0 in the second case.For this simplified exercise (printing the character "C" after switching to the Protected Mode), it isn't necessary to setup the stack especially because of the cli
, but I have included it anyway:
.code16
.global _start
_start:
cli
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov $0x7C00, sp
lgdt (gdt_start)
mov %cr0, %eax
or $1, %al
mov %eax, %cr0
ljmp $CODESEG, $PM
.code32
PM:
mov $DATASEG, %ax
mov %ax, %ds
mov %ax, %ss
mov $0x00007C00, %esp
movw $0x0F43, (0x000B8000)
jmp .
gdt_start:
.short gdt_end - gdt_start - 1
.long gdt_start
.short 0x0
gdt_data:
.short 0xFFFF
.short 0x0
.byte 0x0
.byte 0b10010010
.byte 0b11001111
.byte 0x0
gdt_code:
.short 0xFFFF
.short 0x0
.byte 0x0
.byte 0b10011010
.byte 0b11001111
.byte 0x0
gdt_end:
DATASEG = gdt_data - gdt_start
CODESEG = gdt_code - gdt_start
.fill 510-(.-_start), 1, 0
.word 0xAA55
The first slot of the GDT is unused and normally filled with zeroes. However it is possible to store the GDT_POINTER in there and save some of those precious bootsector bytes, considering its restricted size of 512 bytes.
Upvotes: 1