This is the code for a program that, when booted by a bootloader, disables interrupts, loads a GDT descriptor, enables the A20 Line, enables protected mode, and jumps into 32-bit code.
.code16
.section .text
A20:
call waitA20_1
mov $0xAD,%al
out %al,$0x64
call waitA20_1
mov $0xD0,%al
out %al,$0x64
call waitA20_2
in $0x60,%al
push %eax
call waitA20_1
mov $0xD1,%al
out %al,$0x64
call waitA20_1
pop %eax
or $2,%al
out %al,$0x60
call waitA20_1
mov $0xAE,%al
out %al,$0x64
call waitA20_1
ret
waitA20_1:
in $0x64,%al # store input from keyboard controller (0x64) in AL
test $2,%al # AND operation with 2 (binary: 00000010) and keyboard input
jnz waitA20_1 # if ZFLAG is 0, try again
ret
waitA20_2:
in $0x64,%al
test $1,%al
jz waitA20_2 # if ZFLAG is 1, try again
ret
.globl _start
_start:
cli
lgdt gdtd
call A20
mov %cr0,%eax
or $1,%al
mov %eax,%cr0
ljmp $0x08, $PMode
.code32
PMode:
mov 0xb8000,%edi
movb $'!',(%edi)
inc %edi
movb 0x07,(%edi)
inc %edi
hang:
hlt
jmp hang
.section .data
.align 8
gdt:
.quad 0x0000000000000000 # Null descriptor
# kernel code segment
.word 0xFFFF # lower 16 bits of segment size
.word 0x0000 # lower 16 bits of base address
.byte 0x00 # middle 8 bits of base address
.byte 0x9A # access byte: ring 0, executable only
.byte 0xCF # granularity (0xC)
.byte 0x00 # higher 8 bits of base address
gdt_end:
gdtd:
.word gdt_end - gdt - 1
.long gdt
But nothing shows up at all. What's the issue here?
I tried adding a $ before 0xb8000. I expected it to be about loading an address at a particular location into a register versus loading a constant.