269 lines
8.9 KiB
C
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");
|
|
}
|
|
}
|