.globl _start .code16 _start: cli lgdt (gdtr_desc) # 3. Load the GDTR mov %cr0, %eax or $1, %al mov %eax, %cr0 ljmp $0x8, $PModeMain .align 8 gdt_start: # 1. Define the GDT table in memory .quad 0x0000000000000000 # Null descriptor (required) gdt_code: .word 0xFFFF # Limit (low) .word 0x0000 # Base (low) .byte 0x00 # Base (middle) .byte 0b10011010 # Access byte (code, ring 0) .byte 0b11001111 # Flags + Limit (high) .byte 0x00 # Base (high) gdt_data: .word 0xFFFF .word 0x0000 .byte 0x00 .byte 0b10010010 # Access byte (data, ring 0) .byte 0b11001111 .byte 0x00 gdt_end: gdtr_desc: # 2. Define the GDTR descriptor (limit + base) .word gdt_end - gdt_start - 1 # Limit: Size of GDT - 1 .long gdt_start # Base: Linear address of GDT .code32 PModeMain: # 5. Load Data Segment Selector (Offset 0x10 in GDT) mov $0x10, %ax mov %ax, %ds mov %ax, %ss mov %ax, %es movw $0x0F4A, 0xB8000 # Write 'J' to the top-left pixel hang: jmp hang .fill 510 - (. - _start), 1, 0 .word 0xAA55