diff --git a/codes.zig b/codes.zig index f59be0a..e25d5b7 100644 --- a/codes.zig +++ b/codes.zig @@ -1,5 +1,5 @@ // ┌────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: codes.zig │ +// │ (c) 2026 Linuxperoxo • FILE: codes.zig │ // │ Author: Linuxperoxo │ // └────────────────────────────────────────────┘ diff --git a/config/modules/menuconfig.zig b/config/modules/menuconfig.zig index 7ca286e..5e864a7 100644 --- a/config/modules/menuconfig.zig +++ b/config/modules/menuconfig.zig @@ -9,4 +9,5 @@ pub const Load_T: type = @import("types.zig").Load_T; pub const ModulesSelection: Menuconfig_T = .{ .ke_m_rootfs = .yes, .ke_m_devfs = .yes, + .ke_m_fb = .yes, }; diff --git a/config/modules/types.zig b/config/modules/types.zig index e33be52..ce3335d 100644 --- a/config/modules/types.zig +++ b/config/modules/types.zig @@ -11,4 +11,5 @@ pub const Load_T: type = enum { pub const Menuconfig_T: type = struct { ke_m_rootfs: Load_T, ke_m_devfs: Load_T, + ke_m_fb: Load_T, }; diff --git a/drivers/video/fb/vga/config.zig b/drivers/video/fb/vga/config.zig new file mode 100644 index 0000000..0eb0553 --- /dev/null +++ b/drivers/video/fb/vga/config.zig @@ -0,0 +1,8 @@ +// ┌─────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: config.zig │ +// │ Author: Linuxperoxo │ +// └─────────────────────────────────────────────┘ + +const types: type = @import("types.zig"); + +pub const VideoVendor: types.ConfigVendors_T = .qemu; diff --git a/drivers/video/fb/vga/device.zig b/drivers/video/fb/vga/device.zig new file mode 100644 index 0000000..e5db52a --- /dev/null +++ b/drivers/video/fb/vga/device.zig @@ -0,0 +1,25 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: device.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const devices: type = @import("root").interfaces.devices; +const ops: type = @import("ops.zig"); + +pub var fb_device: devices.Dev_T = .{ + .name = "fb", + .type = .char, + .ops = &fb_device_ops, + .flags = .{ + .control = .{ + .minor = 0, + .max = 0, + }, + }, +}; + +pub const fb_device_ops: devices.DevOps_T = .{ + .write = &ops.write, + .read = &ops.read, + .ioctl = &ops.ioctl, +}; diff --git a/drivers/video/fb/vga/fb.zig b/drivers/video/fb/vga/fb.zig new file mode 100644 index 0000000..9796077 --- /dev/null +++ b/drivers/video/fb/vga/fb.zig @@ -0,0 +1,81 @@ +// ┌─────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: fb.zig │ +// │ Author: Linuxperoxo │ +// └─────────────────────────────────────────────┘ + +const devices: type = @import("root").interfaces.devices; +const module: type = @import("root").interfaces.module; +const device: type = @import("device.zig"); +const ops: type = @import("ops.zig"); +const vfs: type = @import("root").interfaces.vfs; +const devfs: type = __SaturnModuleDescription__.request_lib("devfs-operations").?; + +pub const __SaturnModuleDescription__: module.ModuleDescription_T = .{ + .mod = &vga_fb, + .load = .linkable, + .arch = &[_]module.ModuleDescriptionTarget_T { + .i386, + }, + .libs = .{ + .outside = &[_]module.ModuleDescriptionLibOut_T { + module.ModuleDescriptionLibOut_T { + .mod = "ke_m_devfs", + .lib = "devfs-operations", + .version = .{ + .current = {}, + }, + .flags = .{ + .required = 1, + }, + }, + }, + }, +}; + +const vga_fb: module.Mod_T = .{ + .name = "ke_m_fb", + .desc = "Core Kernel VGA Framebuffer", + .author = "Linuxperoxo", + .version = "0.1.0", + .license = .GPL2_only, + .type = .driver, + .deps = &[_][]const u8 { + "ke_m_devfs" + }, + .init = &init, + .exit = &exit, + .control = &vga_control, +}; + +var vga_control: module.ModControlFlags_T = .{ + .init = 1, + .exit = 1, + .remove = 1, + .anon = 1, +}; + +var major: devices.Major_T = undefined; + +fn init() anyerror!void { + major = + try devices.next_major(); + try devices.dev_add(major, &device.fb_device); + + errdefer devices.dev_rm(major, &device.fb_device) catch unreachable; + try ops.set_video_physio(); + + try devfs.create_device_node(major, 0, 0, 0, vfs.mode_T { + .owner = vfs.R | vfs.W, + .group = vfs.R | vfs.W, + .other = 0, + }); +} + +fn exit() anyerror!void { + errdefer { + // klog() + } + try module.rmmod(&vga_fb); + try devices.dev_rm(major, &device.fb_device); + ops.unset_video_physio(); +} diff --git a/drivers/video/fb/vga/ops.zig b/drivers/video/fb/vga/ops.zig new file mode 100644 index 0000000..57b55be --- /dev/null +++ b/drivers/video/fb/vga/ops.zig @@ -0,0 +1,82 @@ +// ┌─────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: ops.zig │ +// │ Author: Linuxperoxo │ +// └─────────────────────────────────────────────┘ + +const phys: type = @import("root").ar.target_code.physio; +const config: type = @import("config.zig"); +const types: type = @import("types.zig"); +const devices: type = @import("root").interfaces.devices; + +pub var pci_physio_video: ?*phys.PhysIo_T = null; + +// ===================== AUX + +pub inline fn set_video_physio() types.FbErr_T!void { + pci_physio_video = phys.physio_search(.{ + .identified = .{ + .class = .display, + .vendor = switch(comptime config.VideoVendor) { + .qemu => .qemu, + .amd => .amd, + .intel => .intel, + .nvidia => .nvidia, + }, + }, + }) catch return types.FbErr_T.ExpectNoNFound; + // map bars to virtual +} + +pub inline fn unset_video_physio() void { + pci_physio_video = null; +} + +pub inline fn check_video_physio() types.FbErr_T!void { + if(pci_physio_video == null + or pci_physio_video.?.status == .missing) return types.FbErr_T.MissingDevice; +} + +// ===================== OPS + +pub noinline fn write(_: devices.Minor_T, data: []const u8, offset: usize) types.FbErr_T!void { + try check_video_physio(); + _ = data; + _ = offset; +} + +pub noinline fn read(_: devices.Minor_T, offset: usize) types.FbErr_T![]u8 { + try check_video_physio(); + _ = offset; + return @constCast("Hello, World!"); // NOTE: TEST +} + +pub noinline fn ioctl(_: devices.Minor_T, command: usize, data: ?*anyopaque) types.FbErr_T!usize { + try check_video_physio(); + return sw: switch(@as(types.FbCommands_T, @enumFromInt(command))) { + .color => { + if(data == null) break :sw types.FbErr_T.UnexpectedData; + unreachable; + }, + + .move => { + if(data == null) break :sw types.FbErr_T.UnexpectedData; + unreachable; + }, + + .put => { + if(data == null) break :sw types.FbErr_T.UnexpectedData; + unreachable; + }, + + .load => { + if(data == null) break :sw types.FbErr_T.UnexpectedData; + unreachable; + }, + + .clear => { + break :sw 0; + }, + + _ => types.FbErr_T.InvalidCommand, + }; +} diff --git a/drivers/video/fb/vga/types.zig b/drivers/video/fb/vga/types.zig new file mode 100644 index 0000000..219dfdd --- /dev/null +++ b/drivers/video/fb/vga/types.zig @@ -0,0 +1,27 @@ +// ┌─────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: types.zig │ +// │ Author: Linuxperoxo │ +// └─────────────────────────────────────────────┘ + +pub const ConfigVendors_T: type = enum { + nvidia, + qemu, + intel, + amd, +}; + +pub const FbErr_T: type = error { + ExpectNoNFound, + InvalidCommand, + UnexpectedData, + MissingDevice, +}; + +pub const FbCommands_T: type = enum(usize) { + color = 0x80, + clear = 0x70, + move = 0x60, + put = 0x50, + load = 0x40, + _, +}; diff --git a/fs/devfs/allocator.zig b/fs/devfs/allocator.zig new file mode 100644 index 0000000..ce16927 --- /dev/null +++ b/fs/devfs/allocator.zig @@ -0,0 +1,10 @@ +// ┌──────────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: allocator.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────────┘ + +const buildByteAllocator = @import("root").lib.memory.sba.buildByteAllocator; + +pub const sba: type = struct { + pub var allocator = buildByteAllocator(null, .{}) {}; +}; diff --git a/fs/devfs/aux.zig b/fs/devfs/aux.zig new file mode 100644 index 0000000..fc73e5d --- /dev/null +++ b/fs/devfs/aux.zig @@ -0,0 +1,65 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: aux.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const vfs: type = @import("root").interfaces.vfs; +const types: type = @import("types.zig"); +const allocator: type = @import("allocator.zig"); +const dfs: type = @import("fs.zig"); +const devices: type = @import("root").interfaces.devices; +const fmt: type = @import("root").lib.utils.fmt; + +pub inline fn check_init(dev_list: *types.DevfsList_T) types.DevfsListErr_T!void { + if(!dev_list.is_initialized()) + try dev_list.init(&allocator.sba.allocator); +} + +pub inline fn dentry_device_info(dentry: *vfs.Dentry_T) types.DevfsErr_T!*const types.DevfsPrivate_T { + if(dentry.d_private == null) + return types.DevfsErr_T.CorruptDentry; + return @ptrCast(@alignCast(dentry.d_private.?)); +} + +var inode_count: usize = 0; +pub inline fn new_dentry_device(major: devices.Major_T, minor: devices.Minor_T, uid: vfs.uid_T, gid: vfs.gid_T, mode: vfs.mode_T) anyerror!*vfs.Dentry_T { + const new_dentry: *vfs.Dentry_T = &(try allocator.sba.allocator.alloc(vfs.Dentry_T, 1))[0]; + errdefer allocator.sba.allocator.free(new_dentry) catch unreachable; + + const new_device_node: *types.DevfsPrivate_T = &(try allocator.sba.allocator.alloc(types.DevfsPrivate_T, 1))[0]; + errdefer allocator.sba.allocator.free(new_device_node) catch unreachable; + + const new_device_inode: *vfs.Inode_T = &(try allocator.sba.allocator.alloc(vfs.Inode_T, 1))[0]; + errdefer allocator.sba.allocator.free(new_device_inode) catch unreachable; + + const new_device_name: []u8 = try fmt.format(&allocator.sba.allocator, "{s}{d}", .{ + devices.dev_info(major, .name) catch unreachable, + minor, + }); + + new_dentry.* = .{ + .d_name = new_device_name, + .d_inode = new_device_inode, + .d_op = &dfs.devfs_ops, + .d_sblock = null, + .d_private = new_device_node, + .child = null, + .parent = null, + .older_brother = null, + .younger_brother = null, + }; + + new_device_inode.* = .{ + .uid = uid, + .gid = gid, + .mode = mode, + .nlinks = 0, + .inode = inode_count, + .type = .char, + .data_block = @intFromPtr(new_dentry), + .data_inode = @intFromPtr(new_dentry), + }; + + inode_count += 1; + return new_dentry; +} diff --git a/fs/devfs/devfs.zig b/fs/devfs/devfs.zig new file mode 100644 index 0000000..5772696 --- /dev/null +++ b/fs/devfs/devfs.zig @@ -0,0 +1,116 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: devfs.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const ops: type = @import("ops.zig"); +const module: type = @import("root").interfaces.module; +const fs: type = @import("root").interfaces.fs; +const vfs: type = @import("root").interfaces.vfs; +const dfs: type = @import("fs.zig"); +const libs: type = @import("libs.zig"); + +const Mod_T: type = module.Mod_T; +const ModControlFlags_T: type = module.ModControlFlags_T; +const ModErr_T: type = module.ModErr_T; +const ModuleDescription_T: type = module.ModuleDescription_T; +const ModuleDescriptionTarget_T: type = module.ModuleDescriptionTarget_T; +const ModuleDescriptionLibMine_T: type = module.ModuleDescriptionLibMine_T; +const ModuleDescriptionLibOut_T: type = module.ModuleDescriptionLibOut_T; + +pub const create_device_node = ops.create_device_node; + +pub const __SaturnModuleDescription__: ModuleDescription_T = .{ + .mod = &devfs, + .panic = true, + .load = .linkable, + .arch = &[_]ModuleDescriptionTarget_T { + .i386, + .amd64, + .arm, + .avr, + .riscv64, + .xtensa, + }, + .libs = .{ + .mines = &[_]module.ModuleDescriptionLibMine_T { + module.ModuleDescriptionLibMine_T { + .name = "devfs-operations", + .stable = 0, + .current = 0, + .whitelist = null, + .m_types = &[_]module.ModType_T { + .driver, + .filesystem, + }, + .versions = &[_]module.ModuleDescriptionLibMine_T.Version_T { + module.ModuleDescriptionLibMine_T.Version_T { + .tag = "1.0.0", + .lib = @field(libs, "devfs-operations-1.0.0"), + .flags = .{ + .enable = 1, + }, + }, + }, + .flags = .{ + .enable = 1, + .whitelist = 0, + }, + }, + }, + .outside = null, + }, +}; + +pub const devfs: Mod_T = .{ + .name = "ke_m_devfs", + .desc = "Core Kernel Devices Filesystem", + .author = "Linuxperoxo", + .version = "0.1.0", + .license = .GPL2_only, + .type = .filesystem, + .deps = &[_][]const u8{ + "ke_m_rootfs", + }, + .init = &init, + .exit = &exit, + .control = &devfs_control, +}; + +pub var devfs_control: ModControlFlags_T = .{ + .init = 1, + .exit = 0, + .remove = 0, + .anon = 0, +}; + +fn init() anyerror!void { + try fs.register_fs(&dfs.devfs); + + vfs.touch("/dev", null) catch |err| switch(err) { + vfs.VfsErr_T.NoNFound => { + try vfs.mkdir("/", "dev", null, 0, 0, .{ + .owner = vfs.R | vfs.W, + .group = vfs.R, + .other = vfs.R, + }); + + }, + + else => return err, + }; + + errdefer fs.unregister_fs(&dfs.devfs) catch {}; + try vfs.mount("/dev", null, "devfs"); + + dfs.devfs.flags.control = .{ + .anon = 1, + .nomount = 0, + .noumount = 1, + .readonly = 0, + }; +} + +fn exit() anyerror!void { + unreachable; +} diff --git a/fs/devfs/fs.zig b/fs/devfs/fs.zig new file mode 100644 index 0000000..c332327 --- /dev/null +++ b/fs/devfs/fs.zig @@ -0,0 +1,45 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: fs.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const fs: type = @import("root").interfaces.fs; +const vfs: type = @import("root").interfaces.vfs; +const ops: type = @import("ops.zig"); +const types: type = @import("types.zig"); + +pub var devfs: fs.Fs_T = .{ + .name = "devfs", + .mount = ops.devfs_mount, + .umount = ops.devfs_umount, + .flags = .{ + .control = .{ + .nomount = 0, + .noumount = 0, + .readonly = 0, + .anon = 0, + }, + .internal = .{}, + }, +}; + +pub var devfs_superblock: vfs.Superblock_T = .{ + .magic = 0x703, + .block_size = 0, + .total_blocks = 0, + .total_inodes = 0, + .inode_table_start = 0, + .data_block_start = 0, + .private_data = null, + .inode_op = @constCast(&devfs_ops), + .fs = &devfs, +}; + +pub var devfs_ops: vfs.InodeOp_T = .{ + .write = ops.write, + .read = ops.read, + .chmod = ops.chmod, + .chown = ops.chown, + .ioctl = ops.ioctl, + .lookup = ops.lookup, +}; diff --git a/kernel/core/devices/memory.zig b/fs/devfs/libs.zig similarity index 57% rename from kernel/core/devices/memory.zig rename to fs/devfs/libs.zig index 42f6bc0..6b7c4c0 100644 --- a/kernel/core/devices/memory.zig +++ b/fs/devfs/libs.zig @@ -1,9 +1,11 @@ // ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: memory.zig │ +// │ (c) 2026 Linuxperoxo • FILE: libs.zig │ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -pub const SOA: type = switch(@import("builtin").is_test) { - true => @import("test/SOA/SOA.zig"), - false => @import("root").memory.SOA, +const ops: type = @import("ops.zig"); + +pub const @"devfs-operations-1.0.0": type = opaque { + pub const create_device_node = ops.create_device_node; + pub const unlink_device_node = ops.unlink_device_node; }; diff --git a/fs/devfs/main.zig b/fs/devfs/main.zig deleted file mode 100644 index a6d42bd..0000000 --- a/fs/devfs/main.zig +++ /dev/null @@ -1,31 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: main.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Dentry_T: type = @import("root").interfaces.vfs.Dentry_T; -const Superblock_T: type = @import("root").interfaces.vfs.Superblock_T; -const FileType_T: type = @import("root").interfaces.vfs.FileType_T; -const InodeOp_T: type = @import("root").interfaces.vfs.InodeOp_T; -const Inode_T: type = @import("root").interfaces.vfs.Inode_T; -const VfsErr_T: type = @import("root").interfaces.vfs.VfsErr_T; -const FsErr_T: type = @import("root").interfaces.fs.FsErr_T; - -const rootfsSuperblock: *Superblock_T = @constCast(&Superblock_T { - .magic = 0x703, - .block_size = 0, - .total_blocks = 0, - .total_inodes = 0, - .inode_table_start = 0, - .data_block_start = 0, - .root_inode = null, - .private_data = null, -}); - -pub fn devfs_mount() anyerror!*const Superblock_T { - return error.InternalError; -} - -pub fn devfs_umount() anyerror!void { - return error.InternalError; -} diff --git a/fs/devfs/module.zig b/fs/devfs/module.zig deleted file mode 100644 index 1337c1b..0000000 --- a/fs/devfs/module.zig +++ /dev/null @@ -1,119 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: module.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Mod_T: type = @import("root").interfaces.module.Mod_T; -const ModErr_T: type = @import("root").interfaces.module.ModErr_T; -const ModuleDescription_T: type = @import("root").interfaces.module.ModuleDescription_T; -const ModuleDescriptionTarget_T: type = @import("root").interfaces.module.ModuleDescriptionTarget_T; -const ModuleDescriptionLibMine_T: type = @import("root").interfaces.module.ModuleDescriptionLibMine_T; -const ModuleDescriptionLibOut_T: type = @import("root").interfaces.module.ModuleDescriptionLibOut_T; - -const Fs_T: type = @import("root").interfaces.fs.Fs_T; - -const inmod = @import("root").interfaces.module.inmod; -const rmmod = @import("root").interfaces.module.rmmod; - -const devfs_mount = &@import("main.zig").devfs_mount; -const devfs_umount = &@import("main.zig").devfs_umount; - -pub const __SaturnModuleDescription__: ModuleDescription_T = .{ - .name = "ke_m_devfs", - .load = .linkable, - .init = &init, - .after = &after, - .deps = &[_][]const u8 { - "ke_m_rootfs" - }, - .type = .{ - .filesystem = .{ - .compile = .{ - .name = "ke_m_devfs", - .mountpoint = "/dev", - }, - } - }, - .arch = &[_]ModuleDescriptionTarget_T { - .i386, - .amd64, - .arm, - .avr, - .riscv64, - .xtensa, - }, - .flags = .{ - .call = .{ - .handler = 1, - .after = 1, - }, - }, - .libs = .{ - .mines = null, - .outside = null, - }, -}; - -var devfs: Mod_T = .{ - .name = __SaturnModuleDescription__.name, - .desc = "Core Kernel Devices Filesystem", - .author = "Linuxperoxo", - .version = "0.1.0", - .deps = __SaturnModuleDescription__.deps, - .license = .GPL2_only, - .type = .filesystem, - .init = &init, - .after = null, - .exit = &exit, - .private = .{ - .filesystem = .{ - .name = "devfs", - .mount = devfs_mount, - .umount = devfs_umount, - .flags = .{ - .control = .{ - .nomount = 0, - .noumount = 1, - .readonly = 0, - .anon = 0, - }, - .internal = .{}, - }, - }, - }, - .flags = .{ - .control = .{ - .anon = 0, - .call = .{ - .exit = 0, - .remove = 0, - .after = 0, - .init = 0, - .handler = .{ - .install = 1, - .remove = 1, - }, - }, - }, - .internal = .{}, - }, -}; - -fn init() ModErr_T!void { - return @call(.never_inline, inmod, .{ - &devfs - }); -} - -fn after() ModErr_T!void { - if(devfs.flags.check_op_status(.init) == 0) { - // klog() - } - devfs.flags.control.anon = 1; -} - -fn exit() ModErr_T!void { - return @call(.never_inline, rmmod, .{ - &devfs - }); -} diff --git a/fs/devfs/ops.zig b/fs/devfs/ops.zig new file mode 100644 index 0000000..07cdb85 --- /dev/null +++ b/fs/devfs/ops.zig @@ -0,0 +1,103 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: ops.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const vfs: type = @import("root").interfaces.vfs; +const kfs: type = @import("root").interfaces.fs; +const mem: type = @import("root").lib.utils.mem; +const fmt: type = @import("root").lib.utils.fmt; +const dfs: type = @import("fs.zig"); +const aux: type = @import("aux.zig"); +const types: type = @import("types.zig"); +const devices: type = @import("root").interfaces.devices; +const allocator: type = @import("allocator.zig"); + +const Dentry_T: type = vfs.Dentry_T; +const Superblock_T: type = vfs.Superblock_T; +const FileType_T: type = vfs.FileType_T; +const InodeOp_T: type = vfs.InodeOp_T; +const Inode_T: type = vfs.Inode_T; +const VfsErr_T: type = vfs.VfsErr_T; +const mode_T: type = vfs.mode_T; +const uid_T: type = vfs.uid_T; +const gid_T: type = vfs.gid_T; + +const Fs_T: type = kfs.Fs_T; +const FsErr_T: type = kfs.FsErr_T; + +var devices_list: types.DevfsList_T = .{}; + +pub fn devfs_mount() anyerror!*const Superblock_T { + dfs.devfs_superblock.private_data = &devices_list; + return &dfs.devfs_superblock; +} + +pub fn devfs_umount() anyerror!void { + return error.InternalError; +} + +pub fn write(dentry: *Dentry_T, src: []const u8, offset: usize) anyerror!void { + const dev: *const types.DevfsPrivate_T = try aux.dentry_device_info(dentry); + return devices.write(dev.major, dev.minor, src, offset); +} + +pub fn read(dentry: *Dentry_T, offset: usize) anyerror![]u8 { + const dev: *const types.DevfsPrivate_T = try aux.dentry_device_info(dentry); + return devices.read(dev.major, dev.minor, offset); +} + +pub fn chmod(dentry: *Dentry_T, mode: mode_T) anyerror!void { + dentry.d_inode.?.mode = mode; +} + +pub fn chown(dentry: *Dentry_T, uid: uid_T, gid: gid_T) anyerror!void { + dentry.d_inode.?.uid = uid; + dentry.d_inode.?.gid = gid; +} + +pub fn ioctl(dentry: *Dentry_T, command: usize, data: *anyopaque) anyerror!usize { + const dev: *const types.DevfsPrivate_T = try aux.dentry_device_info(dentry); + return devices.ioctl(dev.major, dev.minor, command, data); +} + +pub fn lookup(parent: *Dentry_T, child: []const u8) anyerror!*Dentry_T { + if(parent.d_sblock == null + or parent.d_sblock.?.private_data == null + or @as(@TypeOf(&devices_list), @ptrCast(@alignCast(parent.d_sblock.?.private_data.?))) != &devices_list) return types.DevfsErr_T.CorruptFilesystem; + + if(!devices_list.is_initialized()) + return types.DevfsErr_T.DeviceNoFound; + + return devices_list.iterator_handler(child, &opaque { + pub fn handler(device_dentry: *Dentry_T, device_target_name: @TypeOf(child)) anyerror!void { + if(!mem.eql(device_dentry.d_name, device_target_name, .{})) + return error.Continue; + } + }.handler) catch |err| return switch(err) { + types.DevfsListErr_T.EndOfIterator => types.DevfsErr_T.DeviceNoFound, + else => types.DevfsErr_T.ListOperationFailed, + }; +} + +pub fn create_device_node(major: devices.Major_T, minor: devices.Minor_T, uid: uid_T, gid: gid_T, mode: mode_T) anyerror!void { + if(!devices.valid_major(major)) return types.DevfsErr_T.InvalidMajor; + if(!devices.valid_minor(major, minor)) return types.DevfsErr_T.InvalidMinor; + + if(!devices_list.is_initialized()) + try devices_list.init(&allocator.sba.allocator); + + const device = try aux.new_dentry_device(major, minor, uid, gid, mode); + errdefer { + allocator.sba.allocator.free(device.d_inode.?) catch unreachable; + allocator.sba.allocator.free(@as(*vfs.Inode_T, @alignCast(@ptrCast(device.d_private.?)))) catch unreachable; + allocator.sba.allocator.free(@constCast(device.d_name)) catch unreachable; + allocator.sba.allocator.free(device) catch unreachable; + } + try devices_list.push_in_list(&allocator.sba.allocator, device); +} + +pub fn unlink_device_node(major: devices.Major_T, minor: devices.Minor_T) anyerror!void { + _ = major; + _ = minor; +} diff --git a/fs/devfs/tree.zig b/fs/devfs/tree.zig new file mode 100644 index 0000000..a3de95e --- /dev/null +++ b/fs/devfs/tree.zig @@ -0,0 +1,27 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: tree.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const types: type = @import("types.zig"); +const allocator: type = @import("allocator.zig"); +const devices: type = @import("root").interfaces.devices; +const aux: type = @import("aux.zig"); + +pub inline fn tree_sync(dev_list: *types.DevfsList_T) types.DevfsErr_T!void { + aux.check_init(dev_list) catch + return types.DevfsErr_T.AllocatorFailed; + + for(0..(~@as(devices.Major_T, 0))) |major| { + if(!devices.valid_major(major)) + continue; + for(0..(~@as(devices.Minor_T, 0))) |minor| { + if(!devices.valid_minor(major, minor)) + continue; + + const device_dentry = + + dev_list.push_in_list(&allocator.sba.allocator, data); + } + } +} diff --git a/fs/devfs/types.zig b/fs/devfs/types.zig new file mode 100644 index 0000000..281655c --- /dev/null +++ b/fs/devfs/types.zig @@ -0,0 +1,27 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: types.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const devices: type = @import("root").interfaces.devices; +const list: type = @import("root").lib.utils.list; +const vfs: type = @import("root").interfaces.vfs; + +pub const DevfsList_T: type = list.BuildList(*vfs.Dentry_T); +pub const DevfsListErr_T: type = DevfsList_T.ListErr_T; + +pub const DevfsPrivate_T: type = struct { + major: devices.Major_T, + minor: devices.Minor_T, +}; + +pub const DevfsErr_T: type = error { + CorruptDentry, + CorruptFilesystem, + DeviceNoFound, + UnexpectedAction, + InvalidMajor, + InvalidMinor, + AllocatorFailed, + ListOperationFailed, +}; diff --git a/fs/rootfs/aux.zig b/fs/rootfs/aux.zig index 242efac..d72a594 100644 --- a/fs/rootfs/aux.zig +++ b/fs/rootfs/aux.zig @@ -6,7 +6,6 @@ const types: type = @import("types.zig"); const allocator: type = @import("allocator.zig"); const vfs: type = @import("root").interfaces.vfs; -const mem: type = @import("root").kernel.utils.mem; const rootfs: type = @import("rootfs.zig"); // required const inode_utils: type = rootfs.__SaturnModuleDescription__.request_lib("inode-utils").?; @@ -41,8 +40,8 @@ pub inline fn alloc_inode(uid: vfs.uid_T, gid: vfs.gid_T, mode: vfs.mode_T) type } pub inline fn alloc_name(name: []const u8) types.RootfsErr_T![]const u8 { - const new_buffer: []u8 = (allocator.sba.allocator.alloc(u8, name.len) - catch return types.RootfsErr_T.AllocatorFailed)[0..name.len]; + const new_buffer: []u8 = allocator.sba.allocator.alloc(u8, name.len) + catch return types.RootfsErr_T.AllocatorFailed; @memcpy(new_buffer, name); return new_buffer; } diff --git a/fs/rootfs/fs.zig b/fs/rootfs/fs.zig new file mode 100644 index 0000000..5ad5093 --- /dev/null +++ b/fs/rootfs/fs.zig @@ -0,0 +1,21 @@ +// ┌────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: fs.zig │ +// │ Author: Linuxperoxo │ +// └────────────────────────────────────────────┘ + +const fs: type = @import("root").interfaces.fs; +const ops: type = @import("ops.zig"); + +pub var rootfs: fs.Fs_T = .{ + .name = "rootfs", + .mount = ops.rootfs_mount, + .umount = ops.rootfs_umount, + .flags = .{ + .control = .{ + .nomount = 0, + .noumount = 1, + .readonly = 0, + .anon = 0, + }, + }, +}; diff --git a/fs/rootfs/ops.zig b/fs/rootfs/ops.zig index aed96ff..5e05c58 100644 --- a/fs/rootfs/ops.zig +++ b/fs/rootfs/ops.zig @@ -4,12 +4,12 @@ // └──────────────────────────────────────────────┘ const interfaces: type = @import("root").interfaces; -const rootfs: type = @import("rootfs.zig"); const types: type = @import("types.zig"); const mem: type = @import("root").lib.utils.mem; const c: type = @import("root").lib.utils.c; const allocator: type = @import("allocator.zig"); const aux: type = @import("aux.zig"); +const rfs: type = @import("fs.zig"); const Dentry_T: type = interfaces.vfs.Dentry_T; const Superblock_T: type = interfaces.vfs.Superblock_T; @@ -41,7 +41,7 @@ pub var dir_inode_ops: InodeOp_T = .{ }; var superblock: Superblock_T = .{ - .fs = @alignCast(@ptrCast(&rootfs.rootfs.private)), + .fs = &rfs.rootfs, .block_size = 0, .data_block_start = 0, .inode_table_start = 0, diff --git a/fs/rootfs/rootfs.zig b/fs/rootfs/rootfs.zig index 98b99cc..0ef48ef 100644 --- a/fs/rootfs/rootfs.zig +++ b/fs/rootfs/rootfs.zig @@ -4,52 +4,24 @@ // └──────────────────────────────────────────────┘ const c: type = @import("root").lib.utils.c; -const interfaces: type = @import("root").interfaces; +const module: type = @import("root").interfaces.module; +const fs: type = @import("root").interfaces.fs; +const vfs: type = @import("root").interfaces.vfs; +const rfs: type = @import("fs.zig"); -const Mod_T: type = interfaces.module.Mod_T; -const ModErr_T: type = interfaces.module.ModErr_T; -const ModType_T: type = interfaces.module.ModType_T; -const ModuleDescription_T: type = interfaces.module.ModuleDescription_T; -const ModuleDescriptionTarget_T: type = interfaces.module.ModuleDescriptionTarget_T; -const ModuleDescriptionLibMine_T: type = interfaces.module.ModuleDescriptionLibMine_T; -const ModuleDescriptionLibOut_T: type = interfaces.module.ModuleDescriptionLibOut_T; - -const Fs_T: type = interfaces.fs.Fs_T; - -const inmod = interfaces.module.inmod; -const rmmod = interfaces.module.rmmod; - -const rootfs_mount = &@import("ops.zig").rootfs_mount; -const rootfs_umount = &@import("ops.zig").rootfs_umount; +const Mod_T: type = module.Mod_T; +const ModControlFlags_T: type = module.ModControlFlags_T; +const ModErr_T: type = module.ModErr_T; +const ModType_T: type = module.ModType_T; +const ModuleDescription_T: type = module.ModuleDescription_T; +const ModuleDescriptionTarget_T: type = module.ModuleDescriptionTarget_T; +const ModuleDescriptionLibMine_T: type = module.ModuleDescriptionLibMine_T; +const ModuleDescriptionLibOut_T: type = module.ModuleDescriptionLibOut_T; pub const __SaturnModuleDescription__: ModuleDescription_T = .{ - .name = "ke_m_rootfs", + .mod = &rootfs, .load = .linkable, - .init = &init, - .after = &opaque { - pub fn after() anyerror!void { - // como habilitamos no handler em flags.call.handler = 1 - // vamos chegar nessa funcao ja com o fs registrado, e o - // e o mesmo montado - if(!c.c_bool(rootfs.flags.internal.installed & rootfs.flags.check_op_status(.install))) { - // panic("failed to init rootfs") - } - if(!c.c_bool(rootfs.private.filesystem.flags.internal.mounted & ~rootfs.private.filesystem.flags.internal.fault.mount)) { - // panic("failed to mount rootfs") - } - rootfs.private.filesystem.flags.control.anon = 1; - rootfs.flags.control.anon = 1; - } - }.after, - .deps = null, - .type = .{ - .filesystem = .{ - .compile = .{ - .name = "rootfs", - .mountpoint = "/", - }, - } - }, + .panic = true, .arch = &[_]ModuleDescriptionTarget_T { .i386, .amd64, @@ -58,12 +30,6 @@ pub const __SaturnModuleDescription__: ModuleDescription_T = .{ .riscv64, .xtensa, }, - .flags = .{ - .call = .{ - .handler = 1, - .after = 1, - }, - }, .libs = .{ .mines = &[_]ModuleDescriptionLibMine_T { .{ @@ -104,61 +70,37 @@ pub const __SaturnModuleDescription__: ModuleDescription_T = .{ }, }; -pub var rootfs: Mod_T = .{ - .name = "rootfs", +pub const rootfs: Mod_T = .{ + .name = "ke_m_rootfs", .desc = "Core Kernel Root Filesystem", .author = "Linuxperoxo", .version = "0.1.0", - .deps = null, .license = .GPL2_only, .type = .filesystem, .init = &init, - .after = null, .exit = &exit, - .private = .{ - .filesystem = .{ - .name = "rootfs", - .mount = rootfs_mount, - .umount = rootfs_umount, - .flags = .{ - .control = .{ - .nomount = 0, - .noumount = 1, - .readonly = 0, - .anon = 0, - }, - .internal = .{}, - }, - }, - }, - .flags = .{ - .control = .{ - .anon = 0, - .call = .{ - .exit = 0, - .remove = 0, - .after = 0, - .init = 0, - .handler = .{ - .install = 1, // deixa o proprio inmod chamar o register_fs() - .remove = 0, // deixa o proprio rmmod chamar o unregister_fs() - }, - }, - }, - .internal = .{}, - }, + .control = &rootfs_control, +}; + +pub var rootfs_control: ModControlFlags_T = .{ + .init = 1, + .exit = 0, + .remove = 0, + .anon = 0, }; -fn init() ModErr_T!void { - @call(.never_inline, inmod, .{ - &rootfs - }) catch unreachable; - // aqui nao precisamos nos preocupar com registra o fs, ja que a flag rootfs.flags.control.call.handler.{install,remove} - // ja se encarrega que chamar o register_fs e o unregister_fs quando usamos o inmod e rmmod +fn init() anyerror!void { + try fs.register_fs(&rfs.rootfs); + errdefer fs.unregister_fs(&rfs.rootfs) catch {}; + try vfs.mount("/", null, rfs.rootfs.name); + rfs.rootfs.flags.control = .{ + .anon = 1, + .nomount = 1, + .noumount = 1, + .readonly = 0, + }; } -fn exit() ModErr_T!void { - return @call(.never_inline, rmmod, .{ - &rootfs - }); +fn exit() anyerror!void { + unreachable; } diff --git a/kernel/arch/i386/i386.zig b/kernel/arch/i386/i386.zig index 8b959b1..1eefd0b 100644 --- a/kernel/arch/i386/i386.zig +++ b/kernel/arch/i386/i386.zig @@ -108,6 +108,10 @@ pub const __SaturnArchDescription__: interfaces.arch.ArchDescription_T = .{ .module = "ke_m_devfs", .value = .yes, }, + .{ + .module = "ke_m_fb", + .value = .yes, + } }, .fusioners = null, }, diff --git a/kernel/asl/asl.zig b/kernel/asl/asl.zig index 42f11d7..f2209a8 100644 --- a/kernel/asl/asl.zig +++ b/kernel/asl/asl.zig @@ -1,5 +1,5 @@ // ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: asl.zig │ +// │ (c) 2026 Linuxperoxo • FILE: asl.zig │ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ @@ -13,6 +13,7 @@ const code: type = @import("root").code; const decls: type = @import("root").decls; const config: type = @import("root").config; +const fmt: type = @import("root").lib.utils.compile.fmt; const aux: type = @import("aux.zig"); comptime { @@ -37,13 +38,20 @@ comptime { // usada dentro de um linker ou assembly, isso iria dar um erro de simbolo nao encontrado, ja que como // nao foi usada dentro do proprio codigo zig, o compilador so iria ignorar e nem colocar o export nela if(@field(code.arch, decls.what_is_decl(.arch)).symbols.segments == 1 ) asm( - aux.asm_set("kernel_phys_address", config.kernel.mem.phys.kernel_phys) ++ - aux.asm_set("kernel_virtual_address", config.kernel.mem.virtual.kernel_text) ++ - aux.asm_set("kernel_text_virtual", config.kernel.mem.virtual.kernel_text) ++ - aux.asm_set("kernel_stack_base_virtual", config.kernel.mem.virtual.kernel_stack_base) ++ - aux.asm_set("kernel_data_virtual", config.kernel.mem.virtual.kernel_data) ++ - aux.asm_set("kernel_paged_memory_virtual", config.kernel.mem.virtual.kernel_paged_memory) ++ - aux.asm_set("kernel_mmio_virtual", config.kernel.mem.virtual.kernel_mmio) + &fmt.format(".set {s}, {d}\n", .{ "kernel_phys_address", config.kernel.mem.phys.kernel_phys }) ++ + &fmt.format(".global {s}\n", .{ "kernel_phys_address" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_virtual_address", config.kernel.mem.virtual.kernel_text }) ++ + &fmt.format(".global {s}\n", .{ "kernel_virtual_address" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_text_virtual", config.kernel.mem.virtual.kernel_text }) ++ + &fmt.format(".global {s}\n", .{ "kernel_text_virtual" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_stack_base_virtual", config.kernel.mem.virtual.kernel_stack_base }) ++ + &fmt.format(".global {s}\n", .{ "kernel_stack_base_virtual" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_data_virtual", config.kernel.mem.virtual.kernel_data }) ++ + &fmt.format(".global {s}\n", .{ "kernel_data_virtual" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_paged_memory_virtual", config.kernel.mem.virtual.kernel_paged_memory }) ++ + &fmt.format(".global {s}\n", .{ "kernel_paged_memory_virtual" }) ++ + &fmt.format(".set {s}, {d}\n", .{ "kernel_mmio_virtual", config.kernel.mem.virtual.kernel_mmio }) ++ + &fmt.format(".global {s}\n", .{ "kernel_mmio_virtual" }) ); const arch_decl_type: type = decls.what_is_decl_type(.arch); diff --git a/kernel/asl/aux.zig b/kernel/asl/aux.zig index cd57e6d..992f533 100644 --- a/kernel/asl/aux.zig +++ b/kernel/asl/aux.zig @@ -1,16 +1,10 @@ // ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: aux.zig │ +// │ (c) 2026 Linuxperoxo • FILE: aux.zig │ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ const lib: type = @import("root").lib; -pub fn asm_set(comptime name: []const u8, comptime value: u32) []const u8 { - return ".set " ++ name ++ ", " ++ lib.utils.fmt.intFromArray(value) ++ "\n" - ++ ".globl " ++ name ++ "\n" - ; -} - pub fn ret_export_entry(comptime lhs: anytype, comptime field: []const u8) *anyopaque { const field_access = @field(lhs, field); return @constCast(switch(@typeInfo(@TypeOf(field_access))) { diff --git a/kernel/core/devices/allocator.zig b/kernel/core/devices/allocator.zig index 8349d0e..e664c53 100644 --- a/kernel/core/devices/allocator.zig +++ b/kernel/core/devices/allocator.zig @@ -3,40 +3,8 @@ // │ Author: Linuxperoxo │ // └────────────────────────────────────────────────┘ -const SOA: type = @import("memory.zig").SOA; +const buildByteAllocator = @import("root").lib.memory.sba.buildByteAllocator; -const Cache_T: type = SOA.Cache_T; -const Optimize_T: type = SOA.Optimize_T; - -pub const AllocatorErr_T: type = SOAAllocator_T.err_T; -const SOAAllocator_T: type = SOA.buildObjAllocator( - @import("types.zig").Dev_T, - false, - 256, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} -); - -var allocator: SOAAllocator_T = .{}; - -pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); -} - -pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); -} - -pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); -} +pub const sba: type = struct { + pub const allocator = buildByteAllocator(null, .{}) {}; +}; diff --git a/kernel/core/devices/aux.zig b/kernel/core/devices/aux.zig new file mode 100644 index 0000000..aa0dbf1 --- /dev/null +++ b/kernel/core/devices/aux.zig @@ -0,0 +1,46 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2025 Linuxperoxo • FILE: aux.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const main: type = @import("main.zig"); +const types: type = @import("types.zig"); + +pub inline fn is_valid_major(major: types.Major_T) bool { + return ((main.bitmap >> major) & 1) == 1; +} + +pub inline fn is_valid_minor(major: types.Major_T, minor: types.Minor_T) bool { + return (major_ptr(major) catch return false).is_valid_minor(minor); +} + +pub inline fn minor_op(comptime op: enum { add, rm }, major: types.Major_T, minor: types.Minor_T) types.DevErr_T!void { + const dev_info: *types.DevBranch_T = @constCast(try major_ptr(major)); + const dev: *types.Dev_T = @constCast(dev_info.dev); + if(minor == 0) return types.DevErr_T.MainMinorOperation; + switch(comptime op) { + .add => { + if(dev.flags.control.max == dev.flags.internal.total + or dev.flags.control.minor == 0) return types.DevErr_T.MinorDenied; + if(dev_info.is_valid_minor(minor)) return types.DevErr_T.MinorCollision; + dev_info.validade_minor(minor); + dev.flags.internal.total += 1; + }, + + .rm => { + if(!dev_info.is_valid_minor(minor)) return types.DevErr_T.MinorDoubleFree; + dev_info.invalidate_minor(minor); + dev.flags.internal.total -= 1; + }, + } +} + +pub inline fn major_ptr(major: types.Major_T) types.DevErr_T!*const types.DevBranch_T { + return if(!is_valid_major(major)) types.DevErr_T.MajorNoNFound else + &main.majors[major]; +} + +pub inline fn is_valid_op(ops: *const types.DevOps_T, op: types.Ops_T) types.DevErr_T!void { + return if(@field(ops, @tagName(op)) == null) + types.DevErr_T.InvalidOperation; +} diff --git a/kernel/core/devices/core.zig b/kernel/core/devices/core.zig deleted file mode 100644 index ed468e2..0000000 --- a/kernel/core/devices/core.zig +++ /dev/null @@ -1,314 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: core.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Allocator: type = @import("allocator.zig"); -const Extern: type = struct { - pub const Dev_T: type = @import("types.zig").Dev_T; - pub const DevErr_T: type = @import("types.zig").DevErr_T; - pub const MinorNum_T: type = @import("types.zig").MinorNum_T; - pub const MajorNum_T: type = @import("types.zig").MajorNum_T; -}; -const Internal: type = struct { - pub const DevicesInodeLevel0: type = @import("types.zig").DevicesInodeLevel0; - pub const DevicesInodeLevel1: type = @import("types.zig").DevicesInodeLevel1; - pub const DevicesInodeLevel2: type = @import("types.zig").DevicesInodeLevel2; - pub const Steps: type = enum { - Level0O, - Level1B, - Level1O, - Level2B, - Level2O, - }; -}; - -// A implementacao dos virtual devices e bem parecida com o de drivers. -// Uma coisa que precisamos ter em mente e que os dispositivos virtuais -// so fazem sentido com um devfs, ou seja, aqui vamos armazenar um minor -// com um inode, que deve ser um endereco unico para aquele minor, ja os -// major/drivers usamos apenas o proprio numero de major para armazena-lo -// -// Aqui nao vamos ter uma validacao de colisao de minor em majors, por enquanto, -// vamos passar essa responsabilidade para o proprio driver, ele deve ser responsavel -// por gerenciar os seus minors -// -// OBS: Talvez isso seja mudado no futuro - -var virtual_devices: Internal.DevicesInodeLevel0 = .{ - .base = [_]?*Internal.DevicesInodeLevel1 { - null - } ** @typeInfo(Internal.DevicesInodeLevel0.Base_T).array.len, -}; - -pub fn inodePartBits(inode: Extern.MinorNum_T) struct { u4, u2, u2 } { - return .{ - @intCast((inode >> 4) & 0x0F), - @intCast((inode >> 2) & 0x03), - @intCast(inode & 0x03), - }; -} - -pub fn valid_path(inode: Extern.MinorNum_T) struct { broken: ?Internal.Steps, result: bool } { - const high: u4, const mid: u2, const low: u2 = @call(.always_inline, &inodePartBits, .{ - inode - }); - return if(virtual_devices.base[high] == null) .{ .broken = Internal.Steps.Level0O, .result = false } else r: { - const types = [_]type { - ?*Internal.DevicesInodeLevel1, - ?*Internal.DevicesInodeLevel2, - }; - const offset = [_]u2 { - mid, - low, - }; - var level: *anyopaque = virtual_devices.base[high].?; - inline for(0..types.len) |i| { - const casting: types[i] = @alignCast(@ptrCast(level)); - if(casting.?.base == null or t: { - // esse == 0xaaaaaaaaaaaaaaaa serve para funcionar no -ODebug, o Debug - // usa esse endereco para caso de escrita nesse endereco ele avisa uma - // tentativa de escrita em um null, isso so acontece no Debug, em ReleaseSmall - // funciona perfeitamente sem isso - if(@import("builtin").is_test) break :t (@intFromPtr(casting.?.base) == 0xaaaaaaaaaaaaaaaa) else false; - }) { - break :r .{ - .broken = @enumFromInt(i + i + 1), - .result = false, - }; - } - if(casting.?.base.?[offset[i]] == null or t: { - if(@import("builtin").is_test) break :t (@intFromPtr(casting.?.base.?[offset[i]]) == 0xaaaaaaaaaaaaaaaa) else false; - }) { - break :r .{ - .broken = @enumFromInt(i + i + 2), - .result = false, - }; - } - level = casting.?.base.?[offset[i]].?; - } - break :r .{ - .broken = null, - .result = true, - }; - }; -} - -// As funcoes de add e del poderiam ser menor, mas preferi deixar assim por motivos de visualizacao -// de partes isoladas, ela nao tem um impacto de desempenho por ser longa, por sinal, acredito -// que seja ate a melhor escolha nesse caso - -pub fn add(inode: Extern.MinorNum_T, device: *const Extern.Dev_T) Extern.DevErr_T!void { - const path = @call(.never_inline, valid_path, .{ - inode - }); - return if(path.result) Extern.DevErr_T.MinorInodeCollision else r: { - const high: u4, const mid: u2, const low: u2 = @call(.always_inline, &inodePartBits, .{ - inode - }); - sw: switch(path.broken.?) { - Internal.Steps.Level0O => { - virtual_devices.base[high] = @call(.never_inline, &Internal.DevicesInodeLevel1.Allocator.Level.alloc, .{}) - catch |err| switch(err) { - Internal.DevicesInodeLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DevErr_T.OutOfMinor, - else => break :r Extern.DevErr_T.InternalError, - }; - virtual_devices.map |= (@as(@TypeOf(virtual_devices.map), 0x01) << high); - continue :sw .Level1B; - }, - - Internal.Steps.Level1B => { - virtual_devices.base[high].?.base = @call(.never_inline, &Internal.DevicesInodeLevel1.Allocator.Base.alloc, .{}) - catch |err| switch(err) { - Internal.DevicesInodeLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DevErr_T.OutOfMinor, - else => break :r Extern.DevErr_T.InternalError, - }; - continue :sw .Level1O; - }, - - Internal.Steps.Level1O => { - virtual_devices.base[high].?.base.?[mid] = @call(.never_inline, &Internal.DevicesInodeLevel2.Allocator.Level.alloc, .{}) - catch |err| switch(err) { - Internal.DevicesInodeLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DevErr_T.OutOfMinor, - else => break :r Extern.DevErr_T.InternalError, - }; - virtual_devices.base[high].?.map |= (@as(@TypeOf(virtual_devices.base[high].?.map), 0x01) << mid); - continue :sw .Level2B; - }, - - Internal.Steps.Level2B => { - virtual_devices.base[high].?.base.?[mid].?.base = @call(.never_inline, &Internal.DevicesInodeLevel2.Allocator.Base.alloc, .{}) - catch |err| switch(err) { - Internal.DevicesInodeLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DevErr_T.OutOfMinor, - else => break :r Extern.DevErr_T.InternalError, - }; - continue :sw .Level2O; - }, - - Internal.Steps.Level2O => { - virtual_devices.base[high].?.base.?[mid].?.base.?[low] = @call(.never_inline, &Allocator.alloc, .{}) - catch |err| switch(err) { - Internal.DevicesInodeLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DevErr_T.OutOfMinor, - else => break :r Extern.DevErr_T.InternalError, - }; - virtual_devices.base[high].?.base.?[mid].?.map |= (@as(@TypeOf(virtual_devices.base[high].?.base.?[mid].?.map), 0x01) << low); - }, - } - virtual_devices.base[high].?.base.?[mid].?.base.?[low].?.* = device.*; - }; -} - -pub fn del(inode: Extern.MinorNum_T) Extern.DevErr_T!void { - return if(!(@call(.always_inline, &valid_path, .{ - inode - })).result) Extern.DevErr_T.MinorDoubleFree else r: { - const high: u4, const mid: u2, const low: u2 = @call(.always_inline, &inodePartBits, .{ - inode - }); - // TODO: Tratar melhor possivel error no free de level - sw: switch(Internal.Steps.Level2O) { - Internal.Steps.Level2O => { - @call(.never_inline, &Allocator.free, .{ - virtual_devices.base[high].?.base.?[mid].?.base.?[low] - }) catch break :r Extern.DevErr_T.InternalError; - virtual_devices.base[high].?.base.?[mid].?.map &= ~(@as(@TypeOf(virtual_devices.base[high].?.base.?[mid].?.map), 0x01) << low); - virtual_devices.base[high].?.base.?[mid].?.base.?[low] = null; - if(virtual_devices.base[high].?.base.?[mid].?.map == 0) continue :sw .Level2B; - break :r {}; - }, - - Internal.Steps.Level2B => { - @call(.never_inline, &Internal.DevicesInodeLevel2.Allocator.Base.free, .{ - virtual_devices.base[high].?.base.?[mid].?.base - }) catch break :r Extern.DevErr_T.InternalError; - virtual_devices.base[high].?.base.?[mid].?.base = null; - continue :sw .Level1O; - }, - - Internal.Steps.Level1O => { - @call(.never_inline, &Internal.DevicesInodeLevel2.Allocator.Level.free, .{ - virtual_devices.base[high].?.base.?[mid] - }) catch break: r Extern.DevErr_T.InternalError; - virtual_devices.base[high].?.map &= ~(@as(@TypeOf(virtual_devices.base[high].?.map), 0x01) << mid); - virtual_devices.base[high].?.base.?[mid] = null; - if(virtual_devices.base[high].?.map == 0) continue :sw .Level1B; - break :r {}; - }, - - Internal.Steps.Level1B => { - @call(.never_inline, &Internal.DevicesInodeLevel1.Allocator.Base.free, .{ - virtual_devices.base[high].?.base - }) catch break :r Extern.DevErr_T.InternalError; - virtual_devices.base[high].?.base = null; - continue :sw .Level0O; - }, - - Internal.Steps.Level0O => { - @call(.never_inline, &Internal.DevicesInodeLevel1.Allocator.Level.free, .{ - virtual_devices.base[high] - }) catch break :r Extern.DevErr_T.InternalError; - virtual_devices.map &= ~(@as(@TypeOf(virtual_devices.map), 0x01) << high); - virtual_devices.base[high] = null; - }, - } - }; -} - -pub fn search(inode: Extern.MinorNum_T) Extern.DevErr_T!*Extern.Dev_T { - const path = @call(.always_inline, &valid_path, .{ - inode - }); - return if(!path.result) Extern.DevErr_T.NonMinor else r: { - const high: u4, const mid: u2, const low: u2 = @call(.always_inline, &inodePartBits, .{ - inode - }); - break :r virtual_devices.base[high].?.base.?[mid].?.base.?[low].?; - }; -} - -// == Saturn Devices Allocs Test == -const MaxInodeRange: comptime_int = ( - @typeInfo(Internal.DevicesInodeLevel0.Base_T).array.len * - @typeInfo(Internal.DevicesInodeLevel1.Base_T).array.len * - @typeInfo(Internal.DevicesInodeLevel2.Base_T).array.len -); -const TestErr_T: type = error { - UnreachableCode, - UndefinedAction, - MemoryLeakDetected, -}; -var deviceTester: Extern.Dev_T = .{ - .major = 0, - .minor = 0, - .type = .char, -}; - -test "Continuos Devices Alloc" { - for(0..MaxInodeRange) |i| { - try add(@intCast(i), &deviceTester); - add(@intCast(i), &deviceTester) catch |err| switch(err) { - Extern.DevErr_T.MinorInodeCollision => {}, - else => return TestErr_T.UnreachableCode, - }; - const deviceReturn: *Extern.Dev_T = try search(@intCast(i)); - if( - deviceReturn.major != deviceTester.major or - deviceReturn.minor != deviceTester.minor or - deviceReturn.type != deviceTester.type - ) return TestErr_T.UndefinedAction; - } -} - -test "Continuos Devices Free" { - for(0..MaxInodeRange) |i| { - try del(@intCast(i)); - del(@intCast(i)) catch |err| switch(err) { - Extern.DevErr_T.MinorDoubleFree => {}, - else => return TestErr_T.UnreachableCode, - }; - _ = search(@intCast(i)) catch |err| switch(err) { - Extern.DevErr_T.NonMinor => {}, - else => return TestErr_T.UnreachableCode, - }; - try add(@intCast(i), &deviceTester); - try del(@intCast(i)); - } -} - -test "Continuos Devices Alloc Again" { - for(0..MaxInodeRange) |i| { - try add(@intCast(i), &deviceTester); - add(@intCast(i), &deviceTester) catch |err| switch(err) { - Extern.DevErr_T.MinorInodeCollision => {}, - else => return TestErr_T.UnreachableCode, - }; - const deviceReturn: *Extern.Dev_T = try search(@intCast(i)); - if( - deviceReturn.major != deviceTester.major or - deviceReturn.minor != deviceTester.minor or - deviceReturn.type != deviceTester.type - ) return TestErr_T.UndefinedAction; - } -} - -test "Detect Memory Leak" { - for(0..MaxInodeRange) |i| { - try del(@intCast(i)); - } - const Allocators = [_]type { - Allocator, - Internal.DevicesInodeLevel1.Allocator.Base, - Internal.DevicesInodeLevel1.Allocator.Level, - Internal.DevicesInodeLevel2.Allocator.Base, - Internal.DevicesInodeLevel2.Allocator.Level, - }; - inline for(Allocators) |allocator| { - if(allocator.haveAllocs()) { - const std: type = @import("std"); - std.debug.print("Memory Leak On Allocator: {s}\n", .{ - @typeName(allocator) - }); - return TestErr_T.MemoryLeakDetected; - } - } -} diff --git a/kernel/core/devices/devices.zig b/kernel/core/devices/devices.zig index b4b8e78..aec2c94 100644 --- a/kernel/core/devices/devices.zig +++ b/kernel/core/devices/devices.zig @@ -3,21 +3,30 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -pub const fun: type = struct { - const create = @import("fun.zig").create; - const delete = @import("fun.zig").create; - pub const ops: type = struct { - pub const open = @import("ops.zig").open; - pub const close = @import("ops.zig").close; - pub const minor = @import("ops.zig").minor; - pub const read = @import("ops.zig").read; - pub const write = @import("ops.zig").write; - pub const ioctrl = @import("ops.zig").ioctrl; - }; -}; -pub const types: type = struct { - pub const MinorNum_T: type = @import("types.zig").MinorNum_T; - pub const Dev_T: type = @import("types.zig").Dev_T; - pub const DevErr_T: type = @import("types.zig").DevErr_T; -}; +const types: type = @import("types.zig"); +const main: type = @import("main.zig"); +const ops: type = @import("ops.zig"); +pub const Major_T: type = types.Major_T; +pub const Minor_T: type = types.Minor_T; +pub const Dev_T: type = types.Dev_T; +pub const DevErr_T: type = types.DevErr_T; +pub const DevOps_T: type = types.DevOps_T; +pub const DevType_T: type = types.DevType_T; + +pub const dev_minor_add = main.dev_minor_add; +pub const dev_minor_rm = main.dev_minor_rm; +pub const next_major = main.next_major; +pub const valid_major = main.valid_major; +pub const valid_minor = main.valid_minor; +pub const dev_add = main.dev_add; +pub const dev_rm = main.dev_rm; +pub const dev_info = main.dev_info; + +pub const write = ops.write; +pub const read = ops.read; +pub const ioctl = ops.ioctl; +pub const mount = ops.mount; +pub const umount = ops.umount; +pub const open = ops.open; +pub const close = ops.close; diff --git a/kernel/core/devices/fun.zig b/kernel/core/devices/fun.zig deleted file mode 100644 index 2c033cf..0000000 --- a/kernel/core/devices/fun.zig +++ /dev/null @@ -1,31 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: fun.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Dev_T: type = @import("types.zig").Dev_T; -const DevErr_T: type = @import("types.zig").DevErr_T; -const MinorNum_T: type = @import("types.zig").MinorNum_T; - -const add = @import("core.zig").add; -const del = @import("core.zig").del; - -// Chamar essas funcoes de forma independente, faz com que crie um minor -// anonimo, ou seja, somente quem tem o minor e o major vai conseguir se -// comunicar com ele, nada de criar no vfs - -pub fn create( - D: *const Dev_T, -) DevErr_T!void { - return @call(.always_inline, &add, .{ - D - }); -} - -pub fn delete( - M: MinorNum_T -) DevErr_T!void { - return @call(.always_inline, &del, .{ - M - }); -} diff --git a/kernel/core/devices/main.zig b/kernel/core/devices/main.zig new file mode 100644 index 0000000..ae35ad8 --- /dev/null +++ b/kernel/core/devices/main.zig @@ -0,0 +1,64 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2025 Linuxperoxo • FILE: main.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +const types: type = @import("types.zig"); +const aux: type = @import("aux.zig"); +const mem: type = @import("root").lib.utils.mem; +const builtin: type = @import("builtin"); + +pub var majors: [@bitSizeOf(usize)]types.DevBranch_T = undefined; +pub var bitmap: usize = 0; + +pub inline fn dev_info(major: types.Major_T, comptime field: enum { name, type }) types.DevErr_T!@FieldType(types.Dev_T, @tagName(field)) { + if(!aux.is_valid_major(major)) return types.DevErr_T.MajorNoNFound; + return @field(majors[major].dev, @tagName(field)); +} + +pub noinline fn dev_add(major: types.Major_T, dev: *const types.Dev_T) types.DevErr_T!void { + if(aux.is_valid_major(major)) return types.DevErr_T.MajorCollision; + bitmap |= @as(@TypeOf(bitmap), 1) << major; + majors[major].dev = dev; + majors[major].minors[0] = 1; + for(1..16) |i| + majors[major].minors[i] = 0; +} + +pub inline fn dev_rm(major: types.Major_T, dev: *const types.Dev_T) types.DevErr_T!void { + if((bitmap >> major) == 0 or majors[major].dev != dev) + return types.DevErr_T.MajorNoNFound; + bitmap &= ~major; +} + +pub noinline fn dev_minor_add(major: types.Major_T, minor: types.Minor_T) types.DevErr_T!void { + return aux.minor_op(.add, major, minor); +} + +pub noinline fn dev_minor_rm(major: types.Major_T, minor: types.Minor_T) types.DevErr_T!void { + return aux.minor_op(.rm, major, minor); +} + +pub noinline fn valid_major(major: types.Major_T) bool { + return aux.is_valid_major(major); +} + +pub noinline fn valid_minor(major: types.Major_T, minor: types.Minor_T) bool { + return if(!aux.is_valid_major(major)) false else + majors[major].is_valid_minor(minor); +} + +pub noinline fn next_major() types.DevErr_T!types.Major_T { + if((~bitmap) == 0) return types.DevErr_T.WithoutMajor; + var map: usize = bitmap; + var bit: types.Major_T = 0; + while(map > 0) : ({ map >>= 1; bit += 1; }) { + if((map & 1) == 0) + return bit; + } + unreachable; +} + +pub noinline fn next_minor(major: types.Major_T) types.DevErr_T!types.Minor_T { + _ = major; +} diff --git a/kernel/core/devices/ops.zig b/kernel/core/devices/ops.zig index b67d450..e6d96d9 100644 --- a/kernel/core/devices/ops.zig +++ b/kernel/core/devices/ops.zig @@ -3,64 +3,82 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -const MinorNum_T: type = @import("types.zig").MinorNum_T; -const MajorNum_T: type = @import("root").interfaces.drivers.MajorNum_T; -const Dev_T: type = @import("types.zig").Dev_T; -const DevErr_T: type = @import("types.zig").DevErr_T; -const DriversOps: type = @import("root").interfaces.drivers.fun.ops; +const types: type = @import("types.zig"); +const aux: type = @import("aux.zig"); +const main: type = @import("main.zig"); +const vfs: type = @import("root").interfaces.vfs; -const exist = @import("core.zig").exist; +pub fn ioctl( + major: types.Major_T, + minor: types.Minor_T, + command: usize, + data: ?*anyopaque +) anyerror!usize { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .ioctl); + return dev_info.dev.ops.ioctl.?(minor, command, data); +} -pub fn open(Ma: MajorNum_T, Mi: MinorNum_T) DevErr_T!void { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - @call(.never_inline, &DriversOps.open, .{ - ma, mi - }) catch return DevErr_T.MajorReturnError; +pub fn mount( + major: types.Major_T, + minor: types.Minor_T +) anyerror!*const vfs.Superblock_T { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .mount); + return dev_info.dev.ops.mount.?(minor); } -pub fn close(Ma: MajorNum_T, Mi: MajorNum_T) void { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - @call(.never_inline, &DriversOps.open, .{ - ma, mi - }) catch return DevErr_T.MajorReturnError; +pub fn umount( + major: types.Major_T, + minor: types.Minor_T +) anyerror!void { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .umount); + return dev_info.dev.ops.umount.?(minor); } -pub fn minor(Ma: MajorNum_T, Mi: MinorNum_T) DevErr_T!void { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - @call(.never_inline, &DriversOps.open, .{ - ma, mi - }) catch return DevErr_T.MajorReturnError; +pub fn open( + major: types.Major_T, + minor: types.Minor_T +) anyerror!void { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .open); + return dev_info.dev.ops.open.?(minor); } -pub fn read(Ma: MajorNum_T, Mi: MinorNum_T, offset: usize) []u8 { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - return @call(.never_inline, &DriversOps.open, .{ - ma, mi, offset - }) catch return DevErr_T.MajorReturnError; +pub fn close( + major: types.Major_T, + minor: types.Minor_T +) anyerror!void { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .close); + return dev_info.dev.ops.close.?(minor); } -pub fn write(Ma: MajorNum_T, Mi: MinorNum_T, data: []const u8) void { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - @call(.never_inline, &DriversOps.write, .{ - ma, mi, data - }) catch return DevErr_T.MajorReturnError; +pub fn read( + major: types.Major_T, + minor: types.Minor_T, + offset: usize +) anyerror![]u8 { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .read); + return dev_info.dev.ops.read.?(minor, offset); } -pub fn ioctrl(Ma: MajorNum_T, Mi: MinorNum_T, command: usize, data: usize) DevErr_T!usize { - const ma, const mi, _ = @call(.never_inline, &exist, .{ - Ma, Mi - }).* catch |err| return err; - return @call(.never_inline, &DriversOps.ioctrl, .{ - ma, mi, command, data - }) catch return DevErr_T.MajorReturnError; +pub fn write( + major: types.Major_T, + minor: types.Minor_T, + src: []const u8, + offset: usize +) anyerror!void { + const dev_info: *const types.DevBranch_T = try aux.major_ptr(major); + if(!aux.is_valid_minor(major, minor)) return types.DevErr_T.MinorNoExist; + try aux.is_valid_op(dev_info.dev.ops, .write); + return dev_info.dev.ops.write.?(minor, src, offset); } diff --git a/kernel/core/devices/test.zig b/kernel/core/devices/test.zig new file mode 100644 index 0000000..98de5b0 --- /dev/null +++ b/kernel/core/devices/test.zig @@ -0,0 +1,32 @@ +const main: type = @import("main.zig"); +const ops: type = @import("ops.zig"); +const devices: type = @import("devices.zig"); +const types: type = @import("types.zig"); + +test "Device Operations" { + var dev = comptime devices.new_dev(.char, &types.DevOps_T { + .write = &opaque { + pub fn write(_: types.Minor_T, _: []const u8, _: usize) anyerror!void { + return error.OperationOk; + } + }.write, + }); + try main.dev_add(0, &dev); + if(main.dev_add(0, &dev)) |_| { return error.NoNCollision; } else |_| {} + if(!main.valid_major(0)) return error.UnexpectedAction; + if(ops.write(0, 0, "Hello, World!", 0)) |_| { + return error.UnexpectedAction; + } else |err| switch(err) { + error.OperationOk => {}, + else => return err, + } + if(ops.read(0, 0, 0)) |_| { return error.UnexpectedAction; } else |_| {} + if(main.dev_minor_add(0, 0)) |_| { return error.UnexpectedAction; } else |err| { + if(err != types.DevErr_T.MainMinorOperation) return error.UnexpectedAction; + } + if(main.dev_minor_add(0, 1)) |_| { return error.InvalidMinorAddOperation; } else |_| {} + dev.flags.control.minor = 1; + dev.flags.control.max = 1; + main.dev_minor_add(0, 1) catch |err| return err; + if(dev.flags.internal.total != 1) return error.UnexpectMinorTotal; +} diff --git a/kernel/core/devices/test/SOA/SOA.zig b/kernel/core/devices/test/SOA/SOA.zig deleted file mode 100644 index 8a58f31..0000000 --- a/kernel/core/devices/test/SOA/SOA.zig +++ /dev/null @@ -1,382 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: SOA.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -// === Saturn Object Allocator === -// A SLUB-like allocator -// === === === === === === === === - -pub const Optimize_T: type = @import("types.zig").Optimize_T; -pub const Cache_T: type = @import("types.zig").Cache_T; - -pub const zero = struct { - const Self: type = @This(); - pub fn zero(comptime T: type) T { - @setEvalBranchQuota(4294967295); - switch(@typeInfo(T)) { - .int, .float => return @as(T, 0), - .pointer => |info| if(info.is_allowzero) return @intFromPtr(0) else return undefined, - .null, .optional => return null, - .array => |info| { - var array: T = undefined; - for(0..info.len) |i| { - array[i] = comptime Self.zero(info.child); - } - }, - .@"struct" => |info| { - var @"struct": T = undefined; - for(info.fields) |field| { - @field(@"struct", field.name) = comptime Self.zero(field.type); - } - return @"struct"; - }, - else => {}, - } - return undefined; - } -}.zero; - -pub fn buildObjAllocator( - comptime T: type, - comptime zero_init: bool, - comptime num: usize, - comptime optimize: Optimize_T, - comptime cache: Cache_T, -) type { - comptime { - if(@sizeOf(T) == 0) { - @compileError( - "SOA: type" ++ - @typeName(T) ++ - " cannot have size 0 (incomplete or invalid)." - ); - } - - if(num == 0) { - @compileError("SOA: obj num cannot be zero. This may cause invalid state."); - } - - if((num % 2) != 0) { - @compileError("SOA: obj num must be even. Provided value is odd."); - } - - if(num <= 2) { - @compileError("SOA: obj num must be greater than 2. Provided value is too small. Use 4 with value"); - } - } - return struct { - pool: [num]T = if(zero_init) zero([num]T) else undefined, - allocs: BitMaxIPool = 0, - bitmap: [r: { - break :r (num / BitMap_T.MapSize) + if((num % BitMap_T.MapSize) != 0) 1 else 0; - // essa calculo garante que tenha a quantidade certa - // de bitmap para objetos caso nao seja multiplo do MapSize. - }]BitMap_T = [_]BitMap_T { - BitMap_T { - .map = [_]BitMap_T.Map_T { - .free, - } ** BitMap_T.MapSize, - }, - } ** ((num / BitMap_T.MapSize) + if((num % BitMap_T.MapSize) != 0) 1 else 0), - lindex: ?BitMaxIPool = null, - cindex: CindexType_T = if(CindexType_T == void) {} else null, - cmiss: CmissType_T = if(CmissType_T == void) {} else 0, - cache: CacheType_T = if(optimize.type == .linear) {} else [_]?BitMaxIPool { - null - } ** CacheElementSize, - - const Self: type = @This(); - const BitMap_T: type = struct { - map: [MapSize]Map_T align(1), - - pub const MapSize: comptime_int = 8; - pub const Map_T: type = enum(u1) { - free, - busy, - }; - }; - const BitMaxIPool: type = switch(num) { - 1...255 => u8, - 256...65535 => u16, - else => usize, - }; - const InternalErr_T: type = error { - NonOptimize, - Rangeless, - }; - const CacheType_T: type = if(optimize.type == .linear) void else [CacheElementSize]?BitMaxIPool; - const CindexType_T: type = if(optimize.type == .linear) void else ?BitMaxIPool; - const CmissType_T: type = r: { - if(optimize.type == .linear) break :r void; - switch(cache.sync) { - .burning => break :r void, - else => break :r u2, - } - }; - const CacheElementSize = r: { - const divisor = if(cache.size != .auto and num >= @intFromEnum(cache.size)) @intFromEnum(cache.size) else t: { - sw: switch(@sizeOf(T)) { - 1...16 => if(num <= 16) break :t @intFromEnum(Cache_T.CacheSize_T.huge) else continue :sw 17, - 17...32 => if(num <= 32) break :t @intFromEnum(Cache_T.CacheSize_T.large) else continue :sw 33, - else => break :t @intFromEnum(Cache_T.CacheSize_T.small), - } - }; - break :r num / divisor; - }; - - pub const err_T: type = error { - OutOfMemory, - DoubleFree, - IndexOutBounds, - UndefinedAction, - }; - - pub const Options: type = struct { - pub const Type: type = T; - pub const config: struct { optimize: Optimize_T, cache: Cache_T } = .{ - .optimize = optimize, - .cache = cache, - }; - }; - - const CacheAction: type = struct { - pub const CacheErr_T: type = error { - NonSync, - }; - - var midHigh: u1 = 1; - pub fn sync(self: *Self) CacheErr_T!void { - const init, const end = switch(cache.mode) { - .PrioritizeHits => .{ - 0, self.cache.len - }, - - .PrioritizeSpeed => .{ - (self.cache.len / 2) * midHigh, - (self.cache.len / 2) + ((self.cache.len / 2) * midHigh), - } - }; - var first: ?BitMaxIPool = null; - var bindex: BitMaxIPool, var mindex: BitMaxIPool = .{ 0, 0 }; - for(init..end) |cindex| { - if(self.cache[cindex]) |_| continue; - r: { - while(bindex < self.bitmap.len) : (bindex += 1) { - while(mindex < BitMap_T.MapSize) : (mindex += 1) { - if(self.bitmap[bindex].map[mindex] == .free) { - self.cache[cindex] = @call(.always_inline, &BitMap.bitMapIndexToIPool, .{ - bindex, mindex - }); - first = if(first) |_| first else @intCast(cindex); - mindex += 1; - break :r {}; - } - } - mindex = 0; - } - } - } - midHigh ^= 1; - self.cindex = first orelse return CacheErr_T.NonSync; - } - - pub fn push(_: *Self) CacheErr_T!void { - - } - }; - - const BitMap: type = struct { - fn obtain(ipool: BitMaxIPool) struct { BitMaxIPool, u4 } { - return .{ - ipool / BitMap_T.MapSize, - @intCast(ipool % BitMap_T.MapSize), - }; - } - - pub fn bitMapIndexToIPool(bindex: BitMaxIPool, mindex: BitMaxIPool) BitMaxIPool { - return (bindex * BitMap_T.MapSize) + mindex; - } - - pub fn read(self: *Self, ipool: BitMaxIPool) BitMap_T.Map_T { - const index, const offset = @call(.always_inline, obtain, .{ - ipool - }); - return self.bitmap[index].map[offset]; - } - - pub fn addrsToIPool(self: *Self, obj: *T) ?BitMaxIPool { - return if(@intFromPtr(obj) < @intFromPtr(&self.pool[0]) and @intFromPtr(obj) > @intFromPtr(&self.pool[self.pool.len - 1])) null else r: { - break :r @intCast((@intFromPtr(obj) - @intFromPtr(&self.pool[0])) / @sizeOf(T)); - }; - } - - pub fn set(self: *Self, ipool: BitMaxIPool, value: BitMap_T.Map_T) void { - const index, const offset = @call(.always_inline, obtain, .{ - ipool - }); - self.bitmap[index].map[offset] = value; - } - }; - - fn auto(self: *Self) InternalErr_T!*T { - return r: { - const init, const end = t: { - if(self.cindex != null and self.cindex.? + @intFromEnum(optimize.range) < self.cache.len) - break :t .{ self.cindex.?, self.cindex.? + @intFromEnum(optimize.range) }; - break :t .{ 0, @intFromEnum(optimize.range) }; - }; - for(init..end) |_| { - break :r @call(.always_inline, &fast, .{ - self, false - }) catch continue; - } - t: { - return @call(.never_inline, &continuos, .{ - self, self.lindex orelse break :t {}, self.lindex.? + @intFromEnum(optimize.range) - }) catch break :t {}; - } - return @call(.never_inline, &continuos, .{ - self, null, null - }) catch unreachable; // Se realmente tem memoria disponivel nunca chegara no catch - }; - } - - fn fast(self: *Self, passthrough: bool) InternalErr_T!*T { - return r: { - const Steps: type = enum { - shot, - sync, - continuos, - }; - sw: switch(Steps.shot) { - .shot => { - if(self.cindex) |cindex| { - break :r if(@call(.always_inline, &BitMap.read, .{ - self, self.cache[cindex] orelse continue :sw .sync - }) == .busy) continue :sw .sync else u: { - @call(.always_inline, &BitMap.set, .{ - self, self.cache[cindex].?, .busy - }); - self.allocs += 1; - self.cindex = null; - self.cindex = if(cindex < self.cache.len - 1) cindex + 1 else null; - self.lindex = if(self.lindex) |_| i: { - if(self.lindex.? != self.cache[cindex]) break :i self.lindex.?; - if(self.lindex.? < self.pool.len - 1) break :i self.lindex.? + 1; - break :i null; - } else null; - const ipool = self.cache[cindex].?; - self.cache[cindex] = null; - break :u &self.pool[ipool]; - };} - continue :sw .sync; - }, - - .sync => { - switch(comptime cache.sync) { - .burning => { - @call(.always_inline, &CacheAction.sync, .{ - self - }) catch continue :sw .continuos; - continue :sw .shot; - }, - - .heated, .chilled => { - if(self.cmiss >= @intFromEnum(cache.sync)) { - @call(.never_inline, &CacheAction.sync, .{ - self - }) catch continue :sw .continuos; self.cmiss = 0; - continue :sw .shot; - } - self.cmiss += 1; continue :sw .continuos; - }, - } - }, - - .continuos => { - break :r if(passthrough) @call(.never_inline, &continuos, .{ - self, null, null - }) catch unreachable else break :r InternalErr_T.NonOptimize; - }, - } - unreachable; - }; - } - - fn continuos(self: *Self, init: ?BitMaxIPool, end: ?BitMaxIPool) InternalErr_T!*T { - return r: { - for( - init orelse 0 - .. - if(end == null or end.? > self.pool.len) self.pool.len else end.? - ) |i| { - if(@call(.always_inline, &BitMap.read, .{ - self, @as(BitMaxIPool, @intCast(i)) - }) == .free) { - @call(.always_inline, &BitMap.set, .{ - self, @as(BitMaxIPool, @intCast(i)), .busy - }); - self.allocs += 1; - self.lindex = if(i < self.pool.len - 1) @as(BitMaxIPool, @intCast(i)) + 1 else null; - break : r &self.pool[i]; - } - } - break :r InternalErr_T.Rangeless; - }; - } - - pub const alloc = switch(optimize.type) { - .dinamic => struct { - pub fn dinamic(self: *Self, calling: Optimize_T.CallingAlloc_T) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else switch(calling) { - Optimize_T.CallingAlloc_T.auto => @call(.never_inline, &auto, .{ - self - }) catch err_T.UndefinedAction, - Optimize_T.CallingAlloc_T.continuos => @call(.never_inline, &continuos, .{ - self, self.lindex, self.pool.len - }) catch err_T.UndefinedAction, - Optimize_T.CallingAlloc_T.fast => @call(.never_inline, &fast, .{ - self, true - }) catch err_T.UndefinedAction, - }; - } - }.dinamic, - - .linear => struct { - pub fn linear(self: *Self) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else @call(.always_inline, &continuos, .{ - self, self.lindex, null - }) catch err_T.UndefinedAction; - } - }.linear, - - .optimized => struct { - pub fn optimized(self: *Self) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else @call(.always_inline, &auto, .{ - self - }) catch err_T.UndefinedAction; - } - }.optimized, - }; - - pub fn free(self: *Self, obj: *T) err_T!void { - return r: { - const ipool = @call(.always_inline, &BitMap.addrsToIPool, .{ - self, obj - }); - if(ipool == null) break :r err_T.IndexOutBounds; - if(@call(.always_inline, &BitMap.read, .{ - self, ipool.? - }) == .free) break :r err_T.DoubleFree; - @call(.always_inline, &BitMap.set, .{ - self, ipool.?, .free - }); - self.allocs -= 1; - self.lindex = if(self.lindex) |_| self.lindex else ipool; - if(optimize.type != .linear) - self.cindex = ipool; - }; - } - }; -} diff --git a/kernel/core/devices/test/SOA/types.zig b/kernel/core/devices/test/SOA/types.zig deleted file mode 100644 index 7b206aa..0000000 --- a/kernel/core/devices/test/SOA/types.zig +++ /dev/null @@ -1,116 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: types.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -pub const Optimize_T: type = struct { - /// Defines which allocation strategy will be used. - /// - /// * dynamic: Lets you choose the allocation mode at runtime - /// * linear: Always allocates sequentially in linear order, - /// designed for many consecutive allocations - /// * optimized: Always prioritizes optimization. Use this only when - /// the allocator is “hot,” i.e. many allocations and frees in balance - /// - /// NOTE: For workloads with many consecutive allocations and almost no frees, - /// use `linear`. For balanced allocation/free patterns, use `optimized`. If you - /// want full control, use `dynamic`. - /// - /// Default: .optimized - type: OptimizeAlloc_T = .optimized, - - /// Alignment of allocated objects. - /// - /// Default: .in8 - alignment: OptimizeAlign_T = .in8, - - /// Number of optimization attempts the allocator will try. - /// Using a very large value may add overhead in `optimized` mode - /// if it fails to optimize the allocation. - /// - /// * small: 2 attempts - /// * large: 3 attempts - /// * huge: 4 attempts - /// - /// Default: .large - range: OptimizeRange_T = .large, - - pub const OptimizeAlloc_T: type = enum { - dinamic, - linear, - optimized, - }; - - pub const OptimizeAlign_T: type = enum(u5) { - in2 = 2, - in4 = 4, - in8 = 8, - in16 = 16, - }; - - pub const OptimizeRange_T: type = enum(u5) { - small = 2, - large = 3, - huge = 4, - }; - - pub const CallingAlloc_T: type = enum(u2) { - continuos, - fast, - auto, - }; -}; - -pub const Cache_T: type = struct { - /// Cache size. A larger cache can reduce misses, - /// but cache synchronization may take longer. - /// - /// * auto: Automatically defines the cache size - /// * small: Smaller cache, about 1/4 of the total number of objects - /// * large: Default choice for most cases, about 2/4 of the total objects - /// * huge: Full cache, space for all objects - /// - /// Default: .auto - size: CacheSize_T = .auto, - - /// Frequency of cache synchronization. Higher frequency - /// reduces cache errors, but may negatively impact allocation. - /// - /// * frozen: Never synchronizes, useful when many entries remain free - /// * chilled: Waits for 3 cache misses before synchronizing - /// * heated: Waits for 2 cache misses before synchronizing - /// * burning: Always synchronizes on every allocation - /// - /// Default: .heated - sync: CacheSync_T = .heated, - - /// How synchronization is performed. Choosing the right mode - /// can significantly reduce synchronization cost, especially - /// for larger caches. - /// - /// * PrioritizeHits: Synchronizes the entire cache. Slower, but good - /// when syncs are infrequent (e.g., when using `sync = chilled`) - /// * PrioritizeSpeed: Synchronizes only half of the cache, which helps - /// larger caches maintain steady synchronization and avoid misses - /// - /// Default: .PrioritizeHits - mode: CacheMode_T = .PrioritizeHits, - - pub const CacheMode_T: type = enum(u1) { - PrioritizeHits, - PrioritizeSpeed, - }; - - pub const CacheSize_T: type = enum(u3) { - auto, - small = 4, - large = 2, - huge = 1, - }; - - pub const CacheSync_T: type = enum(u2) { - burning, - chilled = 3, - heated = 2, - }; -}; diff --git a/kernel/core/devices/types.zig b/kernel/core/devices/types.zig index 882a72e..c1dadbb 100644 --- a/kernel/core/devices/types.zig +++ b/kernel/core/devices/types.zig @@ -3,208 +3,81 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -const SOA: type = @import("memory.zig").SOA; +const vfs: type = @import("root").interfaces.vfs; +const builtin: type = @import("builtin"); -pub const MajorNum_T: type = if(@import("builtin").is_test) u6 else @import("root").core.drivers.types.MajorNum_T; -pub const MinorNum_T: type = u8; - -pub const Dev_T: type = struct { - major: MajorNum_T, - minor: MinorNum_T, - type: enum { - char, - block - }, -}; +pub const Major_T: type = u5; +pub const Minor_T: type = u4; pub const DevErr_T: type = error { - MinorInodeCollision, - Locked, - OutOfMinor, - InternalError, + MajorNoNFound, + MinorCollision, + MinorNoExist, + MainMinorOperation, + WithoutMajor, + MajorCollision, + InvalidOperation, + MinorDenied, MinorDoubleFree, - NonMinor, - MajorReturnError, }; -pub const DevicesInodeLevel0: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 2) * (@bitSizeOf(MinorNum_T) / 2); - pub const Base_T: type = [baseSize]?*DevicesInodeLevel1; - base: Base_T, - map: switch(baseSize) { - 8 => u8, - 16 => u16, - else => @compileError( - "representation in bits for minor can not pass from u16" - ), - } = 0, +pub const Ops_T: type = enum { + ioctl, + mount, + umount, + open, + close, + read, + write, }; -pub const DevicesInodeLevel1: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 4) * (@bitSizeOf(MinorNum_T) / 4); - pub const Base_T: type = [baseSize]?*DevicesInodeLevel2; - base: ?*Base_T, - map: switch(baseSize) { - 4 => u4, - 8 => u8, - else => unreachable, - }, - - const Self: type = @This(); - pub const Allocator: type = struct { - pub const Level: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self, - true, - 16, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - - pub const Base: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self.Base_T, - true, - 16, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } +pub const DevType_T: type = enum { + char, + block, +}; - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - }; +pub const DevOps_T: type = struct { + ioctl: ?*const fn(Minor_T, usize, ?*anyopaque) anyerror!usize = null, + mount: if(!builtin.is_test) ?*const fn(Minor_T) anyerror!*const vfs.Superblock_T else void = if(!builtin.is_test) null else {}, + umount: ?*const fn(Minor_T) anyerror!void = null, + open: ?*const fn(Minor_T) anyerror!void = null, + close: ?*const fn(Minor_T) anyerror!void = null, + read: ?*const fn(Minor_T, usize) anyerror![]u8 = null, + write: ?*const fn(Minor_T, []const u8, usize) anyerror!void = null, }; -pub const DevicesInodeLevel2: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 4) * (@bitSizeOf(MinorNum_T) / 4); - pub const Base_T: type = [baseSize]?*Dev_T; - base: ?*Base_T, - map: switch(baseSize) { - 4 => u4, - 8 => u8, - else => unreachable, +pub const Dev_T: type = struct { + name: []const u8, + ops: *const DevOps_T, // device op + type: DevType_T, + minor: ?*const fn(Minor_T) anyerror!void = null, + flags: packed struct { + control: packed struct { + minor: u1, // aceita novos minors + max: u4, // numero maximo de minors + }, + internal: packed struct { + total: u4 = 0, // numero de minors + } = .{}, }, +}; - const Self: type = @This(); - pub const Allocator: type = struct { - pub const Level: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self, - true, - 64, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - - pub const Base: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self.Base_T, - true, - 64, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; +pub const DevBranch_T: type = struct { + dev: *const Dev_T, + minors: [16]u1, - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } + pub fn validade_minor(self: *@This(), minor: Minor_T) void { + self.minors[minor] = 1; + } - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } + pub fn invalidate_minor(self: *@This(), minor: Minor_T) void { + // minor 0 e a primeira instancia do dev, sempre deve existir + if(minor == 0) + return; + self.minors[minor] = 0; + } - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - }; + pub fn is_valid_minor(self: *const @This(), minor: Minor_T) bool { + return self.minors[minor] == 1; + } }; - diff --git a/kernel/core/drivers/allocator.zig b/kernel/core/drivers/allocator.zig deleted file mode 100644 index 99a4115..0000000 --- a/kernel/core/drivers/allocator.zig +++ /dev/null @@ -1,51 +0,0 @@ -// ┌────────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: allocator.zig │ -// │ Author: Linuxperoxo │ -// └────────────────────────────────────────────────┘ - -const memory: type = @import("memory.zig"); -const modules: type = @import("root").modules; - -const SOA: type = memory.SOA; -const Optimize_T: type = SOA.Optimize_T; -const Cache_T: type = SOA.Cache_T; - -const Driver_T: type = @import("types.zig").Driver_T; -const Ops_T: type = @import("types.zig").Ops_T; - -pub const AllocatorErr_T: type = SOAAllocator_T.err_T; -const SOAAllocator_T: type = SOA.buildObjAllocator( - Driver_T, - false, - r: { - if(memory.totalOfPossibleAllocs <= 4) break :r 4; - if((memory.totalOfPossibleAllocs % 2) != 0) break :r memory.totalOfPossibleAllocs + 1; - break :r memory.totalOfPossibleAllocs; - }, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} -); - -var allocator: SOAAllocator_T = .{}; - -pub fn alloc() AllocatorErr_T!*Driver_T { - return @call(.always_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); -} - -pub fn free(obj: ?*Driver_T) AllocatorErr_T!void { - return if(obj == null) {} else @call(.always_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); -} - -pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); -} diff --git a/kernel/core/drivers/core.zig b/kernel/core/drivers/core.zig deleted file mode 100644 index baca309..0000000 --- a/kernel/core/drivers/core.zig +++ /dev/null @@ -1,349 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: core.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Allocator: type = @import("allocator.zig"); -const Extern: type = struct { - pub const Driver_T: type = @import("types.zig").Driver_T; - pub const DriverErr_T: type = @import("types.zig").DriverErr_T; - pub const Ops_T: type = @import("types.zig").Ops_T; - pub const OpsErr_T: type = @import("types.zig").OpsErr_T; - pub const MajorNum_T: type = @import("types.zig").MajorNum_T; - pub const MinorNum_T: type = @import("types.zig").MinorNum_T; -}; -const Internal: type = struct { - pub const MajorLevel0: type = @import("types.zig").MajorLevel0; - pub const MajorLevel1: type = @import("types.zig").MajorLevel1; - pub const MajorLevel2: type = @import("types.zig").MajorLevel2; - pub const Steps: type = enum { - Level0O, - Level1B, - Level1O, - Level2B, - Level2O, - }; -}; - -// A ideia de aplicar esse algoritmo e justamente pensando em -// otimizar acesso a um major, que deve ser extremamente -// eficiente, mas tambem precisamos permitir um tamanho dinamico -// -// Aqui temos um add e um del mais robusto, mas temos uma busca -// por major extremamente veloz, com praticamente 0 overhead, o -// maximo de overhead que vamos ter e ver se o caminho e valido -// mas todos os acessos a busca e sempre certeiro - -var majorsLevels: Internal.MajorLevel0 = .{ - .base = .{ - null - } ** 16, - .map = 0, -}; - -fn majorPartBits(major: Extern.MajorNum_T) struct { u4, u2, u2 } { - return .{ - @intCast((major >> 4) & 0x0F), - @intCast((major >> 2) & 0x03), - @intCast(major & 0x03), - }; -} - -fn valid_path(major: Extern.MajorNum_T) struct { ?Internal.Steps, bool } { - const high, const mid, const low = @call(.always_inline, &majorPartBits, .{ - major - }); - return if(majorsLevels.base[high] == null) .{ Internal.Steps.Level0O, false } else r: { - const Castings = [_]type { - Internal.MajorLevel1, - Internal.MajorLevel2, - }; - const base_offset = [_]u2 { - mid, - low, - }; - var ptr: *anyopaque = &majorsLevels.base[high].?.*; - inline for(0..Castings.len) |i| { - const casting: *Castings[i] = @alignCast(@ptrCast(ptr)); - if(casting.base == null) { - break :r .{ - @as(Internal.Steps, @enumFromInt(i + i + 1)), - false, - }; - } - if(casting.base.?[base_offset[i]] == null) { - break :r .{ - @as(Internal.Steps, @enumFromInt(i + i + 2)), - false, - }; - } - ptr = casting.base.?[base_offset[i]].?; - } - break :r .{ - null, - true, - }; - }; -} - -pub fn add(driver: *const Extern.Driver_T) Extern.DriverErr_T!void { - const broken_level, const result = @call(.never_inline, &valid_path, .{ - driver.major - }); - return if(result) Extern.DriverErr_T.MajorCollision else r: { - const high, const mid, const low = @call(.always_inline, &majorPartBits, .{ - driver.major - }); - sw: switch(broken_level.?) { - .Level0O => { - majorsLevels.base[high] = @call(.never_inline, &Internal.MajorLevel1.Allocator.Level.alloc, .{}) catch |err| switch(err) { - Internal.MajorLevel1.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DriverErr_T.OutMajor, - else => { - break :r Extern.DriverErr_T.InternalError; - }, - }; - majorsLevels.map |= @as(@TypeOf(majorsLevels.map), @intCast(0x01)) << high; - continue :sw .Level1B; - }, - - .Level1B => { - majorsLevels.base[high].?.base = @call(.never_inline, &Internal.MajorLevel1.Allocator.Base.alloc, .{}) catch |err| switch(err) { - Internal.MajorLevel1.Allocator.Base.AllocatorErr_T.OutOfMemory => break :r Extern.DriverErr_T.OutMajor, - else => { - break :r Extern.DriverErr_T.InternalError; - }, - }; for(0..majorsLevels.base[high].?.base.?.len) |i| { - majorsLevels.base[high].?.base.?[i] = null; - } continue :sw .Level1O; - }, - - .Level1O => { - majorsLevels.base[high].?.base.?[mid] = @call(.never_inline, &Internal.MajorLevel2.Allocator.Level.alloc, .{}) catch |err| switch(err) { - Internal.MajorLevel2.Allocator.Level.AllocatorErr_T.OutOfMemory => break :r Extern.DriverErr_T.OutMajor, - else => { - break :r Extern.DriverErr_T.InternalError; - }, - }; - majorsLevels.base[high].?.map |= @as(@TypeOf(majorsLevels.base[high].?.map), @intCast(0x01)) << mid; - continue :sw .Level2B; - }, - - .Level2B => { - majorsLevels.base[high].?.base.?[mid].?.base = @call(.never_inline, &Internal.MajorLevel2.Allocator.Base.alloc, .{}) - catch |err| switch(err) { - Internal.MajorLevel2.Allocator.Base.AllocatorErr_T.OutOfMemory => break :r Extern.DriverErr_T.OutMajor, - else => { - break :r Extern.DriverErr_T.InternalError; - }, - }; for(0..majorsLevels.base[high].?.base.?[mid].?.base.?.len) |i| { - majorsLevels.base[high].?.base.?[mid].?.base.?[i] = null; - } continue :sw .Level2O; - }, - - .Level2O => { - majorsLevels.base[high].?.base.?[mid].?.base.?[low] = @call(.never_inline, &Allocator.alloc, .{}) catch |err| switch(err) { - Allocator.AllocatorErr_T.OutOfMemory => break :r Extern.DriverErr_T.OutMajor, - else => { - break :r Extern.DriverErr_T.InternalError; - }, - }; - majorsLevels.base[high].?.base.?[mid].?.map |= @as(@TypeOf(majorsLevels.base[high].?.base.?[mid].?.map), @intCast(0x01)) << low; - }, - } - majorsLevels.base[high].?.base.?[mid].?.base.?[low].?.* = driver.*; - break :r {}; - }; -} - -pub fn del(major: Extern.MajorNum_T) Extern.DriverErr_T!void { - if(!@import("builtin").is_test) - if(comptime @import("root").modules.countModOfType(.driver) == 0) return; - return if(!@call(.never_inline, &valid_path, .{ - major - }).@"1") Extern.DriverErr_T.DoubleFree else r: { - const high, const mid, const low = @call(.always_inline, &majorPartBits, .{ - major - }); - sw: switch(Internal.Steps.Level2O) { - .Level2O => { - @call(.never_inline, &Allocator.free, .{ - majorsLevels.base[high].?.base.?[mid].?.base.?[low].? - }) catch break :r Extern.DriverErr_T.InternalError; - majorsLevels.base[high].?.base.?[mid].?.base.?[low] = null; - majorsLevels.base[high].?.base.?[mid].?.map &= ~(@as(@TypeOf(majorsLevels.base[high].?.base.?[mid].?.map), 0x01) << low); - continue :sw .Level2B; - }, - - .Level2B => { - if(majorsLevels.base[high].?.base.?[mid].?.map != 0) break :sw {}; - @call(.never_inline, &Internal.MajorLevel2.Allocator.Base.free, .{ - majorsLevels.base[high].?.base.?[mid].?.base - }) catch break :r Extern.DriverErr_T.InternalError; - majorsLevels.base[high].?.base.?[mid].?.base = null; - continue :sw .Level1O; - }, - - .Level1O => { - @call(.never_inline, &Internal.MajorLevel2.Allocator.Level.free, .{ - majorsLevels.base[high].?.base.?[mid] - }) catch break :r Extern.DriverErr_T.InternalError; - majorsLevels.base[high].?.base.?[mid] = null; - majorsLevels.base[high].?.map &= ~(@as(@TypeOf(majorsLevels.base[high].?.map), 0x01) << mid); - continue :sw .Level1B; - }, - - .Level1B => { - if(majorsLevels.base[high].?.map != 0) break :sw {}; - @call(.never_inline, &Internal.MajorLevel1.Allocator.Base.free, .{ - majorsLevels.base[high].?.base - }) catch break :r Extern.DriverErr_T.InternalError; - majorsLevels.base[high].?.base = null; continue :sw .Level0O; - }, - - .Level0O => { - @call(.never_inline, &Internal.MajorLevel1.Allocator.Level.free, .{ - majorsLevels.base[high] - }) catch break :r Extern.DriverErr_T.InternalError; - majorsLevels.base[high] = null; - majorsLevels.map &= ~(@as(@TypeOf(majorsLevels.map), 0x01) << high); - }, - } - break :r {}; - }; -} - -pub fn search(major: Extern.MajorNum_T) Extern.DriverErr_T!*Extern.Driver_T { - const high, const mid, const low = @call(.always_inline, &majorPartBits, .{ - major - }); - return if(!@call(.always_inline, &valid_path, .{ - major - }).@"1") Extern.DriverErr_T.NonFound else majorsLevels.base[high].?.base.?[mid].?.base.?[low].?; -} - -// == Saturn Internal Major Test == - -const TestErr_T: type = error { - UndefinedAction, - UnreachableCode, - MemoryLeakDetected, -}; -const MaxMajorNum: Extern.MajorNum_T = 64; -var majorTester: Extern.Driver_T = .{ - .major = 0, - .ops = .{ - .open = null, - .close = null, - .read = &struct { - pub fn read(_: Extern.MinorNum_T, _: usize) Extern.DriverErr_T![]u8 { - return @constCast("Hello, World!"); - } - }.read, - .write = &struct { - pub fn write(_: Extern.MinorNum_T, _: []const u8) Extern.DriverErr_T!void { - - } - }.write, - .minor = &struct { - pub fn minor(_: Extern.MinorNum_T) Extern.DriverErr_T!void { - - } - }.minor, - .ioctrl = &struct { - fn minor(_: Extern.MinorNum_T, _: usize, _: usize) Extern.OpsErr_T!usize { - return 0xAABB; - } - }.minor, - } -}; - -test "Major Recursive Add" { - majorTester.major = 0; - for(0..MaxMajorNum) |_| { - try add(&majorTester); - add(&majorTester) catch |err| switch(err) { - Extern.DriverErr_T.MajorCollision => {}, - else => return TestErr_T.UnreachableCode, - }; - if((try search(majorTester.major)).major != majorTester.major) { - return TestErr_T.UndefinedAction; - } - majorTester.major += 1; - } -} - -test "Major Recursive Del" { - majorTester.major = 0; - for(0..MaxMajorNum) |_| { - try del(majorTester.major); - del(majorTester.major) catch |err| switch(err) { - Extern.DriverErr_T.DoubleFree => {}, - else => return TestErr_T.UnreachableCode, - }; - try add(&majorTester); - if((try search(majorTester.major)).major != majorTester.major) { - return TestErr_T.UndefinedAction; - } - try del(majorTester.major); - del(majorTester.major) catch |err| switch(err) { - Extern.DriverErr_T.DoubleFree => {}, - else => return TestErr_T.UnreachableCode, - }; - _ = search(majorTester.major) catch |err| switch(err) { - Extern.DriverErr_T.NonFound => {}, - else => return TestErr_T.UnreachableCode, - }; - majorTester.major += 1; - } -} - -test "Major Search With 0 Major" { - majorTester.major = 0; - for(0..MaxMajorNum) |_| { - _ = search(majorTester.major) catch |err| switch(err) { - Extern.DriverErr_T.NonFound => { - majorTester.major += 1; continue; - }, - else => return TestErr_T.UndefinedAction, - }; - return TestErr_T.UnreachableCode; - } -} - -test "Major Recursive Add Again" { - majorTester.major = 0; - for(0..MaxMajorNum) |_| { - try add(&majorTester); - add(&majorTester) catch |err| switch(err) { - Extern.DriverErr_T.MajorCollision => {}, - else => return TestErr_T.UnreachableCode, - }; - if((try search(majorTester.major)).major != majorTester.major) { - return TestErr_T.UndefinedAction; - } - majorTester.major += 1; - } -} - -test "Major Memory Leak Detect" { - for(0..MaxMajorNum) |i| { - try del(@intCast(i)); - } - const Allocators = [_]type { - Allocator, - Internal.MajorLevel1.Allocator.Base, - Internal.MajorLevel1.Allocator.Level, - Internal.MajorLevel2.Allocator.Base, - Internal.MajorLevel2.Allocator.Level, - }; - inline for(Allocators) |allocator| { - if(allocator.haveAllocs()) { - const std: type = @import("std"); - std.debug.print("Memory Leak On Allocator: {s}\n", .{ - @typeName(allocator) - }); - return TestErr_T.MemoryLeakDetected; - } - } -} - diff --git a/kernel/core/drivers/drivers.zig b/kernel/core/drivers/drivers.zig deleted file mode 100644 index 0f6fa93..0000000 --- a/kernel/core/drivers/drivers.zig +++ /dev/null @@ -1,29 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: drivers.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -pub const fun: type = struct { - pub const register = @import("fun.zig").register; - pub const unregister = @import("fun.zig").unregister; - pub const ops: type = struct { - pub const open = @import("ops.zig").open; - pub const close = @import("ops.zig").close; - pub const minor = @import("ops.zig").minor; - pub const read = @import("ops.zig").read; - pub const write = @import("ops.zig").write; - pub const ioctrl = @import("ops.zig").ioctrl; - }; -}; -pub const types: type = struct { - pub const Driver_T: type = @import("types.zig").Driver_T; - pub const DriverErr_T: type = @import("types.zig").DriverErr_T; - pub const Ops_T: type = @import("types.zig").Ops_T; - pub const OpsErr_T: type = @import("types.zig").OpsErr_T; - pub const MajorNum_T: type = @import("types.zig").MajorNum_T; - pub const MinorNum_T: type = @import("types.zig").MinorNum_T; -}; -pub const info: type = struct { - pub const total = @import("memory.zig").totalOfPossibleAllocs; - pub const bits = @import("memory.zig").totalInBits; -}; diff --git a/kernel/core/drivers/fun.zig b/kernel/core/drivers/fun.zig deleted file mode 100644 index 57d3842..0000000 --- a/kernel/core/drivers/fun.zig +++ /dev/null @@ -1,26 +0,0 @@ -// ┌─────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: fun.zig │ -// │ Author: Linuxperoxo │ -// └─────────────────────────────────────────────┘ - -const Driver_T: type = @import("types.zig").Driver_T; -const DriverErr_T: type = @import("types.zig").DriverErr_T; -const Ops_T: type = @import("types.zig").Ops_T; -const OpsErr_T: type = @import("types.zig").OpsErr_T; - -const MajorNum_T: type = @import("types.zig").MajorNum_T; - -const add = @import("core.zig").add; -const del = @import("core.zig").del; - -pub fn register(comptime D: *const Driver_T) DriverErr_T!void { - return @call(.always_inline, &add, .{ - D - }); -} - -pub fn unregister(M: MajorNum_T) DriverErr_T!void { - return @call(.always_inline, &del, .{ - M - }); -} diff --git a/kernel/core/drivers/memory.zig b/kernel/core/drivers/memory.zig deleted file mode 100644 index 0d2b6db..0000000 --- a/kernel/core/drivers/memory.zig +++ /dev/null @@ -1,21 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: memory.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -pub const SOA: type = switch(@import("builtin").is_test) { - true => @import("test/SOA/SOA.zig"), - false => @import("root").memory.SOA, -}; -pub const totalOfPossibleAllocs: comptime_int = if(@import("builtin").is_test) totalInBits else r: { - if(@import("root").config.modules.options.AllowDynamicModulesLoad) - break :r totalInBits; - break :r @import("root").modules.countModOfType(.driver); -}; -pub const totalInBits: comptime_int = r: { - var max: usize = 1; - for(0..@bitSizeOf(@import("types.zig").MajorNum_T)) |_| { - max *= 2; - } - break :r max; -}; diff --git a/kernel/core/drivers/ops.zig b/kernel/core/drivers/ops.zig deleted file mode 100644 index a64b3f3..0000000 --- a/kernel/core/drivers/ops.zig +++ /dev/null @@ -1,69 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: ops.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const Core: type = @import("core.zig"); - -const Driver_T: type = @import("types.zig").Driver_T; -const DriverErr_T: type = @import("types.zig").DriverErr_T; -const Ops_T: type = @import("types.zig").Ops_T; -const OpsErr_T: type = @import("types.zig").OpsErr_T; -const MajorNum_T: type = @import("types.zig").MajorNum_T; -const MinorNum_T: type = @import("types.zig").MinorNum_T; - -const Allocator: type = @import("allocator.zig"); - -const search = struct { - pub fn search(major: MajorNum_T) DriverErr_T!*Driver_T { - return @call(.always_inline, &Core.search, .{ - major - }); - } -}; - -// NOTE: Qualquer acesso ao major, deve passar pelo device, o devfs vai -// auxiliar qualquer acesso do userspace para um major, ele deve pegar o -// o device criado, buscar informacoes sobre ele usando seu minor, para criar -// um device no userspace vamos precisar de um minor obrigatoriamente, podemos -// passar um major tambem, mas nao deve ser obrigatorio. Depois disso, qualquer -// acesso ao dispositivo o devfs vai saber qual o seu minor, e assim consegue -// acessar seu major usando o minor. - -pub fn open(Major: MajorNum_T, Minor: MajorNum_T) DriverErr_T!void { - const major: *Driver_T = @call(.never_inline, &search, .{ - Major - }) catch |err| return err; - return if(major.ops.open) |_| major.ops.open.?(Minor) else DriverErr_T.Unreachable; -} - -pub fn close(Major: MajorNum_T, Minor: MinorNum_T) void { - const major: *Driver_T = @call(.never_inline, &search, .{ - Major - }) catch |err| return err; - return if(major.ops.close) |_| major.ops.close.?(Minor) else DriverErr_T.Unreachable; -} - -pub fn minor(Major: MajorNum_T, Minor: MinorNum_T) DriverErr_T!void { - return (@call(.never_inline, &search, .{ - Major - })).ops.minor.*(Minor); -} - -pub fn read(Major: MajorNum_T, Minor: MinorNum_T, offset: usize) []u8 { - return (@call(.never_inline, &search, .{ - Major - })).ops.read.*(Minor, offset); -} - -pub fn write(Major: MajorNum_T, Minor: MinorNum_T, data: []const u8) void { - return (@call(.never_inline, &search, .{ - Major - })).ops.write.*(Minor, data); -} - -pub fn ioctrl(Major: MajorNum_T, Minor: MinorNum_T, command: usize, data: usize) OpsErr_T!usize { - return (@call(.never_inline, &search, .{ - Major - })).ops.ioctrl.*(Minor, command, data); -} diff --git a/kernel/core/drivers/test/SOA/SOA.zig b/kernel/core/drivers/test/SOA/SOA.zig deleted file mode 100644 index 8a58f31..0000000 --- a/kernel/core/drivers/test/SOA/SOA.zig +++ /dev/null @@ -1,382 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: SOA.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -// === Saturn Object Allocator === -// A SLUB-like allocator -// === === === === === === === === - -pub const Optimize_T: type = @import("types.zig").Optimize_T; -pub const Cache_T: type = @import("types.zig").Cache_T; - -pub const zero = struct { - const Self: type = @This(); - pub fn zero(comptime T: type) T { - @setEvalBranchQuota(4294967295); - switch(@typeInfo(T)) { - .int, .float => return @as(T, 0), - .pointer => |info| if(info.is_allowzero) return @intFromPtr(0) else return undefined, - .null, .optional => return null, - .array => |info| { - var array: T = undefined; - for(0..info.len) |i| { - array[i] = comptime Self.zero(info.child); - } - }, - .@"struct" => |info| { - var @"struct": T = undefined; - for(info.fields) |field| { - @field(@"struct", field.name) = comptime Self.zero(field.type); - } - return @"struct"; - }, - else => {}, - } - return undefined; - } -}.zero; - -pub fn buildObjAllocator( - comptime T: type, - comptime zero_init: bool, - comptime num: usize, - comptime optimize: Optimize_T, - comptime cache: Cache_T, -) type { - comptime { - if(@sizeOf(T) == 0) { - @compileError( - "SOA: type" ++ - @typeName(T) ++ - " cannot have size 0 (incomplete or invalid)." - ); - } - - if(num == 0) { - @compileError("SOA: obj num cannot be zero. This may cause invalid state."); - } - - if((num % 2) != 0) { - @compileError("SOA: obj num must be even. Provided value is odd."); - } - - if(num <= 2) { - @compileError("SOA: obj num must be greater than 2. Provided value is too small. Use 4 with value"); - } - } - return struct { - pool: [num]T = if(zero_init) zero([num]T) else undefined, - allocs: BitMaxIPool = 0, - bitmap: [r: { - break :r (num / BitMap_T.MapSize) + if((num % BitMap_T.MapSize) != 0) 1 else 0; - // essa calculo garante que tenha a quantidade certa - // de bitmap para objetos caso nao seja multiplo do MapSize. - }]BitMap_T = [_]BitMap_T { - BitMap_T { - .map = [_]BitMap_T.Map_T { - .free, - } ** BitMap_T.MapSize, - }, - } ** ((num / BitMap_T.MapSize) + if((num % BitMap_T.MapSize) != 0) 1 else 0), - lindex: ?BitMaxIPool = null, - cindex: CindexType_T = if(CindexType_T == void) {} else null, - cmiss: CmissType_T = if(CmissType_T == void) {} else 0, - cache: CacheType_T = if(optimize.type == .linear) {} else [_]?BitMaxIPool { - null - } ** CacheElementSize, - - const Self: type = @This(); - const BitMap_T: type = struct { - map: [MapSize]Map_T align(1), - - pub const MapSize: comptime_int = 8; - pub const Map_T: type = enum(u1) { - free, - busy, - }; - }; - const BitMaxIPool: type = switch(num) { - 1...255 => u8, - 256...65535 => u16, - else => usize, - }; - const InternalErr_T: type = error { - NonOptimize, - Rangeless, - }; - const CacheType_T: type = if(optimize.type == .linear) void else [CacheElementSize]?BitMaxIPool; - const CindexType_T: type = if(optimize.type == .linear) void else ?BitMaxIPool; - const CmissType_T: type = r: { - if(optimize.type == .linear) break :r void; - switch(cache.sync) { - .burning => break :r void, - else => break :r u2, - } - }; - const CacheElementSize = r: { - const divisor = if(cache.size != .auto and num >= @intFromEnum(cache.size)) @intFromEnum(cache.size) else t: { - sw: switch(@sizeOf(T)) { - 1...16 => if(num <= 16) break :t @intFromEnum(Cache_T.CacheSize_T.huge) else continue :sw 17, - 17...32 => if(num <= 32) break :t @intFromEnum(Cache_T.CacheSize_T.large) else continue :sw 33, - else => break :t @intFromEnum(Cache_T.CacheSize_T.small), - } - }; - break :r num / divisor; - }; - - pub const err_T: type = error { - OutOfMemory, - DoubleFree, - IndexOutBounds, - UndefinedAction, - }; - - pub const Options: type = struct { - pub const Type: type = T; - pub const config: struct { optimize: Optimize_T, cache: Cache_T } = .{ - .optimize = optimize, - .cache = cache, - }; - }; - - const CacheAction: type = struct { - pub const CacheErr_T: type = error { - NonSync, - }; - - var midHigh: u1 = 1; - pub fn sync(self: *Self) CacheErr_T!void { - const init, const end = switch(cache.mode) { - .PrioritizeHits => .{ - 0, self.cache.len - }, - - .PrioritizeSpeed => .{ - (self.cache.len / 2) * midHigh, - (self.cache.len / 2) + ((self.cache.len / 2) * midHigh), - } - }; - var first: ?BitMaxIPool = null; - var bindex: BitMaxIPool, var mindex: BitMaxIPool = .{ 0, 0 }; - for(init..end) |cindex| { - if(self.cache[cindex]) |_| continue; - r: { - while(bindex < self.bitmap.len) : (bindex += 1) { - while(mindex < BitMap_T.MapSize) : (mindex += 1) { - if(self.bitmap[bindex].map[mindex] == .free) { - self.cache[cindex] = @call(.always_inline, &BitMap.bitMapIndexToIPool, .{ - bindex, mindex - }); - first = if(first) |_| first else @intCast(cindex); - mindex += 1; - break :r {}; - } - } - mindex = 0; - } - } - } - midHigh ^= 1; - self.cindex = first orelse return CacheErr_T.NonSync; - } - - pub fn push(_: *Self) CacheErr_T!void { - - } - }; - - const BitMap: type = struct { - fn obtain(ipool: BitMaxIPool) struct { BitMaxIPool, u4 } { - return .{ - ipool / BitMap_T.MapSize, - @intCast(ipool % BitMap_T.MapSize), - }; - } - - pub fn bitMapIndexToIPool(bindex: BitMaxIPool, mindex: BitMaxIPool) BitMaxIPool { - return (bindex * BitMap_T.MapSize) + mindex; - } - - pub fn read(self: *Self, ipool: BitMaxIPool) BitMap_T.Map_T { - const index, const offset = @call(.always_inline, obtain, .{ - ipool - }); - return self.bitmap[index].map[offset]; - } - - pub fn addrsToIPool(self: *Self, obj: *T) ?BitMaxIPool { - return if(@intFromPtr(obj) < @intFromPtr(&self.pool[0]) and @intFromPtr(obj) > @intFromPtr(&self.pool[self.pool.len - 1])) null else r: { - break :r @intCast((@intFromPtr(obj) - @intFromPtr(&self.pool[0])) / @sizeOf(T)); - }; - } - - pub fn set(self: *Self, ipool: BitMaxIPool, value: BitMap_T.Map_T) void { - const index, const offset = @call(.always_inline, obtain, .{ - ipool - }); - self.bitmap[index].map[offset] = value; - } - }; - - fn auto(self: *Self) InternalErr_T!*T { - return r: { - const init, const end = t: { - if(self.cindex != null and self.cindex.? + @intFromEnum(optimize.range) < self.cache.len) - break :t .{ self.cindex.?, self.cindex.? + @intFromEnum(optimize.range) }; - break :t .{ 0, @intFromEnum(optimize.range) }; - }; - for(init..end) |_| { - break :r @call(.always_inline, &fast, .{ - self, false - }) catch continue; - } - t: { - return @call(.never_inline, &continuos, .{ - self, self.lindex orelse break :t {}, self.lindex.? + @intFromEnum(optimize.range) - }) catch break :t {}; - } - return @call(.never_inline, &continuos, .{ - self, null, null - }) catch unreachable; // Se realmente tem memoria disponivel nunca chegara no catch - }; - } - - fn fast(self: *Self, passthrough: bool) InternalErr_T!*T { - return r: { - const Steps: type = enum { - shot, - sync, - continuos, - }; - sw: switch(Steps.shot) { - .shot => { - if(self.cindex) |cindex| { - break :r if(@call(.always_inline, &BitMap.read, .{ - self, self.cache[cindex] orelse continue :sw .sync - }) == .busy) continue :sw .sync else u: { - @call(.always_inline, &BitMap.set, .{ - self, self.cache[cindex].?, .busy - }); - self.allocs += 1; - self.cindex = null; - self.cindex = if(cindex < self.cache.len - 1) cindex + 1 else null; - self.lindex = if(self.lindex) |_| i: { - if(self.lindex.? != self.cache[cindex]) break :i self.lindex.?; - if(self.lindex.? < self.pool.len - 1) break :i self.lindex.? + 1; - break :i null; - } else null; - const ipool = self.cache[cindex].?; - self.cache[cindex] = null; - break :u &self.pool[ipool]; - };} - continue :sw .sync; - }, - - .sync => { - switch(comptime cache.sync) { - .burning => { - @call(.always_inline, &CacheAction.sync, .{ - self - }) catch continue :sw .continuos; - continue :sw .shot; - }, - - .heated, .chilled => { - if(self.cmiss >= @intFromEnum(cache.sync)) { - @call(.never_inline, &CacheAction.sync, .{ - self - }) catch continue :sw .continuos; self.cmiss = 0; - continue :sw .shot; - } - self.cmiss += 1; continue :sw .continuos; - }, - } - }, - - .continuos => { - break :r if(passthrough) @call(.never_inline, &continuos, .{ - self, null, null - }) catch unreachable else break :r InternalErr_T.NonOptimize; - }, - } - unreachable; - }; - } - - fn continuos(self: *Self, init: ?BitMaxIPool, end: ?BitMaxIPool) InternalErr_T!*T { - return r: { - for( - init orelse 0 - .. - if(end == null or end.? > self.pool.len) self.pool.len else end.? - ) |i| { - if(@call(.always_inline, &BitMap.read, .{ - self, @as(BitMaxIPool, @intCast(i)) - }) == .free) { - @call(.always_inline, &BitMap.set, .{ - self, @as(BitMaxIPool, @intCast(i)), .busy - }); - self.allocs += 1; - self.lindex = if(i < self.pool.len - 1) @as(BitMaxIPool, @intCast(i)) + 1 else null; - break : r &self.pool[i]; - } - } - break :r InternalErr_T.Rangeless; - }; - } - - pub const alloc = switch(optimize.type) { - .dinamic => struct { - pub fn dinamic(self: *Self, calling: Optimize_T.CallingAlloc_T) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else switch(calling) { - Optimize_T.CallingAlloc_T.auto => @call(.never_inline, &auto, .{ - self - }) catch err_T.UndefinedAction, - Optimize_T.CallingAlloc_T.continuos => @call(.never_inline, &continuos, .{ - self, self.lindex, self.pool.len - }) catch err_T.UndefinedAction, - Optimize_T.CallingAlloc_T.fast => @call(.never_inline, &fast, .{ - self, true - }) catch err_T.UndefinedAction, - }; - } - }.dinamic, - - .linear => struct { - pub fn linear(self: *Self) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else @call(.always_inline, &continuos, .{ - self, self.lindex, null - }) catch err_T.UndefinedAction; - } - }.linear, - - .optimized => struct { - pub fn optimized(self: *Self) err_T!*T { - return if(self.allocs >= num) err_T.OutOfMemory else @call(.always_inline, &auto, .{ - self - }) catch err_T.UndefinedAction; - } - }.optimized, - }; - - pub fn free(self: *Self, obj: *T) err_T!void { - return r: { - const ipool = @call(.always_inline, &BitMap.addrsToIPool, .{ - self, obj - }); - if(ipool == null) break :r err_T.IndexOutBounds; - if(@call(.always_inline, &BitMap.read, .{ - self, ipool.? - }) == .free) break :r err_T.DoubleFree; - @call(.always_inline, &BitMap.set, .{ - self, ipool.?, .free - }); - self.allocs -= 1; - self.lindex = if(self.lindex) |_| self.lindex else ipool; - if(optimize.type != .linear) - self.cindex = ipool; - }; - } - }; -} diff --git a/kernel/core/drivers/test/SOA/types.zig b/kernel/core/drivers/test/SOA/types.zig deleted file mode 100644 index 7b206aa..0000000 --- a/kernel/core/drivers/test/SOA/types.zig +++ /dev/null @@ -1,116 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: types.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -pub const Optimize_T: type = struct { - /// Defines which allocation strategy will be used. - /// - /// * dynamic: Lets you choose the allocation mode at runtime - /// * linear: Always allocates sequentially in linear order, - /// designed for many consecutive allocations - /// * optimized: Always prioritizes optimization. Use this only when - /// the allocator is “hot,” i.e. many allocations and frees in balance - /// - /// NOTE: For workloads with many consecutive allocations and almost no frees, - /// use `linear`. For balanced allocation/free patterns, use `optimized`. If you - /// want full control, use `dynamic`. - /// - /// Default: .optimized - type: OptimizeAlloc_T = .optimized, - - /// Alignment of allocated objects. - /// - /// Default: .in8 - alignment: OptimizeAlign_T = .in8, - - /// Number of optimization attempts the allocator will try. - /// Using a very large value may add overhead in `optimized` mode - /// if it fails to optimize the allocation. - /// - /// * small: 2 attempts - /// * large: 3 attempts - /// * huge: 4 attempts - /// - /// Default: .large - range: OptimizeRange_T = .large, - - pub const OptimizeAlloc_T: type = enum { - dinamic, - linear, - optimized, - }; - - pub const OptimizeAlign_T: type = enum(u5) { - in2 = 2, - in4 = 4, - in8 = 8, - in16 = 16, - }; - - pub const OptimizeRange_T: type = enum(u5) { - small = 2, - large = 3, - huge = 4, - }; - - pub const CallingAlloc_T: type = enum(u2) { - continuos, - fast, - auto, - }; -}; - -pub const Cache_T: type = struct { - /// Cache size. A larger cache can reduce misses, - /// but cache synchronization may take longer. - /// - /// * auto: Automatically defines the cache size - /// * small: Smaller cache, about 1/4 of the total number of objects - /// * large: Default choice for most cases, about 2/4 of the total objects - /// * huge: Full cache, space for all objects - /// - /// Default: .auto - size: CacheSize_T = .auto, - - /// Frequency of cache synchronization. Higher frequency - /// reduces cache errors, but may negatively impact allocation. - /// - /// * frozen: Never synchronizes, useful when many entries remain free - /// * chilled: Waits for 3 cache misses before synchronizing - /// * heated: Waits for 2 cache misses before synchronizing - /// * burning: Always synchronizes on every allocation - /// - /// Default: .heated - sync: CacheSync_T = .heated, - - /// How synchronization is performed. Choosing the right mode - /// can significantly reduce synchronization cost, especially - /// for larger caches. - /// - /// * PrioritizeHits: Synchronizes the entire cache. Slower, but good - /// when syncs are infrequent (e.g., when using `sync = chilled`) - /// * PrioritizeSpeed: Synchronizes only half of the cache, which helps - /// larger caches maintain steady synchronization and avoid misses - /// - /// Default: .PrioritizeHits - mode: CacheMode_T = .PrioritizeHits, - - pub const CacheMode_T: type = enum(u1) { - PrioritizeHits, - PrioritizeSpeed, - }; - - pub const CacheSize_T: type = enum(u3) { - auto, - small = 4, - large = 2, - huge = 1, - }; - - pub const CacheSync_T: type = enum(u2) { - burning, - chilled = 3, - heated = 2, - }; -}; diff --git a/kernel/core/drivers/types.zig b/kernel/core/drivers/types.zig deleted file mode 100644 index f4e7da7..0000000 --- a/kernel/core/drivers/types.zig +++ /dev/null @@ -1,224 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: types.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -pub const MajorNum_T: type = u8; -pub const MinorNum_T: type = if(@import("builtin").is_test) u8 else @import("root").interfaces.devices.MinorNum_T; - -pub const OpsErr_T: type = error { - NoCMD, - Failed, - Unreachable, -}; - -pub const DriverErr_T: type = error { - InternalError, - Blocked, - NonFound, - MajorCollision, - OutMajor, - DoubleFree, - MinorCollision, - UndefinedMajor, - UndefinedMinor, - Unreachable, -}; - -pub const Ops_T: type = struct { - read: *const fn(minor: MinorNum_T, offset: usize) DriverErr_T![]u8, - write: *const fn(minor: MinorNum_T, data: []const u8) DriverErr_T!void, - ioctrl: *const fn(minor: MinorNum_T, command: usize, data: usize) OpsErr_T!usize, - minor: *const fn(minor: MinorNum_T) DriverErr_T!void, - open: ?*const fn(minor: MinorNum_T) DriverErr_T!void, - close: ?*const fn(minor: MinorNum_T) DriverErr_T!void, -}; - -pub const Driver_T: type = struct { - major: MajorNum_T, - ops: Ops_T, -}; - -pub const MajorLevel0: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 2) * (@bitSizeOf(MinorNum_T) / 2); - pub const Base_T: type = [baseSize]?*MajorLevel1; - base: Base_T, - map: switch(baseSize) { - 16 => u16, - else => @compileError( - "" - ), - }, -}; - -pub const MajorLevel1: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 4) * (@bitSizeOf(MinorNum_T) / 4); - pub const Base_T: type = [baseSize]?*MajorLevel2; - base: ?*Base_T, - map: switch(baseSize) { - 4 => u4, - else => @compileError( - "" - ), - }, - - const SOA: type = @import("memory.zig").SOA; - const Self: type = @This(); - pub const Allocator: type = struct { - pub const Level: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self, - true, - 16, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.never_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.never_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - - pub const Base: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self.Base_T, - true, - 16, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.never_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.never_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - }; -}; - -pub const MajorLevel2: type = struct { - pub const baseSize: comptime_int = (@bitSizeOf(MinorNum_T) / 4) * (@bitSizeOf(MinorNum_T) / 4); - pub const Base_T: type = [baseSize]?*Driver_T; - base: ?*Base_T, - map: switch(baseSize) { - 4 => u4, - else => @compileError( - "" - ), - }, - - const SOA: type = @import("memory.zig").SOA; - const Self: type = @This(); - pub const Allocator: type = struct { - pub const Level: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self, - true, - 64, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.never_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.never_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - - pub const Base: type = struct { - pub const AllocatorErr_T: type = SOAAllocator_T.err_T; - const SOAAllocator_T: type = SOA.buildObjAllocator( - Self.Base_T, - true, - 64, - .{ - .alignment = @enumFromInt(@sizeOf(usize)), - .range = .large, - .type = .linear, - }, - .{} - ); - - var allocator: SOAAllocator_T = .{}; - - pub fn alloc() AllocatorErr_T!*SOAAllocator_T.Options.Type { - return @call(.never_inline, &SOAAllocator_T.alloc, .{ - &allocator - }); - } - - pub fn free(obj: ?*SOAAllocator_T.Options.Type) AllocatorErr_T!void { - return if(obj == null) {} else @call(.never_inline, &SOAAllocator_T.free, .{ - &allocator, obj.? - }); - } - - pub fn haveAllocs() bool { - return if(@import("builtin").is_test) allocator.allocs != 0 else @compileError( - "fn haveAllocs run in test mode only" - ); - } - }; - }; -}; diff --git a/kernel/core/module/aux.zig b/kernel/core/module/aux.zig index f859b4a..13663e5 100644 --- a/kernel/core/module/aux.zig +++ b/kernel/core/module/aux.zig @@ -23,75 +23,29 @@ pub inline fn module_root_entry(mod_type: ModType_T) *ModRoot_T { unreachable; } -pub inline fn find_handler(mod_type: ModType_T) *const ModHandler_T { - for(&main.handlers) |*handler| { - switch(handler.*) { - .filesystem => if(mod_type == .filesystem) return handler else continue, - else => unreachable, - } - } - unreachable; -} - -pub inline fn resolve_mod_type(mod: *const Mod_T) ModType_T { - return switch(mod.type) { - .filesystem => ModType_T.filesystem, - else => unreachable, - }; -} - -pub inline fn calling_handler(mod: *Mod_T, comptime op: enum { install, remove }) ModErr_T!void { - const handler: *const ModHandler_T = find_handler( - resolve_mod_type(mod) - ); - switch(handler.*) { - .filesystem => |f| { - switch(@typeInfo(@TypeOf(f))) { - .void => return, - else => {}, - } - if(@field(f, @tagName(op)) != null) { - @call(.never_inline, @field(f, @tagName(op)).?, .{ - &mod.private.filesystem - }) catch return ModErr_T.SectionHandlerError; - } - }, - else => unreachable, - } -} - -pub fn search_by_module(module_root: *ModRoot_T, ptr: ?*const Mod_T, name: ?[]const u8) ModErr_T!struct { *Mod_T, ModFoundByType_T } { +pub fn search_by_module(module_root: *ModRoot_T, ptr: ?*const Mod_T, name: ?[]const u8) ModErr_T!*const Mod_T { var param: struct { mod_ptr: ?*const Mod_T, mod_name: ?[]const u8, - mod_found: ?ModFoundByType_T, } = .{ .mod_ptr = ptr, .mod_name = name, - .mod_found = null, }; - return .{ - module_root.list.iterator_handler( - ¶m, - &opaque { - pub fn handler(iterator_mod: *Mod_T, mod_to_found: @TypeOf(¶m)) anyerror!void { - if(mod_to_found.mod_ptr != null and iterator_mod == mod_to_found.mod_ptr.?) { - mod_to_found.mod_found = .pointer; - return; - } - if(mod_to_found.mod_name != null - and mem.eql(iterator_mod.name, mod_to_found.mod_name.?, .{ .case = true })) { - mod_to_found.mod_found = .pointer; - return; - } - return error.Continue; + return module_root.list.iterator_handler( + ¶m, + &opaque { + pub fn handler(iterator_mod: *const Mod_T, mod_to_found: @TypeOf(¶m)) anyerror!void { + if(mod_to_found.mod_ptr != null and iterator_mod == mod_to_found.mod_ptr.? or + (mod_to_found.mod_name != null and + mem.eql(iterator_mod.name, mod_to_found.mod_name.?, .{ .case = true }))) { + return; } - }.handler, - ) catch |err| return switch (err) { - @TypeOf(module_root.list).ListErr_T.EndOfIterator, - @TypeOf(module_root.list).ListErr_T.WithoutNodes => ModErr_T.NoNFound, - else => ModErr_T.IteratorFailed, - }, - param.mod_found.?, + return error.Continue; + } + }.handler, + ) catch |err| return switch (err) { + @TypeOf(module_root.list).ListErr_T.EndOfIterator, + @TypeOf(module_root.list).ListErr_T.WithoutNodes => ModErr_T.NoNFound, + else => ModErr_T.IteratorFailed, }; } diff --git a/kernel/core/module/main.zig b/kernel/core/module/main.zig index a0189a4..314fced 100644 --- a/kernel/core/module/main.zig +++ b/kernel/core/module/main.zig @@ -15,20 +15,7 @@ const builtin: type = @import("builtin"); const allocator: type = @import("allocator.zig"); const mem: type = if(!builtin.is_test) @import("root").lib.utils.mem else @import("test/mem.zig"); const fs: type = @import("root").interfaces.fs; - -// poderiamos colocar os tipos nos index -// @intFromEnum() do array, mas decidi deixar -// assim do jeito que esta ja que sao poucos -// tipos de modulos - -pub const handlers = [_]ModHandler_T { - ModHandler_T { - .filesystem = if(builtin.is_test) {} else .{ - .install = fs.register_fs, - .remove = fs.unregister_fs, - }, - }, -}; +const devices: type = @import("root").interfaces.devices; // nenhuma das outras partes do kernel tem obrigacao de salvar // os modulos do seu tipo, mas podem sim querer salvar e deixar @@ -38,114 +25,79 @@ pub var modules_entries = [_]ModRoot_T { ModRoot_T { .list = .{}, .type = .filesystem, - .flags = .{ - .init = 0 - }, + .init = 0 + }, + + ModRoot_T { + .list = .{}, + .type = .driver, + .init = 0, }, }; pub const test_fn = if(!builtin.is_test) @compileError("only in tests") else opaque { pub fn entry_init_flag(index: usize) u1 { - return modules_entries[index].flags.init; + return modules_entries[index].init; } }; /// * search module by name and type -pub fn srchmod(name: []const u8, mod_type: ModType_T) ModErr_T!*const Mod_T { - const module_root: *ModRoot_T = aux.module_root_entry( - mod_type - ); - if(module_root.flags.init == 0) return ModErr_T.NoNFound; +pub noinline fn srchmod(name: []const u8, mod_type: ModType_T) ModErr_T!*const Mod_T { + const module_root: *ModRoot_T = aux.module_root_entry(mod_type); if(aux.search_by_module(module_root, null, name)) |mod_found| { - const module, _ = mod_found; - if(module.flags.control.anon == 1) + if(mod_found.control.anon == 1) return ModErr_T.NoNFound; - return module; + return mod_found; } else |err| { return err; } } /// * install module -pub fn inmod(mod: *Mod_T) ModErr_T!void { - const module_root: *ModRoot_T = aux.module_root_entry( - aux.resolve_mod_type(mod) - ); - module_root.flags.init = if(module_root.flags.init == 1) module_root.flags.init else r: { +pub noinline fn inmod(mod: *const Mod_T) ModErr_T!void { + const module_root: *ModRoot_T = aux.module_root_entry(mod.type); + + module_root.init = if(module_root.init == 1) module_root.init else r: { module_root.list.init(&allocator.sba.allocator) catch return ModErr_T.ListInitFailed; break :r 1; }; - if(aux.search_by_module(module_root, mod, mod.name)) |mod_found| { - const module, const collision = mod_found; - @as(*u2, @alignCast(@ptrCast(&module.flags.internal.collision))).* = @as(u2, @intCast(@intFromEnum(collision))); + + if(aux.search_by_module(module_root, mod, mod.name)) |_| { return ModErr_T.ModuleCollision; } else |err| switch(err) { ModErr_T.NoNFound => {}, else => return err, } + module_root.list.push_in_list(&allocator.sba.allocator, mod) catch return ModErr_T.ListOperationError; - mod.flags.internal.installed = 1; - mod.flags.internal.removed = 0; - if(mod.flags.control.call.init == 1) { - mod.flags.internal.call.init = 1; - mod.init() catch { - mod.flags.internal.fault.call.init = 1; - return; - }; - } - if(c.c_bool(mod.flags.control.call.handler.install)) { - mod.flags.internal.call.handler.install = 1; - aux.calling_handler(mod, .install) catch { - mod.flags.internal.fault.call.handler.install = 1; - // klog() - // aqui nao deve dar return - }; - } - if(mod.flags.control.call.after == 1) { - if(mod.after == null) { - mod.flags.internal.fault.call.after = 1; - return; - } - mod.flags.internal.call.after = 1; - mod.after.?() catch { - mod.flags.internal.fault.call.after = 1; - }; - } + + if(mod.control.init == 1) + mod.init() catch return ModErr_T.InitFailed; } /// * remove module -pub fn rmmod(mod: *Mod_T) ModErr_T!void { - const module_root: *ModRoot_T = aux.module_root_entry( - aux.resolve_mod_type(mod) - ); +pub noinline fn rmmod(mod: *const Mod_T) ModErr_T!void { + const module_root: *ModRoot_T = aux.module_root_entry(mod.type); + if(module_root.init == 0) + return ModErr_T.NoNFound; + // esse iterator serve para colocar o index do iterator exatamente // no modulo que queremos _ = try aux.search_by_module(module_root, mod, null); - if(mod.flags.control.call.remove == 0) { - mod.flags.internal.fault.remove = 1; + if(mod.control.remove == 0) return ModErr_T.OperationDenied; - } + module_root.list.drop_on_list( // o index do iterator - 1 vai estar exatamente no modulo // que queremos (module_root.list.iterator_index() catch unreachable) - 1, &allocator.sba.allocator, ) catch return ModErr_T.AllocatorError; // aqui so pode dar erro do alocador - module_root.flags.init = @intFromBool(module_root.list.how_many_nodes() > 0); - if(c.c_bool(mod.flags.control.call.handler.remove)) { - mod.flags.internal.call.handler.remove = 1; - aux.calling_handler(mod, .remove) catch { - mod.flags.internal.fault.call.handler.remove = 1; - }; - } - mod.flags.internal.installed = 0; - mod.flags.internal.removed = 1; - if(mod.flags.control.call.exit == 1) { - mod.flags.internal.call.exit = 1; - mod.exit() catch { - mod.flags.internal.fault.call.exit = 1; - }; - } + + module_root.init = @intFromBool(module_root.list.how_many_nodes() > 0); + + if(mod.control.exit == 1) + mod.exit() catch return ModErr_T.ExitFailed; } diff --git a/kernel/core/module/module.zig b/kernel/core/module/module.zig index f6c54a8..0084c9c 100644 --- a/kernel/core/module/module.zig +++ b/kernel/core/module/module.zig @@ -4,6 +4,7 @@ // └──────────────────────────────────────────────┘ pub const Mod_T: type = @import("types.zig").Mod_T; +pub const ModControlFlags_T: type = @import("types.zig").ModControlFlags_T; pub const ModType_T: type = @import("types.zig").ModType_T; pub const ModErr_T: type = @import("types.zig").ModErr_T; pub const ModuleDescriptionTarget_T: type = @import("types.zig").ModuleDescriptionTarget_T; diff --git a/kernel/core/module/types.zig b/kernel/core/module/types.zig index 2d07e37..41469e2 100644 --- a/kernel/core/module/types.zig +++ b/kernel/core/module/types.zig @@ -7,10 +7,8 @@ const builtin: type = @import("builtin"); const list: type = @import("test/list.zig"); const arch: type = @import("root").interfaces.arch; const fs: type = @import("root").interfaces.fs; +const devices: type = @import("root").interfaces.devices; const modsys: type = @import("root").modsys; -const csl: type = @import("root").interfaces.csl; - -// Interfaces pub const ModuleDescriptionTarget_T: type = arch.Target_T; @@ -29,133 +27,46 @@ pub const Mod_T: type = struct { license: ModLicense_T, type: ModType_T, init: *const fn() anyerror!void, - after: ?*const fn() anyerror!void = null, exit: *const fn() anyerror!void, - private: union(ModType_T) { - driver: void, - syscall: void, - irq: void, - filesystem: if(!builtin.is_test) fs.Fs_T else void, - }, - flags: packed struct { - control: packed struct(u8) { - anon: u1, // srchmod() nao expoe modulo - call: packed struct { - init: u1, // chama init logo no inmod() - after: u1, // chama o after logo no inmod() apos chamada de init - exit: u1, // chama exit logo no rmmod() - remove: u1, // modulo aceita ser removido - handler: packed struct { - install: u1, - remove: u1, - }, - }, - reserved: u1 = 0, - }, - internal: packed struct(u16) { - installed: u1 = 0, // foi instalado - removed: u1 = 0, // foi removido - collision: packed struct { - name: u1 = 0, // nomes iguais - pointer: u1 = 0, // ponteiros iguais (double reg) - } = .{}, - call: packed struct { - init: u1 = 0, // init foi chamado - after: u1 = 0, // after foi chamado - exit: u1 = 0, // exit foi chamado - handler: packed struct { - install: u1 = 0, - remove: u1 = 0, - } = .{}, - } = .{}, - fault: packed struct { - remove: u1 = 0, // tentativa de remover o modulo que nao aceita ser removido - // para saber se a operacao deu certo basta fazer - // (control.call.init & internal.call.init & ~internal.fault.call.init) == 1 - call: packed struct { - init: u1 = 0, // init retornou erro - after: u1 = 0, // after retornou erro ou tentou ser chamado com ptr sendo null - exit: u1 = 0, // exit retornou erro - handler: packed struct { - install: u1 = 0, - remove: u1 = 0, - } = .{}, - } = .{}, - } = .{}, - reserved: u1 = 0, - } = .{}, - - pub inline fn check_op_status(self: *const @This(), comptime op: enum { init, after, exit, install, remove }) u1 { - return switch (comptime op) { - .init => self.control.call.init & self.internal.call.init & (~self.internal.fault.call.init), - .after => self.control.call.after & self.internal.call.after & (~self.internal.fault.call.after), - .exit => self.control.call.exit & self.internal.call.exit & (~self.internal.fault.call.exit), - .install => self.control.call.handler.install & self.internal.call.handler.install & (~self.internal.fault.call.handler.install), - .remove => self.control.call.handler.remove & self.internal.call.handler.remove & (~self.internal.fault.call.handler.remove), - }; - } - }, + control: *const ModControlFlags_T, }; -pub const ModType_T: type = enum(u8) { - driver, - syscall, - irq, - filesystem, +pub const ModControlFlags_T: type = packed struct { + anon: u1, + init: u1, + exit: u1, + remove: u1, }; -pub const ModLicense_T: type = enum(u8) { - GPL2_only, - GPL2_or_later, - GPL3_only, - GPL3_or_later, - BSD_2_Clause, - BSD_3_Clause, - MIT, - APACHE_2_0, - PROPRIETARY, -}; +pub const ModuleDescription_T: type = struct { + mod: *const Mod_T, + load: ModuleDescriptionLoad_T, + arch: []const ModuleDescriptionTarget_T, // arch suportadas + c_sources: ?[]const[]const u8 = null, + panic: bool = false, + blacklist: ?[]const[]const u8 = null, + libs: struct { + mines: ?[]const ModuleDescriptionLibMine_T = null, + outside: ?[]const ModuleDescriptionLibOut_T = null, + } = .{}, -pub const ModFoundByType_T: type = enum(u2) { - name = 0b01, - pointer = 0b10, -}; + pub fn request_all(comptime self: *const @This()) struct { [ + if(self.libs.outside == null) 0 else + self.libs.outside.?.len + ]?type, bool } { + return comptime modsys.smll.search_all(self); + } -pub const ModRoot_T: type = struct { - list: list.BuildList(*Mod_T), - type: ModType_T, - flags: packed struct(u8) { - init: u1, - reserved: u7 = 0, - }, -}; + pub fn request_libs(comptime self: *const @This(), comptime libs: []const[]const u8) struct { [libs.len]?type, bool } { + return comptime modsys.smll.search_libs(self, libs); + } -pub const ModErr_T: type = error { - SectionHandlerError, - NoNFound, - IteratorFailed, - ListInitFailed, - AllocatorError, - ListOperationError, - RemovedButWithHandlerError, - ModuleCollision, - OperationDenied, -}; + pub fn request_lib(self: *const @This(), lib: []const u8) ?type { + return comptime modsys.smll.search_lib(self, lib); + } -pub const ModHandler_T: type = union(ModType_T) { - driver: default_struct(null, null), - syscall: default_struct(null, null), - irq: default_struct(null, null), - filesystem: default_struct( - if(!builtin.is_test) *fs.Fs_T else null, - if(!builtin.is_test) fs.FsErr_T else null, - ), - - fn default_struct(comptime mod_struct: ?type, comptime mod_error: ?type) type { - return if(mod_struct == null) void else struct { - install: ?*const fn(mod_struct.?) if(mod_error != null) mod_error.?!void else anyerror!void, - remove: ?*const fn(mod_struct.?) if(mod_error != null) mod_error.?!void else anyerror!void, - }; + pub fn abort_compile(self: *const @This(), comptime msg: []const u8) noreturn { + @compileError(self.name ++ ": " ++ msg); } }; @@ -195,55 +106,41 @@ pub const ModuleDescriptionLibOut_T: type = struct { }, }; -pub const ModuleDescription_T: type = struct { - name: []const u8, - load: ModuleDescriptionLoad_T, - init: *const fn() anyerror!void, // ponteiro para a funcao init - after: ?*const fn() anyerror!void = null, // funcao executada apos init - arch: []const ModuleDescriptionTarget_T, // arch suportadas - deps: ?[]const[]const u8 = null, - c_sources: ?[]const[]const u8 = null, - libs: struct { - mines: ?[]const ModuleDescriptionLibMine_T = null, - outside: ?[]const ModuleDescriptionLibOut_T = null, - } = .{}, - type: union(ModType_T) { - driver: void, - syscall: void, - irq: void, - filesystem: union(enum(u1)) { - // faz a montagem de forma direta no kernel (fstab permanente) - compile: struct { - name: []const u8, - mountpoint: []const u8, - }, - dynamic: void, // sera adicionado ao kernel, mas sua montagem acontece em runtime - }, - }, - flags: packed struct(u8) { - call: packed struct { - handler: u1, // chama handler responsavel pelo type do modulo, por exemplo, fs chama o handler fs - after: u1, // chama funcao after, caso after seja null e essa flag seja 1, obtemos um erro em comptime - }, - reserved: u6 = 0, - }, - - pub fn request_all(comptime self: *const @This()) struct { [ - if(self.libs.outside == null) 0 else - self.libs.outside.?.len - ]?type, bool } { - return comptime modsys.smll.search_all(self); - } +pub const ModType_T: type = enum(u8) { + driver, + syscall, + irq, + filesystem, +}; - pub fn request_libs(comptime self: *const @This(), comptime libs: []const[]const u8) struct { [libs.len]?type, bool } { - return comptime modsys.smll.search_libs(self, libs); - } +pub const ModLicense_T: type = enum(u8) { + GPL2_only, + GPL2_or_later, + GPL3_only, + GPL3_or_later, + BSD_2_Clause, + BSD_3_Clause, + MIT, + APACHE_2_0, + PROPRIETARY, +}; - pub fn request_lib(self: *const @This(), lib: []const u8) ?type { - return comptime modsys.smll.search_lib(self, lib); - } +pub const ModRoot_T: type = struct { + list: list.BuildList(*const Mod_T), + type: ModType_T, + init: u1, +}; - pub fn abort_compile(self: *const @This(), comptime msg: []const u8) noreturn { - @compileError(self.name ++ ": " ++ msg); - } +pub const ModErr_T: type = error { + SectionHandlerError, + NoNFound, + IteratorFailed, + ListInitFailed, + AllocatorError, + ListOperationError, + RemovedButWithHandlerError, + ModuleCollision, + OperationDenied, + InitFailed, + ExitFailed, }; diff --git a/kernel/core/vfs/main.zig b/kernel/core/vfs/main.zig index 3fcd34b..74356b3 100644 --- a/kernel/core/vfs/main.zig +++ b/kernel/core/vfs/main.zig @@ -44,16 +44,23 @@ pub fn mount( const dentry_mount: *Dentry_T = try @call(.never_inline, aux.resolve_path, .{ path, current, &root }); - if(dentry_mount.d_sblock != null) return VfsErr_T.AlreadyMounted; - const fs_struct: *fs.Fs_T = @constCast(fs.search_fs(fs_name) catch return VfsErr_T.FilesystemMountError); + + if(dentry_mount.d_sblock != null) + return VfsErr_T.AlreadyMounted; + + const fs_struct: *fs.Fs_T = @constCast(fs.search_fs(fs_name) + catch return VfsErr_T.FilesystemMountError); + if(c.c_bool(fs_struct.flags.control.nomount)) { fs_struct.flags.internal.fault.mount = 1; return VfsErr_T.FilesystemMountError; } + const sblock = fs_struct.mount() catch { fs_struct.flags.internal.fault.mount = 1; return VfsErr_T.FilesystemMountError; }; + dentry_mount.d_sblock = @constCast(sblock); dentry_mount.d_op = sblock.inode_op; fs_struct.flags.internal.mounted = 1; @@ -76,7 +83,7 @@ pub fn umount(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { // preferi deixar create/mkdir e chmod/chown em funcoes diferentes por mais que a logica // seja exatamente a mesma, isso facilita achar problemas -pub fn create( +pub noinline fn create( parent: []const u8, name: []const u8, current: ?*Dentry_T, @@ -94,7 +101,7 @@ pub fn create( }; } -pub fn mkdir( +pub noinline fn mkdir( parent: []const u8, name: []const u8, current: ?*Dentry_T, @@ -112,7 +119,7 @@ pub fn mkdir( }; } -pub fn chmod( +pub noinline fn chmod( path: []const u8, current: ?*Dentry_T, mode: mode_T, @@ -127,7 +134,7 @@ pub fn chmod( }; } -pub fn chown( +pub noinline fn chown( path: []const u8, current: ?*Dentry_T, uid: uid_T, @@ -143,29 +150,29 @@ pub fn chown( }; } -pub fn read(path: []const u8, current: ?*Dentry_T) VfsErr_T![]u8 { +pub noinline fn read(path: []const u8, offset: usize, current: ?*Dentry_T) VfsErr_T![]u8 { const dentry_read: *Dentry_T = try @call(.never_inline, aux.resolve_path, .{ path, current, &root }); try aux.is_valid_op(dentry_read, .read); - return @call(.never_inline, dentry_read.d_op.?.read.?, .{ dentry_read }) catch { + return @call(.never_inline, dentry_read.d_op.?.read.?, .{ dentry_read, offset }) catch { // klog() return VfsErr_T.OperationFailed; }; } -pub fn write(path: []const u8, current: ?*Dentry_T, src: []const u8) VfsErr_T!void { +pub noinline fn write(path: []const u8, src: []const u8, offset: usize, current: ?*Dentry_T) VfsErr_T!void { const dentry_write: *Dentry_T = try @call(.never_inline, aux.resolve_path, .{ path, current, &root }); try aux.is_valid_op(dentry_write, .write); - @call(.never_inline,dentry_write.d_op.?.write.?, .{ dentry_write, src }) catch { + @call(.never_inline,dentry_write.d_op.?.write.?, .{ dentry_write, src, offset }) catch { // klog() return VfsErr_T.OperationFailed; }; } -pub fn unlink(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { +pub noinline fn unlink(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { const dentry_unlink: *Dentry_T = try @call(.never_inline, aux.resolve_path, .{ path, current, &root }); @@ -186,7 +193,7 @@ pub fn unlink(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { }; } -pub fn touch(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { +pub noinline fn touch(path: []const u8, current: ?*Dentry_T) VfsErr_T!void { _ = try @call(.never_inline, aux.resolve_path, .{ path, current, &root }); diff --git a/kernel/core/vfs/types.zig b/kernel/core/vfs/types.zig index 2438f2a..b04d292 100644 --- a/kernel/core/vfs/types.zig +++ b/kernel/core/vfs/types.zig @@ -5,6 +5,7 @@ const builtin: type = @import("builtin"); const fs: type = @import("root").core.fs; +const drivers: type = @import("root").core.drivers; pub const uid_T: type = if(@bitSizeOf(usize) >= 16) u16 else u8; pub const gid_T: type = if(@bitSizeOf(usize) >= 32) u32 else uid_T; @@ -28,15 +29,16 @@ pub const FileType_T: type = enum { }; pub const InodeOp_T: type = struct { - read: ?*const fn(*Dentry_T) anyerror![]u8, - write: ?*const fn(*Dentry_T, []const u8) anyerror!void, - lookup: ?*const fn(*Dentry_T, []const u8) anyerror!*Dentry_T, - mkdir: ?*const fn(*Dentry_T, []const u8, uid_T, gid_T, mode_T) anyerror!void, - create: ?*const fn(*Dentry_T, []const u8, uid_T, gid_T, mode_T) anyerror!void, - unlink: ?*const fn(*Dentry_T) anyerror!void, - chmod: ?*const fn(*Dentry_T, mode_T) anyerror!void, - chown: ?*const fn(*Dentry_T, uid_T, gid_T) anyerror!void, - iterator: ?*const fn(*Dentry_T) []const *Dentry_T, + read: ?*const fn(*Dentry_T, usize) anyerror![]u8 = null, + write: ?*const fn(*Dentry_T, []const u8, usize) anyerror!void = null, + lookup: ?*const fn(*Dentry_T, []const u8) anyerror!*Dentry_T = null, + mkdir: ?*const fn(*Dentry_T, []const u8, uid_T, gid_T, mode_T) anyerror!void = null, + create: ?*const fn(*Dentry_T, []const u8, uid_T, gid_T, mode_T) anyerror!void = null, + unlink: ?*const fn(*Dentry_T) anyerror!void = null, + chmod: ?*const fn(*Dentry_T, mode_T) anyerror!void = null, + chown: ?*const fn(*Dentry_T, uid_T, gid_T) anyerror!void = null, + iterator: ?*const fn(*Dentry_T) []const *Dentry_T = null, + ioctl: ?*const fn(*Dentry_T, usize, *anyopaque) anyerror!usize = null, }; pub const Dentry_T: type = struct { diff --git a/kernel/entries/i386/entry.zig b/kernel/entries/i386/entry.zig index f333a8f..3f7760d 100644 --- a/kernel/entries/i386/entry.zig +++ b/kernel/entries/i386/entry.zig @@ -5,8 +5,8 @@ const arch: type = @import("root").code.arch; const config: type = @import("root").config; -const lib: type = @import("root").lib; const atlas: type = @import("atlas.zig"); +const fmt: type = @import("root").lib.utils.compile.fmt; const section_text_loader = arch.sections.section_text_loader; const section_data_loader = arch.sections.section_data_loader; @@ -23,11 +23,6 @@ const section_data_persist = arch.sections.section_data_persist; // em qualquer arquivo, já que o símbolo está vísivel em todo o assembly. comptime { - const aux: type = opaque { - pub fn make_asm_set(comptime name: []const u8, comptime value: u32) []const u8 { - return ".set " ++ name ++ ", " ++ lib.utils.fmt.intFromArray(value) ++ "\n"; - } - }; // AtlasB Headers // // Esse Headers deve ser colocado no inicio do binario, em @@ -41,9 +36,9 @@ comptime { // * AtlasFlags: Flags gerais para o Atlas, consulte a documentaçao no fonte do atlas // NOTE: https://github.com/Linuxperoxo/AtlasB/blob/master/src/atlas.s asm( - aux.make_asm_set("AtlasLoadDest", atlas.atlas_load_dest) ++ - aux.make_asm_set("AtlasVMode", atlas.atlas_vmode) ++ - aux.make_asm_set("AtlasFlags", atlas.atlas_flags) ++ + &fmt.format(".set AtlasLoadDest, {d}\n", .{ atlas.atlas_load_dest }) ++ + &fmt.format(".set AtlasVMode, {d}\n", .{ atlas.atlas_vmode }) ++ + &fmt.format(".set AtlasFlags, {d}\n", .{ atlas.atlas_flags }) ++ \\ .set AtlasMagic, 0xAB00 \\ .weak AtlasImgSize \\ .section .opensaturn.data.atlas.header,"a",@progbits diff --git a/kernel/interrupts/i386/handler.zig b/kernel/interrupts/i386/handler.zig index 7b92f30..399c6eb 100644 --- a/kernel/interrupts/i386/handler.zig +++ b/kernel/interrupts/i386/handler.zig @@ -3,7 +3,7 @@ // │ Author: Linuxperoxo │ // └─────────────────────────────────────────────────┘ -const lib: type = @import("root").lib; +const fmt: type = @import("root").lib.utils.compile.fmt; const events: type = @import("root").core.events; const csi: type = @import("csi.zig"); @@ -14,7 +14,7 @@ pub var csi_isr = r: { comptime { // apenas para facilitar a busca no assembly @export(&isr_handler, .{ - .name = ".i386.csi.isr" ++ lib.utils.fmt.intFromArray(i), + .name = &fmt.format(".i386.csi.isr{d}\n", .{ i }), }); } pub fn isr_handler() callconv(.naked) void { diff --git a/kernel/kernel.zig b/kernel/kernel.zig index 64a3431..55ab970 100644 --- a/kernel/kernel.zig +++ b/kernel/kernel.zig @@ -74,6 +74,14 @@ fn saturn_main() callconv(.c) noreturn { // Depois da arquitetura resolver todos os seus detalhes, podemos iniciar // os modulos linkados ao kernel @call(.always_inline, modsys.core.saturn_modules_loader, .{}); - @call(.always_inline, fusium.saturn_fusium_loader, .{ .after }); + //@call(.always_inline, fusium.saturn_fusium_loader, .{ .after }); + + //modules.__SaturnAllMods__[1].create_device_node() catch { + // asm volatile( + // \\ jmp . + // \\ jmp 0xAA000 + // ); + //}; + @call(.always_inline, opaque { pub fn trap() noreturn { while(true) {} } }.trap, .{}); // noreturn fn } diff --git a/kernel/modsys/aux.zig b/kernel/modsys/aux.zig index f608b73..b72eb06 100644 --- a/kernel/modsys/aux.zig +++ b/kernel/modsys/aux.zig @@ -3,21 +3,26 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ +const interfaces: type = @import("root").interfaces; +const menuconfig: type = @import("menuconfig.zig"); +const config: type = @import("root").config; const module: type = @import("root").interfaces.module; const mem: type = @import("root").lib.utils.mem; -const modules: type = @import("modules.zig"); +const lmodules: type = @import("modules.zig"); // local modules +const gmodules: type = @import("root").modules; // global modules + +// =============== for smll.zig pub fn find_module_by_name(mod_name: []const u8) anyerror!*const module.ModuleDescription_T { - for(&modules.saturn_modules) |*mod_desc| { - if(mem.eql(mod_desc.name, mod_name, .{ .case = true})) + for(&lmodules.saturn_modules) |*mod_desc| { + if(mem.eql(mod_desc.mod.name, mod_name, .{ .case = true})) return mod_desc; } return error.NoNFound; } pub fn find_module_lib_by_name(mod: *const module.ModuleDescription_T, lib_name: []const u8) anyerror!module.ModuleDescriptionLibMine_T { - if(mod.libs.mines == null - or mod.libs.outside.?.len == 0) return error.NoNFound; + if(mod.libs.mines == null) return error.NoNFound; for(mod.libs.mines.?) |mine_lib| { if(mem.eql(lib_name, mine_lib.name, .{ .case = true })) return mine_lib; @@ -53,7 +58,91 @@ pub fn find_lib_version(mod_out: module.ModuleDescriptionLibOut_T, mod_mine: mod pub fn valid_type_for_lib(mod: *const module.ModuleDescription_T, mod_mine: module.ModuleDescriptionLibMine_T) bool { if(mod_mine.m_types == null or mod_mine.m_types.?.len == 0) return true; for(mod_mine.m_types.?) |m_type| { - if(m_type == mod.type) return true; + if(m_type == mod.mod.type) return true; } return false; } + +// ============= for modules.zig + +pub fn check_blacklist(mod: *const interfaces.module.ModuleDescription_T) void { + if(mod.blacklist == null or mod.blacklist.?.len == 0) return; + for(mod.blacklist.?) |blacklist_mod| { + if(!@hasField(config.modules.menuconfig.Menuconfig_T, blacklist_mod)) + @compileError( + "Modsys Error: module \"" ++ blacklist_mod ++ "\" in blacklist of module \"" ++ + mod.mod.name ++ "\" needs to be added in Menuconfig_T" + ); + if(@field(menuconfig.ModulesSelection, blacklist_mod) == .yes) + @compileError( + "Modsys Error: module \"" ++ mod.mod.name ++ + "\" requires blacklist mod \"" ++ blacklist_mod ++ + "\" == .no, but found .yes. Check menuconfig and arch overrides." + ); + } +} + +pub fn check_module_arch(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { + for(mod.arch) |mod_arch| { + if(config.arch.options.Target == mod_arch) return; + } + if(!config.modules.options.IgnoreModuleWithArchNotSupported) { + @compileError( + "Modsys Error: module name " ++ mod.mode.name ++ + " is not supported by target architecture " ++ + @tagName(config.arch.options.Target) + ); + } + return error.IgnoreThis; +} + +pub fn check_module_in_menuconfig(mod: *const interfaces.module.ModuleDescription_T) void { + if(!@hasField(config.modules.menuconfig.Menuconfig_T, mod.mod.name)) @compileError( + "Modsys Error: module \"" ++ mod.mod.name ++ "\" needs to be added in Menuconfig_T" + ); +} + +pub fn check_module_load(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { + return if(mod.load == .unlinkable) return error.IgnoreThis else {}; +} + +pub fn check_module_menuconfig_enable(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { + if(config.modules.options.UseMenuconfigAsRef) { + switch(@field(menuconfig.ModulesSelection, mod.mod.name)) { + .yes => {}, + .no => return error.IgnoreThis, + } + } +} + +pub fn check_module_collision() usize { + var collision_count: usize = 0; + for(gmodules.__SaturnAllMods__, 0..) |mod, i| { + for(0..i) |j| { + if(mem.eql( + mod.__SaturnModuleDescription__.mod.name, gmodules.__SaturnAllMods__[j].__SaturnModuleDescription__.mod.name, .{ + .len = true, + .case = false + } + )) { + // caso modulos diferentes compartilham do mesmo nome, precisa dar erro, isso e critico + if(&mod.__SaturnModuleDescription__ != &gmodules.__SaturnAllMods__[j].__SaturnModuleDescription__) { + @compileError( + "Modsys Error: collision module name " ++ gmodules.__SaturnAllMods__[j].__SaturnModuleDescription__.mod.name ++ + " files " ++ @typeName(gmodules.__SaturnAllMods__[j]) ++ + " " ++ @typeName(mod) + ); + } + if(!config.modules.options.IgnoreModuleCollision) { + @compileError( + "Modsys Error: collision with the module " ++ mod.__SaturnModuleDescription__.mod.name ++ + " itself (double module register)" + ); + } + collision_count += 1; + break; + } + } + } + return collision_count; +} diff --git a/kernel/modsys/deps.zig b/kernel/modsys/deps.zig index 295b708..d939bc0 100644 --- a/kernel/modsys/deps.zig +++ b/kernel/modsys/deps.zig @@ -37,7 +37,7 @@ fn vertex_recursive( if(child.?.flags.done) continue; if(child.? == root_vertex) - @compileError("circular dependency \"" ++ current_vertex.module.?.name ++ "\" with \"" ++ root_vertex.module.?.name ++ "\""); + @compileError("Modsys Error: circular dependency \"" ++ current_vertex.module.?.mod.name ++ "\" with \"" ++ root_vertex.module.?.mod.name ++ "\""); if(child.?.flags.any) vertex_recursive(child.?, init_order, init_order_index, root_vertex); @@ -71,19 +71,19 @@ pub fn resolve_dependencies() [modules.saturn_modules.len]*const interfaces.modu // montando grafo for(&graph_vertex_pool, 0..) |*vertex, j| { var i: usize = 0; - if(vertex.module.?.deps == null or vertex.module.?.deps.?.len == 0) continue; - if(vertex.module.?.deps.?.len > max_childs) - @compileError(vertex.module.?.name ++ ".deps.len > 16"); + if(vertex.module.?.mod.deps == null or vertex.module.?.mod.deps.?.len == 0) continue; + if(vertex.module.?.mod.deps.?.len > max_childs) + @compileError("Modsys Error: " ++ vertex.module.?.mod.name ++ "deps.len > 16"); graph_vertex_pool[j].flags.any = true; - for(vertex.module.?.deps.?) |dep| { + for(vertex.module.?.mod.deps.?) |dep| { vertex.childs[i] = r: { for(&graph_vertex_pool) |*current_dep_vertex| { - if(mem.eql(current_dep_vertex.module.?.name, dep, .{ .case = true } )) + if(mem.eql(current_dep_vertex.module.?.mod.name, dep, .{ .case = true } )) break :r current_dep_vertex; } - @compileError("\"" ++ dep ++ "\" dependency of \"" ++ vertex.module.?.name ++ "\" does not exist"); + @compileError("Modsys Error: \"" ++ dep ++ "\" dependency of \"" ++ vertex.module.?.mod.name ++ "\" does not exist"); }; i += 1; } diff --git a/kernel/modsys/menuconfig.zig b/kernel/modsys/menuconfig.zig index b609920..8c83456 100644 --- a/kernel/modsys/menuconfig.zig +++ b/kernel/modsys/menuconfig.zig @@ -11,7 +11,7 @@ pub const ModulesSelection: config.modules.menuconfig.Menuconfig_T = r: { if(arch.__SaturnArchDescription__.overrider.modules == null or arch.__SaturnArchDescription__.overrider.modules.?.len == 0) { if(!config.modules.options.IgnoreOverriderIfNoExist) @compileError( - "modsys: ForceModuleArchOverrider = true expects an architecture module overrider, but the " ++ + "Modsys Error: ForceModuleArchOverrider = true expects an architecture module overrider, but the " ++ @tagName(config.arch.options.Target) ++ " architecture does not have an module overrider" ); @@ -20,7 +20,7 @@ pub const ModulesSelection: config.modules.menuconfig.Menuconfig_T = r: { var over_menuconfig = config.modules.menuconfig.ModulesSelection; for(arch.__SaturnArchDescription__.overrider.modules.?) |overrider| { if(!@hasField(config.modules.menuconfig.Menuconfig_T, overrider.module)) @compileError( - "modsys: attempt to overrider a non-existent module " ++ + "Modsys Error: attempt to overrider a non-existent module " ++ overrider.module ++ " in arch " ++ @tagName(config.arch.options.Target) diff --git a/kernel/modsys/modsys.zig b/kernel/modsys/modsys.zig index f5a6e76..99505b7 100644 --- a/kernel/modsys/modsys.zig +++ b/kernel/modsys/modsys.zig @@ -8,48 +8,37 @@ const deps: type = @import("deps.zig"); pub fn saturn_modules_loader() void { inline for(comptime deps.resolve_dependencies()) |module| { - // Skip nao pode ser comptime se nao vamos ter um - // erro de compilacao, ja que ele vai tentar carregar - // os modulos em comptime skip: { switch(comptime module.load) { .dynamic, .unlinkable => break :skip {}, .linkable => { - @call(.never_inline, module.init, .{}) catch { - // klog error - }; - }, - } - if(module.flags.call.handler == 0) break :skip {}; - // resolvendo modulo com base no seu tipo - switch(comptime module.type) { - .driver => {}, - .syscall => {}, - .irq => {}, - .filesystem => { - switch(comptime module.type.filesystem) { - // caso o modulo fs use compile, vamos fazer uma - // montagem do fs em tempo de compilacao - .compile => |fs_info| { - @call(.never_inline, interfaces.vfs.mount, .{ - fs_info.mountpoint, null, fs_info.name - }) catch { + @call(.never_inline, interfaces.module.inmod, .{ module.mod }) catch |err| { + switch(err) { + interfaces.module.ModErr_T.InitFailed => { + // klog() + interfaces.module.rmmod(module.mod) catch { + // klog() + }; + }, + + interfaces.module.ModErr_T.ModuleCollision => { // klog() - }; - }, - .dynamic => break :skip, - } + }, + + interfaces.module.ModErr_T.ListInitFailed, + interfaces.module.ModErr_T.ListOperationError => { + // klog() + }, + + else => unreachable, + } + if(module.panic) { + // panic(); + //unreachable; + } + }; }, } - if(module.flags.call.after == 1) { - if(module.after == null) @compileError( - "modsys: module " ++ module.name ++ - " expect call after fn, but after is null in module description" - ); - @call(.never_inline, module.after.?, .{}) catch { - // klog() - }; - } } } } diff --git a/kernel/modsys/modules.zig b/kernel/modsys/modules.zig index 2661be0..623b60f 100644 --- a/kernel/modsys/modules.zig +++ b/kernel/modsys/modules.zig @@ -5,107 +5,45 @@ const decls: type = @import("root").decls; const modules: type = @import("root").modules; -const lib: type = @import("root").lib; -const config: type = @import("root").config; +const mem: type = @import("root").lib.utils.mem; const interfaces: type = @import("root").interfaces; -const menuconfig: type = @import("menuconfig.zig"); +const aux: type = @import("aux.zig"); pub const saturn_modules = r: { - const aux: type = opaque { - pub fn check_module_arch(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { - for(mod.arch) |mod_arch| { - if(config.arch.options.Target == mod_arch) return; - } - if(!config.modules.options.IgnoreModuleWithArchNotSupported) { - @compileError("module name " ++ mod.name ++ - " is not supported by target architecture " ++ - @tagName(config.arch.options.Target) - ); - } - return error.IgnoreThis; - } - - pub fn check_module_in_menuconfig(mod: *const interfaces.module.ModuleDescription_T) void { - if(!@hasField(config.modules.menuconfig.Menuconfig_T, mod.name)) @compileError( - "module " ++ mod.name ++ - " needs to be added in Menuconfig_T" - ); - } - - pub fn check_module_load(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { - return if(mod.load == .unlinkable) return error.IgnoreThis else {}; - } - - pub fn check_module_menuconfig_enable(mod: *const interfaces.module.ModuleDescription_T) anyerror!void { - if(config.modules.options.UseMenuconfigAsRef) { - switch(@field(menuconfig.ModulesSelection, mod.name)) { - .yes => {}, - .no => return error.IgnoreThis, - } - } - } - - pub fn check_module_collision() usize { - var collision_count: usize = 0; - for(modules.__SaturnAllMods__, 0..) |mod, i| { - for(0..i) |j| { - if(lib.utils.mem.eql( - mod.__SaturnModuleDescription__.name, modules.__SaturnAllMods__[j].__SaturnModuleDescription__.name, .{ - .len = true, - .case = false - } - )) { - // caso modulos diferentes compartilham do mesmo nome, precisa dar erro, isso e critico - if(&mod.__SaturnModuleDescription__ != &modules.__SaturnAllMods__[j].__SaturnModuleDescription__) { - @compileError( - "modsys: collision module name " ++ modules.__SaturnAllMods__[j].__SaturnModuleDescription__.name ++ - " files " ++ @typeName(modules.__SaturnAllMods__[j]) ++ - " " ++ @typeName(mod) - ); - } - if(!config.modules.options.IgnoreModuleCollision) { - @compileError( - "modsys: collision with the module " ++ mod.__SaturnModuleDescription__.name ++ - " itself (double module register)" - ); - } - collision_count += 1; - break; - } - } - } - return collision_count; - } - }; var modules_check_index: usize = 0; var modules_check: [(modules.__SaturnAllMods__.len - aux.check_module_collision())]interfaces.module.ModuleDescription_T = undefined; for(modules.__SaturnAllMods__, 0..) |mod, i| { t: { for(0..i) |j| { - if(lib.utils.mem.eql( - mod.__SaturnModuleDescription__.name, modules.__SaturnAllMods__[j].__SaturnModuleDescription__.name, .{ + if(mem.eql( + mod.__SaturnModuleDescription__.mod.name, modules.__SaturnAllMods__[j].__SaturnModuleDescription__.mod.name, .{ .len = true, .case = false, } )) break :t {}; } + if(!decls.container_decl_exist(mod, .module)) { @compileError( - decls.what_is_decl(.module) ++ + "Modsys Error: " ++ decls.what_is_decl(.module) ++ " is not defined in the module file " ++ @typeName(mod) ); } + if(!decls.container_decl_type(@TypeOf(mod.__SaturnModuleDescription__), .module)) { @compileError( - "declaration " ++ decls.what_is_decl(.module) ++ + "Modsys Error: declaration " ++ decls.what_is_decl(.module) ++ " for module " ++ @typeName(mod) ++ " must be type: " ++ @typeName(decls.what_is_decl_type(.module)) ); } + aux.check_module_load(&mod.__SaturnModuleDescription__) catch continue; aux.check_module_in_menuconfig(&mod.__SaturnModuleDescription__); + aux.check_blacklist(&mod.__SaturnModuleDescription__); aux.check_module_menuconfig_enable(&mod.__SaturnModuleDescription__) catch continue; aux.check_module_arch(&mod.__SaturnModuleDescription__) catch continue; + modules_check[modules_check_index] = mod.__SaturnModuleDescription__; modules_check_index += 1; } diff --git a/kernel/modsys/smll.zig b/kernel/modsys/smll.zig index 4fadb2a..e07ed61 100644 --- a/kernel/modsys/smll.zig +++ b/kernel/modsys/smll.zig @@ -15,7 +15,7 @@ pub fn search_all(comptime mod: *const module.ModuleDescription_T) struct { [ mod.libs.outside.?.len ]?type, bool } { if(mod.libs.outside == null or mod.libs.outside.?.len == 0) @compileError( - "modsys: " ++ mod.name ++ " request libs without outside lib" + "Modsys Error: " ++ mod.mod.name ++ " request libs without outside lib" ); return comptime search_libs(mod, r: { var libs: [mod.libs.outside.?.len][]const u8 = undefined; @@ -42,7 +42,7 @@ pub fn search_libs(mod: *const module.ModuleDescription_T, libs: []const[]const pub fn search_lib(mod: *const module.ModuleDescription_T, lib: []const u8) ?type { if(mod.libs.outside == null or mod.libs.outside.?.len == 0) @compileError( - "modsys: \"" ++ mod.name ++ "\" request libs without outside lib" + "Modsys Error: \"" ++ mod.mod.name ++ "\" request libs without outside lib" ); const outside_lib = r: { for(mod.libs.outside.?) |outside_lib| { @@ -50,14 +50,14 @@ pub fn search_lib(mod: *const module.ModuleDescription_T, lib: []const u8) ?type break :r outside_lib; } @compileError( - "modsys: \"" ++ lib ++ "\" " ++ + "Modsys Error: \"" ++ lib ++ "\" " ++ "lib requested does not exist in outside" ); }; const mod_found = aux.find_module_by_name(outside_lib.mod) catch if(outside_lib.flags.required == 0) return null else @compileError( - "modsys: lib request by \"" ++ mod.name ++ "\" " ++ + "Modsys Error: lib request by \"" ++ mod.mod.name ++ "\" " ++ "for module \"" ++ outside_lib.mod ++ "\", " ++ "but this mod is not added to the kernel! check the architecture " ++ @tagName(config.arch.options.Target) ++ " " ++ "overrider and menuconfig to see if the module really exists" @@ -66,38 +66,38 @@ pub fn search_lib(mod: *const module.ModuleDescription_T, lib: []const u8) ?type const lib_found = aux.find_module_lib_by_name(mod_found, outside_lib.lib) catch if(config.modules.options.IgnoreFaultNoExistentLib) return null else @compileError( - "modsys: module \"" ++ mod.name ++ "\" " ++ + "Modsys Error: module \"" ++ mod.mod.name ++ "\" " ++ "is requesting lib \"" ++ outside_lib.lib ++ "\" " ++ "for module \"" ++ outside_lib.mod ++ "\", " ++ "but this lib does not exist" ); if(lib_found.flags.enable == 0) @compileError( - "modsys: lib \"" ++ lib_found.name ++ "\" " ++ + "Modsys Error: lib \"" ++ lib_found.name ++ "\" " ++ "of module \"" ++ mod_found.name ++ "\" " ++ "is disable" ); // verifica se o modulo esta na whitelist da lib - if(!aux.mod_whitelisted(mod.name, lib_found)) @compileError( - "modsys: module \"" ++ mod.name ++ "\" " ++ + if(!aux.mod_whitelisted(mod.mod.name, lib_found)) @compileError( + "Modsys Error: module \"" ++ mod.mod.name ++ "\" " ++ "is not whitelisted in lib \"" ++ lib_found.name ++ "\" " ++ "of module \"" ++ mod_found.name ++ "\"" ); if(aux.find_lib_version(outside_lib, lib_found)) |version_found| { if(version_found.flags.enable == 0) @compileError( - "modsys: module \"" ++ mod.name ++ "\" is requesting lib" ++ " " ++ + "Modsys Error: module \"" ++ mod.mod.name ++ "\" is requesting lib" ++ " " ++ "\"" ++ outside_lib.lib ++ "\" version \"" ++ outside_lib.version.tag ++ "\" " ++ "for module \"" ++ outside_lib.mod ++ "\", but this lib version is disable" ); // verifica se a o tipo do modulo e permitido pela lib if(!aux.valid_type_for_lib(mod, lib_found)) @compileError( - "modsys: " + "Modsys Error: " ); return version_found.lib; } else { if(config.modules.options.IgnoreVersionNoFound) return null; @compileError( - "modsys: module \"" ++ mod.name ++ "\" is requesting lib" ++ " " ++ + "Modsys Error: module \"" ++ mod.mod.name ++ "\" is requesting lib" ++ " " ++ "\"" ++ outside_lib.lib ++ "\" version \"" ++ outside_lib.version.tag ++ "\" " ++ "for module \"" ++ outside_lib.mod ++ "\", but this lib version does not exist" ); diff --git a/kernel/physio/i386/init.zig b/kernel/physio/i386/init.zig index 92888bc..9c04cee 100644 --- a/kernel/physio/i386/init.zig +++ b/kernel/physio/i386/init.zig @@ -5,6 +5,6 @@ const scan: type = @import("scan.zig"); -pub fn physio_init() callconv(.c) void { +pub noinline fn physio_init() callconv(.c) void { @call(.always_inline, scan.physio_scan, .{}); } diff --git a/lib/saturn/interfaces/devices.zig b/lib/saturn/interfaces/devices.zig index c702a53..834668d 100644 --- a/lib/saturn/interfaces/devices.zig +++ b/lib/saturn/interfaces/devices.zig @@ -3,8 +3,31 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -const types: type = @import("root").core.devices.types; +const devices: type = @import("root").core.devices; -pub const Dev_T: type = types.Dev_T; -pub const DevErr_T: type = types.DevErr_T; -pub const MinorNum_T: type = types.MinorNum_T; +pub const Major_T: type = devices.Major_T; +pub const Minor_T: type = devices.Minor_T; +pub const Dev_T: type = devices.Dev_T; +pub const DevErr_T: type = devices.DevErr_T; +pub const DevOps_T: type = devices.DevOps_T; +pub const Devdevices_T: type = devices.DevOps_T; +pub const DevType_T: type = devices.DevType_T; + +pub const dev_minor_add = devices.dev_minor_add; +pub const dev_minor_rm = devices.dev_minor_rm; +pub const next_major = devices.next_major; +pub const valid_major = devices.valid_major; +pub const valid_minor = devices.valid_minor; +pub const dev_add = devices.dev_add; +pub const dev_rm = devices.dev_rm; +pub const dev_info = devices.dev_info; + +pub const write = devices.write; +pub const read = devices.read; +pub const ioctl = devices.ioctl; +pub const mount = devices.mount; +pub const umount = devices.umount; +pub const open = devices.open; +pub const close = devices.close; + +pub const new_dev = devices.new_dev; diff --git a/lib/saturn/interfaces/drivers.zig b/lib/saturn/interfaces/drivers.zig deleted file mode 100644 index cc2041b..0000000 --- a/lib/saturn/interfaces/drivers.zig +++ /dev/null @@ -1,12 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: drivers.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -const types: type = @import("root").core.drivers.types; - -pub const Driver_T: type = types.Driver_T; -pub const DriverErr_T: type = types.DriverErr_T; -pub const Ops_T: type = types.Ops_T; -pub const OpsErr_T: type = types.OpsErr_T; -pub const MajorNum_T: type = types.MajorNum_T; diff --git a/lib/saturn/interfaces/module.zig b/lib/saturn/interfaces/module.zig index 4bcc24c..f6a1eb5 100644 --- a/lib/saturn/interfaces/module.zig +++ b/lib/saturn/interfaces/module.zig @@ -7,6 +7,7 @@ const module: type = @import("root").core.module; pub const ModType_T: type = module.ModType_T; pub const Mod_T: type = module.Mod_T; +pub const ModControlFlags_T: type = module.ModControlFlags_T; pub const ModErr_T: type = module.ModErr_T; pub const ModuleDescriptionTarget_T: type = module.ModuleDescriptionTarget_T; pub const ModuleDescription_T: type = module.ModuleDescription_T; diff --git a/lib/saturn/kernel/memory/sba/sba.zig b/lib/saturn/kernel/memory/sba/sba.zig index c51aa1d..6ef8639 100644 --- a/lib/saturn/kernel/memory/sba/sba.zig +++ b/lib/saturn/kernel/memory/sba/sba.zig @@ -165,9 +165,7 @@ pub fn buildByteAllocator( inline fn mark_blocks(pool: *Pool_T, index: usize, blocks: usize) err_T!void { // total_bytes_of_pool / block_size = bitmap.len - if((index + blocks) > pool.bitmap.len) { - return err_T.IndexOutBounds; - } + if((index + blocks) > pool.bitmap.len) return err_T.IndexOutBounds; for(index..(index + blocks)) |i| pool.bitmap[i] = 1; } @@ -178,7 +176,8 @@ pub fn buildByteAllocator( var current_pool: *Pool_T = &self.root; while(true) { if(check_bounds(current_pool, ptr)) { - child_pool = current_pool; break; + child_pool = current_pool; + break; } if(current_pool.flags.parent == 0) break; parent_pool = current_pool; @@ -196,8 +195,10 @@ pub fn buildByteAllocator( fn alloc_sigle_frame(self: *@This(), bytes: usize) err_T![]u8 { if(self.root.flags.full == 1) return err_T.OutOfMemory; - var index: usize = self.root.next orelse 0; + const blocks_to_alloc: usize = cast_bytes_to_block(bytes); + var index: usize = self.root.next orelse 0; + for(index..self.root.bitmap.len) |_| { const check = check_blocks_range(&self.root, blocks_to_alloc, index, 0); if(check.result) break; @@ -205,8 +206,10 @@ pub fn buildByteAllocator( index = check.index.? + 1; } try mark_blocks(&self.root, index, blocks_to_alloc); + self.root.refs += blocks_to_alloc; self.root.flags.full = if(self.root.refs >= self.root.bitmap.len) 1 else 0; + return self.root.bytes.?[cast_block_to_byte(index)..cast_block_to_byte(index + blocks_to_alloc)]; } @@ -217,8 +220,9 @@ pub fn buildByteAllocator( }); break :r self.top.?; }; - var index: usize = current_pool.next orelse blocks_reserved; const blocks_to_alloc: usize = cast_bytes_to_block(bytes); + var index: usize = current_pool.next orelse blocks_reserved; + for(index..current_pool.bitmap.len) |_| { const check = check_blocks_range(current_pool, blocks_to_alloc, index, 0); if(check.result) break; @@ -233,8 +237,10 @@ pub fn buildByteAllocator( index = check.index.? + 1; } try mark_blocks(current_pool, index, blocks_to_alloc); + current_pool.refs += blocks_to_alloc; current_pool.flags.full = if(current_pool.refs >= current_pool.bitmap.len) 1 else 0; + return current_pool.bytes.?[cast_block_to_byte(index)..cast_block_to_byte(index + blocks_to_alloc)]; } @@ -251,22 +257,25 @@ pub fn buildByteAllocator( if(comptime personality.resize) { return @as([]T, @alignCast(@ptrCast(try @call(.always_inline, alloc_resized_frame, .{ self, bytes - })))); + }))))[0..N]; } return @as([]T, @alignCast(@ptrCast(try @call(.always_inline, alloc_sigle_frame, .{ self, bytes - })))); + }))))[0..N]; } fn free_resized_frame(self: *@This(), ptr: []u8) err_T!void { const parent_pool, const alloc_pool = self.found_pool_of_ptr(ptr); - if(alloc_pool == null) return err_T.IndexOutBounds; + if(alloc_pool == null) + return err_T.IndexOutBounds; + const block_to_free: usize = cast_bytes_to_block(ptr.len); - const initial_block: usize = cast_bytes_to_block( - @intFromPtr(ptr.ptr) - @intFromPtr(&alloc_pool.?.bytes.?[0]) - ); + const initial_block: usize = cast_bytes_to_block(@intFromPtr(ptr.ptr) - @intFromPtr(&alloc_pool.?.bytes.?[0])); + const check = check_blocks_range(alloc_pool.?, block_to_free, initial_block, null); // NULL == 1 - if(check.index != null and !check.result) return err_T.DoubleFree; + if(check.index != null and !check.result) + return err_T.DoubleFree; + if((alloc_pool.?.refs - block_to_free) == blocks_reserved and parent_pool != null) { @branchHint(.cold); self.top = if(alloc_pool.?.flags.parent == 0) parent_pool else self.top; @@ -280,10 +289,10 @@ pub fn buildByteAllocator( const src: *Pool_T = @alignCast(@ptrCast(&alloc_pool.?.bytes.?[0])); dest.* = src.*; } - if(builtin.is_test) - self.pools -= 1; + if(builtin.is_test) self.pools -= 1; return; } + for(initial_block..(initial_block + block_to_free)) |i| { alloc_pool.?.bitmap[i] = 0; } @@ -293,13 +302,16 @@ pub fn buildByteAllocator( fn free_single_frame(self: *@This(), ptr: []u8) err_T!void { if(self.root.bytes == null) return err_T.NonPoolInitialized; - if(!check_bounds(&self.root, ptr)) return err_T.IndexOutBounds; + if(!check_bounds(&self.root, ptr)) + return err_T.IndexOutBounds; + const block_to_free: usize = cast_bytes_to_block(ptr.len); - const initial_block: usize = cast_bytes_to_block( - @intFromPtr(ptr.ptr) - @intFromPtr(&self.root.bytes.?[0]) - ); + const initial_block: usize = cast_bytes_to_block(@intFromPtr(ptr.ptr) - @intFromPtr(&self.root.bytes.?[0])); + const check = check_blocks_range(&self.root, block_to_free, initial_block, null); // NULL == 1 - if(check.index != null and !check.result) return err_T.DoubleFree; + if(check.index != null and !check.result) + return err_T.DoubleFree; + for(initial_block..(initial_block + block_to_free)) |i| { self.root.bitmap[i] = 0; } diff --git a/lib/saturn/kernel/memory/sba/test.zig b/lib/saturn/kernel/memory/sba/test.zig index 9a0e35a..5a483ed 100644 --- a/lib/saturn/kernel/memory/sba/test.zig +++ b/lib/saturn/kernel/memory/sba/test.zig @@ -175,3 +175,12 @@ test "SBA Resize After Free For Resized Frame" { const new_frame: []u8 = free_pool.bytes.?; if(@intFromPtr(new_frame.ptr) == @intFromPtr(unsed_frame.ptr)) return TestResizedErr_T.NonNewFrame; } + +test "SBA Slice Len Test" { + var sba_allocator: SBAResized_T = .{}; + const some: type = struct { usize, usize, usize }; + const slice: []const u8 = try sba_allocator.alloc(u8, 8); + const other_slice: []const some = try sba_allocator.alloc(some, 8); + if(slice.len != 8) return error.SliceSizeFailed; + if(other_slice.len != 8) return error.SliceSizeFailed; +} diff --git a/lib/saturn/kernel/utils/comptime/fmt/aux.zig b/lib/saturn/kernel/utils/comptime/fmt/aux.zig new file mode 100644 index 0000000..245fec5 --- /dev/null +++ b/lib/saturn/kernel/utils/comptime/fmt/aux.zig @@ -0,0 +1,145 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: aux.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +pub const format: type = opaque { + pub fn format(allocator: anytype, comptime fmt: []const u8, args: anytype) anyerror![]u8 { + const buffer_len: usize = (comptime total_bytes_fmt(fmt, args)) + total_bytes_args(args); + const buffer: []u8 = try allocator.alloc(u8, buffer_len); + var buffer_index: usize = 0; + + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + + comptime var fmt_index: usize = 0; + comptime var fields_index: usize = 0; + comptime var inside: bool = false; + + inline while(fmt_index < fmt.len) { + const char: u8 = fmt[fmt_index]; + if(char == '{') { + inside = true; + fmt_index += 1; + continue; + } + if(comptime inside) switch(comptime char) { + 's' => { + const src = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + src.len)]; + @memcpy(dest, src); + buffer_index += src.len; + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + 'd' => { + const int = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..buffer_index + int_to_bytes(int)]; + buffer_index += str_from_int(int, dest); + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + else => unreachable, + }; + buffer[buffer_index] = char; + buffer_index += 1; + fmt_index += 1; + } + return buffer; + } + + pub fn str_from_int(int: usize, buffer: []u8) usize { + var current: usize = int; + var i: usize = 0; + while(current != 0 and i < buffer.len) : ({ current /= 10; i += 1; }) + buffer[buffer.len - 1 - i] = @as(u8, @truncate(current % 10)) + '0'; + return i; + } + + pub fn total_bytes_fmt(comptime fmt: []const u8, args: anytype) usize { + if(@typeInfo(@TypeOf(args)) != .@"struct") + @compileError("expect a tuple"); + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + var fields_index: usize = 0; + var inside: bool = false; + var fmt_len: usize = 0; + var fmt_index: usize = 0; + while(fmt_index < fmt.len) : (fmt_index += 1) { + const char: u8 = fmt[fmt_index]; + switch(char) { + '{' => { + if(inside) @compileError("missing clossing }"); + inside = true; + continue; + }, + '}' => @compileError("missing openning }"), + else => {}, + } + if(inside) { + if(fields_index + 1 > fields.len) + @compileError("too many args"); + const field: type = fields[fields_index].type; + sw0: switch(char) { + 's' => { + sw1: switch(@typeInfo(field)) { + .pointer => |ptr| { + if(ptr.size == .c or ptr.size == .many) { + if(@typeInfo(ptr.child) == .array) + continue :sw1 1; + continue :sw0 0; + } + }, + .array => |arr| { + if(arr.child != u8) + continue :sw0 0; + }, + else => continue :sw0 0, + } + }, + 'd' => { + switch(@typeInfo(field)) { + .int => {}, + .comptime_int => {}, + else => continue :sw0 ' ', + } + }, + else => @compileError("invalid format string \"" ++ fmt[fmt_index..fmt_index + 1] ++ "\" for type \"" ++ @typeName(field) ++ "\""), + } + if(fmt_index + 1 > fmt.len or fmt[fmt_index + 1] != '}') + @compileError("missing clossing }"); + fmt_index += 1; + fields_index += 1; + inside = false; + continue; + } + fmt_len += 1; + } + if(fields_index != fields.len) + @compileError("too many args"); + return fmt_len; + } + + pub fn total_bytes_args(args: anytype) usize { + var total: usize = 0; + inline for(@typeInfo(@TypeOf(args)).@"struct".fields) |field| { + total += switch(@typeInfo(field.type)) { + .pointer => (@field(args, field.name)).len, + .int => int_to_bytes(@field(args, field.name)), + .comptime_int => comptime int_to_bytes(@field(args, field.name)), + else => unreachable, + }; + } + return total; + } + + pub fn int_to_bytes(int: usize) usize { + if(int == 0) return 1; + var current: usize = int; + var total: usize = 0; + while(current != 0) : ({ current /= 10; total += 1; }) {} + return total; + } +}; diff --git a/lib/saturn/kernel/utils/comptime/fmt/fmt.zig b/lib/saturn/kernel/utils/comptime/fmt/fmt.zig index 7535a98..f4cec1a 100644 --- a/lib/saturn/kernel/utils/comptime/fmt/fmt.zig +++ b/lib/saturn/kernel/utils/comptime/fmt/fmt.zig @@ -3,4 +3,57 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ +const aux: type = @import("aux.zig"); +pub fn format(comptime fmt: []const u8, comptime args: anytype) [aux.format.total_bytes_fmt(fmt, args) + aux.format.total_bytes_args(args)]u8 { + if(!@inComptime()) + @compileError("comptime only fn"); + + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + + var buffer = [_]u8 { + 0 + } ** (aux.format.total_bytes_fmt(fmt, args) + aux.format.total_bytes_args(args)); + + var fmt_index: usize = 0; + var fields_index: usize = 0; + var inside: bool = false; + var buffer_index: usize = 0; + + inline while(fmt_index < fmt.len) { + const char: u8 = fmt[fmt_index]; + if(char == '{') { + inside = true; + fmt_index += 1; + continue; + } + if(comptime inside) switch(comptime char) { + 's' => { + const src = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + src.len)]; + @memcpy(dest, src); + buffer_index += src.len; + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + + 'd' => { + const int = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + aux.format.int_to_bytes(int))]; + buffer_index += aux.format.str_from_int(int, dest); + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + + else => unreachable, + }; + buffer[buffer_index] = char; + buffer_index += 1; + fmt_index += 1; + } + return buffer; +} diff --git a/lib/saturn/kernel/utils/comptime/fmt/formats.zig b/lib/saturn/kernel/utils/comptime/fmt/formats.zig deleted file mode 100644 index e5d2d33..0000000 --- a/lib/saturn/kernel/utils/comptime/fmt/formats.zig +++ /dev/null @@ -1,31 +0,0 @@ -// ┌──────────────────────────────────────────────┐ -// │ (c) 2025 Linuxperoxo • FILE: formats.zig │ -// │ Author: Linuxperoxo │ -// └──────────────────────────────────────────────┘ - -fn str_from_int(comptime int: anytype) []const u8 { - switch(@typeInfo(@TypeOf(int))) { - .int => {}, - else => @compileError( - "expect int type" - ), - } - if(int == 0) return &[_]u8 { 48 }; - var int_str = [_]u8 { - 0 - } ** r: { - var count: usize = 0; - var number = int; - while(number != 0) : (number /= 10) { - count += 1; - } - break :r count; - }; - var number = int; - var i: usize = 0; - while(number != 0) : (number /= 10) { - int_str[int_str.len - 1 - i] = @intCast((number % 10) + '0'); - i += 1; - } - return int_str[0..int_str.len]; -} diff --git a/lib/saturn/kernel/utils/fmt/aux.zig b/lib/saturn/kernel/utils/fmt/aux.zig new file mode 100644 index 0000000..0c6b384 --- /dev/null +++ b/lib/saturn/kernel/utils/fmt/aux.zig @@ -0,0 +1,189 @@ +// ┌──────────────────────────────────────────────┐ +// │ (c) 2026 Linuxperoxo • FILE: aux.zig │ +// │ Author: Linuxperoxo │ +// └──────────────────────────────────────────────┘ + +pub const format: type = opaque { + pub fn format(allocator: anytype, comptime fmt: []const u8, args: anytype) anyerror![]u8 { + const buffer_len: usize = (comptime total_bytes_fmt(fmt, args)) + total_bytes_args(args); + const buffer: []u8 = try allocator.alloc(u8, buffer_len); + var buffer_index: usize = 0; + + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + + comptime var fmt_index: usize = 0; + comptime var fields_index: usize = 0; + comptime var inside: bool = false; + + inline while(fmt_index < fmt.len) { + const char: u8 = fmt[fmt_index]; + if(char == '{') { + inside = true; + fmt_index += 1; + continue; + } + if(comptime inside) switch(comptime char) { + 's' => { + const src = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + src.len)]; + @memcpy(dest, src); + buffer_index += src.len; + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + 'd' => { + const int = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..buffer_index + int_to_bytes(int)]; + buffer_index += str_from_int(int, dest); + fmt_index += 2; + fields_index += 1; + inside = false; + continue; + }, + else => unreachable, + }; + buffer[buffer_index] = char; + buffer_index += 1; + fmt_index += 1; + } + return buffer; + } + + + pub fn str_from_int(int: usize, buffer: []u8) usize { + var current: usize = int; + var i: usize = @intFromBool(int == 0); + buffer[0] = '0'; + while (current != 0 and i < buffer.len) : ({current /= 10; i += 1; }) + buffer[buffer.len - 1 - i] = @as(u8, @truncate(current % 10)) + '0'; + return i; + } + + pub fn total_bytes_fmt(comptime fmt: []const u8, args: anytype) usize { + var fmt_len: usize = 0; + comptime { + if(@typeInfo(@TypeOf(args)) != .@"struct") + @compileError("expect a tuple"); + + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + + var fields_index: usize = 0; + var inside: bool = false; + var fmt_index: usize = 0; + + while(fmt_index < fmt.len) : (fmt_index += 1) { + const char: u8 = fmt[fmt_index]; + switch(char) { + '{' => { + if(inside) @compileError("missing clossing }"); + inside = true; + continue; + }, + + '}' => @compileError("missing openning }"), + + else => {}, + } + + if(inside) { + if(fields_index + 1 > fields.len) @compileError("too many args"); + + const field: type = fields[fields_index].type; + sw0: switch(char) { + 's' => { + sw1: switch(@typeInfo(field)) { + .pointer => |ptr| { + if(ptr.size == .c or ptr.size == .many) { + if(@typeInfo(ptr.child) == .array) + continue :sw1 1; + continue :sw0 0; + } + }, + + .array => |arr| { + if(arr.child != u8) + continue :sw0 0; + }, + + else => continue :sw0 0, + } + }, + + 'd' => { + switch(@typeInfo(field)) { + .int => {}, + .comptime_int => {}, + else => continue :sw0 ' ', + } + }, + + else => @compileError("invalid format string \"" ++ fmt[fmt_index..fmt_index + 1] ++ "\" for type \"" ++ @typeName(field) ++ "\""), + } + + if(fmt_index + 1 > fmt.len or fmt[fmt_index + 1] != '}') + @compileError("missing clossing }"); + + fmt_index += 1; + fields_index += 1; + inside = false; + + continue; + } + fmt_len += 1; + } + + if(fields_index != fields.len) + @compileError("too many args"); + } + return fmt_len; + } + + pub fn total_bytes_args(args: anytype) usize { + var total: usize = 0; + inline for(@typeInfo(@TypeOf(args)).@"struct".fields) |field| { + total += switch(@typeInfo(field.type)) { + .pointer => (@field(args, field.name)).len, + .int => int_to_bytes(@field(args, field.name)), + .comptime_int => comptime int_to_bytes(@field(args, field.name)), + else => unreachable, + }; + } + return total; + } + + pub fn int_to_bytes(int: usize) usize { + if(int == 0) return 1; + var current: usize = int; + var total: usize = 0; + while(current != 0) : ({ current /= 10; total += 1; }) {} + return total; + } +}; + +pub const broken_str: type = opaque { + pub inline fn broken_info(strr: []const u8, brokenn: u8) anyerror!struct { usize, usize, usize } { + if(strr.len == 0) return error.Empty; + r: { + for(0..strr.len) |i| + if(strr[i] != brokenn) break :r {}; + return error.WithoutSub; + } + const final_offset: usize = r: { + var count: usize = strr.len; + while(strr[count - 1] == brokenn) : (count -= 1) {} + break :r count; + }; + const initial_offset: usize = if(strr[0] != brokenn) 1 else 0; + var subs: usize = initial_offset; + for(subs..final_offset) |i| { + subs += if(strr[i] == brokenn) 1 else 0; + } + return .{ + initial_offset, + final_offset, + subs, + }; + } +}; diff --git a/lib/saturn/kernel/utils/fmt/fmt.zig b/lib/saturn/kernel/utils/fmt/fmt.zig index 9b67b11..ae257fb 100644 --- a/lib/saturn/kernel/utils/fmt/fmt.zig +++ b/lib/saturn/kernel/utils/fmt/fmt.zig @@ -3,70 +3,80 @@ // │ Author: Linuxperoxo │ // └──────────────────────────────────────────────┘ -fn numSize(comptime num: usize) usize { - if(num < 10) return 1; - var context: usize = num; - var size: usize = 0; - while(context != 0) : (context /= 10) { - size += 1; - } - return size; -} +const aux: type = @import("aux.zig"); + +pub fn format(allocator: anytype, comptime fmt: []const u8, args: anytype) anyerror![]u8 { + const buffer_len: usize = (aux.format.total_bytes_fmt(fmt, args) + aux.format.total_bytes_args(args)); + const buffer: []u8 = try allocator.alloc(u8, buffer_len); + var buffer_index: usize = 0; + + const fields = @typeInfo(@TypeOf(args)).@"struct".fields; + + comptime var fmt_index: usize = 0; + comptime var fields_index: usize = 0; + comptime var inside: bool = false; + + inline while(fmt_index < fmt.len) { + const char: u8 = fmt[fmt_index]; + if(char == '{') { + inside = true; + fmt_index += 1; + continue; + } + + if(comptime inside) switch(comptime char) { + 's' => { + const src = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + src.len)]; + + @memcpy(dest, src); + + buffer_index += src.len; + fmt_index += 2; + fields_index += 1; + inside = false; -pub fn intFromArray(comptime num: usize) [r: { - break :r numSize(num); -}]u8 { - const size = numSize(num); - var context: usize = num; - var result = [_]u8 { - 0 - } ** size; - context = num; - for(0..size) |i| { - result[(size - 1) - i] = (context % 10) + '0'; - context /= 10; + continue; + }, + + 'd' => { + const int = @field(args, fields[fields_index].name); + const dest = buffer[buffer_index..(buffer_index + aux.format.int_to_bytes(int))]; + + buffer_index += aux.format.str_from_int(int, dest); + fmt_index += 2; + fields_index += 1; + inside = false; + + continue; + }, + + else => unreachable, + }; + buffer[buffer_index] = char; + buffer_index += 1; + fmt_index += 1; } - return result; + return buffer; } pub fn broken_str(str: []const u8, broken: u8, allocator: anytype) anyerror![][]const u8 { - const aux: type = opaque { - inline fn BrokenInfo(strr: []const u8, brokenn: u8) anyerror!struct { usize, usize, usize } { - if(strr.len == 0) return error.Empty; - r: { - for(0..strr.len) |i| - if(strr[i] != brokenn) break :r {}; - return error.WithoutSub; - } - const final_offset: usize = r: { - var count: usize = strr.len; - while(strr[count - 1] == brokenn) : (count -= 1) {} - break :r count; - }; - const initial_offset: usize = if(strr[0] != brokenn) 1 else 0; - var subs: usize = initial_offset; - for(subs..final_offset) |i| { - subs += if(strr[i] == brokenn) 1 else 0; - } - return .{ - initial_offset, - final_offset, - subs, - }; - } - }; const initial_offset, const final_offset, - const subs = try aux.BrokenInfo(str, broken); - const sub_strs: [][]const u8 = (try allocator.alloc([]const u8, subs)).ptr[0..subs]; // FIXME: alloc retorna .len errado para o slice + const subs = try aux.broken_str.broken_info(str, broken); + const sub_strs: [][]const u8 = try allocator.alloc([]const u8, subs); + var sub_strs_index: usize = 0; var i: usize = initial_offset; + while(i < final_offset) : (i += 1) { while(i < final_offset and str[i] == broken) : (i += 1) {} + var sub_str_end: usize = i; while(sub_str_end < final_offset and str[sub_str_end] != broken) : (sub_str_end += 1) {} + sub_strs[sub_strs_index] = str[i..sub_str_end]; sub_strs_index += 1; i = sub_str_end; diff --git a/lib/saturn/kernel/utils/hashtable/hashtable.zig b/lib/saturn/kernel/utils/hashtable/hashtable.zig index 754da29..926179c 100644 --- a/lib/saturn/kernel/utils/hashtable/hashtable.zig +++ b/lib/saturn/kernel/utils/hashtable/hashtable.zig @@ -3,38 +3,214 @@ // │ Author: Linuxperoxo │ // └─────────────────────────────────────────────────┘ -pub fn buildHashtable( - comptime K: type, - comptime T: type, - comptime max_index: u8, - comptime root_size: u2, - comptime hash_gen: ?*const fn(anytype) u8 +const builtin: type = @import("builtin"); +const mem: type = if(!builtin.is_test) @import("root").lib.utils.mem else struct { + pub fn eql(noalias b0: []const u8, noalias b1: []const u8, comptime rule: struct { + len: bool = true, + case: bool = false, + }) bool { + return r: { + if(comptime rule.len) { + if(b0.len != b1.len) { + return false; + } + } + const end: usize = if(b0.len > b1.len) b1.len else b0.len; + for(0..end) |i| { + if( + (b0[i] & if(!rule.case) (~(@as(u8, @intCast(0x20)))) else 0xFF) != + (b1[i] & if(!rule.case) (~(@as(u8, @intCast(0x20)))) else 0xFF) + ) { + break :r false; + } + } + break :r true; + }; + } +}; + +fn type_resolver(t: type) enum { num, string, other } { + return switch(@typeInfo(t)) { + .int, .float => .num, + .pointer => |ptr| if(ptr.size != .slice or ptr.child != u8) .other else .string, + else => .other, + }; +} + +pub fn buildHashTable( + comptime key_T: type, + comptime data_T: type, + comptime table_size: ?usize, + comptime hash_gen_fn: ?*const fn(key_T) usize, ) type { return struct { - private: ?*anyopaque = null, + comptime { + if(type_resolver(key_T) == .other) @compileError( + "hashtable_builder: expected key_T to be an integer, float or string" + ); + } - const HashtableInfo_T: type = struct { - root_ptr: ?*[max_index]?*HashtableRootNode_T, + const ListHead_T: type = struct { + first: ?*Node_T, + last: ?*Node_T, }; - const HashtableRootNode_T: type = struct { - root: ?*[root_size]?*HashtableNode_T, + const Node_T: type = struct { + key: key_T, + data: data_T, + next: ?*Node_T, + prev: ?*Node_T, }; - const HashtableNode_T: type = struct { - next: ?*@This(), - prev: ?*@This(), - key: K, - data: T, + pub const Err_T: type = error { + AllocatorFailed, + KeyCollision, + KeyNotFound, }; - fn cast_private(self: *const @This()) *HashtableInfo_T { - // is_initialized after call this fn - return @ptrCast(@alignCast(self.private.?)); + table: [table_size orelse 24]ListHead_T = [_]ListHead_T { + ListHead_T { + .first = null, + .last = null, + }, + } ** (table_size orelse 24), + + // internal fn + + inline fn default_hash_gen(key: key_T) usize { + return sw: switch(comptime type_resolver(key_T)) { + // *% mult with overflow + .num => break :sw key *% @as(usize, ~0), + .string => { + const fnv_prime: usize = 1099511628211; + var hash: usize = 14695981039346656037; + for (key) |char| { + hash = hash ^ char; + hash = hash *% fnv_prime; + } + break :sw hash; + }, + .other => unreachable, + }; + } + + inline fn cmp_key(node: *Node_T, key: key_T) bool { + return sw: switch(comptime type_resolver(key_T)) { + .num => break :sw node.key == key, + .string => break :sw mem.eql(key, node.key, .{}), + .other => unreachable, + }; + } + + inline fn find_by_key(list_head: *const ListHead_T, key: key_T) ?*Node_T { + var current_node: ?*Node_T = list_head.first; + while(current_node != null) : (current_node = current_node.?.next) { + if(cmp_key(current_node.?, key)) + return current_node; + } + return null; + } + + inline fn hash_gen(key: key_T) usize { + return if(hash_gen_fn != null) hash_gen_fn.?(key) else + default_hash_gen(key); + } + + // hashtable fn + + pub fn add(self: *@This(), key: key_T, data: data_T, allocator: anytype) Err_T!void { + const table_index: usize = hash_gen(key) % self.table.len; + const list_head: *ListHead_T = &self.table[table_index]; + + if(list_head.first == null) { + const first_node: *Node_T = @ptrCast((allocator.alloc(Node_T, 1) + catch return Err_T.AllocatorFailed).ptr); + + first_node.* = .{ + .key = key, + .data = data, + .next = null, + .prev = null, + }; + + list_head.* = .{ + .first = first_node, + .last = first_node, + }; + return; + } + + if(find_by_key(list_head, key)) |_| { + return Err_T.KeyCollision; + } + + const current_last: *Node_T = list_head.last.?; + + current_last.next = @ptrCast((allocator.alloc(Node_T, 1) catch return Err_T.AllocatorFailed).ptr); + current_last.next.?.* = .{ + .key = key, + .data = data, + .next = null, + .prev = current_last, + }; + + list_head.last = current_last.next; + } + + pub fn del(self: *@This(), key: key_T, allocator: anytype) Err_T!void { + const table_index: usize = hash_gen(key) % self.table.len; + const list_head: *ListHead_T = &self.table[table_index]; + + if(list_head.first == null) + return Err_T.KeyNotFound; + + if(find_by_key(list_head, key)) |node| { + if(node == list_head.first.?) { + if(node.next == null) { + list_head.* = .{ + .first = null, + .last = null, + }; + } else { + list_head.first = node.next; + } + } else { + node.prev.?.next = node.next; + } + allocator.free(node[0..1]); + } } - pub fn is_initialized(self: *const @This()) bool { - return (self.private != null and s); + pub fn search(self: *const @This(), key: key_T) Err_T!data_T { + const table_index: usize = hash_gen(key) % self.table.len; + const list_head: *const ListHead_T = &self.table[table_index]; + + if(list_head.first == null) + return Err_T.KeyNotFound; + + if(find_by_key(list_head, key)) |found| return found.data else + return Err_T.KeyNotFound; } }; } + +test "Add" { + const std: type = @import("std"); + const HashTable_T: type = buildHashTable([]const u8, bool, null, null); + var gpa = std.heap.GeneralPurposeAllocator(.{}) {}; + var allocator = gpa.allocator(); + var hashtable: HashTable_T = .{}; + + try hashtable.add("tty_output_buffer", true, &allocator); + try hashtable.add("tty_input_buffer", false, &allocator); + + std.debug.print("{any}\n{any}\n", .{ + try hashtable.search("tty_output_buffer"), + try hashtable.search("tty_input_buffer"), + }); + + try hashtable.del("tty_output_buffer", &allocator); + + //_ = try hashtable.search("tty_output_buffer"); + _ = try hashtable.search("tty_input_buffer"); +} diff --git a/lib/saturn/kernel/utils/mem/mem.zig b/lib/saturn/kernel/utils/mem/mem.zig index c08ba86..6affaac 100644 --- a/lib/saturn/kernel/utils/mem/mem.zig +++ b/lib/saturn/kernel/utils/mem/mem.zig @@ -26,7 +26,49 @@ pub fn eql(noalias b0: []const u8, noalias b1: []const u8, comptime rule: struct }; } -pub fn zero(comptime T: type) T { +pub fn zeroe_mem(lhs: anytype) if(@typeInfo(@TypeOf(lhs)) == .pointer) void else @TypeOf(lhs){ + switch(@typeInfo(@TypeOf(lhs))) { + .pointer => |ptr| { + switch(ptr.size) { + .one, .c => { + lhs.* = zero(lhs.*); + }, + + .slice => { + for(0..lhs.len) |i| { + lhs[i] = zero(lhs[i]); + } + }, + + .many => @compileError( + "is not possible to initialize a [*], use slice!" + ), + } + }, + + .@"struct" => |str| { + var zero_struct = lhs; + inline for(str.fields) |field| { + @field(zero_struct, field.name) = zero( + @field(zero_struct, field.name) + ); + } + return zero_struct; + }, + + .int => return 0, + + .optional => return null, + + else => @compileError( + "type \"" ++ @typeName(@TypeOf(lhs)) ++ "\" not supported!" + ), + } +} + +pub const zero = zeroe_type; + +pub fn zeroe_type(comptime T: type) T { @setEvalBranchQuota(4294967295); switch(@typeInfo(T)) { .int, .float => return @as(T, 0), diff --git a/mm/i386/zone.zig b/mm/i386/zone.zig index 06653e3..f912049 100644 --- a/mm/i386/zone.zig +++ b/mm/i386/zone.zig @@ -87,7 +87,7 @@ pub fn alloc_zone_page( const base, const offset = t: { for(0..comptime(self.table.len / 7)) |i| { // verificando se existe alguma pagina livre - if((self.table[i * 7].reserved ^ @as(u7, 0b111_1111)) != 0) { + if((~self.table[i * 7].reserved) != 0) { for(0..7) |j| { if(((self.table[i * 7].reserved >> @intCast(j)) & 0x01) == 0) { break :t .{ diff --git a/modules.zig b/modules.zig index c4abe81..1bd6d45 100644 --- a/modules.zig +++ b/modules.zig @@ -21,5 +21,6 @@ pub const __SaturnAllMods__ = [_]type { // Module Location! @import("fs/rootfs/rootfs.zig"), - @import("fs/devfs/module.zig"), + @import("fs/devfs/devfs.zig"), + @import("drivers/video/fb/vga/fb.zig"), }; diff --git a/saturn.zig b/saturn.zig index 66b10df..e60146c 100644 --- a/saturn.zig +++ b/saturn.zig @@ -23,7 +23,6 @@ pub const core: type = struct { pub const vfs: type = @import("kernel/core/vfs/vfs.zig"); pub const devices: type = @import("kernel/core/devices/devices.zig"); pub const fs: type = @import("kernel/core/fs/fs.zig"); - pub const drivers: type = @import("kernel/core/drivers/drivers.zig"); pub const events: type = @import("kernel/core/events/events.zig"); }; @@ -40,7 +39,6 @@ pub const interfaces: type = struct { pub const module: type = @import("lib/saturn/interfaces/module.zig"); pub const arch: type = @import("lib/saturn/interfaces/arch.zig"); pub const vfs: type = @import("lib/saturn/interfaces/vfs.zig"); - pub const drivers: type = @import("lib/saturn/interfaces/drivers.zig"); pub const events: type = @import("lib/saturn/interfaces/events.zig"); };