Merge pull request #285 from ZystemOS/feature/fat32-write
Feature/fat32 write
This commit is contained in:
commit
ddbbff8651
19 changed files with 3192 additions and 959 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,3 +13,4 @@
|
|||
# Custom ignore
|
||||
**/mock_framework.zig
|
||||
**/*.ramdisk
|
||||
**/*.img
|
||||
|
|
|
@ -523,8 +523,8 @@ pub const Fat32 = struct {
|
|||
}
|
||||
|
||||
// Valid clusters are 1, 2, 4, 8, 16, 32, 64 and 128
|
||||
if (options.cluster_size < 0 or options.cluster_size > 128 or !std.math.isPowerOfTwo(options.cluster_size)) {
|
||||
log.err("Sectors per cluster is invalid. Must be less then 32 and a power of 2. Found: {}", .{options.cluster_size});
|
||||
if (options.cluster_size < 1 or options.cluster_size > 128 or !std.math.isPowerOfTwo(options.cluster_size)) {
|
||||
log.err("Sectors per cluster is invalid. Must be less then or equal to 128 and a power of 2. Found: {}", .{options.cluster_size});
|
||||
return Error.InvalidOptionValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@ const MemProfile = mem.MemProfile;
|
|||
/// The type of a device.
|
||||
pub const Device = pci.PciDeviceInfo;
|
||||
|
||||
/// The type of the date and time structure.
|
||||
pub const DateTime = rtc.DateTime;
|
||||
|
||||
/// The virtual end of the kernel code.
|
||||
extern var KERNEL_VADDR_END: *u32;
|
||||
|
||||
|
@ -565,10 +568,32 @@ pub fn initTask(task: *Task, entry_point: usize, allocator: *Allocator) Allocato
|
|||
task.stack_pointer = @ptrToInt(&stack.*[kernel_stack_bottom]);
|
||||
}
|
||||
|
||||
///
|
||||
/// Get a list of hardware devices attached to the system.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *Allocator - An allocator for getting the devices
|
||||
///
|
||||
/// Return: []Device
|
||||
/// A list of hardware devices.
|
||||
///
|
||||
/// Error: Allocator.Error
|
||||
/// OutOfMemory - Unable to allocate space the operation.
|
||||
///
|
||||
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
|
||||
return pci.getDevices(allocator);
|
||||
}
|
||||
|
||||
///
|
||||
/// Get the system date and time.
|
||||
///
|
||||
/// Return: DateTime
|
||||
/// The current date and time.
|
||||
///
|
||||
pub fn getDateTime() DateTime {
|
||||
return rtc.getDateTime();
|
||||
}
|
||||
|
||||
///
|
||||
/// Initialise the architecture
|
||||
///
|
||||
|
|
|
@ -24,8 +24,14 @@ const CURRENT_CENTURY: u32 = 2000;
|
|||
/// could report that the CMOS chip is faulty or the battery is dyeing.
|
||||
const CENTURY_REGISTER: bool = false;
|
||||
|
||||
/// The error set that can be returned from some RTC functions.
|
||||
const RtcError = error{
|
||||
/// If setting the rate for interrupts is less than 3 or greater than 15.
|
||||
RateError,
|
||||
};
|
||||
|
||||
/// A structure to hold all the date and time information in the RTC.
|
||||
const DateTime = struct {
|
||||
pub const DateTime = struct {
|
||||
second: u32,
|
||||
minute: u32,
|
||||
hour: u32,
|
||||
|
@ -36,12 +42,6 @@ const DateTime = struct {
|
|||
day_of_week: u32,
|
||||
};
|
||||
|
||||
/// The error set that can be returned from some RTC functions.
|
||||
const RtcError = error{
|
||||
/// If setting the rate for interrupts is less than 3 or greater than 15.
|
||||
RateError,
|
||||
};
|
||||
|
||||
/// The number of ticks that has passed when RTC was initially set up.
|
||||
var ticks: u32 = 0;
|
||||
|
||||
|
@ -145,66 +145,6 @@ fn readRtcRegisters() DateTime {
|
|||
return date_time;
|
||||
}
|
||||
|
||||
///
|
||||
/// Read a stable time from the real time clock registers on the CMOS chip and return a BCD and
|
||||
/// 12 hour converted date and time.
|
||||
///
|
||||
/// Return: DateTime
|
||||
/// The data from the CMOS RTC registers with correct BCD conversions, 12 hour conversions and
|
||||
/// the century added to the year.
|
||||
///
|
||||
fn readRtc() DateTime {
|
||||
var date_time1 = readRtcRegisters();
|
||||
var date_time2 = readRtcRegisters();
|
||||
|
||||
// Use the method: Read the registers twice and check if they are the same so to avoid
|
||||
// inconsistent values due to RTC updates
|
||||
|
||||
var compare = false;
|
||||
|
||||
inline for (@typeInfo(DateTime).Struct.fields) |field| {
|
||||
compare = compare or @field(date_time1, field.name) != @field(date_time2, field.name);
|
||||
}
|
||||
|
||||
while (compare) {
|
||||
date_time1 = readRtcRegisters();
|
||||
date_time2 = readRtcRegisters();
|
||||
|
||||
compare = false;
|
||||
inline for (@typeInfo(DateTime).Struct.fields) |field| {
|
||||
compare = compare or @field(date_time1, field.name) != @field(date_time2, field.name);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert BCD to binary if necessary
|
||||
if (isBcd()) {
|
||||
date_time1.second = bcdToBinary(date_time1.second);
|
||||
date_time1.minute = bcdToBinary(date_time1.minute);
|
||||
// Needs a special calculation because the upper bit is set
|
||||
date_time1.hour = ((date_time1.hour & 0x0F) + (((date_time1.hour & 0x70) / 16) * 10)) | (date_time1.hour & 0x80);
|
||||
date_time1.day = bcdToBinary(date_time1.day);
|
||||
date_time1.month = bcdToBinary(date_time1.month);
|
||||
date_time1.year = bcdToBinary(date_time1.year);
|
||||
if (CENTURY_REGISTER) {
|
||||
date_time1.century = bcdToBinary(date_time1.century);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to add on the century to the year
|
||||
if (CENTURY_REGISTER) {
|
||||
date_time1.year += date_time1.century * 100;
|
||||
} else {
|
||||
date_time1.year += CURRENT_CENTURY;
|
||||
}
|
||||
|
||||
// Convert to 24hr time
|
||||
if (is12Hr(date_time1)) {
|
||||
date_time1.hour = ((date_time1.hour & 0x7F) + 12) % 24;
|
||||
}
|
||||
|
||||
return date_time1;
|
||||
}
|
||||
|
||||
///
|
||||
/// The interrupt handler for the RTC.
|
||||
///
|
||||
|
@ -262,6 +202,66 @@ fn enableInterrupts() void {
|
|||
cmos.writeStatusRegister(cmos.StatusRegister.B, status_b | 0x40, true);
|
||||
}
|
||||
|
||||
///
|
||||
/// Read a stable time from the real time clock registers on the CMOS chip and return a BCD and
|
||||
/// 12 hour converted date and time.
|
||||
///
|
||||
/// Return: DateTime
|
||||
/// The data from the CMOS RTC registers with correct BCD conversions, 12 hour conversions and
|
||||
/// the century added to the year.
|
||||
///
|
||||
pub fn getDateTime() DateTime {
|
||||
var date_time1 = readRtcRegisters();
|
||||
var date_time2 = readRtcRegisters();
|
||||
|
||||
// Use the method: Read the registers twice and check if they are the same so to avoid
|
||||
// inconsistent values due to RTC updates
|
||||
|
||||
var compare = false;
|
||||
|
||||
inline for (@typeInfo(DateTime).Struct.fields) |field| {
|
||||
compare = compare or @field(date_time1, field.name) != @field(date_time2, field.name);
|
||||
}
|
||||
|
||||
while (compare) {
|
||||
date_time1 = readRtcRegisters();
|
||||
date_time2 = readRtcRegisters();
|
||||
|
||||
compare = false;
|
||||
inline for (@typeInfo(DateTime).Struct.fields) |field| {
|
||||
compare = compare or @field(date_time1, field.name) != @field(date_time2, field.name);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert BCD to binary if necessary
|
||||
if (isBcd()) {
|
||||
date_time1.second = bcdToBinary(date_time1.second);
|
||||
date_time1.minute = bcdToBinary(date_time1.minute);
|
||||
// Needs a special calculation because the upper bit is set
|
||||
date_time1.hour = ((date_time1.hour & 0x0F) + (((date_time1.hour & 0x70) / 16) * 10)) | (date_time1.hour & 0x80);
|
||||
date_time1.day = bcdToBinary(date_time1.day);
|
||||
date_time1.month = bcdToBinary(date_time1.month);
|
||||
date_time1.year = bcdToBinary(date_time1.year);
|
||||
if (CENTURY_REGISTER) {
|
||||
date_time1.century = bcdToBinary(date_time1.century);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to add on the century to the year
|
||||
if (CENTURY_REGISTER) {
|
||||
date_time1.year += date_time1.century * 100;
|
||||
} else {
|
||||
date_time1.year += CURRENT_CENTURY;
|
||||
}
|
||||
|
||||
// Convert to 24hr time
|
||||
if (is12Hr(date_time1)) {
|
||||
date_time1.hour = ((date_time1.hour & 0x7F) + 12) % 24;
|
||||
}
|
||||
|
||||
return date_time1;
|
||||
}
|
||||
|
||||
///
|
||||
/// Initialise the RTC.
|
||||
///
|
||||
|
@ -558,7 +558,7 @@ test "readRtc unstable read" {
|
|||
.century = 2000,
|
||||
.day_of_week = 5,
|
||||
};
|
||||
const actual = readRtc();
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ test "readRtc is BCD" {
|
|||
.century = 2000,
|
||||
.day_of_week = 5,
|
||||
};
|
||||
const actual = readRtc();
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ test "readRtc is 12 hours" {
|
|||
.century = 2000,
|
||||
.day_of_week = 5,
|
||||
};
|
||||
const actual = readRtc();
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -371,7 +371,7 @@ test "open valid file" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file1.close();
|
||||
|
@ -401,7 +401,7 @@ test "open fail with invalid flags" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_FILE));
|
||||
|
@ -428,7 +428,7 @@ test "open fail with NoSuchFileOrDir" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
expectError(error.NoSuchFileOrDir, vfs.openFile("/text10.txt", .NO_CREATION));
|
||||
expectError(error.NoSuchFileOrDir, vfs.openDir("/temp/", .NO_CREATION));
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ test "open a file, out of memory" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, &fa.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
expectError(error.OutOfMemory, vfs.openFile("/test1.txt", .NO_CREATION));
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ test "open two of the same file" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
const file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file1.close();
|
||||
|
@ -482,7 +482,7 @@ test "close a file" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
|
||||
|
@ -514,7 +514,7 @@ test "close a non-opened file" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
// Open a valid file
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
|
@ -541,7 +541,7 @@ test "read a file" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file1.close();
|
||||
|
@ -565,7 +565,7 @@ test "read a file, invalid/not opened/crafted *const Node" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
// Open a valid file
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
|
@ -594,7 +594,7 @@ test "write does nothing" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
vfs.setRoot(fs.root_node);
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
// Open a valid file
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
|
@ -663,7 +663,9 @@ fn rt_openReadClose(allocator: *Allocator) void {
|
|||
fn runtimeTests(rd_fs: *InitrdFS) void {
|
||||
// There will be test files provided for the runtime tests
|
||||
// Need to init the VFS. This will be overridden after the tests.
|
||||
vfs.setRoot(rd_fs.root_node);
|
||||
vfs.setRoot(rd_fs.root_node) catch |e| {
|
||||
panic(@errorReturnTrace(), "Ramdisk root node isn't a directory node: {}\n", .{e});
|
||||
};
|
||||
rt_openReadClose(rd_fs.allocator);
|
||||
if (rd_fs.opened_files.count() != 0) {
|
||||
panic(@errorReturnTrace(), "FAILURE: Didn't close all files\n", .{});
|
||||
|
|
|
@ -488,7 +488,7 @@ pub fn openDir(path: []const u8, flags: OpenFlags) (Allocator.Error || Error)!*D
|
|||
file.close();
|
||||
break :blk Error.IsAFile;
|
||||
},
|
||||
// We instructed open to folow symlinks above, so this is impossible
|
||||
// We instructed open to follow symlinks above, so this is impossible
|
||||
.Symlink => unreachable,
|
||||
.Dir => &node.Dir,
|
||||
};
|
||||
|
@ -499,7 +499,7 @@ pub fn openDir(path: []const u8, flags: OpenFlags) (Allocator.Error || Error)!*D
|
|||
///
|
||||
/// Arguments:
|
||||
/// IN path: []const u8 - The path to open. Must be absolute (see isAbsolute)
|
||||
/// IN tareget: ?[]const u8 - The target to use when creating the symlink. Can be null if .NO_CREATION is used as the open flag
|
||||
/// IN target: ?[]const u8 - The target to use when creating the symlink. Can be null if .NO_CREATION is used as the open flag
|
||||
/// IN flags: OpenFlags - The flags specifying if this node should be created if it doesn't exist. Cannot be CREATE_FILE
|
||||
///
|
||||
/// Return: []const u8
|
||||
|
@ -552,7 +552,13 @@ pub fn isAbsolute(path: []const u8) bool {
|
|||
/// Arguments:
|
||||
/// IN node: *Node - The node to initialise the root node.
|
||||
///
|
||||
pub fn setRoot(node: *Node) void {
|
||||
/// Error: Error
|
||||
/// Error.NotADirectory - The node isn't a directory node.
|
||||
///
|
||||
pub fn setRoot(node: *Node) Error!void {
|
||||
if (!node.isDir()) {
|
||||
return Error.NotADirectory;
|
||||
}
|
||||
root = node;
|
||||
}
|
||||
|
||||
|
@ -972,8 +978,8 @@ test "read" {
|
|||
testing.expectEqual(test_link, "/foo.txt");
|
||||
var link_file = try openFile("/link", .NO_CREATION);
|
||||
{
|
||||
const length = try link_file.read(buffer[0..0]);
|
||||
testing.expect(std.mem.eql(u8, str[0..0], buffer[0..length]));
|
||||
const length = try link_file.read(buffer[0..]);
|
||||
testing.expect(std.mem.eql(u8, str[0..], buffer[0..length]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,9 @@ export fn kmain(boot_payload: arch.BootPayload) void {
|
|||
};
|
||||
|
||||
// Need to init the vfs after the ramdisk as we need the root node from the ramdisk filesystem
|
||||
vfs.setRoot(ramdisk_filesystem.root_node);
|
||||
vfs.setRoot(ramdisk_filesystem.root_node) catch |e| {
|
||||
panic_root.panic(@errorReturnTrace(), "Ramdisk root node isn't a directory node: {}\n", .{e});
|
||||
};
|
||||
}
|
||||
|
||||
scheduler.init(&kernel_heap.allocator, &mem_profile) catch |e| {
|
||||
|
|
1
test/fat32/test_files/file~a.txt
Normal file
1
test/fat32/test_files/file~a.txt
Normal file
|
@ -0,0 +1 @@
|
|||
file~a.txt
|
1
test/fat32/test_files/folder1/file1.txt
Normal file
1
test/fat32/test_files/folder1/file1.txt
Normal file
|
@ -0,0 +1 @@
|
|||
file1.txt
|
1
test/fat32/test_files/folder1/folder2/file2.txt
Normal file
1
test/fat32/test_files/folder1/folder2/file2.txt
Normal file
|
@ -0,0 +1 @@
|
|||
file2.txt
|
1
test/fat32/test_files/folder1/folder2/folder3/file3.txt
Normal file
1
test/fat32/test_files/folder1/folder2/folder3/file3.txt
Normal file
|
@ -0,0 +1 @@
|
|||
file3.txt
|
|
@ -0,0 +1 @@
|
|||
file4.txt
|
|
@ -0,0 +1 @@
|
|||
file5.txt
|
|
@ -0,0 +1 @@
|
|||
file6.txt
|
|
@ -0,0 +1 @@
|
|||
file7.txt
|
|
@ -0,0 +1 @@
|
|||
file8.txt
|
|
@ -0,0 +1 @@
|
|||
file9.txt
|
|
@ -10,10 +10,19 @@ const paging = @import("paging_mock.zig");
|
|||
const Serial = @import("../../../src/kernel/serial.zig").Serial;
|
||||
const TTY = @import("../../../src/kernel/tty.zig").TTY;
|
||||
const Keyboard = @import("../../../src/kernel/keyboard.zig").Keyboard;
|
||||
|
||||
pub const task = @import("../../../src/kernel/task.zig");
|
||||
const task = @import("../../../src/kernel/task.zig");
|
||||
|
||||
pub const Device = pci.PciDeviceInfo;
|
||||
pub const DateTime = struct {
|
||||
second: u32,
|
||||
minute: u32,
|
||||
hour: u32,
|
||||
day: u32,
|
||||
month: u32,
|
||||
year: u32,
|
||||
century: u32,
|
||||
day_of_week: u32,
|
||||
};
|
||||
|
||||
const mock_framework = @import("mock_framework.zig");
|
||||
pub const initTest = mock_framework.initTest;
|
||||
|
@ -151,10 +160,25 @@ pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
|
|||
return &[_]Device{};
|
||||
}
|
||||
|
||||
pub fn getDateTime() DateTime {
|
||||
// TODO: Use the std lib std.time.timestamp() and convert
|
||||
// Hard code 12:12:13 12/12/12 for testing
|
||||
return .{
|
||||
.second = 13,
|
||||
.minute = 12,
|
||||
.hour = 12,
|
||||
.day = 12,
|
||||
.month = 12,
|
||||
.year = 2012,
|
||||
.century = 2000,
|
||||
.day_of_week = 4,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(mem_profile: *const MemProfile) void {
|
||||
// I'll get back to this as this doesn't effect the current testing.
|
||||
// When I come on to the mem.zig testing, I'll fix :)
|
||||
//return mock_framework.performAction("init", void, mem_profile, allocator);
|
||||
//return mock_framework.performAction("init", void, mem_profile);
|
||||
}
|
||||
|
||||
// User defined mocked functions
|
||||
|
|
Loading…
Reference in a new issue