/* 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 . * * Valentin Verdier */ #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"); } }