Shellscript improvement plus FAT driver implementations

- Improved the run bash script to exit when an error occurs in one of the sub tasks
- Wrote basic FAT16 functions that should give enough information to properly implement the rest of the driver
- FAT structure namings are now in accordence with the microsoft spec of March 2005
This commit is contained in:
Nigel Barink 2023-02-23 23:54:02 +01:00
parent 50bf952a49
commit a77621faf5
20 changed files with 760 additions and 495 deletions

View File

@ -1,6 +1,6 @@
AS = ${HOME}/opt/cross/bin/i686-elf-as
CC = ${HOME}/opt/cross/bin/i686-elf-gcc
CPP = ${HOME}/opt/cross/bin/i686-elf-g++
AS = /opt/cross/bin/i686-elf-as
CC = /opt/cross/bin/i686-elf-gcc
CPP = /opt/cross/bin/i686-elf-g++
CFLAGS = -ffreestanding -Og -ggdb -Wall -Wextra -I ../build/CoreLib/include
BUILD_DIR = ../build/kernel
OBJ_DIR = ../bin/kernel

View File

@ -15,6 +15,8 @@
#include "interrupts/idt.h"
#include "serial.h"
#include "storage/vfs/vfs.h"
#include "storage/filesystems/FAT/FAT.h"
extern "C" void LoadGlobalDescriptorTable();
extern "C" void jump_usermode();
@ -54,20 +56,83 @@ extern "C" void kernel ()
printf("booted from floppy disk\n");
printf("Part1: %d, Part2: %d, Part3: %d\n", part1, part2 , part3);
ATAPIO::Identify(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
auto* bpb = FAT::getBPB(false);
auto* mbr = GetPartitions(false);
auto fsType = FAT::determineFATType(bpb);
switch (fsType) {
case FAT_TYPE::FAT12:
printf("FAT12 Disk!\n");
break;
case FAT_TYPE::FAT16:
printf("FAT16 Disk!\n");
break;
case FAT_TYPE::FAT32:
printf("FAT32 Disk!\n");
break;
}
VirtualFileSystem::initialize();
// list files in root
int total_sectors = bpb->TotSec32;
int fat_size = bpb->FATSz16;
int root_dir_sectors = FAT::RootDirSize(bpb);
int first_data_sector = bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sectors ;
int first_fat_sector = bpb->RsvdSecCnt;
int data_sectors = bpb->TotSec32 - (bpb->RsvdSecCnt + (bpb->NumFATs * fat_size) + root_dir_sectors);
int total_clusters = data_sectors / bpb->SecPerClus;
// Try and open hello.txt file
VirtualFileSystem::OpenFile("a:hello.txt");
int first_root_dir_sector = first_data_sector - root_dir_sectors;
//int first_sector_of_cluster = ((cluster - 2) * bpb->SecPerClus) + first_data_sector;
uint16_t data[256];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, first_root_dir_sector, data);
auto* RootDirectory = (DIR*)data;
for(int i = 0; i < sizeof(data) / sizeof (DIR); i++)
{
DIR* entry = (DIR*)((uint32_t)RootDirectory + (i * sizeof(DIR)));
if(entry->Name[0] == FAT::FREE_DIR || entry->Name[0] == FAT::FREE_DIR_2 || entry->Name[0] == 0xE5){
continue;
}
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_HIDDEN){
continue;
}
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_SYSTEM)
continue;
if(entry->ATTR & FAT::ATTRIBUTES::ATTR_VOLUME_ID){
continue;
}
if (!(entry->ATTR & FAT::ATTRIBUTES::ATTR_LONG_NAME)){
for(char n : entry->Name){
if(n == 0x20)
continue;
kterm_put(n);
}
}else{
printf("Long file name detected!\n");
}
printf(" [Size: %d bytes, Attributes: %x\n", entry->ATTR, entry->FileSize);
}
// Try and open grub.cfg file
VirtualFileSystem::OpenFile("a:boot/grub/grub.cfg");
// VirtualFileSystem::initialize();
// VirtualFileSystem::open("/hello.txt", 0);
#ifdef USERMODE_RELEASE
// Lets jump into user mode
jump_usermode();

View File

@ -1,21 +0,0 @@
#pragma once
#include <stdint.h>
#include "./ExtendBootRecord.h"
struct BiosParameterBlock {
uint8_t BootLoaderCodeSection [3];
uint8_t OEM_id [8];
uint16_t BytesPerSector ; // I suspect would be 512
uint8_t SectorsPerCluster ;
uint16_t ReservedSectors;
uint8_t NumberOfFileAllocationTables; // Probably equals 2
uint16_t NumberOfDirectoryEntries; // Root directory must contain entire sectors
uint16_t TotalSectorsInLogicalVolume ; // 0 means >65535 sectors in volume , actual count can be found in LargeSectorCount
uint8_t MediaDescriptor ; // Indication the media descriptor type
uint16_t NumberOfSectorsPerFAT;// only in FAT12 / FAT 16
uint16_t NumberOfSectorsPerTrack;
uint16_t NumberOfHeadsOnMedia;
uint32_t NumberOfHiddenSectors;
uint32_t LargeSectorCount;
ExtendedBootRecord_FAT16 ebpb;
}__attribute__((packed));

View File

@ -1,37 +0,0 @@
#pragma once
#include <stdint-gcc.h>
struct DirectoryEntry {
uint8_t filename [8];
uint8_t Extension [3];
uint8_t attribute;
uint8_t Reserved;
uint8_t creation; // Creation in tenths of a second
uint16_t CreationTime; // Time Created NOTE: Multiply the seconds by 2
uint16_t CreationDate; // Date Created
uint16_t LastAccessDate;
uint16_t ReservedFAT32;
uint16_t LastWriteTime;
uint16_t LastWriteDate;
uint16_t StartingCluster;
uint32_t FilesizeInBytes;
}__attribute__((packed));
typedef struct _DIRECTORY{
uint8_t Filename[8];
uint8_t Ext[3];
uint8_t Attrib;
uint8_t Reserved;
uint8_t TimeCreatedMs;
uint16_t TimeCreated;
uint16_t DateCreated;
uint16_t DateLastAccessed;
uint16_t FirstClusterHiBytes;
uint16_t LastModTime;
uint16_t LastModDate;
uint16_t FirstCluster;
uint32_t FileSize;
}__attribute__((packed)) DIRECTORY, *PDIRECTORY;

View File

@ -1,32 +0,0 @@
#pragma once
#include <stdint.h>
struct ExtendedBootRecord_FAT16{
uint8_t DriveNumber;
uint8_t Reserved;
uint8_t Signature;
const uint32_t VOLUME_ID_SERIAL_NUMBER;
uint8_t volume_label [11];
uint8_t Identifier_string [8];
uint8_t bootCode [448];
uint16_t partitionSignature;
}__attribute__((packed));
struct ExtendedBootRecord_FAT32{
uint32_t SectorsPerFAT;
uint16_t Flags;
const uint16_t FAT_VERSION_NUMBER;
uint32_t rootDirectory_clusterNumber;// Often set to 2;
uint16_t FSInfo_SectorNumber;
uint16_t backup_bpb_sectorNumber;
uint8_t Reserved [12];
uint8_t DriveNumber;
uint8_t Reserved2;
uint8_t Signature; // must be 0x28 or 0x29
uint32_t VOLUME_ID_SERIAL;
uint8_t volume_label[11];
uint8_t SystemIdentifierString [8]; // ALWAYS "FAT32 " but spec says do not trust
uint8_t BootCode [420]; // NICE
uint16_t PartitionSignature; // 0xAA55
}__attribute__((packed));

View File

@ -4,105 +4,198 @@
#include "FAT.h"
#include "../../ata pio/ATAPIO.h"
#include "../../../memory/KernelHeap.h"
#include "../../../../CoreLib/Memory.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
#include <CoreLib/Memory.h>
void FAT::Read(PFILE file, unsigned char* buffer , unsigned int length)
superblock* FAT::Mount(filesystem *fs, const char* name ,vfsmount *mnt)
{
}
FILE FAT::Open(char* filename)
{
char* tokstate = NULL;
char* nextdir = strtok(filename, "/", &tokstate);
while (nextdir)
if( strncmp (fs->name, "fat", 3 ) != 0 )
{
// Read the root directory
printf("First entry to look for: %s\n", nextdir);
nextdir = strtok(NULL, "/", &tokstate);
printf("Can't mount filesystem with none fat type!\n");
return nullptr;
}
FILE file;
file.flags = FS_INVALID;
return file;
superblock* sb = (superblock*) malloc(sizeof(superblock));
directoryEntry* root = (directoryEntry*) malloc(sizeof (directoryEntry));
root->name = (char*) name;
root->node = nullptr;
root->parent = nullptr;
dentry_operations* op = (dentry_operations*) malloc(sizeof(dentry_operations));
op->compare = FAT::compare;
root->op = op;
mnt->mnt_count =1;
mnt->mnt_devname = "QEMU HDD";
mnt->mnt_flags = 0;
mnt->mnt_parent = nullptr;
mnt->root = root;
mnt->sb = sb;
sb->type = fs;
sb->root = root;
//sb->fs_info = getBPB();
return sb;
}
void FAT::Write(PFILE file, unsigned char* buffer, unsigned int length)
int FAT::Read(file* file, void* buffer , int length)
{
return 0;
}
void ParseDateInteger(unsigned int date){
printf("Date (hex) 0x%x\n", date);
unsigned int year = (date >> 9 )+ 1980;
unsigned int month = (date & 0xf0 ) >> 4;
unsigned int day = date & 0xf ;
printf("Date: (D,M,Y) %d, %d ,%d\n", day , month, year );
int FAT::Write(file* file, const void* buffer, int length)
{
return 0;
}
int FAT::compare (directoryEntry*, char* filename, char* filename2)
{
// use the size of the smallest string
int a = strlen(filename);
int b = strlen(filename2);
if( a == b ){
return strncmp(filename, filename2, a);
}
return a-b;
}
int FAT::create(inode* dir_node, inode** target, const char* component_name){}
int FAT::lookup (inode*, inode**, const char*){}
BiosParameterBlock* getBPB(PTR_PARTITION partition, bool DEBUG =false ){
FAT_TYPE FAT::determineFATType(BiosParameterBlock* bpb){
int RootDirSector = ((bpb->RootEntCnt * 32) + (bpb->BytsPerSec -1)) / bpb->BytsPerSec;
int FATSz = 0;
if(bpb->FATSz16 != 0){
FATSz = bpb->FATSz16;
} else{
// FATSz = bpb->FATSz32;
}
int TotSec = 0;
if(bpb->TotSec16 != 0){
TotSec= bpb->TotSec16;
}else{
TotSec = bpb->TotSec32;
}
int DataSec = TotSec - (bpb->RsvdSecCnt + (bpb->NumFATs * FATSz) + RootDirSector);
int CountofClusters = DataSec / bpb->SecPerClus;
if(CountofClusters < 4085){
return FAT_TYPE::FAT12;
} else if (CountofClusters < 65525) {
return FAT_TYPE::FAT16;
} else{
return FAT_TYPE::FAT32;
}
};
BiosParameterBlock* FAT::getBPB( bool DEBUG ){
BiosParameterBlock* bpb = (BiosParameterBlock*) malloc(sizeof(BiosParameterBlock));
ATAPIO_PORT port = (ATAPIO_PORT)(partition->Disk & 0x01FF);
DEVICE_DRIVE drive = (DEVICE_DRIVE)(partition->Disk >> 16);
printf("ATAPIO_PORT: 0x%x DEVICE_DRIVE: 0x%x\n",port, drive);
printf("Partition Start Address (LBA): 0x%x\n", partition->StartAddress);
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, partition->StartAddress, (uint16_t*) bpb);
uint16_t StartAddress = 0x00 ;
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, StartAddress, (uint16_t*) bpb);
if(DEBUG)
{
printf("OEM ID: %s\n", bpb->OEM_id);
printf("Bytes per sector: %d\n", bpb->BytesPerSector);
printf("Sectors per cluster: %d\n", bpb->SectorsPerCluster);
printf("Reserved sectors: %d\n", bpb->ReservedSectors);
printf("Number of FAT: %d\n", bpb->NumberOfFileAllocationTables);
printf("Number of Dir entries: %d\n", bpb->NumberOfDirectoryEntries);
printf("Total Sectors in volume: %d\n", bpb->TotalSectorsInLogicalVolume);
printf("Sectors per FAT: %d\n", bpb->NumberOfSectorsPerFAT);
printf("OEM ID: %s\n", bpb->OEMName);
printf("Bytes per sector: %d\n", bpb->BytsPerSec);
printf("Sectors per cluster: %d\n", bpb->SecPerClus);
printf("Reserved sectors: %d\n", bpb->RsvdSecCnt);
printf("Number of FAT: %d\n", bpb->NumFATs);
printf("Number of Dir entries: %d\n", bpb->RootEntCnt);
printf("Total Sectors in volume: %d\n", bpb->TotSec16 == 0 ? bpb->TotSec32 : bpb->TotSec16);
printf("Sectors per FAT: %d\n", bpb->FATSz16 );
}
return bpb;
}
bool FAT::Validate(PTR_PARTITION partition )
{
auto* bootParams = getBPB(partition, true);
if(bootParams->OEM_id) {
return true;
uint16_t FAT::GetFATEntry (BiosParameterBlock* bpb, unsigned int cluster){
int FATSz =0;
if(bpb->FATSz16 != 0){
FATSz = bpb->FATSz16;
} else{
//FATSz = bpb->FATSz32;
}
return false;
int FATOffset = 0;
FAT_TYPE type = FAT::determineFATType(bpb);
if( type == FAT_TYPE::FAT16){
FATOffset = cluster *2;
} else if( type == FAT_TYPE::FAT32){
FATOffset = cluster * 4;
}
int thisFATSecNum = bpb->RsvdSecCnt + (FATOffset / bpb->BytsPerSec); // Sector number containing the entry for the cluster
// For any other FAT other then the default
// SectorNumber = (FATNumber * FATSz) + ThisFATSecNum
uint16_t buff[bpb->BytsPerSec];
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, thisFATSecNum, buff );
int thisFATEntOffset = FATOffset % bpb->BytsPerSec; // offset for the entry in the sector containing the entry for the cluster
uint16_t ClusterEntryValue = 0;
// Get the FATEntry
if(type == FAT_TYPE::FAT16){
return *((uint16_t*) &buff[thisFATEntOffset]);
}
else{
// FAT32 logic
return 0;
}
}
void FAT::Info(_PARTITION *pPartition, PFS pSystem) {
pSystem->Read = FAT::Read;
pSystem->Write = FAT::Write;
pSystem->Open = FAT::Open;
uint16_t FAT::DetermineFreeSpace()
{
// Loop through all FAT entries in all FAT's
// to construct a list of free/available clusters
// Free clusters are recorded with all 0's except on FAT32 where
// the highest order 4 bits should be ignored.
/*
* The number of sectors reserved for each FAT (count of sectors in the BPB_FATSz16 or
BPB_FATSz32 fields) may be bigger than the actual number of sectors required for
containing the entire FAT. Therefore, there may be totally unused FAT sectors at the end of
each FAT in the FAT region of the volume. Each implementation must determine the value
for the last valid sector in the FAT using CountOfClusters (the last valid sector in the FAT
is the one containing the FAT entry numbered CountOfClusters + 1).
All sectors reserved for the FAT beyond the last valid sector (defined as the one containing
the FAT entry for the last cluster) must be set to 0x0 during volume initialization/format.
*/
}
uint16_t* ReadFAT (BiosParameterBlock& bpb , PTR_PARTITION partition, bool DEBUG = false ) {
uint32_t FATAddress = partition->StartAddress + bpb.ReservedSectors ;
int FAT::GetSectorOfRootDirectory (BiosParameterBlock* bpb)
{
return (bpb->RsvdSecCnt + (bpb->NumFATs * bpb->FATSz16));
}
int FAT::RootDirSize(BiosParameterBlock* bpb)
{
int size = bpb->RootEntCnt * 32;
if((size % bpb->BytsPerSec) != 0){
printf("ERR: Root entry count invalid!\n");
return -1;
}
return size;
}
uint16_t* ReadFAT (BiosParameterBlock& bpb , bool DEBUG = false ) {
uint32_t FATAddress = /*StartAddress*/ 0x00 + bpb.RsvdSecCnt ;
uint16_t* FAT = (uint16_t*)malloc(sizeof (uint16_t) * 256);
ATAPIO_PORT port = (ATAPIO_PORT)(partition->Disk & 0x01FF);
DEVICE_DRIVE drive = (DEVICE_DRIVE)(partition->Disk >> 16);
ATAPIO::Read(port, drive, FATAddress, FAT );
ATAPIO::Read(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER, FATAddress, FAT );
// Show data in terminal
if(DEBUG){
@ -115,14 +208,15 @@ uint16_t* ReadFAT (BiosParameterBlock& bpb , PTR_PARTITION partition, bool DEBUG
return FAT;
}
void readFile(uint32_t DataRegion, DirectoryEntry* entry, uint16_t FATentry, BiosParameterBlock& bpb ){
void readFile(uint32_t DataRegion, DIR* entry, uint16_t FATentry, BiosParameterBlock& bpb ){
printf("Show contents");
printf("Start cluster of the file: 0x%x\n", entry->StartingCluster);
printf("Start cluster of the file: 0x%x\n", entry->FileSize);
printf("IS it only 1 cluster? %s\n", FATentry == 0xFFFF ? "Yes" : "No");
uint32_t sector = DataRegion + ((entry->StartingCluster - 0x02) * bpb.SectorsPerCluster);
uint32_t sector = DataRegion + ((entry->FileSize - 0x02) * bpb.SecPerClus);
uint16_t dataBlob[256];
@ -134,66 +228,21 @@ void readFile(uint32_t DataRegion, DirectoryEntry* entry, uint16_t FATentry, Bio
}
kterm_put('\n');
}
/*
void listFilesInRoot(MBR& mbr, BiosParameterBlock& bpb ){
auto FATAddress = mbr.TableEntries[0].LBA_partition_start + bpb.ReservedSectors;
uint32_t RootDirectoryRegion = FATAddress + ( bpb.NumberOfFileAllocationTables * bpb.NumberOfSectorsPerFAT );
uint32_t DataRegion = RootDirectoryRegion + ((bpb.NumberOfDirectoryEntries * 32) / bpb.BytesPerSector );
uint16_t* FAT = ReadFAT(bpb, mbr);
uint16_t data2 [256];
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, RootDirectoryRegion, data2 );
auto* RootDirectory = (DirectoryEntry*) data2;
// List files in root
for(int i= 0; i < sizeof (data2) / sizeof (DirectoryEntry); i++ ) {
auto *entry = (DirectoryEntry * )((uint32_t) RootDirectory + (i * sizeof(DirectoryEntry)));
if (entry->filename[0] == (uint8_t) 0x00)
continue; // There are no more entries in this directory or the entry is free
if (entry->attribute & ATTRIBUTES::ATT_HIDDEN)
continue;
if(entry->attribute & ATTRIBUTES::ATTR_SYSTEM)
continue;
if(entry->attribute & ATTRIBUTES::ATTR_VOLUME_ID)
continue;
// Print the filename;
for (char n: entry->filename) {
if (n == 0x20)
break;
kterm_put(n);
}
for (unsigned char n: entry->Extension) {
kterm_put(n);
}
kterm_put('\n');
printf("Attribute: %x \n", entry->attribute);
printf("FileSize: %d Bytes\n", entry->FilesizeInBytes);
if (entry->FilesizeInBytes != 0x0 && (entry->attribute != 0x10)) {
readFile(DataRegion,entry, FAT[i], bpb);
}
}
free(FAT);
}
FILE fsysFatDirectory (const char* DirectoryName){
FILE file;
file fsysFatDirectory (const char* DirectoryName){
file file;
unsigned char* buf;
PDIRECTORY directory;
char DosFileName[11];
ToDosFileName(DirectoryName, DosFileName, 11);
//ToDosFileName(DirectoryName, DosFileName, 11);
DosFileName[11] =0;
for (int sector=0; sector <14 ; sector++){
ATA_DEVICE::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mountInfo.rootOffset + sector, (uint16_t*)buf);
ATAPIO::Read(BUS_PORT::Primary, DEVICE_DRIVE::MASTER, mountInfo.rootOffset + sector, (uint16_t*)buf);
directory = (PDIRECTORY) buf;
for (int i =0; i < 16; i++){
@ -209,9 +258,9 @@ FILE fsysFatDirectory (const char* DirectoryName){
file.filelength = directory->FileSize;
if(directory->Attrib == 0x10){
file.flags = FS_DIRECTORY;
file.flags = 2;
} else {
file.flags = FS_FILE;
file.flags = 1;
}
return file;
}
@ -220,7 +269,7 @@ FILE fsysFatDirectory (const char* DirectoryName){
}
// Can't find file
file.flags = FS_INVALID;
file.flags = -1;
return file;
}
@ -300,9 +349,9 @@ FILE fsysFatOpenSubDir(FILE kFile, const char* filename){
// set file type;
if(pkDir->Attrib == 0x10){
file.flags = FS_DIRECTORY;
file.flags = 2;
} else{
file.flags = FS_FILE;
file.flags = 1;
}
return file;
@ -312,7 +361,7 @@ FILE fsysFatOpenSubDir(FILE kFile, const char* filename){
}
}
// unable to find file
file.flags = FS_INVALID;
file.flags = -1;
return file;
}
*/
*/

View File

@ -2,48 +2,152 @@
// Created by nigel on 21/02/23.
//
#pragma once
#include "ExtendBootRecord.h"
#include "BiosParameterBlock.h"
#include "DirectoryEntry.h"
#include "../../vfs/StorageTypes.h"
#include "../../vfs/vfs_types.h"
#include "../../vfs/vfs_types.h"
#include "../../partitiontables/mbr/MasterBootRecord.h"
// Date Format
// [0..4] Day
// [5..8] Month
// [9..15] Year
struct ExtendedBootRecord_FAT16{
uint8_t DrvNum;
uint8_t Reserved1;
uint8_t BootSig;
const uint32_t VolID;
uint8_t VolLab [11];
uint8_t FilSysType [8];
uint8_t bootCode [448];
uint16_t Signature_word;
uint8_t SecRmndr[512];
}__attribute__((packed));
// Time Format
// [0..4] Seconds
// [5..10] Minute
// [11..15] Hour
struct ExtendedBootRecord_FAT32{
uint32_t SectorsPerFAT;
uint16_t Flags;
const uint16_t FAT_VERSION_NUMBER;
uint32_t rootDirectory_clusterNumber;// Often set to 2;
uint16_t FSInfo_SectorNumber;
uint16_t backup_bpb_sectorNumber;
uint8_t Reserved [12];
uint8_t DriveNumber;
uint8_t Reserved2;
uint8_t Signature; // must be 0x28 or 0x29
uint32_t VOLUME_ID_SERIAL;
uint8_t volume_label[11];
uint8_t SystemIdentifierString [8]; // ALWAYS "FAT32 " but spec says do not trust
uint8_t BootCode [420]; // NICE
uint16_t PartitionSignature; // 0xAA55
}__attribute__((packed));
struct BiosParameterBlock {
uint8_t jmpBoot[3];
uint8_t OEMName [8];
uint16_t BytsPerSec ; // I suspect would be 512
uint8_t SecPerClus ;
uint16_t RsvdSecCnt;
uint8_t NumFATs; // Probably equals 2
uint16_t RootEntCnt; // Root directory must contain entire sectors
uint16_t TotSec16 ; // 0 means >65535 sectors in volume , actual count can be found in LargeSectorCount
uint8_t Media ; // Indication the media descriptor type
uint16_t FATSz16;// only in FAT12 / FAT 16
uint16_t SecPerTrk;
uint16_t NumHeads;
uint32_t HiddSec;
uint32_t TotSec32;
ExtendedBootRecord_FAT16 ebpb;
}__attribute__((packed));
struct DIR {
uint8_t Name [11];
uint8_t ATTR ;
uint8_t NTRes;
uint8_t CrtTimeTenth; // File Creation time component - count of tenths of a second (between 0 and 199)
uint16_t CrtTime; // Creation time. Granularity is 2 seconds
uint16_t CrtDate; // Creation date.
uint16_t LstAccDate; // Last Access Date (Last read or write date)
uint16_t FstClusHi; // High Word of first data cluster for file/directory described
uint16_t WrtTime; // Last Modification time | Must equal CrtTime
uint16_t WrtDate; // Last Modification date | Must equal CrtDate
uint16_t FstClusLO; // Low word of first data cluster for file/directory described
uint32_t FileSize; // size in bytes of file/directory described
}__attribute__((packed));
typedef struct _DIRECTORY{
uint8_t Filename[8];
uint8_t Ext[3];
uint8_t Attrib;
uint8_t Reserved;
uint8_t TimeCreatedMs;
uint16_t TimeCreated;
uint16_t DateCreated;
uint16_t DateLastAccessed;
uint16_t FirstClusterHiBytes;
uint16_t LastModTime;
uint16_t LastModDate;
uint16_t FirstCluster;
uint32_t FileSize;
}__attribute__((packed)) DIRECTORY, *PDIRECTORY;
enum struct FAT_TYPE{
FAT12,
FAT16,
FAT32,
VFAT,
UNKOWN
};
class FAT {
public:
// Wanted API for vfs
static file Open(char* filename);
static int close(file* file);
static int Read(file* file, void* buffer , int length);
static int Write(file* file, const void* buffer, int length);
static int create(inode* dir_node, inode** target, const char* component_name);
static int lookup(inode* , inode**, const char*);
static int compare(directoryEntry* , char* , char*);
static superblock* Mount(filesystem* fs, const char* name ,vfsmount* mount);
static bool Validate(PTR_PARTITION partition );
// TEMP
static void listFilesInRoot(MBR* mbr, BiosParameterBlock* bpb );
static BiosParameterBlock* getBPB( bool DEBUG =false );
static FAT_TYPE determineFATType(BiosParameterBlock* bpb);
static uint16_t GetFATEntry(BiosParameterBlock*, unsigned int);
static uint16_t DetermineFreeSpace();
static int GetSectorOfRootDirectory(BiosParameterBlock*);
static int RootDirSize(BiosParameterBlock*);
static FILE Open(char* filename);
static void Read(PFILE file, unsigned char* buffer , unsigned int length);
static void Write(PFILE file, unsigned char* buffer, unsigned int length);
static const int FREE = 0x0000;
static const int ALLOCATED = 0x0002;
static const int BAD = 0xFFF7;
static const int EOF = 0xFFFF;
static void Info(_PARTITION *pPartition, PFS pSystem);
static const int ClnShutBitMask = 0x8000;
static const int HrdErrBitMask = 0x4000;
static const char DOS_TRAILING_SPACE = 0x20;
static const char FREE_DIR = 0xE5; // If KANJI charset 0x05
static const char FREE_DIR_2 = 0x00; // All directories after this are free including this one
private:
enum struct TYPE{
FAT,
FAT16,
FAT32,
VFAT
};
enum ATTRIBUTES {
ATTR_READ_ONLY = 0x01,
ATT_HIDDEN = 0x02,
ATTR_HIDDEN = 0x02,
ATTR_SYSTEM = 0x04,
ATTR_VOLUME_ID = 0x08,
ATTR_DIRECTORY = 0x10,
ATTR_ARCHIVE = 0x20
ATTR_ARCHIVE = 0x20,
ATTR_LONG_NAME = (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
};
private:
enum ENTRY_SIZE {
FAT12 = 12,
FAT16 = 16,
FAT32 = 32
};
};

View File

@ -0,0 +1,40 @@
//
// Created by nigel on 23/02/23.
//
#pragma once
#include "../../../terminal/kterm.h"
// Date Format
// [0..4] Day
// [5..8] Month
// [9..15] Year
class MSDOSDATE {
static void ParseDate(unsigned int date){
printf("Date (hex) 0x%x\n", date);
unsigned int year = (date >> 9 )+ 1980;
unsigned int month = (date & 0xf0 ) >> 4;
unsigned int day = date & 0xf ;
printf("Date: (D,M,Y) %d, %d ,%d\n", day , month, year );
}
};
// Time Format
// [0..4] Seconds
// [5..10] Minute
// [11..15] Hour
class MSDOSTIME {
static void ParseTime(unsigned int time)
{
printf("Time (hex) 0x%x\n", time);
unsigned int seconds = ( time & 0x0f) * 2;
unsigned int minutes = (time & 0xf0);
unsigned int hours = (time & 0xf00);
printf("Time (H:M:S) %d:%d:%d\n", hours, minutes, seconds);
}
};

View File

@ -0,0 +1,18 @@
//
// Created by nigel on 23/02/23.
//
#include "partitionManager.h"
bool partitionManager::Validate( )
{
//auto* bootParams = getBPB(this, true);
//if(bootParams->OEM_id) {
// return true;
//}
return true;
}

View File

@ -0,0 +1,11 @@
//
// Created by nigel on 23/02/23.
//
#pragma once
class partitionManager {
public:
static bool Validate();
};

View File

@ -1,41 +0,0 @@
//
// Created by nigel on 21/02/23.
//
#include "FileSystem.h"
void FileSystem::WriteFile(int file, unsigned char* buffer, unsigned int length) {
}
void FileSystem::ReadFile(int file, unsigned char* buffer, unsigned int length) {
}
FILE FileSystem::OpenFile(const char* fname){
if(fname){
unsigned char device = 'a';
char* filename = (char*) fname;
if(fname[1]== ':'){
device = fname[0];
filename += 2; // strip the volume component from the path
}
if(_filesystems[device - 'a']){
FILE file = _filesystems[device-'a']->Open(filename);
file.device = device;
return file;
}
}
FILE file;
file.flags = FS_INVALID;
return file;
}
void FileSystem::CloseFile(PFILE file) {
if(file->device < DEVICE_MAX){
// _filesystems[file->device]->Close(file);
}
}

View File

@ -1,18 +0,0 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
#include "StorageTypes.h"
class FileSystem {
public:
static void WriteFile(PFILE file, unsigned char* beffer, unsigned int length);
static void ReadFile(PFILE file, unsigned char* buffer, unsigned int length);
static FILE OpenFile(const char* fname);
static void CloseFile(PFILE file);
};

View File

@ -1,5 +0,0 @@
//
// Created by nigel on 21/02/23.
//
#include "Inode.h"

View File

@ -1,24 +0,0 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
enum struct NODE_TYPE {
FILESYSTEM,
FILE,
DIRECTORY
};
enum struct PERMISSIONS {
READ,
WRITE,
EXECUTE
};
struct Inode {
NODE_TYPE type;
PERMISSIONS permissions;
Inode* Parent;
Inode* sibling;
};

View File

@ -1,40 +0,0 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
#include <stdint-gcc.h>
enum FS_TYPES {
FS_FILE =0,
FS_DIRECTORY =1,
FS_INVALID=2
};
typedef struct _FILE {
char name [32];
uint32_t flags;
uint32_t filelength;
uint32_t id;
uint32_t eof;
uint32_t position;
uint32_t currentCluster;
uint32_t device;
}FILE, *PFILE;
typedef struct _FILE_SYSTEM{
char name[8];
FILE (*Directory) (const char* Directoryname);
void (*Mount) ();
void (*Read) (PFILE file, unsigned char* buffer, unsigned int length);
void (*Write)(PFILE file, unsigned char* buffer, unsigned int length);
void (*Close) (PFILE);
FILE (*Open) (char* filename);
}FILESYSTEM, *PFS;
typedef struct _PARTITION {
uint32_t Disk;
uint32_t StartAddress;
uint32_t Sectors;
uint8_t Fs_hint;
uint8_t Attributes;
}PARTITION, *PTR_PARTITION;

View File

@ -4,127 +4,183 @@
#include "../ata pio/ATAPIO.h"
#include "../partitiontables/mbr/MasterBootRecord.h"
#include "../filesystems/FAT/FAT.h"
#include "StorageTypes.h"
#include "vfs_types.h"
#include "../../../CoreLib/Memory.h"
#include <CoreLib/Memory.h>
PFS VirtualFileSystem::_filesystems[VirtualFileSystem::DEVICE_MAX];
PTR_PARTITION VirtualFileSystem::_partitions [VirtualFileSystem::PARTITION_MAX];
unsigned int VirtualFileSystem::num_partitions = 0;
vfsmount* VirtualFileSystem::rootfs;
int VirtualFileSystem::mount_number = 0;
int VirtualFileSystem::superblock_number =0;
int VirtualFileSystem::filesystem_number =0;
filesystem* VirtualFileSystem::filesystems[4];
superblock* VirtualFileSystem::superblocks[8];
vfsmount* VirtualFileSystem::mounts[12];
void VirtualFileSystem::Mount(filesystem* fs, const char* name)
{
vfsmount* mnt_point = (vfsmount*) malloc(sizeof(vfsmount));
superblock* sb = fs->mount(fs, name, mnt_point);
mounts[mount_number++] = mnt_point;
superblocks[superblock_number++] = sb;
rootfs = mnt_point;
}
void VirtualFileSystem::initialize()
{
// TODO: setup memory pools etc to speed things up
// a bit
// TODO: Add a devfs, procfs etc...
// Mount the boot disk
// NOTE: we assume for now that it is the only disk in the system
// This information could possibly be had from the bootloader (GRUB)
// We als assume it is the primary device on the Master port.
ATAPIO::Soft_Reset(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
bool isAvailable = ATAPIO::Identify(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
if(!isAvailable){
// PANIC!!!
printf("Failed to mount root filesystem!\n");
return;
}
auto masterbootrecord = GetPartitions(false);
for (auto partition : masterbootrecord->TableEntries)
{
if(partition.PartitionType == 0x0) continue; // Consider marked as free
PTR_PARTITION found_partition = (PARTITION*) malloc(sizeof(PARTITION));
found_partition->Disk = ATAPIO_PORT::Primary | ( DEVICE_DRIVE::MASTER << 16);
printf("Disk Identifier: 0x%x\n", found_partition->Disk);
found_partition->Attributes = partition.driveAttribute;
found_partition->StartAddress = partition.LBA_partition_start;
found_partition->Sectors = partition.Number_sectors_inPartition;
found_partition->Fs_hint = partition.PartitionType;
VirtualFileSystem::RegisterPartition(found_partition);
}
printf("Found %d partitions on disk!\n", num_partitions);
for (int i = 0; i < num_partitions; i++)
{
auto* partition = _partitions[i];
// Check the fs_hint for a proper driver
if ( partition->Fs_hint != 0x06){
printf("Assumed Unkown filesystem!\n");
continue;
}
// Check if filesystem OK
printf("Partition Start Address (LBA): 0x%x\n", partition->StartAddress);
bool valid = FAT::Validate(partition);
if(!valid)
{
printf("Not a valid FAT fs!\n");
continue;
}
// setup FileSystem Description before mounting
PFS FS_FAT = (PFS)malloc(sizeof(FILESYSTEM));
FAT::Info(partition, FS_FAT);
// Mount the partition/filesystem
Mount(FS_FAT , i);
}
filesystem* fat_fs = (filesystem*) malloc(sizeof (filesystem));
fat_fs->name = "fat";
fat_fs->mount = FAT::Mount;
//register_filesystem(fat_fs);
// Mount the bootdrive
// NOTE: for now will hardcode this
Mount(fat_fs, "/");
};
void VirtualFileSystem::RegisterPartition(PTR_PARTITION partition) {
_partitions[num_partitions] = partition;
num_partitions++;
int VirtualFileSystem::register_filesystem(struct filesystem* fs) {
// register the filesystem to the kernel.
filesystems[filesystem_number] = fs;
filesystem_number++;
}
FILE VirtualFileSystem::OpenFile(const char* path)
{
struct file* VirtualFileSystem::open(const char* pathname, int flags){
// 1. Lookup pathname from the root node
// 2. Create a new file descriptor for this v_node if found.
// 3. Create a new file if O_CREATE is specified in the flags.
// See reference material (1) https://man7.org/linux/man-pages/man7/path_resolution.7.html
unsigned char device = 'a';
char* filename = (char*)path;
char* cpy = filename;
if(filename[1] == ':'){
device = filename[0];
filename += 2;
// FILE file = ->Open(filename);
if(pathname[0] != '/'){
printf("We won't handle relative paths yet!");
file file;
file.flags = 1;
return &file;
}
if ( _filesystems[device - 'a']){
// Unfortunately this way the FAT Driver doesn't know which device and which partition to read from
// leaving us hopeless of finding the file.
FILE file = _filesystems[device-'a']->Open(filename);
file.device = device;
free(cpy);
return file;
auto* dentry = rootfs->root;
int result = dentry->op->compare(dentry, "/", dentry->name);
if(result != 0 ){
printf("rootfs not called / \n");
file file;
file.flags = 1;
return &file;
}
free(cpy);
FILE file;
file.flags = FS_INVALID;
return file;
char* tokstate = nullptr;
auto nextdir = strtok ((char*)pathname, "/", &tokstate );
while (nextdir)
{
printf("Look for dentry: %s\n", nextdir);
// look to its children
if (dentry->children ) {
printf("No children | children unknown!\n");
break;
}
if (dentry->op->compare(dentry, nextdir, dentry->name))
{
// file found
nextdir = strtok(nullptr, "/", &tokstate);
}
}
file file;
file.flags = 1;
return &file;
}
void VirtualFileSystem::Mount(PFS filesystemDescriptor, unsigned int DeviceID)
{
if(DeviceID < DEVICE_MAX)
if(filesystemDescriptor)
_filesystems[DeviceID] = filesystemDescriptor;
int VirtualFileSystem::close (struct file* file){
// 1. release the file descriptor
}
int VirtualFileSystem::write(struct file* file, const void* buf, size_t len){
// 1. Write len bytes from buf to the opened file.
// 2. return written size or error code if an error occurs
}
int VirtualFileSystem::read (struct file* file, void* buf, size_t len){
// 1. read min(len, readable file data size) bytes ro buf from the opened file.
// 2. return read size or error code if an error occurs
}
void VirtualFileSystem::Unmount(unsigned int DeviceID) {
if(DeviceID < DEVICE_MAX)
_filesystems[DeviceID] = nullptr;
/*
void fs_discovery(){
// Mount the boot disk
// NOTE: we assume for now that it is the only disk in the system
// This information could possibly be had from the bootloader (GRUB)
// We als assume it is the primary device on the Master port.
ATAPIO::Soft_Reset(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
bool isAvailable = ATAPIO::Identify(ATAPIO_PORT::Primary, DEVICE_DRIVE::MASTER);
if(!isAvailable){
// PANIC!!!
printf("Failed to mount root filesystem!\n");
return;
}
auto masterbootrecord = GetPartitions(false);
for (auto partition : masterbootrecord->TableEntries)
{
if(partition.PartitionType == 0x0) continue; // Consider marked as free
PTR_PARTITION found_partition = (PARTITION*) malloc(sizeof(PARTITION));
found_partition->Disk = ATAPIO_PORT::Primary | ( DEVICE_DRIVE::MASTER << 16);
printf("Disk Identifier: 0x%x\n", found_partition->Disk);
found_partition->Attributes = partition.driveAttribute;
found_partition->StartAddress = partition.LBA_partition_start;
found_partition->Sectors = partition.Number_sectors_inPartition;
found_partition->Fs_hint = partition.PartitionType;
}
printf("Found %d partitions on disk!\n", num_partitions);
for (int i = 0; i < num_partitions; i++)
{
auto* partition = _partitions[i];
// Check the fs_hint for a proper driver
if ( partition->Fs_hint != 0x06){
printf("Assumed Unkown filesystem!\n");
continue;
}
// Check if filesystem OK
printf("Partition Start Address (LBA): 0x%x\n", partition->StartAddress);
bool valid = FAT::Validate(partition);
if(!valid)
{
printf("Not a valid FAT fs!\n");
continue;
}
// setup FileSystem Description before mounting
PFS FS_FAT = (PFS)malloc(sizeof(FILESYSTEM));
FAT::Info(partition, FS_FAT);
// Mount the partition/filesystem
}
}
*/

View File

@ -1,20 +1,32 @@
#pragma once
#include <stdint-gcc.h>
#include "../../../CoreLib/Path.h"
#include "StorageTypes.h"
#include "vfs_types.h"
#include "vfs_types.h"
class VirtualFileSystem
{
public:
static void initialize();
static void Mount(PFS fs, unsigned int DeviceID);
static void Unmount(unsigned int DeviceID);
static FILE OpenFile(const char* path);
static void RegisterPartition(PTR_PARTITION partition);
static void Mount(filesystem* fs, const char* name);
static int register_filesystem(struct filesystem* fs);
static struct file* open(const char* pathname, int flags);
static int close(struct file* file);
static int write(struct file* file, const void* buf, size_t len);
static int read(struct file* file, void* buf, size_t len);
private:
static const unsigned int DEVICE_MAX = 26;
static const unsigned int PARTITION_MAX = 4 * DEVICE_MAX;
static PFS _filesystems[DEVICE_MAX];
static unsigned int num_partitions;
static PTR_PARTITION _partitions [PARTITION_MAX];
};
static vfsmount* rootfs;
static int mount_number;
static int superblock_number;
static int filesystem_number;
static filesystem* filesystems[];
static superblock* superblocks[];
static vfsmount* mounts[];
};

View File

@ -0,0 +1,116 @@
//
// Created by nigel on 21/02/23.
//
#pragma once
// grasslab.github.io/osdi/en/labs/lab7.html
#include <stddef.h>
#include <stdint.h>
struct inode_operations;
struct vfsmount;
struct superblock;
struct inode;
struct dentry_operations;
struct directoryEntry;
struct filesystem;
struct superblock;
struct file;
struct file_operations{
int(*write) (file* file, const void* buf, size_t len);
int(*read) (file* file, void* buf, size_t len);
};
struct inode_operations {
int (*create)(inode*, directoryEntry*, const char* );
directoryEntry* (*lookup)(inode* , directoryEntry*);
int (*link)(directoryEntry*, inode* , directoryEntry*);
int (*unlink)(inode*, directoryEntry*);
int (*symlink)(inode*, directoryEntry*);
int (*mkdir)(inode*, directoryEntry*, const char*);
int (*rmdir)(inode*, directoryEntry*);
int (*rename)(inode*, directoryEntry*, inode*, directoryEntry*);
void (*truncate)(inode*);
int (*permission)(inode*, int);
int (*setattr)(directoryEntry, unsigned long*);
int (*getattr)(vfsmount* mnt, directoryEntry*, unsigned long*);
};
// Describes a mount
struct vfsmount {
vfsmount* mnt_parent; // fs we are mounted on
directoryEntry* mountpoint; // dentry of mount point
directoryEntry* root; // root of the mounted tree
superblock* sb; // pointer to the superblock
unsigned int mnt_count; // keep track of users of this structure
int mnt_flags;
char* mnt_devname; // name of device eg /dev/dsk/hda1
};
struct superblock;
// Represents a filesystem object (i.e. a file or directory or device)
struct inode {
unsigned long mode; // access permissions
unsigned long uid; // user id owner
unsigned long gid; // group id owner
unsigned int flags;
inode_operations* i_op; // operations possible on inode
superblock* sb;
unsigned long ino; // unique number of this inode
unsigned int links; // number of hard links
void* device;
unsigned long size; // size of inode contents in bytes
unsigned long atime; // Access time
unsigned long mtime; // Modify time
unsigned long ctime; // Creation time
unsigned short bytes; // bytes consumed
file_operations* fop;
void* internal; // point to underlying representation of this virtual node (e.g. FAT entry or Directory Entry)
};
// Represents the possible operations on a directory entry
struct dentry_operations
{
int (*compare)(directoryEntry*, char*, char* );
int (*o_delete)(directoryEntry*);
void (*release)(directoryEntry*);
void (*iput)(directoryEntry*, inode* );
};
// Represents the name of files in the filesystem
// it identifies the file that an inode represents
struct directoryEntry {
char* name; // name of the file on the disk
directoryEntry* parent; // parent of the file
inode* node; // node belongs to...
dentry_operations* op;
directoryEntry* children[];
};
// Represents a filesystem type
struct filesystem {
const char* name;
superblock* (*mount)(filesystem* self, const char* name, vfsmount* mnt);
};
// Represents a mounted filesystem
struct superblock {
void* device; // device associated with the filesystem
unsigned long blocksize;
unsigned long maxbytes;
filesystem* type;
unsigned long magic; // IDK
directoryEntry* root; // Root dentry
int count; // IDK
void* fs_info; // pointer to raw filesystem info
dentry_operations* d_op;
inode* inodes[];
};
// Represents an opened file
struct file {
inode* root;
size_t f_pos; // The next read/write position of this file descriptor;
file_operations* f_ops;
int flags;
};

View File

@ -1,8 +1,7 @@
#include "superVisorTerminal.h"
#include "../storage/ata pio/ATAPIO.h"
#include "../storage/partitiontables/mbr/MasterBootRecord.h"
#include "../storage/filesystems/FAT/BiosParameterBlock.h"
#include "../storage/filesystems/FAT/DirectoryEntry.h"
#include "../storage/filesystems/FAT/FAT.h"
bool isRunning = true;
extern "C" void startSuperVisorTerminal()

21
run.sh
View File

@ -1,12 +1,25 @@
#!/bin/bash
PROC=$$
# Build the Corelib static library
(cd CoreLib
if ! make; then
echo "Build failed!"
kill -10 $PROC
fi)
cd CoreLib
make
cd ../kernel
# Build the kernel image
(cd kernel
make clean
make
cd ..
if ! make; then
echo "Build failed!"
kill -10 $PROC
fi)
./scripts/update_harddrive.sh
./scripts/run_qemu.sh