//----------------------------------------------------------------------------//
//                           GNU GPL OS/K                                     //
//                                                                            //
//  Desc:       Initialization of boot info                                   //
//                                                                            //
//                                                                            //
//  Copyright © 2018-2019 The OS/K Team                                       //
//                                                                            //
//  This file is part of OS/K.                                                //
//                                                                            //
//  OS/K 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         //
//  any later version.                                                        //
//                                                                            //
//  OS/K 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 OS/K.  If not, see <https://www.gnu.org/licenses/>.            //
//----------------------------------------------------------------------------//

#include <init/boot.h>

//
// BootInfo_t initialization. It is necessary because grub will potentially be
//  wiped since it is below 1MB.... And we must reorganize all that stuff.
//
void BtInitBootInfo(multiboot_info_t *mbi, void *codeSeg)
{
    extern ulong BtHeader;
    extern ulong newKernelEnd;
    extern ulong newStackEnd;

    // We need the multiboot structure
    assert_always(mbi);

    // Retrieves the bootloader flags to ensure infos are valid
    BtLoaderInfo.grubFlags            = mbi->flags;

    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
        BtLoaderInfo.grubName   = (char*)(ulong)(mbi->boot_loader_name);
        BtLoaderInfo.kernelAddr       = (void*)&BtHeader;
        BtLoaderInfo.kernelEndAddr    = (void*)newKernelEnd;
        BtLoaderInfo.stackEndAddr    = (void*)newStackEnd;
        BtLoaderInfo.codeSegment      = codeSeg;
        BtLoaderInfo.valid            = 1;
    }
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_MODS) {
        BtLoaderInfo.modulesCount     = mbi->mods_count;
        BtLoaderInfo.modulesAddr      = (void*)(ulong)mbi->mods_addr;
    }
    // Retrieves the drives informations
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_DRIVE_INFO) {
        BtBootTab.drives.bufferLength    = mbi->drives_length;
        BtBootTab.drives.bufferAddr      = (void*)(ulong)mbi->drives_addr;
        BtBootTab.drives.bufferValid     = 1;
    }
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_BOOTDEV) {
        BtBootTab.drives.bootDrv         = mbi->boot_device;
        BtBootTab.drives.drvValid        = 1;
    }

    // Retrieves the memory informations
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_MEMORY) {
        BtMemoryInfo.lowMemory       = mbi->mem_lower;
        BtMemoryInfo.upMemory        = mbi->mem_upper;
        BtMemoryInfo.memValid        = 1;
    }
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_MEM_MAP) {
        BtMemoryInfo.mapAddr         = (void*)(ulong)mbi->mmap_addr;
        BtMemoryInfo.mapLength       = mbi->mmap_length;
        BtMemoryInfo.mapValid        = 1;
    }

    // Retrieves video mode informations
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_VBE_INFO) {
        BtVideoInfo.vbeControl  = (void*)(ulong)mbi->vbe_control_info;
        BtVideoInfo.vbeModeInfo = (void*)(ulong)mbi->vbe_mode_info;
        BtVideoInfo.vbeMode          = mbi->vbe_mode;
        BtVideoInfo.vbeInterfaceSeg  = mbi->vbe_interface_seg;
        BtVideoInfo.vbeInterfaceOff  = mbi->vbe_interface_off;
        BtVideoInfo.vbeInterfaceLen  = mbi->vbe_interface_len;
        BtVideoInfo.vbeValid         = 1;
    }
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) {
        BtVideoInfo.framebufferAddr  = (void*)mbi->framebuffer_addr;
        BtVideoInfo.framebufferPitch = mbi->framebuffer_pitch;
        BtVideoInfo.framebufferWidth = mbi->framebuffer_width;
        BtVideoInfo.framebufferHeight= mbi->framebuffer_height;
        BtVideoInfo.framebufferBpp   = mbi->framebuffer_bpp;
        BtVideoInfo.framebufferType  = mbi->framebuffer_type;
        BtVideoInfo.fbuValid         = 1;
    }

    // Retrieves the firmware infos
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_CONFIG_TABLE) {
        BtFirmwareInfo.romTable      = mbi->config_table;
        BtFirmwareInfo.romValid      = 1;
    }
    if (BtLoaderInfo.grubFlags & MULTIBOOT_INFO_APM_TABLE) {
        BtFirmwareInfo.apmTable      = mbi->apm_table;
        BtFirmwareInfo.apmValid      = 1;
    }
}

void BtDoSanityChecks(uint mbMagic) {

    if (!(mbMagic == MULTIBOOT_BOOTLOADER_MAGIC))
        KeStartPanic("Magic number %x is incorrect\n", mbMagic);

    DebugLog("\t Kernel successfully loaded at %p\n",
            BtLoaderInfo.kernelAddr);
}