Created
January 2, 2014 17:34
-
-
Save jonasschneider/8222876 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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