;
; boot.asm
;
; Copyright (C) 2015 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Affero 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 Affero General Public License for more details.
;
; You should have received a copy of the GNU Affero General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

global start
global multiboot

extern _stack
extern _stack_top
extern _end
extern kernel_main

MULTIBOOT_MAGIC         EQU     0xE85250D6
PHYSICAL_ADDRESS        EQU     0x100000
VIRTUAL_ADDRESS         EQU     0x80000000
PAGE_DIR_SELF_ENTRY     EQU     768

multiboot:              DD      MULTIBOOT_MAGIC
                        DD      0
                        DD      start - multiboot
                        DD      multiboot - start - MULTIBOOT_MAGIC

info_tag:               DW      1                           ; Information request tag
                        DW      0
                        DD      24
                        DD      1                           ; Boot command line
                        DD      3                           ; Boot modules
                        DD      6                           ; Memory map
                        DD      9                           ; Symbols

                        DD      0                           ; End tag
                        DD      8

bits 32

start:                  mov     esp, _stack_top - VIRTUAL_ADDRESS + PHYSICAL_ADDRESS
                        mov     eax, dword [ebx]
                        sub     eax, 8
                        push    eax
                        add     ebx, 8
                        push    ebx
                        mov     ebp, _stack - VIRTUAL_ADDRESS + PHYSICAL_ADDRESS
                        mov     ebx, _end - VIRTUAL_ADDRESS + PHYSICAL_ADDRESS 
                        xor     eax, eax
                        mov     edi, ebp
                        mov     ecx, ebx
                        add     ecx, 0x3FFFFF
                        and     ecx, 0xFFC00000
                        add     ecx, ebx
                        add     ecx, 0x3FFFFF - PHYSICAL_ADDRESS
                        and     ecx, 0xFFC00000
                        shr     ecx, 12
                        add     ecx, 0x400
                        cld
                        rep stosd
                        mov     dword [ebp + PAGE_DIR_SELF_ENTRY * 4], ebp
                        or      dword [ebp + PAGE_DIR_SELF_ENTRY * 4], 3
                        mov     eax, ebp
                        add     eax, 0x1003
                        mov     edi, ebp
                        mov     ecx, ebx
                        add     ecx, 0x3FFFFF
                        shr     ecx, 22
.fill_directory_low:    stosd
                        add     eax, 0x1000
                        loop    .fill_directory_low
                        lea     edi, [ebp + 0x800]
                        mov     ecx, ebx
                        add     ecx, 0x3FFFFF
                        shr     ecx, 22
.fill_directory_high:   stosd
                        add     eax, 0x1000
                        loop    .fill_directory_high
                        lea     edi, [ebp + 0x1000]
                        mov     eax, 3
.fill_tables:           stosd
                        add     eax, 0x1000
                        cmp     eax, ebx
                        jb      .fill_tables
                        lea     esi, [ebp + 0x1000 + (PHYSICAL_ADDRESS >> 12) * 4]
                        mov     edi, dword [ebp + 0x800]
                        and     edi, 0xFFFFF000
                        mov     ecx, ebx
                        sub     ecx, PHYSICAL_ADDRESS
                        shr     ecx, 12
                        rep movsd
.done:                  mov     cr3, ebp
                        mov     eax, cr4
                        or      eax, 0x80
                        mov     cr4, eax
                        mov     eax, cr0
                        or      eax, 0x80010000
                        mov     cr0, eax
                        mov     eax, .continue
                        jmp     eax
.continue:              add     esp, VIRTUAL_ADDRESS - PHYSICAL_ADDRESS
                        xor     ebp, ebp
                        call    kernel_main
.return:                add     esp, 8
                        cli
                        hlt
