aboutsummaryrefslogtreecommitdiff
path: root/kernel/boot/init/boot.s
blob: c558c9716faa944e489adc31eb457d5da9ee3ffc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
;;
;; bubbl
;; Copyright (C) 2024-2025  Raghuram Subramani <raghus2247@gmail.com>
;;
;; 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/>.
;;

;; Adapted from https://wiki.osdev.org/Bare_Bones

MBALIGN  equ  1 << 0              ;; align loaded modules on page boundaries
MEMINFO  equ  1 << 1              ;; provide memory map
MBFLAGS  equ  MBALIGN | MEMINFO   ;; this is the Multiboot 'flag' field
MAGIC    equ  0x1BADB002          ;; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + MBFLAGS)   ;; checksum of above, to prove we are multiboot

; Declare a multiboot header that marks the program as a kernel. These are magic
; values that are documented in the multiboot standard. The bootloader will
; search for this signature in the first 8 KiB of the kernel file, aligned at a
; 32-bit boundary. The signature is in its own section so the header can be
; forced to be within the first 8 KiB of the kernel file.
section .multiboot
align 4
dd MAGIC
dd MBFLAGS
dd CHECKSUM

;; The multiboot standard does not define the value of the stack pointer register
;; (esp) and it is up to the kernel to provide a stack. This allocates room for a
;; small stack by creating a symbol at the bottom of it, then allocating 16384
;; bytes for it, and finally creating a symbol at the top. The stack grows
;; downwards on x86. The stack is in its own section so it can be marked nobits,
;; which means the kernel file is smaller because it does not contain an
;; uninitialized stack. 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 .bss
align 16
stack_bottom:
resb 16384 ;;16KiB	
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. It
;; doesn't make sense to return from this function as the bootloader is gone.
section .text
global _start
_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 the
  ;; 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 esp, stack_top

  ;; Push Multiboot values to stack for kernel_main
  push ebx
  push eax

  ;;
  ;; 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.

  ;; Call the global constructors.
  extern _init
  call _init

  ;; 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.
  extern kernel_main
  call kernel_main