#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace kstd::units_literals; auto test_device_names() -> void { auto storage_mgmt = kernel::devices::storage::management::get(); std::ranges::for_each(storage_mgmt.all_controllers(), [](auto const & controller) { std::ranges::for_each(controller->all_devices(), [](auto const & device) { kstd::println("{}", device->name().view()); }); }); } auto test_file_descriptor_manually() -> void { // setup auto fd_table = kernel::filesystem::file_descriptor_table::get(); auto storage_mgmt = kernel::devices::storage::management::get(); auto device = storage_mgmt.device_by_major_minor(1, 0); auto dev_node = kstd::make_shared(device); auto ofd = kstd::make_shared(dev_node); auto fd_index = fd_table.add_file(ofd); // use: read two bytes and write two again auto fd = fd_table.get_file(fd_index); if (!fd) { kstd::os::panic("test code failed"); } kstd::vector buffer{2}; auto number_of_read_bytes = fd->read(buffer.data(), buffer.size()); kstd::println("read bytes: {}", number_of_read_bytes); kstd::println("buffer: {::#04x}", buffer); // write half of the file new auto const value1 = std::byte{0xAA}; auto const value2 = std::byte{0xBB}; kstd::vector write_buffer{value1, value2}; auto written_bytes = fd->write(write_buffer.data(), write_buffer.size()); kstd::println("written bytes: {}", written_bytes); fd_table.remove_file(fd_index); // use: read four bytes again -> two old bytes two new bytes auto ofd1 = kstd::make_shared(dev_node); fd_index = fd_table.add_file(ofd1); auto fd1 = fd_table.get_file(fd_index); if (!fd1) { kstd::os::panic("test code failed"); } kstd::vector buffer1{4}; number_of_read_bytes = fd1->read(buffer1.data(), buffer1.size()); kstd::println("read bytes: {}", number_of_read_bytes); kstd::println("buffer: {::#04x}", buffer1); } auto test_device_with_vfs() -> void { auto vfs = kernel::filesystem::vfs::get(); auto dentry = vfs.open("/dev/ram0"); if (!dentry) { kstd::os::panic("test code failed"); } auto fd_table = kernel::filesystem::file_descriptor_table::get(); auto ofd = kstd::make_shared(dentry->get_inode()); auto fd = fd_table.add_file(ofd); kstd::vector buffer{2}; auto file = fd_table.get_file(fd); if (!file) { kstd::os::panic("test code failed"); } auto number_of_read_bytes = file->read(buffer.data(), buffer.size()); kstd::println("read bytes: {}", number_of_read_bytes); kstd::println("buffer: {::#04x}", buffer); } auto test_file_lookup() -> void { auto vfs = kernel::filesystem::vfs::get(); auto read_and_write_file = [&vfs](std::string_view path) { kstd::println("[TEST] Reading and writing file at path: {}", path); auto dentry = vfs.open(path); if (!dentry) { kstd::os::panic("test code failed"); } kstd::vector buffer{32}; auto ofd = kstd::make_shared(dentry->get_inode()); auto number_of_read_bytes = ofd->read(buffer.data(), buffer.size()); kstd::println("read bytes: {}", number_of_read_bytes); kstd::println("buffer: {::#04x}", buffer); std::string_view buffer_as_str{reinterpret_cast(buffer.data()), number_of_read_bytes}; kstd::println("buffer_as_str: {}", buffer_as_str); }; read_and_write_file("/info.txt"); read_and_write_file("/enclosures/info.txt"); read_and_write_file("/enclosures/aquarium/tank_1/fish_4.txt"); read_and_write_file("/enclosures/elephant_house/elephant_1.txt"); read_and_write_file( "/enclosures/aquarium/tank_2/" "this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_" "limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt"); vfs.do_mount("/dev/ram16", "/enclosures/aquarium"); read_and_write_file("/enclosures/aquarium/closed.txt"); read_and_write_file("/enclosures/aquarium/information/info_2.txt"); vfs.unmount("/enclosures/aquarium"); read_and_write_file("/enclosures/aquarium/tank_1/fish_4.txt"); vfs.do_mount("/dev/ram32", "/enclosures/elephant_house"); read_and_write_file("/enclosures/elephant_house/monkey_house/infrastructure/info.txt"); vfs.do_mount("/dev/ram16", "/enclosures/elephant_house/monkey_house"); read_and_write_file("/enclosures/elephant_house/monkey_house/information/info_2.txt"); auto result = vfs.unmount("/enclosures/elephant_house"); if (result == kernel::filesystem::vfs::operation_result::unmount_failed) { kstd::println("[TEST] Unmount failed as expected due to active child mount."); } vfs.unmount("/enclosures/elephant_house/monkey_house"); result = vfs.unmount("/enclosures/elephant_house"); if (result == kernel::filesystem::vfs::operation_result::success) { kstd::println("[TEST] Unmount succeeded after unmounting child mount."); } } auto run_test_code() -> void { kstd::println("[TEST] Running test code..."); kstd::println("[TEST] device names"); test_device_names(); kstd::println("---------------------------------"); kstd::println("[TEST] file descriptor manually"); test_file_descriptor_manually(); kstd::println("---------------------------------"); kstd::println("[TEST] device with VFS"); test_device_with_vfs(); kstd::println("---------------------------------"); kstd::println("[TEST] file lookup"); test_file_lookup(); kstd::println("---------------------------------"); } auto run_demo() -> void { // 1) open a file auto fd_1 = kapi::filesystem::open("/entrance/tickets.txt"); if (fd_1 == -1) { kstd::os::panic("demo failed"); } // 2) read from the file kstd::vector buffer_1{10}; auto bytes_read = kapi::filesystem::read(fd_1, buffer_1.data(), buffer_1.size()); auto buffer_as_str = std::string_view{reinterpret_cast(buffer_1.data()), static_cast(bytes_read)}; kstd::println("Read {} bytes from /entrance/tickets.txt: {}", bytes_read, buffer_as_str); // 3) show that /entrance/information/info_1.txt is not accessible before mounting auto fd_before_mount = kapi::filesystem::open("/entrance/information/info_1.txt"); if (fd_before_mount == -1) { kstd::println("/entrance/information/info_1.txt is not accessible before mounting, as expected."); } // 4) mount a new filesystem on top of /entrance kapi::filesystem::mount("/dev/ram16", "/entrance"); // 5) open a file from the new filesystem auto fd_2 = kapi::filesystem::open("/entrance/information/info_1.txt"); if (fd_2 == -1) { kstd::os::panic("demo failed"); } // 6) read from the new file kstd::vector buffer_2{10}; bytes_read = kapi::filesystem::read(fd_2, buffer_2.data(), buffer_2.size()); buffer_as_str = std::string_view{reinterpret_cast(buffer_2.data()), static_cast(bytes_read)}; kstd::println("Read {} bytes from /entrance/information/info_1.txt: {}", bytes_read, buffer_as_str); // 7) open device as file auto fd_3 = kapi::filesystem::open("/dev/ram48"); if (fd_3 == -1) { kstd::os::panic("demo failed"); } // 8) read from the device file kstd::vector buffer_3{2}; bytes_read = kapi::filesystem::read(fd_3, buffer_3.data(), buffer_3.size()); kstd::println("Read {} bytes from /dev/ram48: {::#04x}", bytes_read, buffer_3); // 9) write to the device file kstd::vector write_buffer{std::byte{0xAA}, std::byte{0xAA}}; auto bytes_written = kapi::filesystem::write(fd_3, write_buffer.data(), write_buffer.size()); kstd::println("Written {} bytes to /dev/ram48: {::#04x}", bytes_written, write_buffer); // 10) do memory dump to show that the write to the device file had an effect } auto main() -> int { kapi::cio::init(); kstd::println("[OS] IO subsystem initialized."); kapi::cpu::init(); kapi::memory::init(); kernel::memory::init_heap(kapi::memory::heap_base); kapi::system::memory_initialized(); kapi::memory::init_mmio(kapi::memory::mmio_base, 1_GiB / kapi::memory::page::size); kstd::println("[OS] Memory subsystem initialized."); kapi::devices::init(); kstd::println("[OS] System root bus initialized."); kapi::devices::init_platform_devices(); kstd::println("[OS] Platform devices initialized."); kapi::interrupts::enable(); kstd::println("[OS] Interrupts enabled."); kapi::boot_modules::init(); kstd::println("[OS] Boot module registry initialized."); kernel::devices::storage::management::init(); kstd::println("[OS] Storage management initialized."); kernel::filesystem::file_descriptor_table::init(); kstd::println("[OS] Global file descriptor table initialized."); kernel::filesystem::vfs::init(); kstd::println("[OS] Virtual filesystem initialized."); // TODO BA-FS26 remove demo and test code again? // run_demo(); // TODO BA-FS26 remove demo and test code again? run_test_code(); kstd::println("[TEST] All tests completed."); kapi::system::panic("Returning from kernel main!"); }