I have assembly code that switches to 32bit mode and prints a character successfully when I have it inside the boot sector - But when I use a disk read to load the code to the next sector the GDT table is misplaced even with the org directive, print fails, and the program gets into a boot loop. The disk read is successful, I tested it, and the code is exactly same in both cases except that I'm using org 0x7C00 in boot sector and 0x7E00 in 2nd sector.
I tried removing org and replacing dd gdt_start
with dd gdt_start + 0x7E00
, as well as hard-coding the exact address.
Working code sets GDT table to the right address containing 7C03, 3 bytes after the start. Not working code sets GDT to 000f61e0 00000037 (Not even close to right)
Stage 2 code:
BITS 16
org 0x7E00
cli
jmp code
gdt_start:
dq 0x0000000000000000 ; Null descriptor
dq 0x00CF9A000000FFFF ; Code segment
dq 0x00CF92000000FFFF ; Data segment
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Size
dd gdt_start
code:
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 1 ; Change PE (Protection Enable) bit if 0
mov cr0, eax
jmp 0x08:protected_mode
[BITS 32]
; Registers are 16-bit and map to 32-bit addresses through GDT table
protected_mode:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, 0xB8000
mov byte [eax], 'D'
mov byte [eax+1], 0x01
jmp $
And in case you want to see the disk read code from first stage:
BITS 16
org 0x7C00
jmp code
boot_drive: db 0
code:
mov byte [boot_drive], dl ; dl is loaded at boot and has the source drive
xor ax, ax
mov ah, 0x02 ; Disk read
mov al, 3 ; Sector read count
mov ch, 0 ; Cylinder
mov cl, 2 ; Sector
mov dh, 0 ; Head
mov dl, [boot_drive] ; Drive
mov es, ax ; Segment
mov bx, 0x7E00 ; Offset
int 0x13 ; Disk service
jc error ; Jmp if CF = 1
jmp 0x0000:0x7e00
error:
mov ah, 0x0E
mov al, 'E'
mov bh, 00
mov bl, 0x07
int 0x10
times 510 - ($ - $$) db 0
dw 0xAA55
Every piece of trouble got touched on in the comments. To make sure the corrections get to their right place, I will quickly summarize it here. For more info on much the same stuff, see Segment:Offset instead of org 0x7C00 directive.
BITS 16
org 0x7C00
jmp code
boot_drive: db 0
code:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
mov [boot_drive], dl ; dl is loaded at boot and has the source drive
mov ah, 0x02 ; Disk read
mov al, 3 ; Sector read count
mov ch, 0 ; Cylinder
mov cl, 2 ; Sector
mov dh, 0 ; Head
mov dl, [boot_drive] ; Drive
mov bx, 0x7E00 ; Offset
int 0x13 ; Disk service
jc error ; Jmp if CF = 1
jmp 0x0000:0x7e00
error:
mov ah, 0x0E
mov al, 'E'
mov bh, 00
mov bl, 0x07
int 0x10
cli
hlt
jmp $-2
times 510 - ($ - $$) db 0
dw 0xAA55
BITS 16
org 0x7E00
cli
jmp code
gdt_start:
dq 0x0000000000000000 ; Null descriptor
dq 0x00CF9A000000FFFF ; Code segment
dq 0x00CF92000000FFFF ; Data segment
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Size
dd gdt_start
code:
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 1 ; Change PE (Protection Enable) bit if 0
mov cr0, eax
jmp 0x08:protected_mode
[BITS 32]
; Registers are 16-bit and map to 32-bit addresses through GDT table
protected_mode:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 00007C00h
mov eax, 000B8000h
mov byte [eax], 'D'
mov byte [eax+1], 0x01
cli
hlt
jmp $-2