aboutsummaryrefslogtreecommitdiff
path: root/src/boot.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot.S')
-rw-r--r--src/boot.S97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/boot.S b/src/boot.S
new file mode 100644
index 0000000..fff1644
--- /dev/null
+++ b/src/boot.S
@@ -0,0 +1,97 @@
+/*
+ Declare a multiboot header that marks the program as a kernel.
+ https://www.gnu.org/software/grub/manual/multiboot2/html_node/index.html
+
+ The Multiboot2 header must be contained completely within the first
+ 32kB of the OS image, and must be 64-bit (8 byte) aligned.
+*/
+.set MULTIBOOT_HEADER_MAGIC, 0xe85250d6 # multiboot2 magic number
+.set MULTIBOOT_ARCHITECTURE, 0 # protected mode i386
+.set MULTIBOOT_HEADER_TAG_END, 0
+
+.section .multiboot
+.align 8
+header_start:
+ .int MULTIBOOT_HEADER_MAGIC
+ .int MULTIBOOT_ARCHITECTURE
+ .int header_end - header_start
+ .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE + (header_end - header_start))
+
+ # TODO tags go here
+
+ .short MULTIBOOT_HEADER_TAG_END
+ .short 0
+ .int 8
+header_end:
+
+/*
+ The stack on x86 must be 16-byte aligned according to the System V ABI
+ standard and de-facto extensions. The compiler will assume the stack is
+ properly aligned and failure to align the stack will result in undefined
+ behavior.
+*/
+.section .stack, "aw", @nobits
+.align 16
+stack_bottom:
+ .skip 16 * 1024
+stack_top:
+
+/*
+ The linker script specifies _start as the entry point to the kernel and the
+ bootloader will jump to this position once the kernel has been loaded.
+*/
+.section .text
+.extern kernel_constructors
+.extern kernel_main
+.global _start
+.type _start, @function
+_start:
+ mov $stack_bottom, %ebp
+ mov $stack_top, %esp # point the stack pointer to the stack
+
+ /*
+ This is a good place to initialize crucial processor state before the
+ high-level kernel is entered. It's best to minimize the early
+ environment where crucial features are offline. Note that the
+ processor is not fully initialized yet: Features such as floating
+ point instructions and instruction set extensions are not initialized
+ yet. The GDT should be loaded here. Paging should be enabled here.
+ C++ features such as global constructors and exceptions will require
+ runtime support to work as well.
+ */
+
+ pushl %ebx # push the pointer to the multiboot structure
+ pushl %eax # push the multiboot magic value
+ call kernel_constructors
+
+ /*
+ Enter the high-level kernel. The ABI requires the stack is 16-byte
+ aligned at the time of the call instruction (which afterwards pushes
+ the return pointer of size 4 bytes). The stack was originally 16-byte
+ aligned above and we've pushed a multiple of 16 bytes to the
+ stack since (pushed 0 bytes so far), so the alignment has thus been
+ preserved and the call is well defined.
+ */
+ call kernel_main
+
+ /*
+ If the system has nothing more to do, put the computer into an
+ infinite loop. To do that:
+ 1) Disable interrupts with cli (clear interrupt enable in eflags).
+ They are already disabled by the bootloader, so this is not needed.
+ Mind that you might later enable interrupts and return from
+ kernel_main (which is sort of nonsensical to do).
+ 2) Wait for the next interrupt to arrive with hlt (halt instruction).
+ Since they are disabled, this will lock up the computer.
+ 3) Jump to the hlt instruction if it ever wakes up due to a
+ non-maskable interrupt occurring or due to system management mode.
+ */
+ cli
+hang: hlt
+ jmp hang
+
+/*
+Set the size of the _start symbol to the current location '.' minus its start.
+This is useful when debugging or when you implement call tracing.
+*/
+.size _start, . - _start