126 lines
4.3 KiB
Plaintext
126 lines
4.3 KiB
Plaintext
/* Inspired by from https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#boot_002eS */
|
|
|
|
/* boot.S - bootstrap the kernel */
|
|
/* Copyright (C) 1999, 2001, 2010 Free Software Foundation, Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define ASM_FILE 1
|
|
#include <multiboot2.h>
|
|
|
|
.section .multiboot
|
|
.align 4
|
|
/* Multiboot header. */
|
|
multiboot_header:
|
|
/* magic */
|
|
.long MULTIBOOT2_HEADER_MAGIC
|
|
/* ISA: i386 */
|
|
.long MULTIBOOT_ARCHITECTURE_I386
|
|
/* Header length. */
|
|
.long multiboot_header_end - multiboot_header
|
|
/* checksum */
|
|
.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header))
|
|
multiboot_header_end:
|
|
|
|
.section .bss
|
|
.align 4096
|
|
stack_bottom:
|
|
.skip 16384 # 16 KiB
|
|
stack_top:
|
|
|
|
|
|
.section .text
|
|
.global _start
|
|
.type _start, @function
|
|
_start:
|
|
/*
|
|
The bootloader has loaded us into 32-bit protected mode on a x86
|
|
machine. Interrupts are disabled. Paging is disabled. The processor
|
|
state is as defined in the multiboot standard. The kernel has full
|
|
control of the CPU. The kernel can only make use of hardware features
|
|
and any code it provides as part of itself. There's no printf
|
|
function, unless the kernel provides its own <stdio.h> header and a
|
|
printf implementation. There are no security restrictions, no
|
|
safeguards, no debugging mechanisms, only what the kernel provides
|
|
itself. It has absolute and complete power over the
|
|
machine.
|
|
*/
|
|
|
|
/*
|
|
To set up a stack, we set the esp register to point to the top of our
|
|
stack (as it grows downwards on x86 systems). This is necessarily done
|
|
in assembly as languages such as C cannot function without a stack.
|
|
*/
|
|
mov $stack_top, %esp
|
|
mov $stack_bottom, %ebp
|
|
|
|
/*
|
|
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.
|
|
*/
|
|
|
|
/* Reset EFLAGS. */
|
|
pushl $0
|
|
popf
|
|
|
|
|
|
/*
|
|
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 since pushed a multiple of 16 bytes to the
|
|
stack since (pushed 0 bytes so far) and the alignment is thus
|
|
preserved and the call is well defined.
|
|
*/
|
|
/* Push the pointer to the Multiboot information structure. */
|
|
pushl %ebx
|
|
/* Push the magic value. */
|
|
pushl %eax
|
|
call kmain
|
|
|
|
/*
|
|
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
|
|
1: hlt
|
|
jmp 1b
|
|
|
|
/*
|
|
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
|
|
.global _stack_bottom
|
|
_stack_bottom:
|
|
.long stack_bottom
|
|
.global _stack_top
|
|
_stack_top:
|
|
.long stack_top
|