NutsOS/boot/kernloader/kernldr_main.c
2020-04-17 17:44:23 +02:00

269 lines
8.9 KiB
C

/* kernLdr_main.c - This file is a part of NutsOS
*
* NutsOS
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* NutsOS 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.
*
* NutsOS 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 NutsOS; If not, see <http://www.gnu.org/licenses/>.
*
* Valentin Verdier <valentin.verdier03@gmail.com>
*/
#include "types.h"
#include "kernLdr.h"
#include "drivers/ATA.h"
static void detectMemory(T_bootArgs* bargs, T_kernelArgs* kargs)
{
T_dword* test1 = (T_dword*) 0x500;
T_dword* test2 = (T_dword*) 0x100500;
*test1 = 0;
*test2 = 0xFFFFFFFF;
if(*test1 == 0) {
print("-> A20 line enabled\n", DEFAULT_COLOR);
} else {
print("-> A20 line disabled\n", DEFAULT_COLOR);
asm("hlt");
}
unsigned int i;
kargs->phyMemSize = 0;
for(i = 0; i < bargs->memListEntryCount; i++) {
//print("-> (0x%x - 0x%x) type=%d\n", DEFAULT_COLOR, bargs->memMap[i].baseAddr_1, bargs->memMap[i].baseAddr_1 + bargs->memMap[i].size_1, bargs->memMap[i].type);
if(bargs->memMap[i].type == 1) {
kargs->phyMemSize += bargs->memMap[i].size_1;
}
}
print("-> Physical memory size : %d Ko\n", DEFAULT_COLOR, (kargs->phyMemSize / 1024));
}
static int getPartition(unsigned int partNumber, T_ATA_device device, T_FAT32_partition* part)
{
partNumber &= 0x3;
print("-> Partition : %d\n", DEFAULT_COLOR, partNumber);
/* On récupère le MBR */
T_mbr* mbr = (T_mbr*) 0x15000;
ATA_read(device, 0, 1, mbr);
if(mbr->partitionTable[partNumber].fileSytemID == VFAT32_PARTITION_ID) {
part->device = device;
part->LBA_dbr = mbr->partitionTable[partNumber].startingLBA;
// On charge le Dos Boot Record de la partition
ATA_read(part->device, part->LBA_dbr, 1, (void*) &part->dbr);
// On calcul l'adresse de la FAT ainsi que l'adresse du premier cluster
if(part->dbr.fatInfo >> 7) {
unsigned int activeFAT = part->dbr.fatInfo & 0x0F;
part->LBA_fileAllocationTable = part->LBA_dbr + part->dbr.reservedSectors + (activeFAT * part->dbr.sectorsPerFat);
} else {
part->LBA_fileAllocationTable = part->LBA_dbr + part->dbr.reservedSectors;
}
ATA_read(part->device, part->LBA_fileAllocationTable, 1, part->fatSectorBuffer);
part->LBA_firstDataSector = part->LBA_dbr + part->dbr.reservedSectors + (part->dbr.fatNumber * part->dbr.sectorsPerFat);
return 1;
} else {
print("-> ERROR : The partition is not VFAT32 type\n", DEFAULT_COLOR);
return 0;
}
}
static T_dword getFat32ClusterLBA(unsigned int clusterNum, T_FAT32_partition* part) {
return ((clusterNum - 2) * part->dbr.sectorsPerCluster) + part->LBA_firstDataSector;
}
static unsigned int getFat32NextClusterNum(unsigned int clusterNum, T_FAT32_partition* part) {
unsigned int nextCluster;
unsigned int sector = part->LBA_fileAllocationTable + ((clusterNum * 4) / 512);
if(sector != part->loadedFatSector) {
ATA_read(part->device, sector, 1, part->fatSectorBuffer);
part->loadedFatSector = sector;
}
nextCluster = part->fatSectorBuffer[((clusterNum * 4) % 512) / 4];
if(nextCluster >= 0x0FFFFFF8) {
return 0;
} else if(nextCluster == 0x0FFFFFF7) {
print("-> ERROR : A BAD CLUSTER WAS FOUND (PREVIOUS CLUSTER = %d)\n", DEFAULT_COLOR, clusterNum);
asm("hlt");
} else {
return nextCluster;
}
}
static unsigned int loadFile(char *target, T_dword destAddr, T_FAT32_partition* part)
{
print("-> Loading '%s'\n", DEFAULT_COLOR, target);
unsigned int currentCluster = part->dbr.rootDirFirstCluster; /* Numéro d'un cluster du répertoire courant */
T_FAT32_stdEntry* entry = (T_FAT32_stdEntry*) part->dirClusterBuffer; /* Buffer utilisé pour stocker un cluster du répertoire courant */
ATA_read(part->device, getFat32ClusterLBA(currentCluster, part), part->dbr.sectorsPerCluster, entry);
unsigned int i = 0;
while(target[i] != 0) {
char entity[256];
unsigned int j;
char isDirectory = 0, isFile = 0;
for(j = 0; target[i] != 0; i++, j++) {
if(j >= 256) {
print("-> ERROR : INVALID TARGET '%s'\n", DEFAULT_COLOR, target);
return 0;
} else if(target[i] == '/') {
isDirectory = 1;
i++;
break;
} else {
entity[j] = target[i];
}
}
/* On ferme la chaine de caractères */
entity[j] = '\0';
if(!isDirectory) {
isFile = 1;
}
/* Chargement */
if(entity[0] != '\0') {
unsigned int lfnAvailable = 0;
unsigned int stopLoop = 0;
while(currentCluster && (!stopLoop)) {
unsigned int k;
char *entityLFN = (char*) 0x4200;
for(k = 0; k < ((part->dbr.sectorsPerCluster * 512) / FAT32_DIR_ENTRY_SIZE); k++) {
if((entry[k].fileName[0] != 0) && (entry[k].fileName[0] != 0xE5)) { /* Si l'entrée est valide */
if(entry[k].attribute == 0x0F) { /* Si on trouve une entrée LFN */
T_FAT32_lfnEntry* lfnEntry = (T_FAT32_lfnEntry*) &entry[k];
lfnAvailable = 1;
/* On récupère les parties de nom */
unsigned int l;
unsigned int offset = ((lfnEntry->entryNum & 0x3F) - 1) * 13; /* offset de la section du nom dans la chaine finale */
for(l = 0; l < 13; l++) {
if(l < 5) {
entityLFN[offset + l] = lfnEntry->char_part1[l * 2];
} else if(l < 11) {
entityLFN[offset + l] = lfnEntry->char_part2[(l - 5) * 2];
} else if(l < 13) {
entityLFN[offset + l] = lfnEntry->char_part3[(l - 11) * 2];
}
}
} else { /* Sinon c'est une entrée standard */
char *entityNameCmp;
if(lfnAvailable) {
entityNameCmp = entityLFN;
lfnAvailable = 0;
} else {
entityNameCmp = (char*) 0x4400;
unsigned int l, m;
for(l = 0; l < 8 && entry[k].fileName[l] != ' '; l++) {
entityNameCmp[l] = entry[k].fileName[l];
}
entityNameCmp[l] = '.';
for(m = 0; m < 3 && entry[k].extention[m] != ' '; m++, l++) {
entityNameCmp[l] = entry[k].extention[m];
}
entityNameCmp[l] = '\0';
}
if(isDirectory) {
if((strcmp(entity, entityNameCmp)) && (entry[k].attribute & 0x10)) {
currentCluster = ((T_dword) entry[k].firstCluster_high << 16) | entry[k].firstCluster_low;
ATA_read(part->device, getFat32ClusterLBA(currentCluster, part), part->dbr.sectorsPerCluster, part->dirClusterBuffer);
stopLoop = 1;
break;
}
} else if(isFile) {
if((strcmp(entity, entityNameCmp)) && (entry[k].attribute & 0x20)) {
unsigned int cluster = ((T_dword) entry[k].firstCluster_high << 16) | entry[k].firstCluster_low;
unsigned int size = 0;
while(cluster) {
ATA_read(part->device, getFat32ClusterLBA(cluster, part), part->dbr.sectorsPerCluster, (void*) destAddr);
destAddr += (part->dbr.sectorsPerCluster * 512);
cluster = getFat32NextClusterNum(cluster, part);
size += (part->dbr.sectorsPerCluster * 512);
}
return size;
}
}
}
}
}
if(!stopLoop) {
currentCluster = getFat32NextClusterNum(currentCluster, part);
}
}
if(!stopLoop) {
print("-> ERROR : UNABLE TO FIND '%s' FOR '%s'\n", DEFAULT_COLOR, entity, target);
return 0;
}
}
}
}
void kernLdr_main()
{
/* On définit les adresse des structure en mémoire */
T_bootArgs* bootArgs = (T_bootArgs*) BOOT_ARGS_ADDR;
T_kernelArgs* kernelArgs = (T_kernelArgs*) KERNEL_ARGS_ADDR;
/* Position du curseur */
posX = bootArgs->cursor_X;
posY = bootArgs->cursor_Y;
showCursor();
print("Welcome to NutsOS KernelLoader v1.0.0\n", DEFAULT_COLOR);
/* On affiche la memory map */
print("[MEMORY DETECTION]\n", 0x02);
detectMemory(bootArgs, kernelArgs);
T_ATA_device bootDevice;
T_FAT32_partition bootPartition;
bootPartition.loadedFatSector = 0;
bootPartition.dirClusterBuffer = (T_dword*) 0x2000;
print("[FILES LOADING]\n", 0x02);
if(!ATA_getDevice(0, 0, &bootDevice)) {
asm("hlt");
}
if(!getPartition(0, bootDevice, &bootPartition)) {
asm("hlt");
}
if(loadFile("/boot/NOS-kernel32.bin", 0x100000, &bootPartition)) { /* On charge KERNEL32 à la bonne adresse et on passe les arguments */
kernelArgs->initProcessAddr = 0x28000;
kernelArgs->initProcessSize = loadFile("/boot/init", kernelArgs->initProcessAddr, &bootPartition);
if(!kernelArgs->initProcessSize) {
asm("hlt");
} else if(kernelArgs->initProcessSize > 819200) {
print("ERROR : INIT PROCESS IS TOO LARGE\n", DEFAULT_COLOR);
asm("hlt");
} else {
print("[BOOTING]\n", 0x02);
kernelArgs->cursor_X = posX;
kernelArgs->cursor_Y = posY;
kernelArgs->memListEntryCount = bootArgs->memListEntryCount;
kernelArgs->memMap = bootArgs->memMap;
}
} else {
asm("hlt");
}
}