Moved to a new Filesystem, ATA and FAT16 driver.
This commit is contained in:
parent
ed34174d68
commit
a0d0454e32
73
Makefile
73
Makefile
@ -1,67 +1,60 @@
|
|||||||
CFLAGS = -g -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast
|
CFLAGS = -g -std=gnu11 -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast -Isrc/
|
||||||
CXXFLAGS = -g -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -I.
|
CXXFLAGS = -g -m32 -fno-use-cxa-atexit -mgeneral-regs-only -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -fpermissive -fno-pie -fno-stack-protector -Isrc/
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
|
|
||||||
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt \
|
DISK_IMG_FILES = build/kernel/kernel.bin hello.txt alpha.txt
|
||||||
build/hello/hello.bin
|
|
||||||
|
|
||||||
KERNEL_CPP_SRCS = $(wildcard src/kernel/*.cpp) $(wildcard src/kernel/*/*.cpp)
|
KERNEL_CPP_SRCS = $(shell find src/kernel/ -name '*.cpp')
|
||||||
KERNEL_ASM_SRCS = $(wildcard src/kernel/*.asm)
|
KERNEL_ASM_SRCS = $(shell find src/kernel/ -name '*.asm')
|
||||||
KERNEL_CPP_OBJS = $(patsubst src/%.cpp,build/%.o,$(KERNEL_CPP_SRCS))
|
KERNEL_CPP_OBJS = $(patsubst src/%.cpp,build/%.o,$(KERNEL_CPP_SRCS))
|
||||||
KERNEL_ASM_OBJS = $(patsubst src/%.asm,build/%.o,$(KERNEL_ASM_SRCS))
|
KERNEL_ASM_OBJS = $(patsubst src/%.asm,build/%.o,$(KERNEL_ASM_SRCS))
|
||||||
|
|
||||||
KERNEL_OBJS = build/kernel/isr.o $(KERNEL_CPP_OBJS) $(KERNEL_ASM_OBJS)
|
KERNEL_OBJS = build/kernel/isr.o $(KERNEL_CPP_OBJS) $(KERNEL_ASM_OBJS)
|
||||||
|
|
||||||
STAGE2_C_SRCS = $(wildcard src/boot_stage2/*.c)
|
STAGE2_C_SRCS = $(wildcard src/bootstage2/*.c)
|
||||||
STAGE2_C_OBJS = $(patsubst src/%.c,build/%.o,$(STAGE2_C_SRCS))
|
STAGE2_C_OBJS = $(patsubst src/%.c,build/%.o,$(STAGE2_C_SRCS))
|
||||||
|
|
||||||
STAGE2_OBJS = build/c_code_entry.o $(STAGE2_C_OBJS)
|
STAGE2_OBJS = build/c_code_entry.o $(STAGE2_C_OBJS)
|
||||||
|
|
||||||
PROGRAM_COMMON = build/program_code_entry.o build/common/common.o
|
PROGRAM_COMMON = build/programs/entry.o build/common/common.o
|
||||||
|
|
||||||
PROGRAM_C_SRCS = $(wildcard src/program/*.c)
|
SRC_DIRS = $(shell find src/ -type d)
|
||||||
PROGRAM_C_OBJS = $(patsubst src/%.c,build/%.o,$(PROGRAM_C_SRCS))
|
BUILD_DIRS = $(subst src/,build/,$(SRC_DIRS))
|
||||||
PROGRAM_OBJS = $(PROGRAM_COMMON) $(PROGRAM_C_OBJS)
|
|
||||||
|
|
||||||
HELLO_C_SRCS = $(wildcard src/hello/*.c)
|
PROGRAMS = $(shell find src/programs/* -type d)
|
||||||
HELLO_C_OBJS = $(patsubst src/%.c,build/%.o,$(HELLO_C_SRCS))
|
$(foreach program,$(PROGRAMS),\
|
||||||
HELLO_OBJS = $(PROGRAM_COMMON) $(HELLO_C_OBJS)
|
$(eval $(program)_C_SRCS := $(shell find $(program) -name '*.c')) \
|
||||||
|
$(eval $(program)_CPP_SRCS := $(shell find $(program) -name '*.cpp')) \
|
||||||
|
$(eval $(program)_OBJS := $(patsubst src/%.c,build/%.o,$($(program)_C_SRCS)) \
|
||||||
|
$(patsubst src/%.cpp,build/%.o,$($(program)_CPP_SRCS))) \
|
||||||
|
$(eval DISK_IMG_FILES += $(subst src/,build/,$(program))/$(shell basename $(program).bin)) \
|
||||||
|
)
|
||||||
|
|
||||||
WORLD_C_SRCS = $(wildcard src/world/*.c)
|
.PHONY: run debug prepare clean cleanbuild
|
||||||
WORLD_C_OBJS = $(patsubst src/%.c,build/%.o,$(WORLD_C_SRCS))
|
|
||||||
WORLD_OBJS = $(PROGRAM_COMMON) $(WORLD_C_OBJS)
|
|
||||||
|
|
||||||
.PHONY: run debug prepare clean
|
|
||||||
|
|
||||||
run: disk.img
|
run: disk.img
|
||||||
qemu-system-i386 disk.img
|
qemu-system-i386 disk.img
|
||||||
|
|
||||||
debug: disk.img
|
cleanbuild: clean disk.img
|
||||||
|
qemu-system-i386 disk.img
|
||||||
|
|
||||||
|
debug: clean disk.img
|
||||||
qemu-system-i386 -s -S -no-reboot -no-shutdown disk.img & gdb --command=gdbscript
|
qemu-system-i386 -s -S -no-reboot -no-shutdown disk.img & gdb --command=gdbscript
|
||||||
|
|
||||||
disk.img: prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IMG_FILES) build/world/world.bin
|
disk.img: prepare build/boot/boot.bin build/bootstage2/boot.bin $(DISK_IMG_FILES)
|
||||||
dd if=/dev/zero of=disk.img count=43 bs=100k
|
dd if=/dev/zero of=disk.img count=43 bs=100k
|
||||||
dd if=build/boot/boot.bin of=disk.img conv=notrunc
|
dd if=build/boot/boot.bin of=disk.img conv=notrunc
|
||||||
dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc
|
dd obs=512 seek=1 if=build/bootstage2/boot.bin of=disk.img conv=notrunc
|
||||||
mount disk.img img.d
|
mount disk.img img.d
|
||||||
mkdir img.d/etc/
|
mkdir img.d/etc/
|
||||||
cp $(DISK_IMG_FILES) img.d/
|
cp $(DISK_IMG_FILES) img.d/
|
||||||
cp build/world/world.bin img.d/etc/world.bin
|
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
umount img.d
|
umount img.d
|
||||||
chmod 777 disk.img
|
chmod 777 disk.img
|
||||||
|
|
||||||
prepare:
|
prepare:
|
||||||
mkdir -p img.d
|
mkdir -p img.d
|
||||||
mkdir -p build/boot
|
mkdir -p $(BUILD_DIRS)
|
||||||
mkdir -p build/boot_stage2
|
|
||||||
mkdir -p build/kernel
|
|
||||||
mkdir -p build/kernel/datatypes
|
|
||||||
mkdir -p build/kernel/stdio
|
|
||||||
mkdir -p build/program
|
|
||||||
mkdir -p build/hello
|
|
||||||
mkdir -p build/world
|
|
||||||
mkdir -p build/common
|
|
||||||
mountpoint img.d | grep not || umount img.d
|
mountpoint img.d | grep not || umount img.d
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@ -71,10 +64,10 @@ build/boot/boot.bin: src/boot/boot.asm
|
|||||||
nasm $< -o $@
|
nasm $< -o $@
|
||||||
|
|
||||||
# Boot Stage 2
|
# Boot Stage 2
|
||||||
build/boot_stage2/boot.bin: src/boot_stage2/boot_stage2.ld $(STAGE2_OBJS)
|
build/bootstage2/boot.bin: src/bootstage2/bootstage2.ld $(STAGE2_OBJS)
|
||||||
ld $(LDFLAGS) -T $< $(STAGE2_OBJS)
|
ld $(LDFLAGS) -T $< $(STAGE2_OBJS)
|
||||||
|
|
||||||
build/boot_stage2/%.o: src/boot_stage2/%.c
|
build/bootstage2/%.o: src/bootstage2/%.c
|
||||||
gcc $(CFLAGS) -o $@ -c $<
|
gcc $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
# Kernel
|
# Kernel
|
||||||
@ -101,12 +94,6 @@ src/kernel/isr.S: src/kernel/isr.S.base src/kernel/gen_isr_asm.sh
|
|||||||
|
|
||||||
# Program
|
# Program
|
||||||
|
|
||||||
build/program/program.bin: src/program/program.ld $(PROGRAM_OBJS)
|
.SECONDEXPANSION:
|
||||||
echo $(PROGRAM_OBJS)
|
build/programs/%.bin: src/programs/userspace.ld build/programs/entry.o $$(src/programs/$$(basename $$(notdir $$*))_OBJS) $(PROGRAM_COMMON)
|
||||||
ld $(LDFLAGS) -T $< $(PROGRAM_OBJS)
|
ld -o $@ -T $^
|
||||||
|
|
||||||
build/hello/hello.bin: src/hello/hello.ld $(HELLO_OBJS)
|
|
||||||
ld $(LDFLAGS) -T $< $(HELLO_OBJS)
|
|
||||||
|
|
||||||
build/world/world.bin: src/world/world.ld $(WORLD_OBJS)
|
|
||||||
ld $(LDFLAGS) -T $< $(WORLD_OBJS)
|
|
161
src/kernel/ata.cpp
Normal file
161
src/kernel/ata.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include "ata.h"
|
||||||
|
|
||||||
|
uint16_t controlBase[4] = {0x1f0, 0x170, 0x1e8, 0x168};
|
||||||
|
uint16_t dcrBase[4] = {0x3f6, 0x376, 0x3e6, 0x366};
|
||||||
|
|
||||||
|
uint8_t ATA::readStatus() {
|
||||||
|
uint8_t status;
|
||||||
|
for (int i=0; i<15; i++)
|
||||||
|
status=StatusRegister.readb();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ATA::pollTillNotBSY() {
|
||||||
|
uint8_t lastStatus;
|
||||||
|
while (((lastStatus=StatusRegister.readb()) & 0x80))
|
||||||
|
if (lastStatus&0x1)
|
||||||
|
return lastStatus;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ATA::pollTillDRQ() {
|
||||||
|
uint8_t lastStatus;
|
||||||
|
while (!((lastStatus=StatusRegister.readb()) & 0x8))
|
||||||
|
if (lastStatus&0x1)
|
||||||
|
return lastStatus;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATA::ATA(uint32_t bus) :
|
||||||
|
DataRegister(controlBase[bus]+0),
|
||||||
|
ErrorRegister(controlBase[bus]+1),
|
||||||
|
FeaturesRegister(controlBase[bus]+1),
|
||||||
|
SectorCountRegister(controlBase[bus]+2),
|
||||||
|
LBOLo(controlBase[bus]+3),
|
||||||
|
LBOMid(controlBase[bus]+4),
|
||||||
|
LBOHi(controlBase[bus]+5),
|
||||||
|
DriveSelectRegister(controlBase[bus]+6),
|
||||||
|
StatusRegister(controlBase[bus]+7),
|
||||||
|
CommandRegister(controlBase[bus]+7) {
|
||||||
|
this->isValid = 0;
|
||||||
|
|
||||||
|
DriveSelectRegister.writeb(0xA0);
|
||||||
|
LBOLo.writeb(0);
|
||||||
|
LBOMid.writeb(0);
|
||||||
|
LBOHi.writeb(0);
|
||||||
|
CommandRegister.writeb(0xEC);
|
||||||
|
|
||||||
|
if (!readStatus()) {
|
||||||
|
this->isValid = false;
|
||||||
|
} else {
|
||||||
|
pollTillNotBSY();
|
||||||
|
uint8_t lbomid;
|
||||||
|
uint8_t lbohi;
|
||||||
|
if ((lbomid = LBOMid.readb()) || (lbohi = LBOHi.readb())) {
|
||||||
|
this->isValid = false;
|
||||||
|
} else {
|
||||||
|
uint8_t status = pollTillDRQ();
|
||||||
|
if (!(status&0x1)) {
|
||||||
|
for (int i=0; i<256; i++)
|
||||||
|
((uint16_t*)identifyResult)[i] = DataRegister.readw();
|
||||||
|
this->isValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->isValid) {
|
||||||
|
this->totalLBA28Sectors = *((uint32_t*)(identifyResult+60));
|
||||||
|
this->diskSize = this->totalLBA28Sectors * 512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATA::validDevice() {
|
||||||
|
return this->isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATA::ATARead(uint32_t sector, uint8_t* buffer) {
|
||||||
|
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
||||||
|
SectorCountRegister.writeb(1);
|
||||||
|
LBOLo.writeb((uint8_t)sector);
|
||||||
|
LBOMid.writeb((uint8_t)(sector>>8));
|
||||||
|
LBOHi.writeb((uint8_t)(sector>>16));
|
||||||
|
CommandRegister.writeb(0x20);
|
||||||
|
pollTillNotBSY();
|
||||||
|
for (int i=0; i<256; i++)
|
||||||
|
((uint16_t*)buffer)[i] = DataRegister.readw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATA::ATAWrite(uint32_t sector, uint8_t* buffer) {
|
||||||
|
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
||||||
|
SectorCountRegister.writeb(1);
|
||||||
|
LBOLo.writeb((uint8_t)sector);
|
||||||
|
LBOMid.writeb((uint8_t)(sector>>8));
|
||||||
|
LBOHi.writeb((uint8_t)(sector>>16));
|
||||||
|
CommandRegister.writeb(0x30);
|
||||||
|
pollTillNotBSY();
|
||||||
|
for (int i=0; i<256; i++)
|
||||||
|
DataRegister.writew(((uint16_t*)buffer)[i]);
|
||||||
|
CommandRegister.writeb(0xe7);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATAReadWriter::ATAReadWriter(uint32_t owner, uint32_t bus):
|
||||||
|
ATA(bus),
|
||||||
|
ReadWriter(owner) {
|
||||||
|
this->currentPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ATAReadWriter::read(uint32_t count, uint8_t* buffer) {
|
||||||
|
uint32_t remainingBytes = count;
|
||||||
|
uint32_t inThisSector = currentPosition % 512;
|
||||||
|
|
||||||
|
uint32_t index=0;
|
||||||
|
|
||||||
|
uint32_t c=0;
|
||||||
|
|
||||||
|
ATARead(currentPosition / 512, sectorBuffer);
|
||||||
|
while (remainingBytes) {
|
||||||
|
if (currentPosition >= diskSize)
|
||||||
|
break;
|
||||||
|
buffer[index++] = sectorBuffer[inThisSector++];
|
||||||
|
remainingBytes--;
|
||||||
|
currentPosition++;
|
||||||
|
if (inThisSector == 512) {
|
||||||
|
ATARead(currentPosition / 512, sectorBuffer);
|
||||||
|
inThisSector = 0;
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
uint32_t ATAReadWriter::write(uint32_t count, uint8_t* buffer) {
|
||||||
|
uint32_t remainingBytes = count;
|
||||||
|
uint32_t inThisSector = currentPosition % 512;
|
||||||
|
|
||||||
|
uint32_t index=0;
|
||||||
|
|
||||||
|
uint32_t c=0;
|
||||||
|
|
||||||
|
ATARead(currentPosition / 512, sectorBuffer);
|
||||||
|
while (remainingBytes) {
|
||||||
|
if (currentPosition >= diskSize)
|
||||||
|
break;
|
||||||
|
sectorBuffer[inThisSector++] = buffer[index++];
|
||||||
|
remainingBytes--;
|
||||||
|
currentPosition++;
|
||||||
|
if (inThisSector == 512) {
|
||||||
|
ATAWrite((currentPosition / 512) - 1, sectorBuffer);
|
||||||
|
ATARead(currentPosition / 512, sectorBuffer);
|
||||||
|
inThisSector = 0;
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
// Perform a final write to ensure that we've written everything to disk.
|
||||||
|
ATAWrite((currentPosition / 512), sectorBuffer);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
uint32_t ATAReadWriter::size() {
|
||||||
|
return this->diskSize;
|
||||||
|
}
|
||||||
|
uint32_t ATAReadWriter::seek(uint32_t position) {
|
||||||
|
this->currentPosition = position;
|
||||||
|
}
|
110
src/kernel/ata.h
Normal file
110
src/kernel/ata.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#ifndef ATA_PIO
|
||||||
|
#define ATA_PIO
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "allocate.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "ioport.h"
|
||||||
|
|
||||||
|
#include "stdio/readwriter.h"
|
||||||
|
|
||||||
|
// Bus 0
|
||||||
|
// Control Ports: 1F0-1F7
|
||||||
|
// DCR / Alt Status: 3F6
|
||||||
|
// IRQ: 14
|
||||||
|
|
||||||
|
// Bus 1
|
||||||
|
// Control Ports: 170-177
|
||||||
|
// DCR / Alt Status: 376
|
||||||
|
// IRQ: 15
|
||||||
|
|
||||||
|
// Bus 2
|
||||||
|
// Control Ports: 1E8-1EF
|
||||||
|
// DCR / Alt Status: 3E6
|
||||||
|
// IRQ: Determine via PCI
|
||||||
|
|
||||||
|
// Bus 3
|
||||||
|
// Control Ports: 168-16F
|
||||||
|
// DCR / Alt Status: 366
|
||||||
|
// IRQ: Determine via PCI
|
||||||
|
|
||||||
|
// Control Port Map
|
||||||
|
// Name | RW | Offset | Size28 | Size48
|
||||||
|
// Data Register RW 0 2 2
|
||||||
|
// Error Register R 1 1 2
|
||||||
|
// Features Reg. W 1 1 2
|
||||||
|
// Sector Count Reg. RW 2 1 2
|
||||||
|
// LBOlo RW 3 1 2
|
||||||
|
// LBOmid RW 4 1 2
|
||||||
|
// LBOhi RW 5 1 2
|
||||||
|
// Drive Select RW 6 1 1
|
||||||
|
// Status Reg R 7 1 1
|
||||||
|
// Command Reg W 7 1 1
|
||||||
|
|
||||||
|
// DCR Port Map
|
||||||
|
// Name | RW | Offset | Size28 | Size48
|
||||||
|
// Alt. Status R 0 1 1
|
||||||
|
// Device Control W 1 1 1
|
||||||
|
// Device Address R 1 1 1
|
||||||
|
|
||||||
|
enum ATADriveType {
|
||||||
|
ATA,
|
||||||
|
ATAPI,
|
||||||
|
SATA
|
||||||
|
};
|
||||||
|
|
||||||
|
class ATA {
|
||||||
|
private:
|
||||||
|
ATADriveType type;
|
||||||
|
protected:
|
||||||
|
uint32_t bus;
|
||||||
|
|
||||||
|
uint32_t totalLBA28Sectors;
|
||||||
|
|
||||||
|
uint32_t diskSize;
|
||||||
|
uint8_t identifyResult[512];
|
||||||
|
|
||||||
|
Port DataRegister;
|
||||||
|
Port ErrorRegister;
|
||||||
|
Port FeaturesRegister;
|
||||||
|
Port SectorCountRegister;
|
||||||
|
Port LBOLo;
|
||||||
|
Port LBOMid;
|
||||||
|
Port LBOHi;
|
||||||
|
Port DriveSelectRegister;
|
||||||
|
Port StatusRegister;
|
||||||
|
Port CommandRegister;
|
||||||
|
|
||||||
|
bool isValid;
|
||||||
|
|
||||||
|
uint8_t readStatus();
|
||||||
|
uint8_t pollTillNotBSY();
|
||||||
|
uint8_t pollTillDRQ();
|
||||||
|
public:
|
||||||
|
ATA(uint32_t bus);
|
||||||
|
|
||||||
|
bool validDevice();
|
||||||
|
|
||||||
|
void ATARead(uint32_t sector, uint8_t* buffer);
|
||||||
|
void ATAWrite(uint32_t sector, uint8_t* buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ATAReadWriter: public ReadWriter, public ATA {
|
||||||
|
private:
|
||||||
|
uint8_t sectorBuffer[512];
|
||||||
|
uint32_t currentPosition;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ATAReadWriter(uint32_t owner, uint32_t bus);
|
||||||
|
|
||||||
|
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t size() override;
|
||||||
|
uint32_t seek(uint32_t position) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,255 +0,0 @@
|
|||||||
#include "atapio.h"
|
|
||||||
|
|
||||||
// Disk code
|
|
||||||
|
|
||||||
// Primary ATA Bus: 0x1f0 to 0x1f7
|
|
||||||
// Device Control Register: 0x3f6
|
|
||||||
// Secondary ATA Bus: 0x170 to 0x177
|
|
||||||
// Device Control Register: 0x376
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t identify_result[256];
|
|
||||||
uint32_t total_28_lbas = 0;
|
|
||||||
|
|
||||||
DirectoryEntry* rootDirEntries;
|
|
||||||
uint16_t* FAT1;
|
|
||||||
|
|
||||||
uint16_t countReserved;
|
|
||||||
uint8_t countFATs;
|
|
||||||
uint16_t countRDEs;
|
|
||||||
uint16_t sectorsPerFAT;
|
|
||||||
|
|
||||||
|
|
||||||
void init_atapio() {
|
|
||||||
rootDirEntries = (DirectoryEntry*)new uint8_t[8192];
|
|
||||||
FAT1 = (uint16_t*)(new uint8_t[512 * 34]);
|
|
||||||
|
|
||||||
uint32_t boot_sector = new uint32_t[1024];
|
|
||||||
read_sectors(0, 1, (uint8_t*)boot_sector);
|
|
||||||
|
|
||||||
countReserved = *((uint16_t*)(boot_sector + 0x0e));
|
|
||||||
countFATs = *((uint8_t*)(boot_sector + 0x10));
|
|
||||||
countRDEs = *((uint16_t*)(boot_sector + 0x11));
|
|
||||||
sectorsPerFAT = *((uint16_t*)(boot_sector + 0x16));
|
|
||||||
|
|
||||||
// Select Drive 0 on the Primary Bus
|
|
||||||
outb(0x1f6, 0xa0);
|
|
||||||
|
|
||||||
// Set sector count to 0 for IDENTIFY
|
|
||||||
outb(0x1f2, 0);
|
|
||||||
// Set LBAlo to 0
|
|
||||||
outb(0x1f3, 0);
|
|
||||||
// Set LBAmid to 0
|
|
||||||
outb(0x1f4, 0);
|
|
||||||
// Set LBAhi to 0
|
|
||||||
outb(0x1f5, 0);
|
|
||||||
|
|
||||||
// Send IDENTIFY command
|
|
||||||
outb(0x1f7, 0xec);
|
|
||||||
|
|
||||||
uint8_t status = inb(0x1f7);
|
|
||||||
if (status) {
|
|
||||||
while ((status = inb(0x1f7)) & 0x80);
|
|
||||||
|
|
||||||
if ( !(inb(0x1f4) || inb(0x1f5)) ) {
|
|
||||||
while ( !(status & 8 || status & 1) )
|
|
||||||
status = inb(0x1f7);
|
|
||||||
|
|
||||||
if (!(status & 1)) {
|
|
||||||
for (int index=0; index<256; index++)
|
|
||||||
identify_result[index] = inw(0x1f0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_28_lbas = *(uint32_t*)(identify_result+60);
|
|
||||||
|
|
||||||
// We've initialised now, let's load the FAT and RootDirEntries.
|
|
||||||
read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, (uint8_t*)rootDirEntries);
|
|
||||||
read_sectors(countReserved, sectorsPerFAT, (uint8_t*)FAT1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_sector(uint32_t address, uint8_t* buffer) {
|
|
||||||
outb(0x1f6, 0xe0 | ((address>>24)&0x0f));
|
|
||||||
// Read a single sector
|
|
||||||
outb(0x1f2, 1);
|
|
||||||
// Set LBAlo, LBAmid and LBAhi
|
|
||||||
outb(0x1f3, address);
|
|
||||||
outb(0x1f4, address>>8);
|
|
||||||
outb(0x1f5, address>>16);
|
|
||||||
|
|
||||||
// Send read command
|
|
||||||
outb(0x1f7, 0x20);
|
|
||||||
// Poll
|
|
||||||
uint8_t status = inb(0x1f7);
|
|
||||||
while ( (status & 0x80) && !(status & 8) )
|
|
||||||
status = inb(0x1f7);
|
|
||||||
|
|
||||||
for (int index=0; index<256; index++)
|
|
||||||
((uint16_t*)buffer)[index] = inw(0x1f0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_sectors(uint32_t address, int count, uint8_t* buffer) {
|
|
||||||
for (int i=0; i<count; i++) {
|
|
||||||
read_sector(address+i, buffer+512*i);
|
|
||||||
for (int i=0; i<15; i++)
|
|
||||||
inb(0x1f7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t clusterToSector(uint32_t cluster) {
|
|
||||||
return cluster + (sectorsPerFAT * countFATs) + (countRDEs / 16) + (countReserved - 1) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int split_on_char(char c, char* str, char** split) {
|
|
||||||
char* cstr = str;
|
|
||||||
char* last = str;
|
|
||||||
uint32_t count = 0;
|
|
||||||
while (*cstr) {
|
|
||||||
if (*cstr == c) {
|
|
||||||
*cstr = 0;
|
|
||||||
split[count++] = last;
|
|
||||||
last = cstr+1;
|
|
||||||
}
|
|
||||||
cstr++;
|
|
||||||
}
|
|
||||||
split[count++] = last;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void to83(char* filename, char* buf83) {
|
|
||||||
char* c = filename;
|
|
||||||
for (int i=0;i<11;i++)
|
|
||||||
buf83[i] = ' ';
|
|
||||||
uint32_t bufpos = 0;
|
|
||||||
while (*c && bufpos != 11) {
|
|
||||||
if (*c == '.')
|
|
||||||
bufpos = 8;
|
|
||||||
else
|
|
||||||
buf83[bufpos++] = *c & 223;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_file(uint32_t location, uint8_t* destination) {
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
bool loaded = false;
|
|
||||||
while (!loaded) {
|
|
||||||
uint16_t fromSector = clusterToSector(location);
|
|
||||||
read_sector(fromSector, destination+offset);
|
|
||||||
offset += 512;
|
|
||||||
|
|
||||||
location = FAT1[location++];
|
|
||||||
if (location == 0xffff)
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int calc_size(uint32_t location) {
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
bool loaded = false;
|
|
||||||
while (!loaded) {
|
|
||||||
uint16_t fromSector = clusterToSector(location);
|
|
||||||
offset += 512;
|
|
||||||
|
|
||||||
location = FAT1[location++];
|
|
||||||
if (location == 0xffff)
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryEntry* get_DE(char* filename) {
|
|
||||||
DirectoryEntry* dirbuf;
|
|
||||||
Directory dir = {
|
|
||||||
.entry = rootDirEntries,
|
|
||||||
.entries = countRDEs
|
|
||||||
};
|
|
||||||
|
|
||||||
char* levels[8];
|
|
||||||
int count = split_on_char('/', filename, levels);
|
|
||||||
|
|
||||||
for (int i=0; i<(count-1); i++) {
|
|
||||||
char normalname[11] = {' '};
|
|
||||||
to83(levels[i], normalname);
|
|
||||||
for (int e=0; e<dir.entries; e++) {
|
|
||||||
bool found=strcmp(dir.entry[e].name, normalname, 11);
|
|
||||||
if (found) {
|
|
||||||
DirectoryEntry* de = &dir.entry[e];
|
|
||||||
uint32_t size = calc_size(de->firstClusterLow);
|
|
||||||
dirbuf = (DirectoryEntry*)(new uint8_t[size]);
|
|
||||||
uint32_t cluster = de->firstClusterLow;
|
|
||||||
load_file(cluster, (uint8_t*)dirbuf);
|
|
||||||
dir.entry = dirbuf;
|
|
||||||
dir.entries = size / 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char normalname[11];
|
|
||||||
to83(levels[count-1], normalname);
|
|
||||||
|
|
||||||
for (int i=0; i<dir.entries; i++) {
|
|
||||||
bool found = strcmp(dir.entry[i].name, normalname, 11);
|
|
||||||
if (found) {
|
|
||||||
return &dir.entry[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t file_exists(char* filename) {
|
|
||||||
DirectoryEntry* de = get_DE(filename);
|
|
||||||
if (de)
|
|
||||||
return de->firstClusterLow;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t file_size(char* filename) {
|
|
||||||
for (int i=0; i<countRDEs; i++) {
|
|
||||||
bool found = strcmp(rootDirEntries[i].name, filename, 11);
|
|
||||||
if (found) {
|
|
||||||
if (rootDirEntries[i].size % 512)
|
|
||||||
return ((rootDirEntries[i].size / 512) + 1) * 512;
|
|
||||||
else
|
|
||||||
return rootDirEntries[i].size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_file(char* filename, uint8_t* location) {
|
|
||||||
DirectoryEntry* de = get_DE(filename);
|
|
||||||
load_file(de->firstClusterLow, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
FATFileReadWriter::FATFileReadWriter(uint32_t owner, char* filename)
|
|
||||||
: ReadWriter(owner) {
|
|
||||||
this->bytesRead = 0;
|
|
||||||
DirectoryEntry* de = get_DE(filename);
|
|
||||||
this->sizeBytes = de->size;
|
|
||||||
this->currentCluster = de->firstClusterLow;
|
|
||||||
this->read_buffer = new uint8_t[512];
|
|
||||||
read_sector(clusterToSector(this->currentCluster), this->read_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FATFileReadWriter::read(uint32_t count, uint8_t* buffer) {
|
|
||||||
int index = 0;
|
|
||||||
while (count) {
|
|
||||||
buffer[index] = this->read_buffer[this->bytesRead++];
|
|
||||||
if (this->bytesRead == 512) {
|
|
||||||
this->currentCluster = FAT1[this->currentCluster++];
|
|
||||||
read_sector(clusterToSector(this->currentCluster), this->read_buffer);
|
|
||||||
this->bytesRead = 0;
|
|
||||||
}
|
|
||||||
count--;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t FATFileReadWriter::write(uint32_t count, uint8_t* buffer) {}
|
|
||||||
uint32_t FATFileReadWriter::size() {
|
|
||||||
return this->sizeBytes;
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
#ifndef ATA_PIO
|
|
||||||
#define ATA_PIO
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "io.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "strings.h"
|
|
||||||
#include "allocate.h"
|
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
#include "stdio/readwriter.h"
|
|
||||||
|
|
||||||
struct __attribute__((packed)) DirectoryEntry {
|
|
||||||
char name[11];
|
|
||||||
uint8_t _ignored0 : 3;
|
|
||||||
uint8_t archive : 1;
|
|
||||||
uint8_t directory : 1;
|
|
||||||
uint8_t volumeid : 1;
|
|
||||||
uint8_t system : 1;
|
|
||||||
uint8_t hidden : 1;
|
|
||||||
uint8_t readonly : 1;
|
|
||||||
uint8_t _ignored1;
|
|
||||||
uint16_t createdHour : 5;
|
|
||||||
uint16_t createdMinute : 6;
|
|
||||||
uint16_t createdSecond : 5;
|
|
||||||
|
|
||||||
uint16_t createdYear : 7;
|
|
||||||
uint16_t createdMonth : 4;
|
|
||||||
uint16_t createdDay : 5;
|
|
||||||
|
|
||||||
uint16_t lastAccessYear : 7;
|
|
||||||
uint16_t lastAccessMonth : 4;
|
|
||||||
uint16_t lastAccessDay : 5;
|
|
||||||
|
|
||||||
uint16_t firstClusterHigh;
|
|
||||||
|
|
||||||
uint16_t modifiedHour : 5;
|
|
||||||
uint16_t modifiedMinute : 6;
|
|
||||||
uint16_t modifiedSecond : 5;
|
|
||||||
|
|
||||||
uint16_t modifiedYear : 7;
|
|
||||||
uint16_t modifiedMonth : 4;
|
|
||||||
uint16_t modifiedDay : 5;
|
|
||||||
|
|
||||||
uint16_t firstClusterLow;
|
|
||||||
uint32_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Directory {
|
|
||||||
DirectoryEntry* entry;
|
|
||||||
uint32_t entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_atapio();
|
|
||||||
void read_sector(uint32_t address, uint8_t* buffer);
|
|
||||||
void read_sectors(uint32_t address, int count, uint8_t* buffer);
|
|
||||||
uint16_t file_exists(char* filename);
|
|
||||||
void load_file(char* filename, uint8_t* location);
|
|
||||||
|
|
||||||
uint32_t file_size(char* filename);
|
|
||||||
|
|
||||||
class FATFileReadWriter : public ReadWriter {
|
|
||||||
private:
|
|
||||||
uint32_t sizeBytes;
|
|
||||||
uint32_t bytesRead;
|
|
||||||
uint32_t currentCluster;
|
|
||||||
uint8_t* read_buffer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FATFileReadWriter(uint32_t owner, char* filename);
|
|
||||||
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
|
||||||
uint32_t size() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -27,11 +27,21 @@ namespace xnoe {
|
|||||||
while (start) {
|
while (start) {
|
||||||
if (start->elem == t)
|
if (start->elem == t)
|
||||||
return true;
|
return true;
|
||||||
|
//current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
xnoe::linkedlistelem<T>* current = this->start;
|
||||||
|
while (current) {
|
||||||
|
xnoe::linkedlistelem<T>* c = current;
|
||||||
|
current = current->next;
|
||||||
|
delete c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void append(T t) {
|
void append(T t) {
|
||||||
xnoe::linkedlistelem<T>* llelem = new xnoe::linkedlistelem<T>(t);
|
xnoe::linkedlistelem<T>* llelem = new xnoe::linkedlistelem<T>(t);
|
||||||
append(llelem);
|
append(llelem);
|
||||||
|
27
src/kernel/filesystem/devfs.cpp
Normal file
27
src/kernel/filesystem/devfs.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "devfs.h"
|
||||||
|
|
||||||
|
bool DevFS::exists(Path p) {
|
||||||
|
if (p.start->elem == PathEntry{3, "ata"})
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSType DevFS::type(Path p) {
|
||||||
|
if (p.start->elem == PathEntry{3, "ata"})
|
||||||
|
return BlockDev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReadWriter* DevFS::open(Path p) {
|
||||||
|
if (p.start->elem == PathEntry{3, "ata"}) {
|
||||||
|
return new ATAReadWriter(0, 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t DevFS::getDentsSize(Path p) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevFS::getDents(Path p, FSDirectoryListing* buffer) {}
|
18
src/kernel/filesystem/devfs.h
Normal file
18
src/kernel/filesystem/devfs.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef DEVFS_H
|
||||||
|
#define DEVFS_H
|
||||||
|
|
||||||
|
#include "fstree.h"
|
||||||
|
#include "../ata.h"
|
||||||
|
#include "../kernel.h"
|
||||||
|
|
||||||
|
class DevFS: public FSTree {
|
||||||
|
bool exists(Path p) override;
|
||||||
|
FSType type(Path p) override;
|
||||||
|
|
||||||
|
ReadWriter* open(Path p) override;
|
||||||
|
|
||||||
|
uint32_t getDentsSize(Path p) override;
|
||||||
|
void getDents(Path p, FSDirectoryListing* buffer) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
394
src/kernel/filesystem/fat16.cpp
Normal file
394
src/kernel/filesystem/fat16.cpp
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
#include "fat16.h"
|
||||||
|
|
||||||
|
uint32_t FAT16FileReadWriter::offsetBytesToCluster(uint32_t offset) {
|
||||||
|
uint32_t cluster = this->firstCluster;
|
||||||
|
uint32_t remaining = offset;
|
||||||
|
while (remaining > 512) {
|
||||||
|
cluster = this->backingFS->FAT1[this->firstCluster];
|
||||||
|
remaining -= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAT16FileReadWriter::FAT16FileReadWriter(uint32_t owner, uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS)
|
||||||
|
: ReadWriter(owner) {
|
||||||
|
this->firstCluster = firstCluster;
|
||||||
|
this->sizeBytes = sizeBytes;
|
||||||
|
this->currentPosition = 0;
|
||||||
|
this->backingFS = backingFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FileReadWriter::read(uint32_t count, uint8_t* buffer) {
|
||||||
|
uint8_t* clusterBuffer = new uint8_t[512];
|
||||||
|
uint32_t clusterToRead = offsetBytesToCluster(this->currentPosition);
|
||||||
|
uint32_t sectorToRead = this->backingFS->clusterToSector(clusterToRead);
|
||||||
|
this->backingFS->backingDevice->seek(sectorToRead * 512);
|
||||||
|
this->backingFS->backingDevice->read(512, clusterBuffer);
|
||||||
|
|
||||||
|
uint32_t currentClusterIndex = this->currentPosition % 512;
|
||||||
|
|
||||||
|
uint32_t remaining = count;
|
||||||
|
|
||||||
|
uint32_t index = 0;
|
||||||
|
while (remaining) {
|
||||||
|
if (currentClusterIndex == 512) {
|
||||||
|
clusterToRead = this->backingFS->FAT1[clusterToRead];
|
||||||
|
if (clusterToRead == 0xffff)
|
||||||
|
break;
|
||||||
|
sectorToRead = this->backingFS->clusterToSector(clusterToRead);
|
||||||
|
this->backingFS->backingDevice->seek(sectorToRead * 512);
|
||||||
|
this->backingFS->backingDevice->read(512, clusterBuffer);
|
||||||
|
currentClusterIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = clusterBuffer[currentClusterIndex++];
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] clusterBuffer;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {}
|
||||||
|
|
||||||
|
uint32_t FAT16FileReadWriter::size() {
|
||||||
|
return this->sizeBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FileReadWriter::seek(uint32_t position) {
|
||||||
|
if (position < this->sizeBytes) {
|
||||||
|
this->currentPosition = position;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char safeUppercase(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case 'a'...'z':
|
||||||
|
return c & ~32;
|
||||||
|
default:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) {
|
||||||
|
uint32_t maxSize = pe.length;
|
||||||
|
uint8_t* data = pe.path;
|
||||||
|
|
||||||
|
uint32_t readIndex=0;
|
||||||
|
uint32_t writeIndex=0;
|
||||||
|
|
||||||
|
while (writeIndex<11 && readIndex < maxSize) {
|
||||||
|
char c;
|
||||||
|
if ((c=data[readIndex++]) == '.') {
|
||||||
|
writeIndex = 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer[writeIndex++] = safeUppercase(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FS::clusterToSector(uint32_t cluster) {
|
||||||
|
return cluster + (*sectorsPerFAT * *countFATs) + (*countRDEs / 16) + (*countReserved - 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAT16FS::load_file(uint32_t location, uint8_t* destination) {
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
bool loaded = false;
|
||||||
|
while (!loaded) {
|
||||||
|
uint16_t fromSector = clusterToSector(location);
|
||||||
|
this->backingDevice->seek(fromSector * 512);
|
||||||
|
this->backingDevice->read(512, destination+offset);
|
||||||
|
offset += 512;
|
||||||
|
|
||||||
|
location = FAT1[location++];
|
||||||
|
if (location == 0xffff)
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FS::calc_size(uint32_t location) {
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
bool loaded = false;
|
||||||
|
while (!loaded) {
|
||||||
|
uint16_t fromSector = clusterToSector(location);
|
||||||
|
offset += 512;
|
||||||
|
|
||||||
|
location = FAT1[location++];
|
||||||
|
if (location == 0xffff)
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntry(Path p) {
|
||||||
|
PathElement* current = p.start;
|
||||||
|
|
||||||
|
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
|
||||||
|
for (int i=0; i < *countRDEs; i++)
|
||||||
|
currentDirectory[i] = rootDirEntries[i];
|
||||||
|
|
||||||
|
uint32_t count = *countRDEs;
|
||||||
|
|
||||||
|
if (!current)
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
|
||||||
|
escape_for:
|
||||||
|
while (current != p.end) {
|
||||||
|
char name83[12] = " ";
|
||||||
|
pathEntryTo83(current->elem, name83);
|
||||||
|
for (int i=0; i < count; i++) {
|
||||||
|
if (strcmp(currentDirectory[i].name, name83, 11)) {
|
||||||
|
DirectoryEntry found = currentDirectory[i];
|
||||||
|
if (!(found.directory))
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
|
||||||
|
delete currentDirectory;
|
||||||
|
uint32_t sizeBytes = calc_size(found.firstClusterLow);
|
||||||
|
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
|
||||||
|
|
||||||
|
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
|
||||||
|
|
||||||
|
i=0;
|
||||||
|
count = sizeBytes / sizeof(DirectoryEntry);
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
goto escape_for;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> FAT16FS::getDirectoryEntryFull(Path p) {
|
||||||
|
PathElement* current = p.start;
|
||||||
|
|
||||||
|
DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs];
|
||||||
|
for (int i=0; i < *countRDEs; i++)
|
||||||
|
currentDirectory[i] = rootDirEntries[i];
|
||||||
|
|
||||||
|
uint32_t count = *countRDEs;
|
||||||
|
|
||||||
|
if (!current)
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
|
||||||
|
escape_for:
|
||||||
|
while (current) {
|
||||||
|
char name83[12] = " ";
|
||||||
|
pathEntryTo83(current->elem, name83);
|
||||||
|
for (int i=0; i < count; i++) {
|
||||||
|
if (strcmp(currentDirectory[i].name, name83, 11)) {
|
||||||
|
DirectoryEntry found = currentDirectory[i];
|
||||||
|
if (!(found.directory))
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
|
||||||
|
delete currentDirectory;
|
||||||
|
uint32_t sizeBytes = calc_size(found.firstClusterLow);
|
||||||
|
currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]);
|
||||||
|
|
||||||
|
load_file(found.firstClusterLow, (uint8_t*)currentDirectory);
|
||||||
|
|
||||||
|
i=0;
|
||||||
|
count = sizeBytes / sizeof(DirectoryEntry);
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
goto escape_for;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xnoe::tuple<DirectoryEntry*, uint32_t, bool>(currentDirectory, count, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
FAT16FS::FAT16FS(ReadWriter* disk) {
|
||||||
|
this->backingDevice = disk;
|
||||||
|
|
||||||
|
this->backingDevice->seek(0);
|
||||||
|
this->backingDevice->read(512, sectorOne);
|
||||||
|
|
||||||
|
this->rootDirEntries = new DirectoryEntry[*countRDEs];
|
||||||
|
|
||||||
|
this->backingDevice->seek(((*sectorsPerFAT) * (*countFATs) + (*countReserved)) * 512);
|
||||||
|
this->backingDevice->read((*countRDEs) * sizeof(DirectoryEntry), (uint8_t*)this->rootDirEntries);
|
||||||
|
|
||||||
|
this->FAT1 = new uint16_t[(*sectorsPerFAT) * 256];
|
||||||
|
|
||||||
|
this->backingDevice->seek((*countReserved) * 512);
|
||||||
|
this->backingDevice->read((*sectorsPerFAT) * 512, (uint8_t*)FAT1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FAT16FS::exists(Path p) {
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
||||||
|
if (!xnoe::get<2>(directory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
||||||
|
uint32_t count = xnoe::get<1>(directory);
|
||||||
|
|
||||||
|
PathElement* end = p.end;
|
||||||
|
if (!end)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char name83[11] = {' '};
|
||||||
|
pathEntryTo83(end->elem, name83);
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete directoryEntries;
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSType FAT16FS::type(Path p) {
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
||||||
|
if (!xnoe::get<2>(directory))
|
||||||
|
return NoExist;
|
||||||
|
|
||||||
|
FSType found = NoExist;
|
||||||
|
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
||||||
|
uint32_t count = xnoe::get<1>(directory);
|
||||||
|
|
||||||
|
PathElement* end = p.end;
|
||||||
|
if (!end)
|
||||||
|
return NoExist;
|
||||||
|
|
||||||
|
char name83[11] = {' '};
|
||||||
|
pathEntryTo83(end->elem, name83);
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||||
|
if (directoryEntries[i].directory)
|
||||||
|
found = Directory;
|
||||||
|
else
|
||||||
|
found = File;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete directoryEntries;
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriter* FAT16FS::open(Path p) {
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntry(p);
|
||||||
|
if (!xnoe::get<2>(directory))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
||||||
|
uint32_t count = xnoe::get<1>(directory);
|
||||||
|
|
||||||
|
PathElement* end = p.end;
|
||||||
|
if (!end)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t written=0;
|
||||||
|
|
||||||
|
char name83[12] = " ";
|
||||||
|
name83[11] = 0;
|
||||||
|
pathEntryTo83(end->elem, name83);
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
if (strcmp(directoryEntries[i].name, name83, 11)) {
|
||||||
|
if (!directoryEntries[i].directory)
|
||||||
|
return new FAT16FileReadWriter(0, ((uint32_t)directoryEntries[i].firstClusterHigh << 16) | directoryEntries[i].firstClusterLow, directoryEntries[i].size, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete directoryEntries;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathEntry name83ToPathEntry(char* name83, char* text) {
|
||||||
|
uint32_t mainLength = 8;
|
||||||
|
uint32_t index = 7;
|
||||||
|
while (name83[index] == ' ' && index--)
|
||||||
|
mainLength--;
|
||||||
|
|
||||||
|
uint32_t extLength = 3;
|
||||||
|
index = 10;
|
||||||
|
while (name83[index] == ' ' && index-- > 7)
|
||||||
|
extLength--;
|
||||||
|
|
||||||
|
memcpy(name83, text, mainLength);
|
||||||
|
if (name83[8] != ' ') {
|
||||||
|
text[mainLength] = '.';
|
||||||
|
memcpy(name83+8, text+mainLength+1, extLength);
|
||||||
|
}
|
||||||
|
text[mainLength+extLength+1] = 0;
|
||||||
|
return PathEntry{mainLength+extLength+1, text};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getRealCount(DirectoryEntry* directoryEntries, uint32_t c) {
|
||||||
|
uint32_t r = 0;
|
||||||
|
for (int i = 0; i < c; i++) {
|
||||||
|
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid)
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FAT16FS::getDentsSize(Path p) {
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
|
||||||
|
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
||||||
|
if (!xnoe::get<2>(directory)) {
|
||||||
|
delete directoryEntries;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t found = 0;
|
||||||
|
uint32_t count = xnoe::get<1>(directory);
|
||||||
|
|
||||||
|
found += 4;
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
|
||||||
|
found += sizeof(FSDirectoryEntry);
|
||||||
|
found += 13;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete directoryEntries;
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAT16FS::getDents(Path p, FSDirectoryListing* buffer) {
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> directory = getDirectoryEntryFull(p);
|
||||||
|
DirectoryEntry* directoryEntries = xnoe::get<0>(directory);
|
||||||
|
if (!xnoe::get<2>(directory)) {
|
||||||
|
delete directoryEntries;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count = xnoe::get<1>(directory);
|
||||||
|
|
||||||
|
uint32_t written=0;
|
||||||
|
|
||||||
|
buffer->count = getRealCount(directoryEntries, count);
|
||||||
|
|
||||||
|
char* nameBuffer = ((char*)buffer);
|
||||||
|
nameBuffer += sizeof(FSDirectoryEntry)*buffer->count + 4;
|
||||||
|
|
||||||
|
for (int i=0; i<count; i++) {
|
||||||
|
if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) {
|
||||||
|
buffer->entries[written] = FSDirectoryEntry {
|
||||||
|
name83ToPathEntry(directoryEntries[i].name, nameBuffer + 13*written),
|
||||||
|
directoryEntries[i].directory ? Directory : File,
|
||||||
|
directoryEntries[i].size
|
||||||
|
};
|
||||||
|
written++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete directoryEntries;
|
||||||
|
}
|
118
src/kernel/filesystem/fat16.h
Normal file
118
src/kernel/filesystem/fat16.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#ifndef FAT16_H
|
||||||
|
#define FAT16_H
|
||||||
|
|
||||||
|
#include "fstree.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "../memory.h"
|
||||||
|
#include "../stdio/readwriter.h"
|
||||||
|
#include "../datatypes/tuple.h"
|
||||||
|
|
||||||
|
struct __attribute__((packed)) DirectoryEntry {
|
||||||
|
char name[11];
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t readonly : 1;
|
||||||
|
uint8_t hidden : 1;
|
||||||
|
uint8_t system : 1;
|
||||||
|
uint8_t volumeid : 1;
|
||||||
|
uint8_t directory : 1;
|
||||||
|
uint8_t archive : 1;
|
||||||
|
uint8_t device : 1;
|
||||||
|
uint8_t _ignored0 : 1;
|
||||||
|
|
||||||
|
uint8_t f1 : 1;
|
||||||
|
uint8_t f2 : 1;
|
||||||
|
uint8_t f3 : 1;
|
||||||
|
uint8_t f4 : 1;
|
||||||
|
uint8_t _ignored1 : 1;
|
||||||
|
uint8_t deleteRequiresPassword : 1;
|
||||||
|
uint8_t writeRequiresPassword : 1;
|
||||||
|
uint8_t readRequiresPassword : 1;
|
||||||
|
|
||||||
|
uint8_t createTime10ms;
|
||||||
|
|
||||||
|
uint16_t createdHour : 5;
|
||||||
|
uint16_t createdMinute : 6;
|
||||||
|
uint16_t createdSecond : 5;
|
||||||
|
|
||||||
|
uint16_t createdYear : 7;
|
||||||
|
uint16_t createdMonth : 4;
|
||||||
|
uint16_t createdDay : 5;
|
||||||
|
|
||||||
|
uint16_t lastAccessYear : 7;
|
||||||
|
uint16_t lastAccessMonth : 4;
|
||||||
|
uint16_t lastAccessDay : 5;
|
||||||
|
|
||||||
|
uint16_t firstClusterHigh;
|
||||||
|
|
||||||
|
uint16_t modifiedHour : 5;
|
||||||
|
uint16_t modifiedMinute : 6;
|
||||||
|
uint16_t modifiedSecond : 5;
|
||||||
|
|
||||||
|
uint16_t modifiedYear : 7;
|
||||||
|
uint16_t modifiedMonth : 4;
|
||||||
|
uint16_t modifiedDay : 5;
|
||||||
|
|
||||||
|
uint16_t firstClusterLow;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Directory {
|
||||||
|
DirectoryEntry* entry;
|
||||||
|
uint32_t entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FAT16FS;
|
||||||
|
class FAT16FileReadWriter: public ReadWriter {
|
||||||
|
private:
|
||||||
|
uint32_t firstCluster;
|
||||||
|
uint32_t sizeBytes;
|
||||||
|
|
||||||
|
uint32_t currentPosition;
|
||||||
|
|
||||||
|
uint32_t offsetBytesToCluster(uint32_t offset);
|
||||||
|
|
||||||
|
FAT16FS* backingFS;
|
||||||
|
public:
|
||||||
|
FAT16FileReadWriter(uint32_t owner, uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS);
|
||||||
|
|
||||||
|
uint32_t read(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t write(uint32_t count, uint8_t* buffer) override;
|
||||||
|
uint32_t size() override;
|
||||||
|
uint32_t seek(uint32_t position) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FAT16FS: public FSTree {
|
||||||
|
public:
|
||||||
|
DirectoryEntry* rootDirEntries;
|
||||||
|
uint16_t* FAT1;
|
||||||
|
uint8_t sectorOne[512];
|
||||||
|
|
||||||
|
uint16_t* countReserved = ((uint16_t*)(sectorOne + 0x0e));
|
||||||
|
uint8_t* countFATs = ((uint8_t*)(sectorOne + 0x10));
|
||||||
|
uint16_t* countRDEs = ((uint16_t*)(sectorOne + 0x11));
|
||||||
|
uint16_t* sectorsPerFAT = ((uint16_t*)(sectorOne + 0x16));
|
||||||
|
|
||||||
|
ReadWriter* backingDevice;
|
||||||
|
|
||||||
|
bool pathEntryTo83(PathEntry pe, char* buffer);
|
||||||
|
|
||||||
|
uint32_t clusterToSector(uint32_t cluster);
|
||||||
|
void load_file(uint32_t location, uint8_t* destination);
|
||||||
|
uint32_t calc_size(uint32_t location);
|
||||||
|
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntry(Path p);
|
||||||
|
xnoe::tuple<DirectoryEntry*, uint32_t, bool> getDirectoryEntryFull(Path p);
|
||||||
|
|
||||||
|
FAT16FS(ReadWriter* disk);
|
||||||
|
|
||||||
|
bool exists(Path p) override;
|
||||||
|
FSType type(Path p) override;
|
||||||
|
|
||||||
|
ReadWriter* open(Path p) override;
|
||||||
|
|
||||||
|
uint32_t getDentsSize(Path p) override;
|
||||||
|
void getDents(Path p, FSDirectoryListing* buffer) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
204
src/kernel/filesystem/fstree.cpp
Normal file
204
src/kernel/filesystem/fstree.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#include "fstree.h"
|
||||||
|
|
||||||
|
bool operator==(const PathEntry& lhs, const PathEntry& rhs) {
|
||||||
|
if (lhs.length == rhs.length)
|
||||||
|
if (lhs.length == 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return strcmp(lhs.path, rhs.path, lhs.length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FS Tree Skeleton
|
||||||
|
bool FSTree::exists(Path p){}
|
||||||
|
FSType FSTree::type(Path p){}
|
||||||
|
ReadWriter* FSTree::open(Path p){}
|
||||||
|
uint32_t FSTree::getDentsSize(Path p){}
|
||||||
|
void FSTree::getDents(Path p, FSDirectoryListing* buffer){}
|
||||||
|
|
||||||
|
// RootFSTree
|
||||||
|
|
||||||
|
RootFSTree::RootFSTree() {
|
||||||
|
this->node = new FSTreeNode{
|
||||||
|
PathEntry{0,0},
|
||||||
|
xnoe::linkedlist<FSTreeNode*>(),
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pathEntryInFSTreeNode(PathEntry p, FSTreeNode* n) {
|
||||||
|
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
||||||
|
while (current) {
|
||||||
|
if (current->elem->self == p)
|
||||||
|
return true;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSTreeNode* getNodeFromPathEntry(PathEntry p, FSTreeNode* n) {
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
|
||||||
|
while (current) {
|
||||||
|
if (current->elem->self == p)
|
||||||
|
return current->elem;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSTreeNode* RootFSTree::makeNodeIfNotExist(Path p) {
|
||||||
|
PathElement* currentPathElement = p.start;
|
||||||
|
|
||||||
|
FSTreeNode* currentNode = this->node;
|
||||||
|
|
||||||
|
if (!currentPathElement || currentPathElement == p.end)
|
||||||
|
return currentNode;
|
||||||
|
|
||||||
|
nextPE:
|
||||||
|
while (currentPathElement) {
|
||||||
|
xnoe::linkedlistelem<FSTreeNode*>* currentChild = currentNode->children.start;
|
||||||
|
while (currentChild) {
|
||||||
|
if (currentChild->elem->self == currentPathElement->elem) {
|
||||||
|
currentNode = currentChild->elem;
|
||||||
|
currentPathElement = currentPathElement->next;
|
||||||
|
goto nextPE;
|
||||||
|
}
|
||||||
|
currentChild = currentChild->next;
|
||||||
|
}
|
||||||
|
currentNode->children.append(new FSTreeNode{currentPathElement->elem, xnoe::linkedlist<FSTreeNode*>(), 0});
|
||||||
|
currentNode = currentNode->children.end->elem;
|
||||||
|
currentPathElement = currentPathElement->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSTree* RootFSTree::getLongestMatchingUnder(Path p) {
|
||||||
|
PathElement* currentPath = p.start;
|
||||||
|
FSTreeNode* currentNode = this->node;
|
||||||
|
FSTree* lastMountpoint = 0;
|
||||||
|
while (currentPath && currentNode) {
|
||||||
|
if ((currentPath->elem == currentNode->self) && currentNode->mountpoint)
|
||||||
|
lastMountpoint = currentNode->mountpoint;
|
||||||
|
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
|
||||||
|
if (currentNode && currentNode->mountpoint)
|
||||||
|
lastMountpoint = currentNode->mountpoint;
|
||||||
|
currentPath = currentPath->next;
|
||||||
|
}
|
||||||
|
return lastMountpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path* RootFSTree::getRemainingPath(Path p) {
|
||||||
|
PathElement* currentPath = p.start;
|
||||||
|
FSTreeNode* currentNode = this->node;
|
||||||
|
PathElement* lastMountpoint = 0;
|
||||||
|
while (currentPath && currentNode) {
|
||||||
|
if (currentPath->elem == currentNode->self && currentNode->mountpoint)
|
||||||
|
lastMountpoint = currentPath;
|
||||||
|
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
|
||||||
|
if (currentNode && currentNode->mountpoint)
|
||||||
|
lastMountpoint = currentPath;
|
||||||
|
currentPath = currentPath->next;
|
||||||
|
}
|
||||||
|
lastMountpoint = lastMountpoint->next;
|
||||||
|
|
||||||
|
if (lastMountpoint) {
|
||||||
|
Path* np = new Path;
|
||||||
|
PathElement* current = lastMountpoint;
|
||||||
|
while (current) {
|
||||||
|
np->append(current->elem);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T RootFSTree::attempt(T(FSTree::*fn)(Path), Path p, T fallback) {
|
||||||
|
FSTree* mp = getLongestMatchingUnder(p);
|
||||||
|
if (mp) {
|
||||||
|
Path* rp = getRemainingPath(p);
|
||||||
|
T r;
|
||||||
|
if (rp) {
|
||||||
|
r = (mp->*fn)(*rp);
|
||||||
|
rp->destroy();
|
||||||
|
} else {
|
||||||
|
r = (mp->*fn)(Path());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RootFSTree::attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b) {
|
||||||
|
FSTree* mp = getLongestMatchingUnder(p);
|
||||||
|
if (mp) {
|
||||||
|
Path* rp = getRemainingPath(p);
|
||||||
|
if (rp) {
|
||||||
|
(mp->*fn)(*rp, b);
|
||||||
|
rp->destroy();
|
||||||
|
} else {
|
||||||
|
(mp->*fn)(Path(), b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RootFSTree::exists(Path p) {
|
||||||
|
return attempt<bool>(&FSTree::exists, p, false);
|
||||||
|
}
|
||||||
|
FSType RootFSTree::type(Path p){
|
||||||
|
return attempt<FSType>(&FSTree::type, p, Directory);
|
||||||
|
}
|
||||||
|
ReadWriter* RootFSTree::open(Path p){
|
||||||
|
return attempt<ReadWriter*>(&FSTree::open, p, 0);
|
||||||
|
}
|
||||||
|
uint32_t RootFSTree::getDentsSize(Path p){
|
||||||
|
return attempt<uint32_t>(&FSTree::getDentsSize, p, 0);
|
||||||
|
}
|
||||||
|
void RootFSTree::getDents(Path p, FSDirectoryListing* buffer){
|
||||||
|
attempt(&FSTree::getDents, p, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RootFSTree::isMountpoint(Path p) {
|
||||||
|
Path* mp = getRemainingPath(p);
|
||||||
|
if (mp->start->next)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void RootFSTree::mount(Path p, FSTree* f) {
|
||||||
|
FSTreeNode* fstn = makeNodeIfNotExist(p);
|
||||||
|
fstn->mountpoint = f;
|
||||||
|
}
|
||||||
|
void RootFSTree::unmount(Path p) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Path createPathFromString(char* s) {
|
||||||
|
Path p;
|
||||||
|
p.start = 0;
|
||||||
|
p.end = 0;
|
||||||
|
|
||||||
|
char* lastPtr = s;
|
||||||
|
uint32_t length = 0;
|
||||||
|
|
||||||
|
char c;
|
||||||
|
while (c=*(s++)) {
|
||||||
|
if (c == '/') {
|
||||||
|
if (length == 0)
|
||||||
|
p.append(PathEntry{length, 0});
|
||||||
|
else
|
||||||
|
p.append(PathEntry{length, lastPtr});
|
||||||
|
lastPtr = s;
|
||||||
|
length = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
if (length)
|
||||||
|
p.append(PathEntry{length, lastPtr});
|
||||||
|
return p;
|
||||||
|
}
|
85
src/kernel/filesystem/fstree.h
Normal file
85
src/kernel/filesystem/fstree.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef FSTREE_H
|
||||||
|
#define FSTREE_H
|
||||||
|
|
||||||
|
#include "../datatypes/linkedlist.h"
|
||||||
|
#include "strings.h"
|
||||||
|
#include "../stdio/readwriter.h"
|
||||||
|
|
||||||
|
struct PathEntry {
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t* path;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const PathEntry& lhs, const PathEntry& rhs);
|
||||||
|
|
||||||
|
using Path = xnoe::linkedlist<PathEntry>;
|
||||||
|
using PathElement = xnoe::linkedlistelem<PathEntry>;
|
||||||
|
|
||||||
|
enum FSType {
|
||||||
|
File,
|
||||||
|
Directory,
|
||||||
|
CharacterDev,
|
||||||
|
BlockDev,
|
||||||
|
NoExist
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSDirectoryEntry {
|
||||||
|
PathEntry path;
|
||||||
|
FSType type;
|
||||||
|
uint32_t sizeBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSDirectoryListing {
|
||||||
|
uint32_t count;
|
||||||
|
FSDirectoryEntry entries[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class FSTreeNode;
|
||||||
|
class FSTree {
|
||||||
|
public:
|
||||||
|
virtual bool exists(Path p);
|
||||||
|
virtual FSType type(Path p);
|
||||||
|
|
||||||
|
virtual ReadWriter* open(Path p);
|
||||||
|
|
||||||
|
virtual uint32_t getDentsSize(Path p);
|
||||||
|
virtual void getDents(Path p, FSDirectoryListing* buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSTreeNode {
|
||||||
|
PathEntry self;
|
||||||
|
xnoe::linkedlist<FSTreeNode*> children;
|
||||||
|
FSTree* mountpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RootFSTree: public FSTree {
|
||||||
|
private:
|
||||||
|
FSTree* getLongestMatchingUnder(Path p);
|
||||||
|
Path* getRemainingPath(Path p);
|
||||||
|
|
||||||
|
FSTreeNode* makeNodeIfNotExist(Path p);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T attempt(T(FSTree::*fn)(Path), Path p, T fallback);
|
||||||
|
void attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b);
|
||||||
|
public:
|
||||||
|
RootFSTree();
|
||||||
|
|
||||||
|
FSTreeNode* node;
|
||||||
|
|
||||||
|
bool isMountpoint(Path p);
|
||||||
|
void mount(Path p, FSTree* f);
|
||||||
|
void unmount(Path p);
|
||||||
|
|
||||||
|
bool exists(Path p) override;
|
||||||
|
FSType type(Path p) override;
|
||||||
|
|
||||||
|
ReadWriter* open(Path p) override;
|
||||||
|
|
||||||
|
uint32_t getDentsSize(Path p) override;
|
||||||
|
void getDents(Path p, FSDirectoryListing* buffer) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
Path createPathFromString(char* s);
|
||||||
|
|
||||||
|
#endif
|
@ -298,8 +298,9 @@ void syscall(frame_struct* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 15: {
|
case 15: {
|
||||||
ReadWriter* file = new FATFileReadWriter(0, esi);
|
ReadWriter* file = Global::kernel->rootfs->open(createPathFromString(esi));
|
||||||
rval = Global::kernel->mapFH(file);
|
if (file)
|
||||||
|
rval = Global::kernel->mapFH(file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/kernel/ioport.cpp
Normal file
19
src/kernel/ioport.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "ioport.h"
|
||||||
|
|
||||||
|
Port::Port(uint16_t a) {
|
||||||
|
this->addr = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Port::readb() {
|
||||||
|
return inb(this->addr);
|
||||||
|
}
|
||||||
|
uint16_t Port::readw() {
|
||||||
|
return inw(this->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Port::writeb(uint8_t d) {
|
||||||
|
outb(this->addr, d);
|
||||||
|
}
|
||||||
|
void Port::writew(uint16_t d) {
|
||||||
|
outw(this->addr, d);
|
||||||
|
}
|
19
src/kernel/ioport.h
Normal file
19
src/kernel/ioport.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef IOPORT_H
|
||||||
|
#define IOPORT_H
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
class Port {
|
||||||
|
private:
|
||||||
|
uint16_t addr;
|
||||||
|
public:
|
||||||
|
Port(uint16_t a);
|
||||||
|
|
||||||
|
uint8_t readb();
|
||||||
|
uint16_t readw();
|
||||||
|
|
||||||
|
void writeb(uint8_t d);
|
||||||
|
void writew(uint16_t d);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -5,6 +5,7 @@
|
|||||||
#include "datatypes/hashtable.h"
|
#include "datatypes/hashtable.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
#include "filesystem/fstree.h"
|
||||||
|
|
||||||
class Kernel : public Process {
|
class Kernel : public Process {
|
||||||
private:
|
private:
|
||||||
@ -20,6 +21,8 @@ public:
|
|||||||
xnoe::linkedlist<Process*> processes;
|
xnoe::linkedlist<Process*> processes;
|
||||||
xnoe::linkedlist<Process*> KBListeners;
|
xnoe::linkedlist<Process*> KBListeners;
|
||||||
|
|
||||||
|
RootFSTree* rootfs;
|
||||||
|
|
||||||
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
|
Kernel(PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base, uint32_t stack);
|
||||||
|
|
||||||
void init_kernel();
|
void init_kernel();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
#include "atapio.h"
|
#include "ata.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "allocate.h"
|
#include "allocate.h"
|
||||||
@ -14,6 +14,9 @@
|
|||||||
#include "datatypes/hashtable.h"
|
#include "datatypes/hashtable.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
#include "filesystem/fstree.h"
|
||||||
|
#include "filesystem/fat16.h"
|
||||||
|
#include "filesystem/devfs.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
init_gdt();
|
init_gdt();
|
||||||
@ -29,7 +32,6 @@ int main() {
|
|||||||
|
|
||||||
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, 0xc1006000);
|
Kernel kernel = Kernel(&kernel_pd, &phys_pm, &virt_pm, 0xc0000000, 0xc1006000);
|
||||||
kernel.init_kernel();
|
kernel.init_kernel();
|
||||||
init_atapio();
|
|
||||||
|
|
||||||
VGAModeTerminal* term = new VGAModeTerminal(0xc07a0000);
|
VGAModeTerminal* term = new VGAModeTerminal(0xc07a0000);
|
||||||
|
|
||||||
@ -44,14 +46,30 @@ int main() {
|
|||||||
|
|
||||||
term->printf("KERNEL OK!\n");
|
term->printf("KERNEL OK!\n");
|
||||||
|
|
||||||
ReadWriter* worldbin = new FATFileReadWriter(0, "etc/world.bin");
|
ReadWriter* atareadwriter = new ATAReadWriter(0, 0);
|
||||||
|
|
||||||
|
uint8_t* buffer = new uint8_t[512];
|
||||||
|
for (int i=0;i<512;i++)
|
||||||
|
buffer[i]=0;
|
||||||
|
uint32_t size = atareadwriter->size();
|
||||||
|
atareadwriter->seek(268*512);
|
||||||
|
atareadwriter->read(512, buffer);
|
||||||
|
|
||||||
|
kernel.rootfs = new RootFSTree();
|
||||||
|
kernel.rootfs->mount(createPathFromString("/dev"), new DevFS());
|
||||||
|
kernel.rootfs->mount(createPathFromString("/"), new FAT16FS(kernel.rootfs->open(createPathFromString("/dev/ata"))));
|
||||||
|
ReadWriter* worldbin = kernel.rootfs->open(createPathFromString("/world.bin"));
|
||||||
uint32_t fh = kernel.mapFH(worldbin);
|
uint32_t fh = kernel.mapFH(worldbin);
|
||||||
|
|
||||||
Process* p1 = kernel.createProcess(fh, term);
|
Process* p1 = kernel.createProcess(fh, term);
|
||||||
|
|
||||||
init_keyboard();
|
init_keyboard();
|
||||||
|
if (worldbin) {
|
||||||
enable_idt();
|
worldbin->seek(0);
|
||||||
|
worldbin->read(512, buffer);
|
||||||
|
worldbin->seek(0);
|
||||||
|
enable_idt();
|
||||||
|
}
|
||||||
|
|
||||||
while (1) asm ("hlt");
|
while (1) asm ("hlt");
|
||||||
}
|
}
|
@ -8,7 +8,7 @@
|
|||||||
#include "datatypes/maybe.h"
|
#include "datatypes/maybe.h"
|
||||||
#include "screenstuff.h"
|
#include "screenstuff.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "atapio.h"
|
#include "ata.h"
|
||||||
|
|
||||||
#include "stdio/readwriter.h"
|
#include "stdio/readwriter.h"
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ void ReadWriter::giveWritePerm(uint32_t PID) {
|
|||||||
|
|
||||||
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
|
uint32_t ReadWriter::read(uint32_t count, uint8_t* buffer){}
|
||||||
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
|
uint32_t ReadWriter::write(uint32_t count, uint8_t* buffer){}
|
||||||
|
uint32_t ReadWriter::seek(uint32_t position){}
|
||||||
uint32_t ReadWriter::size(){}
|
uint32_t ReadWriter::size(){}
|
||||||
|
|
||||||
bool ReadWriter::canRead(uint32_t PID) {
|
bool ReadWriter::canRead(uint32_t PID) {
|
||||||
|
@ -18,6 +18,7 @@ public:
|
|||||||
virtual uint32_t read(uint32_t count, uint8_t* buffer);
|
virtual uint32_t read(uint32_t count, uint8_t* buffer);
|
||||||
virtual uint32_t write(uint32_t count, uint8_t* buffer);
|
virtual uint32_t write(uint32_t count, uint8_t* buffer);
|
||||||
virtual uint32_t size();
|
virtual uint32_t size();
|
||||||
|
virtual uint32_t seek(uint32_t position);
|
||||||
uint32_t getOwner();
|
uint32_t getOwner();
|
||||||
bool canRead(uint32_t PID);
|
bool canRead(uint32_t PID);
|
||||||
bool canWrite(uint32_t PID);
|
bool canWrite(uint32_t PID);
|
||||||
|
8
src/programs/entry.asm
Normal file
8
src/programs/entry.asm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[BITS 32]
|
||||||
|
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
_loop:
|
||||||
|
jmp _loop
|
||||||
|
|
||||||
|
extern main
|
40
src/programs/hello/hello.c
Normal file
40
src/programs/hello/hello.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "common/common.h"
|
||||||
|
|
||||||
|
void readline(int count, char* buffer) {
|
||||||
|
int index = 0;
|
||||||
|
char c;
|
||||||
|
while (index < count) {
|
||||||
|
if (read(1, 1, &c)) {
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
if (c == '\b') {
|
||||||
|
if (index == 0)
|
||||||
|
continue;
|
||||||
|
else {
|
||||||
|
index--;
|
||||||
|
buffer[index] = 0;
|
||||||
|
write(1, 0, &c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = c;
|
||||||
|
write(1, 0, &c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print("Hello, World!\n");
|
||||||
|
char buffer[32];
|
||||||
|
while (1) {
|
||||||
|
for (int i=0; i<32; i++)
|
||||||
|
buffer[i] = 0;
|
||||||
|
print(">>> ");
|
||||||
|
readline(32, buffer);
|
||||||
|
print("You said: ");
|
||||||
|
print(buffer);
|
||||||
|
print("\n\n");
|
||||||
|
}
|
||||||
|
}
|
11
src/programs/userspace.ld
Normal file
11
src/programs/userspace.ld
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
OUTPUT_ARCH(i386:i386)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x20;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
build/programs/entry.o(.text)
|
||||||
|
build/common/common.o(.text)
|
||||||
|
}
|
||||||
|
}
|
283
src/programs/world/world.c
Normal file
283
src/programs/world/world.c
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#include "common/common.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* buffer;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
uint32_t process;
|
||||||
|
uint32_t stdin;
|
||||||
|
uint32_t stdout;
|
||||||
|
} procbuffer;
|
||||||
|
|
||||||
|
void scrollBuffer(char* buf) {
|
||||||
|
for (int y=0; y<56; y++)
|
||||||
|
for (int x=0; x<43; x++)
|
||||||
|
if (y != 55)
|
||||||
|
buf[y*43+x] = buf[(y+1)*43+x];
|
||||||
|
else
|
||||||
|
buf[y*43+x] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToBuf(char c, procbuffer* buf) {
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
if (buf->x > 0)
|
||||||
|
buf->x--;
|
||||||
|
else if (buf->y > 0) {
|
||||||
|
buf->x = 42;
|
||||||
|
buf->y--;
|
||||||
|
}
|
||||||
|
buf->buffer[buf->y*43+buf->x] = ' ';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
buf->buffer[buf->y*43+buf->x++] = c;
|
||||||
|
}
|
||||||
|
if (buf->x == 43) {
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y++;
|
||||||
|
}
|
||||||
|
if (buf->y == 56) {
|
||||||
|
buf->y--;
|
||||||
|
scrollBuffer(buf->buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeCountToBuf(int count, char* c, procbuffer* buf) {
|
||||||
|
while (count--) {
|
||||||
|
writeToBuf(*(c++), buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBuf(procbuffer* buf) {
|
||||||
|
for (int i=0; i<56*43;i++) {
|
||||||
|
buf->buffer[i] = ' ';
|
||||||
|
}
|
||||||
|
buf->x = 0;
|
||||||
|
buf->y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeStrToBuf(char* c, procbuffer* b) {
|
||||||
|
char* s = c;
|
||||||
|
while(*s)
|
||||||
|
writeToBuf(*(s++), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayBuf(procbuffer* b, int dx, int dy) {
|
||||||
|
char pset[9] = "\x1b[00;00H";
|
||||||
|
for (int i=0; i<dy;i++) {
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<dx;i++) {
|
||||||
|
pset[6]++;
|
||||||
|
if (pset[6] == 0x3a) {
|
||||||
|
pset[6] = 0x30;
|
||||||
|
pset[5]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<56; i++) {
|
||||||
|
print(pset);
|
||||||
|
write(43, 0, b->buffer+(43*i));
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurPos(int x, int y) {
|
||||||
|
char pset[9] = "\x1b[00;00H";
|
||||||
|
for (int i=0; i<y;i++) {
|
||||||
|
pset[3]++;
|
||||||
|
if (pset[3] == 0x3a) {
|
||||||
|
pset[3] = 0x30;
|
||||||
|
pset[2]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<x;i++) {
|
||||||
|
pset[6]++;
|
||||||
|
if (pset[6] == 0x3a) {
|
||||||
|
pset[6] = 0x30;
|
||||||
|
pset[5]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(pset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readline(int count, char* buffer) {
|
||||||
|
int index = 0;
|
||||||
|
char c;
|
||||||
|
while (index < count) {
|
||||||
|
if (read(1, 1, &c)) {
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
if (c == '\b') {
|
||||||
|
if (index == 0)
|
||||||
|
continue;
|
||||||
|
else {
|
||||||
|
index--;
|
||||||
|
buffer[index] = 0;
|
||||||
|
write(1, 0, &c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[index++] = c;
|
||||||
|
write(1, 0, &c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strcmp(char* a, char* b) {
|
||||||
|
int index=0;
|
||||||
|
while (a[index])
|
||||||
|
if (a[index] == b[index])
|
||||||
|
index++;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool strcmpcnt(int count, char* a, char* b) {
|
||||||
|
int index=0;
|
||||||
|
while (index < count)
|
||||||
|
if (a[index] == b[index])
|
||||||
|
index++;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
bindToKeyboard();
|
||||||
|
|
||||||
|
char space = ' ';
|
||||||
|
char plus = '+';
|
||||||
|
|
||||||
|
print("\x1b[1;1H");
|
||||||
|
for (int i=0; i < 1000; i++)
|
||||||
|
write(1, 0, &space);
|
||||||
|
print("\x1b[1;1H");
|
||||||
|
|
||||||
|
char* mid = "+ ++ +";
|
||||||
|
char* bottom = "+ +";
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
for (int i=0; i<56;i++)
|
||||||
|
write(90, 0, mid);
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
write(90, 0, bottom);
|
||||||
|
for (int i=0; i<90;i++)
|
||||||
|
write(1, 0, &plus);
|
||||||
|
|
||||||
|
uint32_t program = fopen("/hello.bin");
|
||||||
|
uint32_t p1 = fork(program);
|
||||||
|
uint32_t p1out = bindStdout(p1);
|
||||||
|
uint32_t p1in = bindStdin(p1);
|
||||||
|
fclose(program);
|
||||||
|
program = fopen("/hello.bin");
|
||||||
|
uint32_t p2 = fork(program);
|
||||||
|
uint32_t p2out = bindStdout(p2);
|
||||||
|
uint32_t p2in = bindStdin(p2);
|
||||||
|
fclose(program);
|
||||||
|
|
||||||
|
procbuffer b1 = {
|
||||||
|
.buffer = localalloc(56 * 43),
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.process = p1,
|
||||||
|
.stdin = p1in,
|
||||||
|
.stdout = p1out
|
||||||
|
};
|
||||||
|
|
||||||
|
procbuffer b2 = {
|
||||||
|
.buffer = localalloc(56 * 43),
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.process = p2,
|
||||||
|
.stdin = p2in,
|
||||||
|
.stdout = p2out
|
||||||
|
};
|
||||||
|
|
||||||
|
procbuffer* selectedBuf = &b1;
|
||||||
|
|
||||||
|
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c[128];
|
||||||
|
int succ = 0;
|
||||||
|
if (b1.process)
|
||||||
|
if (succ = read(128, b1.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b1);
|
||||||
|
if (b2.process)
|
||||||
|
if (succ = read(128, b2.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b2);
|
||||||
|
if (read(1, 1, c)) {
|
||||||
|
if (c[0] == ':') {
|
||||||
|
char buf[32] = {0};
|
||||||
|
print("\x1b[59;2H");
|
||||||
|
print(": ");
|
||||||
|
print("\x1b[59;3H");
|
||||||
|
readline(32, buf);
|
||||||
|
if (strcmpcnt(6, buf, "switch")) {
|
||||||
|
if (selectedBuf == &b1) {
|
||||||
|
selectedBuf = &b2;
|
||||||
|
} else {
|
||||||
|
selectedBuf = &b1;
|
||||||
|
}
|
||||||
|
} else if (strcmpcnt(4, buf, "help")) {
|
||||||
|
writeStrToBuf("\n--------\n", selectedBuf);
|
||||||
|
writeStrToBuf(":help\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Displays this message.\n", selectedBuf);
|
||||||
|
writeStrToBuf(":switch\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Switches which process you're using\n", selectedBuf);
|
||||||
|
writeStrToBuf(":kill\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Kills the current process\n", selectedBuf);
|
||||||
|
writeStrToBuf(":load <filename>\n", selectedBuf);
|
||||||
|
writeStrToBuf(" Loads and executes the program <filename>\n", selectedBuf);
|
||||||
|
writeStrToBuf("--------\n", selectedBuf);
|
||||||
|
} else if (strcmpcnt(4, buf, "kill")) {
|
||||||
|
if (selectedBuf->process) {
|
||||||
|
kill(selectedBuf->process);
|
||||||
|
clearBuf(selectedBuf);
|
||||||
|
selectedBuf->process = 0;
|
||||||
|
selectedBuf->stdin = 0;
|
||||||
|
selectedBuf->stdout = 0;
|
||||||
|
if (selectedBuf == &b1) {
|
||||||
|
selectedBuf = &b2;
|
||||||
|
} else {
|
||||||
|
selectedBuf = &b1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmpcnt(4, buf, "load")) {
|
||||||
|
if (!selectedBuf->process) {
|
||||||
|
char* potFn = buf+5;
|
||||||
|
uint32_t fh = fopen(potFn);
|
||||||
|
selectedBuf->process = fork(fh);
|
||||||
|
selectedBuf->stdout = bindStdout(selectedBuf->process);
|
||||||
|
selectedBuf->stdin = bindStdin(selectedBuf->process);
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectedBuf->process)
|
||||||
|
write(1, selectedBuf->stdin, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayBuf(&b1, 2, 2);
|
||||||
|
displayBuf(&b2, 47, 2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user