;                MentOS, The Mentoring Operating system project
; @file boot.asm
; @brief Kernel start location, multiboot header
; @copyright (c) 2014-2021 This file is distributed under the MIT License.
; See LICENSE.md for details.

bits 32             ; All instructions should be 32-bit.
extern boot_main    ; The start point of our C code

; The magic field should contain this.
MULTIBOOT_HEADER_MAGIC     equ 0x1BADB002
; This should be in %eax.
MULTIBOOT_BOOTLOADER_MAGIC equ 0x2BADB002

; = Specify what GRUB should PROVIDE =========================================
; Align the kernel and kernel modules on i386 page (4KB) boundaries.
MULTIBOOT_PAGE_ALIGN  equ 0x00000001
; Provide the kernel with memory information.
MULTIBOOT_MEMORY_INFO equ 0x00000002
; Must pass video information to OS.
MULTIBOOT_VIDEO_MODE  equ 0x00000004
; -----------------------------------------------------------------------------

; This is the flag combination that we prepare for Grub
; to read at kernel load time.
MULTIBOOT_HEADER_FLAGS  equ (MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE)
; Grub reads this value to make sure it loads a kernel
; and not just garbage.
MULTIBOOT_CHECKSUM      equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

LOAD_MEMORY_ADDRESS equ 0x00000000
; reserve (1024*1024) for the stack on a doubleword boundary
KERNEL_STACK_SIZE   equ 0x100000

; -----------------------------------------------------------------------------
; SECTION (multiboot_header)
; -----------------------------------------------------------------------------
section .multiboot_header
align 4
; This is the GRUB Multiboot header.
multiboot_header:
    ; magic
    dd MULTIBOOT_HEADER_MAGIC
    ; flags
    dd MULTIBOOT_HEADER_FLAGS
    ; checksum
    dd MULTIBOOT_CHECKSUM

; -----------------------------------------------------------------------------
; SECTION (data)
; -----------------------------------------------------------------------------
; section .data nobits
; align 4096

; -----------------------------------------------------------------------------
; SECTION (text)
; -----------------------------------------------------------------------------
section .text
global boot_entry
boot_entry:
    ; Clear interrupt flag [IF = 0]; 0xFA
    cli
    ; To set up a stack, we simply set the esp register to point to the top of
    ; our stack (as it grows downwards).
    mov esp, stack_top
    ; pass the initial ESP
    push esp
    ; pass Multiboot info structure
    push ebx
    ; pass Multiboot magic number
    push eax
    ; Call the boot_main() function inside boot.c
    call boot_main
    ; Set interrupt flag [IF = 1]; 0xFA
    ; Clear interrupts and hang if we return from boot_main
    cli
hang:
    hlt
    jmp hang

global boot_kernel
boot_kernel:
    mov edx, [esp + 4] ; stack_pointer
    mov ebx, [esp + 8] ; entry
    mov eax, [esp + 12] ; boot info
    mov esp, edx ; set stack pointer
    push eax ; push the boot info
    call ebx ; call the kernel main


; -----------------------------------------------------------------------------
; SECTION (bss)
; -----------------------------------------------------------------------------
section .bss
align 16

global stack_bottom
stack_bottom:
    resb KERNEL_STACK_SIZE

global stack_top
stack_top:
    ; the top of the stack is the bottom because the stack counts down
