Skip to content

Instantly share code, notes, and snippets.

@jonasschneider
Created January 2, 2014 17:34
Show Gist options
  • Save jonasschneider/8222876 to your computer and use it in GitHub Desktop.
Save jonasschneider/8222876 to your computer and use it in GitHub Desktop.
# Tell the assembler to output 16-bit code; x86-compatible CPUs start in the 16-bit Real Mode.
.code16gcc
# Export the _start symbol, which is by convention the entry point for the .text
# section. Our makefile places the beginning of the text section at the start of
# the MBR. At runtime, the BIOS loads the MBR into address 0x7c00.
.globl _start
_start:
mov $(startup_message - _start + 0x7c00), %bx
call print_str_BX
# Let's enter protected mode.
# http://wiki.osdev.org/Protected_Mode
cli
lgdt (gdt_descriptor - _start + 0x7c00)
mov %cr0, %eax
or $1, %eax # set Protected bit #0
mov %eax, %cr0
# now we are in 16-bit protected mode. flush the instruction queue
mov $0x60, %ax
jmp in_prot16
in_prot16:
# make a long jump to:
# load CS with a selector to a 32-bit executable code descriptor.
#mov $1, %cs
#mov $0, %ip
ljmp $1, $0
ljmp *(in_prot32 - _start + 0x7c00)
in_prot32:
.code32
# done. ?
movb $'X', 0xB8000
movb $7, 0xB8001
# It's unclear what the processor will do when we just stop doing anything here.
# It'll probably start executing null byte instructions or something else silly.
# So, just busy loop here.
hang:
jmp hang
.code16gcc
startup_message:
.string "Hello from the grid.\r\n\0"
gdt_loaded_msg:
.string "GDT loaded.\r\n\0"
gdt_descriptor:
.word 3 * 4 # gdt size
.word gdt - _start + 0x7c00
gdt:
# null entry
.word 0,0
.word 0,0
# OS code segment
.word 0xffff # limit[15..0]
.word 0x0000 # base[15..00]
.byte 0x00 # base[23..16]
.byte 0b10011010 # P(1) DPL(00) S(1) 1 C(0) R(1) A(0)
.byte 0b11001111 # G(1) D(1) 0 0 Limit[19..16]
.byte 0x00 # base[31..24]
# overlapping OS data segment
.word 0xffff # limit[15..0]
.word 0x0000 # base[15..00]
.byte 0x00 # base[23..16]
.byte 0b10010010 # P(1) DPL(00) S(1) 0 E(0) W(1) A(0)
.byte 0b11001111 # G(1) B(1) 0 0 Limit[19..16]
.byte 0x00 # base[31..24]
print_str_BX:
# BX (Base Index) is one of the few 16-bit registers that can be
# used for address arithmetic. I'm not yet sure why, but it apparently has something to
# do with segments (x86 in Real Mode has a 20-bit address space, but only 16-bit registers).
# Cf. http://f.osdev.org/viewtopic.php?f=13&t=18374
# Load the next byte to print into AL, exit if it's \0.
mov (%bx), %al
test %al, %al
jz print_done
# Invoke INT10/AH=0E, which is by convention a BIOS call to print the character in AL.
mov $0x0e, %ah
int $0x10
# Advance the counter, and rinse
inc %bx
jmp print_str_BX
print_done:
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment