From da1a2345a95d5c3cce22caead2cd4bcea6c3877d Mon Sep 17 00:00:00 2001 From: Dario48 Date: Thu, 17 Jul 2025 04:37:30 +0200 Subject: [PATCH] adding reference impementation for reading files from fat --- build.zig | 57 +++++++++--- src/reference_implementations/fat.zig | 117 +++++++++++++++++++++++++ src/reference_implementations/test.txt | 3 + 3 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 src/reference_implementations/fat.zig create mode 100644 src/reference_implementations/test.txt diff --git a/build.zig b/build.zig index 712b389..e4051ee 100644 --- a/build.zig +++ b/build.zig @@ -18,16 +18,40 @@ pub fn build(b: *std.Build) void { var floppy = createFloppy(b, "main_floppy.img"); floppy.run = formatFloppyFat12(b, floppy); + var installToFloppy = installImgToFloppy(b, floppy, initramfs, &.{ + NamedFile{ .file = .{ .runFile = kernel }, .name = "::kernel.bin" }, + NamedFile{ .file = .{ .simpleFile = b.path("src/reference_implementations/test.txt") }, .name = "::test.txt" }, + }); + const img_install = b.addInstallBinFile(floppy.obj, "main_floppy.img"); - img_install.step.dependOn(&installImgToFloppy(b, floppy, initramfs, kernel).step); + img_install.step.dependOn(&installToFloppy); b.getInstallStep().dependOn(&img_install.step); + const target = b.standardTargetOptions(.{}); + const fat_reference_mod = b.createModule(.{ + .root_source_file = b.path("src/reference_implementations/fat.zig"), + .target = target, + .link_libc = true, + }); + const run = b.addSystemCommand(&.{ "qemu-system-i386", "-fda" }); run.addFileArg(floppy.obj); const run_step = b.step("run", "run the os in qemu"); run_step.dependOn(&run.step); + + const fat_reference = b.addExecutable(.{ + .root_module = fat_reference_mod, + .name = "fat_reference_implementation", + .use_lld = false, + .use_llvm = false, + }); + + const fat_install = b.addInstallArtifact(fat_reference, .{}); + + const build_references = b.step("references", "build the reference implementations"); + build_references.dependOn(&fat_install.step); } const AddNasmFilesOptions = struct { @@ -43,6 +67,11 @@ const NasmFile = struct { const Floppydisk = NasmFile; +const NamedFile = struct { + file: union(enum) { runFile: NasmFile, simpleFile: std.Build.LazyPath }, + name: []const u8, +}; + fn createFloppy(b: *std.Build, name: []const u8) Floppydisk { const dd = b.addSystemCommand(&.{ "dd", "if=/dev/zero" }); const Floppy = dd.addPrefixedOutputFileArg("of=", name); @@ -63,7 +92,7 @@ fn formatFloppyFat12(b: *std.Build, floppy: Floppydisk) *std.Build.Step.Run { return mkfs; } -fn installImgToFloppy(b: *std.Build, floppy: Floppydisk, bootloader: NasmFile, kernel: NasmFile) *std.Build.Step.Run { +fn installImgToFloppy(b: *std.Build, floppy: Floppydisk, bootloader: NasmFile, additional_files: []const NamedFile) std.Build.Step { const dd = b.addSystemCommand(&.{"dd"}); dd.addPrefixedFileArg("if=", bootloader.obj); dd.addPrefixedFileArg("of=", floppy.obj); @@ -71,14 +100,22 @@ fn installImgToFloppy(b: *std.Build, floppy: Floppydisk, bootloader: NasmFile, k dd.step.dependOn(&floppy.run.step); dd.step.dependOn(&bootloader.run.step); - const mcopy = b.addSystemCommand(&.{"mcopy"}); - mcopy.addPrefixedFileArg("-i", floppy.obj); - mcopy.addFileArg(kernel.obj); - mcopy.addArg("::kernel.bin"); - mcopy.step.dependOn(&dd.step); - mcopy.step.dependOn(&kernel.run.step); - - return mcopy; + var mcopy_step = std.Build.Step.init(.{ .name = "mcopy", .owner = b, .id = .custom }); + mcopy_step.dependOn(&dd.step); + for (additional_files) |f| { + const mcopy = b.addSystemCommand(&.{"mcopy"}); + mcopy.addPrefixedFileArg("-i", floppy.obj); + switch (f.file) { + .runFile => |file| { + mcopy.addFileArg(file.obj); + mcopy_step.dependOn(&file.run.step); + }, + .simpleFile => |file| mcopy.addFileArg(file), + } + mcopy.addArg(f.name); + mcopy_step.dependOn(&mcopy.step); + } + return mcopy_step; } // adapted from https://codeberg.org/raddari/zig-nasm-lib.git diff --git a/src/reference_implementations/fat.zig b/src/reference_implementations/fat.zig new file mode 100644 index 0000000..61d7a0f --- /dev/null +++ b/src/reference_implementations/fat.zig @@ -0,0 +1,117 @@ +const std = @import("std"); + +const Errors = error{ InvalidSyntax, ReadSectors, FileNotFound }; + +var buffer: [1024]u8 = undefined; + +var g_Fat: []u8 = undefined; + +const BootSector = extern struct { + BootJumpInstruction: [3]u8 align(1), + OemIdentifier: [8]u8 align(1), + BytesPerSector: u16 align(1), + SectorsPerCluster: u8 align(1), + ReservedSectors: u16 align(1), + FatCount: u8 align(1), + DirEntryCount: u16 align(1), + TotalSectors: u16 align(1), + MediaDescriptorType: u8 align(1), + SectorsPerFat: u16 align(1), + SectorsPerTrack: u16 align(1), + Heads: u16 align(1), + HiddenSectors: u32 align(1), + LargeSectorCount: u32 align(1), + + // ebr + DriveNumber: u8 align(1), + _Reserved: u8 align(1), + Signature: u8 align(1), + VolumeId: u32 align(1), + VolumeLaber: [11]u8 align(1), + SystemId: [8]u8 align(1), +}; + +var g_BootSector: BootSector = undefined; + +const DirectoryEntry = extern struct { + Name: [11]u8 align(1), + Attributes: u8 align(1), + _Reserved: u8 align(1), + CreatedTimeTenths: u8 align(1), + CreatedTime: u16 align(1), + CreatedDate: u16 align(1), + AccessedDate: u16 align(1), + FirstClusterHigh: u16 align(1), + ModifiedTime: u16 align(1), + ModifiedDate: u16 align(1), + FirstClusterLow: u16 align(1), + Size: u32 align(1), +}; + +var g_RootDirectory: []DirectoryEntry = undefined; + +fn readStruct(reader: *std.fs.File.Reader, T: type) !T { + var ret: [@sizeOf(T)]u8 = undefined; + _ = try reader.*.read(&ret); + return @bitCast(ret); +} + +fn readBootSector(disk: *std.fs.File) !void { + var reader = disk.*.reader(&buffer); + g_BootSector = try readStruct(&reader, BootSector); +} + +fn readSectors(disk: *std.fs.File, lba: u32, count: u32, bufferOut: *[]anyopaque) !void { + const dest: []u8 = try std.heap.smp_allocator.alloc(u8, g_BootSector.BytesPerSector * count); + defer std.heap.smp_allocator.free(dest); + var stream = disk.readerStreaming(&buffer); + try stream.seekTo(lba * g_BootSector.BytesPerSector); + if (try stream.readStreaming(dest) != g_BootSector.BytesPerSector * count) return Errors.ReadSectors; + @memcpy(@as(*[]u8, @ptrCast(bufferOut)).*, dest); +} + +fn readFat(disk: *std.fs.File) !void { + g_Fat = try std.heap.smp_allocator.alloc(u8, g_BootSector.SectorsPerFat * g_BootSector.BytesPerSector); + errdefer std.heap.smp_allocator.free(g_Fat); + try readSectors(disk, g_BootSector.ReservedSectors, g_BootSector.SectorsPerFat, &g_Fat); +} + +fn readRootDirectory(disk: std.fs.File) !void { + const lba: u32 = g_BootSector.ReservedSectors + g_BootSector.SectorsPerFat + g_BootSector.FatCount; + const size: u32 = @sizeOf(DirectoryEntry) * g_BootSector.DirEntryCount; + const sectors: u32 = (size / g_BootSector.BytesPerSector); + if (@rem(size, g_BootSector.BytesPerSector > 0)) + sectors += 1; + + g_RootDirectory = try std.heap.smp_allocator.alloc(DirectoryEntry, sectors * g_BootSector.BytesPerSector); + errdefer std.heap.smp_allocator.free(g_RootDirectory); + try readSectors(disk, lba, sectors, &g_RootDirectory); +} + +fn findFile(name: []const u8) !*DirectoryEntry { + for (g_RootDirectory, 0..) |Entry, i| + if (std.mem.eql(u8, Entry.Name, name)) + return &g_RootDirectory[i]; + return Errors.FileNotFound; +} + +pub fn main() !void { + if (std.os.argv.len < 3) { + std.log.err("syntax: {s} ", .{std.os.argv[0]}); + return Errors.InvalidSyntax; + } + + var disk = try std.fs.cwd().openFileZ(std.os.argv[1], .{ .mode = .read_only }); + + _ = &disk; + try readBootSector(&disk); + + try readFat(&disk); + defer std.heap.smp_allocator.free(g_Fat); + + try readRootDirectory(disk); + defer std.heap.smp_allocator.free(g_RootDirectory); + + const fileEntry = try findFile(std.os.argv[2]); + _ = fileEntry; +} diff --git a/src/reference_implementations/test.txt b/src/reference_implementations/test.txt new file mode 100644 index 0000000..20e13f9 --- /dev/null +++ b/src/reference_implementations/test.txt @@ -0,0 +1,3 @@ +testing file +aabaacaadaaeaafaagaahaaiaajaakaalaamaanaaoaapaaqaaraasaataauaavaawaaxaayaaz +tstngfl