Microkernel based hobby OS

Working on fat32 drivers

+2
BOOT_AETHELOS.bat
··· 9 9 10 10 "C:\Program Files\qemu\qemu-system-x86_64.exe" ^ 11 11 -cdrom aethelos.iso ^ 12 + -hda aethelos-test.img ^ 13 + -boot d ^ 12 14 -serial file:serial.log ^ 13 15 -m 256M ^ 14 16 -display gtk ^
aethelos-test.img

This is a binary file and will not be displayed.

aethelos.iso

This is a binary file and will not be displayed.

+332
heartwood/src/drivers/ata.rs
··· 1 + //! ATA/IDE disk driver (PIO mode) 2 + //! 3 + //! This driver supports reading from ATA hard drives using PIO (Programmed I/O) mode. 4 + //! It implements the BlockDevice trait for integration with the VFS layer. 5 + //! 6 + //! **Supported:** 7 + //! - Primary bus (0x1F0-0x1F7) 8 + //! - Master drive 9 + //! - 28-bit LBA addressing 10 + //! - Read operations 11 + //! 12 + //! **Not yet implemented:** 13 + //! - Secondary bus (0x170) 14 + //! - Slave drives 15 + //! - 48-bit LBA 16 + //! - DMA mode 17 + //! - Write operations 18 + 19 + use crate::vfs::block_device::{BlockDevice, BlockDeviceError}; 20 + use alloc::vec::Vec; 21 + use core::arch::asm; 22 + 23 + /// ATA command codes 24 + const ATA_CMD_READ_SECTORS: u8 = 0x20; 25 + const ATA_CMD_IDENTIFY: u8 = 0xEC; 26 + 27 + /// ATA status register bits 28 + const ATA_STATUS_BSY: u8 = 0x80; // Busy 29 + const ATA_STATUS_DRQ: u8 = 0x08; // Data Request Ready 30 + const ATA_STATUS_ERR: u8 = 0x01; // Error 31 + 32 + /// Primary ATA bus base I/O port 33 + const ATA_PRIMARY_BASE: u16 = 0x1F0; 34 + 35 + /// I/O port offsets from base 36 + const ATA_REG_DATA: u16 = 0; // 0x1F0 37 + const ATA_REG_ERROR: u16 = 1; // 0x1F1 38 + const ATA_REG_SECTOR_COUNT: u16 = 2; // 0x1F2 39 + const ATA_REG_LBA_LOW: u16 = 3; // 0x1F3 40 + const ATA_REG_LBA_MID: u16 = 4; // 0x1F4 41 + const ATA_REG_LBA_HIGH: u16 = 5; // 0x1F5 42 + const ATA_REG_DRIVE: u16 = 6; // 0x1F6 43 + const ATA_REG_STATUS: u16 = 7; // 0x1F7 44 + const ATA_REG_COMMAND: u16 = 7; // 0x1F7 (write) 45 + 46 + /// ATA disk drive 47 + pub struct AtaDrive { 48 + bus: u16, 49 + drive: u8, // 0 = master, 1 = slave 50 + sectors: u64, 51 + sector_size: u32, 52 + } 53 + 54 + impl AtaDrive { 55 + /// Get the total number of sectors on this drive 56 + pub fn sector_count(&self) -> u64 { 57 + self.sectors 58 + } 59 + 60 + /// Detect and initialize primary master drive 61 + pub fn detect_primary_master() -> Option<Self> { 62 + let bus = ATA_PRIMARY_BASE; 63 + let drive = 0; 64 + 65 + // Aggressive detection: just assume drive exists and try to use it 66 + // If sector reads work, it's a real drive! 67 + // This avoids IDENTIFY command which was hanging 68 + Some(AtaDrive { 69 + bus, 70 + drive, 71 + sectors: 204800, // Assume 100MB (will be corrected if FAT32 mount works) 72 + sector_size: 512, 73 + }) 74 + } 75 + 76 + /// Send IDENTIFY command to drive 77 + fn identify(bus: u16, drive: u8) -> bool { 78 + // Select drive 79 + outb(bus + ATA_REG_DRIVE, 0xA0 | (drive << 4)); 80 + Self::wait_400ns(bus); 81 + 82 + // Set sector count and LBA to 0 83 + outb(bus + ATA_REG_SECTOR_COUNT, 0); 84 + outb(bus + ATA_REG_LBA_LOW, 0); 85 + outb(bus + ATA_REG_LBA_MID, 0); 86 + outb(bus + ATA_REG_LBA_HIGH, 0); 87 + 88 + // Send IDENTIFY command 89 + outb(bus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); 90 + 91 + // Read status 92 + let status = inb(bus + ATA_REG_STATUS); 93 + if status == 0 { 94 + // Drive does not exist 95 + return false; 96 + } 97 + 98 + // Poll until BSY clears 99 + if !Self::wait_not_busy(bus) { 100 + return false; 101 + } 102 + 103 + // Check if drive is ready 104 + let lba_mid = inb(bus + ATA_REG_LBA_MID); 105 + let lba_high = inb(bus + ATA_REG_LBA_HIGH); 106 + 107 + if lba_mid != 0 || lba_high != 0 { 108 + // Not ATA drive (might be ATAPI) 109 + return false; 110 + } 111 + 112 + // Wait for DRQ or ERR (with timeout) 113 + for _ in 0..1000 { 114 + let status = inb(bus + ATA_REG_STATUS); 115 + if status & ATA_STATUS_ERR != 0 { 116 + return false; 117 + } 118 + if status & ATA_STATUS_DRQ != 0 { 119 + break; 120 + } 121 + } 122 + 123 + // Drive exists and responded to IDENTIFY 124 + // Discard the 256 words of IDENTIFY data for now 125 + for _ in 0..256 { 126 + let _ = inw(bus + ATA_REG_DATA); 127 + } 128 + 129 + true 130 + } 131 + 132 + /// Read sector count from IDENTIFY data 133 + fn read_sector_count(bus: u16, drive: u8) -> u64 { 134 + // Re-send IDENTIFY to get data 135 + outb(bus + ATA_REG_DRIVE, 0xA0 | (drive << 4)); 136 + Self::wait_400ns(bus); 137 + outb(bus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); 138 + Self::wait_not_busy(bus); 139 + 140 + // Wait for DRQ (with timeout) 141 + let mut drq_ready = false; 142 + for _ in 0..1000 { 143 + let status = inb(bus + ATA_REG_STATUS); 144 + if status & ATA_STATUS_DRQ != 0 { 145 + drq_ready = true; 146 + break; 147 + } 148 + } 149 + 150 + if !drq_ready { 151 + // Timeout - return default 152 + return 2048; // 1MB default 153 + } 154 + 155 + // Read IDENTIFY data 156 + let mut identify_data = [0u16; 256]; 157 + for i in 0..256 { 158 + identify_data[i] = inw(bus + ATA_REG_DATA); 159 + } 160 + 161 + // Words 60-61 contain total 28-bit LBA sectors 162 + let sectors_low = identify_data[60] as u32; 163 + let sectors_high = identify_data[61] as u32; 164 + let sectors = (sectors_high as u64) << 16 | sectors_low as u64; 165 + 166 + if sectors > 0 { 167 + sectors 168 + } else { 169 + // Default to small size if IDENTIFY failed 170 + 2048 // 1MB 171 + } 172 + } 173 + 174 + /// Read a single sector (28-bit LBA) 175 + fn read_sector_pio(&self, lba: u64) -> Result<Vec<u8>, BlockDeviceError> { 176 + if lba >= self.sectors { 177 + return Err(BlockDeviceError::InvalidSector); 178 + } 179 + 180 + // Select drive (LBA mode) 181 + let drive_byte = 0xE0 | (self.drive << 4) | ((lba >> 24) & 0x0F) as u8; 182 + outb(self.bus + ATA_REG_DRIVE, drive_byte); 183 + Self::wait_400ns(self.bus); 184 + 185 + // Send sector count (1 sector) 186 + outb(self.bus + ATA_REG_SECTOR_COUNT, 1); 187 + 188 + // Send LBA 189 + outb(self.bus + ATA_REG_LBA_LOW, (lba & 0xFF) as u8); 190 + outb(self.bus + ATA_REG_LBA_MID, ((lba >> 8) & 0xFF) as u8); 191 + outb(self.bus + ATA_REG_LBA_HIGH, ((lba >> 16) & 0xFF) as u8); 192 + 193 + // Send READ SECTORS command 194 + outb(self.bus + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS); 195 + 196 + // Wait for drive to be ready 197 + if !Self::wait_not_busy(self.bus) { 198 + return Err(BlockDeviceError::IoError); 199 + } 200 + 201 + // Wait for DRQ (with timeout) 202 + for _ in 0..1000 { 203 + let status = inb(self.bus + ATA_REG_STATUS); 204 + if status & ATA_STATUS_ERR != 0 { 205 + return Err(BlockDeviceError::IoError); 206 + } 207 + if status & ATA_STATUS_DRQ != 0 { 208 + break; 209 + } 210 + } 211 + 212 + // Read 512 bytes (256 words) 213 + let mut buffer = Vec::with_capacity(512); 214 + for _ in 0..256 { 215 + let word = inw(self.bus + ATA_REG_DATA); 216 + buffer.push((word & 0xFF) as u8); 217 + buffer.push((word >> 8) as u8); 218 + } 219 + 220 + Ok(buffer) 221 + } 222 + 223 + /// Wait for drive to not be busy (with timeout) 224 + fn wait_not_busy(bus: u16) -> bool { 225 + for _ in 0..1000 { // Much shorter timeout 226 + let status = inb(bus + ATA_REG_STATUS); 227 + if status & ATA_STATUS_BSY == 0 { 228 + return true; 229 + } 230 + // No delay - inb() itself provides enough time 231 + } 232 + false 233 + } 234 + 235 + /// Wait 400ns by reading status register 4 times 236 + fn wait_400ns(bus: u16) { 237 + for _ in 0..4 { 238 + let _ = inb(bus + ATA_REG_STATUS); 239 + } 240 + } 241 + 242 + /// Tiny delay for polling loops 243 + fn tiny_delay() { 244 + for _ in 0..100 { 245 + core::hint::spin_loop(); 246 + } 247 + } 248 + } 249 + 250 + impl BlockDevice for AtaDrive { 251 + fn sector_size(&self) -> u32 { 252 + self.sector_size 253 + } 254 + 255 + fn sector_count(&self) -> u64 { 256 + self.sectors 257 + } 258 + 259 + fn read_sector(&self, sector: u64) -> Result<Vec<u8>, BlockDeviceError> { 260 + self.read_sector_pio(sector) 261 + } 262 + 263 + fn read_sectors(&self, start_sector: u64, count: u32) -> Result<Vec<u8>, BlockDeviceError> { 264 + let mut result = Vec::with_capacity((count as usize) * 512); 265 + 266 + for i in 0..count { 267 + let sector_data = self.read_sector(start_sector + i as u64)?; 268 + result.extend_from_slice(&sector_data); 269 + } 270 + 271 + Ok(result) 272 + } 273 + 274 + fn write_sector(&self, _sector: u64, _data: &[u8]) -> Result<(), BlockDeviceError> { 275 + // Write not yet implemented 276 + Err(BlockDeviceError::WriteProtected) 277 + } 278 + 279 + fn write_sectors(&self, _start_sector: u64, _data: &[u8]) -> Result<(), BlockDeviceError> { 280 + // Write not yet implemented 281 + Err(BlockDeviceError::WriteProtected) 282 + } 283 + 284 + fn sync(&self) -> Result<(), BlockDeviceError> { 285 + // No cache to flush in PIO mode 286 + Ok(()) 287 + } 288 + 289 + fn is_read_only(&self) -> bool { 290 + true // For now, until write support is added 291 + } 292 + } 293 + 294 + /// Read byte from I/O port 295 + fn inb(port: u16) -> u8 { 296 + let result: u8; 297 + unsafe { 298 + asm!( 299 + "in al, dx", 300 + out("al") result, 301 + in("dx") port, 302 + options(nomem, nostack, preserves_flags) 303 + ); 304 + } 305 + result 306 + } 307 + 308 + /// Write byte to I/O port 309 + fn outb(port: u16, value: u8) { 310 + unsafe { 311 + asm!( 312 + "out dx, al", 313 + in("dx") port, 314 + in("al") value, 315 + options(nomem, nostack, preserves_flags) 316 + ); 317 + } 318 + } 319 + 320 + /// Read word (16-bit) from I/O port 321 + fn inw(port: u16) -> u16 { 322 + let result: u16; 323 + unsafe { 324 + asm!( 325 + "in ax, dx", 326 + out("ax") result, 327 + in("dx") port, 328 + options(nomem, nostack, preserves_flags) 329 + ); 330 + } 331 + result 332 + }
+7
heartwood/src/drivers/mod.rs
··· 1 + //! Hardware device drivers 2 + //! 3 + //! This module contains drivers for various hardware devices. 4 + 5 + pub mod ata; 6 + 7 + pub use ata::AtaDrive;
+34 -61
heartwood/src/eldarin.rs
··· 946 946 947 947 /// VFS Info - Show filesystem information 948 948 fn cmd_vfs_info() { 949 - use crate::vfs::mock_fat32::MockFat32Device; 950 - use crate::vfs::fat32::Fat32; 951 - use alloc::boxed::Box; 952 - 953 - crate::println!("◈ Filesystem Information"); 954 - crate::println!(); 955 - 956 - let device = Box::new(MockFat32Device::new()); 957 - let fat32 = match Fat32::new(device) { 958 - Ok(fs) => fs, 959 - Err(e) => { 960 - crate::println!("Failed to mount: {:?}", e); 961 - return; 962 - } 963 - }; 964 - 965 - crate::println!(" Filesystem Type: {}", fat32.bpb.fs_type); 966 - crate::println!(" Volume Label: {}", fat32.bpb.volume_label); 967 - crate::println!(); 968 - crate::println!(" Geometry:"); 969 - crate::println!(" Bytes per sector: {}", fat32.bpb.bytes_per_sector); 970 - crate::println!(" Sectors/cluster: {}", fat32.bpb.sectors_per_cluster); 971 - crate::println!(" Cluster size: {} bytes", fat32.bpb.cluster_size()); 972 - crate::println!(" Total sectors: {}", fat32.bpb.total_sectors); 973 - crate::println!(); 974 - crate::println!(" FAT Information:"); 975 - crate::println!(" Number of FATs: {}", fat32.bpb.num_fats); 976 - crate::println!(" Sectors per FAT: {}", fat32.bpb.sectors_per_fat); 977 - crate::println!(" Root cluster: {}", fat32.bpb.root_cluster); 978 - crate::println!(); 979 - crate::println!(" Special Sectors:"); 980 - crate::println!(" FSInfo sector: {}", fat32.bpb.fsinfo_sector); 981 - crate::println!(" Backup boot: {}", fat32.bpb.backup_boot_sector); 982 - 983 - if let Some(free) = fat32.bpb.free_clusters() { 984 - crate::println!(); 985 - crate::println!(" Space (from FSInfo):"); 986 - crate::println!(" Free clusters: {}", free); 987 - if let Some(space) = fat32.bpb.free_space() { 988 - crate::println!(" Free space: {} KB ({} MB)", 989 - space / 1024, space / 1024 / 1024); 990 - } 991 - } 949 + crate::vfs::debug_cmd::show_mount_status(); 992 950 } 993 951 994 952 /// VFS LS - List directory contents 995 953 fn cmd_vfs_ls(args: &str) { 996 954 use crate::vfs::{FileSystem, Path}; 997 - use crate::vfs::mock_fat32::MockFat32Device; 998 - use crate::vfs::fat32::Fat32; 999 - use alloc::boxed::Box; 955 + use crate::vfs::global as vfs_global; 1000 956 1001 957 let path = if args.is_empty() { "/" } else { args.trim() }; 1002 958 1003 - let device = Box::new(MockFat32Device::new()); 1004 - let fat32 = match Fat32::new(device) { 1005 - Ok(fs) => fs, 1006 - Err(e) => { 1007 - crate::println!("Failed to mount: {:?}", e); 959 + // Get global filesystem 960 + let global_fs = match vfs_global::get() { 961 + Some(fs) => fs, 962 + None => { 963 + crate::println!(" ✗ No filesystem mounted"); 964 + crate::println!(" (Reboot with -hda disk.img to mount a drive)"); 965 + return; 966 + } 967 + }; 968 + 969 + let fs_lock = global_fs.lock(); 970 + let fs = match &*fs_lock { 971 + Some(filesystem) => filesystem, 972 + None => { 973 + crate::println!(" ✗ No filesystem mounted"); 1008 974 return; 1009 975 } 1010 976 }; ··· 1012 978 crate::println!("◈ Directory listing: {}", path); 1013 979 crate::println!(); 1014 980 1015 - match fat32.read_dir(&Path::new(path)) { 981 + match fs.read_dir(&Path::new(path)) { 1016 982 Ok(entries) => { 1017 983 let count = entries.len(); 1018 984 if entries.is_empty() { ··· 1036 1002 /// VFS CAT - Display file contents 1037 1003 fn cmd_vfs_cat(args: &str) { 1038 1004 use crate::vfs::{FileSystem, Path}; 1039 - use crate::vfs::mock_fat32::MockFat32Device; 1040 - use crate::vfs::fat32::Fat32; 1041 - use alloc::boxed::Box; 1005 + use crate::vfs::global as vfs_global; 1042 1006 1043 1007 if args.is_empty() { 1044 1008 crate::println!("Usage: vfs-cat <filename>"); ··· 1048 1012 1049 1013 let filename = args.trim(); 1050 1014 1051 - let device = Box::new(MockFat32Device::new()); 1052 - let fat32 = match Fat32::new(device) { 1053 - Ok(fs) => fs, 1054 - Err(e) => { 1055 - crate::println!("Failed to mount: {:?}", e); 1015 + // Get global filesystem 1016 + let global_fs = match vfs_global::get() { 1017 + Some(fs) => fs, 1018 + None => { 1019 + crate::println!(" ✗ No filesystem mounted"); 1020 + return; 1021 + } 1022 + }; 1023 + 1024 + let fs_lock = global_fs.lock(); 1025 + let fs = match &*fs_lock { 1026 + Some(filesystem) => filesystem, 1027 + None => { 1028 + crate::println!(" ✗ No filesystem mounted"); 1056 1029 return; 1057 1030 } 1058 1031 }; ··· 1060 1033 crate::println!("◈ Reading: {}", filename); 1061 1034 crate::println!(); 1062 1035 1063 - match fat32.read(&Path::new(filename)) { 1036 + match fs.read(&Path::new(filename)) { 1064 1037 Ok(data) => { 1065 1038 if let Ok(text) = core::str::from_utf8(&data) { 1066 1039 for line in text.lines() {
+1
heartwood/src/lib.rs
··· 45 45 pub mod eldarin; // The Eldarin Shell 46 46 pub mod irq_safe_mutex; // Interrupt-safe mutex primitive 47 47 pub mod vfs; // Virtual File System layer 48 + pub mod drivers; // Hardware device drivers 48 49 49 50 // Re-export key types 50 51 pub use nexus::{Message, MessageType, MessagePriority, NexusError};
+42
heartwood/src/main.rs
··· 108 108 } 109 109 } 110 110 111 + /// Mount storage - using RAM disk since ATA driver has issues 112 + fn detect_and_mount_storage() { 113 + use heartwood::vfs::mock_fat32::MockFat32Device; 114 + use heartwood::vfs::fat32::Fat32; 115 + use heartwood::vfs::global as vfs_global; 116 + use alloc::boxed::Box; 117 + 118 + // Initialize global VFS 119 + vfs_global::init(); 120 + 121 + println!(" ◈ Creating RAM disk (64KB FAT32 filesystem)..."); 122 + 123 + // Create in-memory FAT32 filesystem 124 + let device = Box::new(MockFat32Device::new()); 125 + 126 + match Fat32::new(device) { 127 + Ok(fs) => { 128 + println!(" ✓ RAM disk created and mounted!"); 129 + 130 + // Mount globally 131 + vfs_global::mount(Box::new(fs)); 132 + println!(" ✓ Filesystem accessible (vfs-ls, vfs-cat)"); 133 + println!(); 134 + println!(" Files available:"); 135 + println!(" /README.TXT - Welcome message"); 136 + println!(" /TEST.TXT - Test file"); 137 + } 138 + Err(e) => { 139 + println!(" ✗ Failed to create RAM disk: {}", e); 140 + } 141 + } 142 + 143 + println!(); 144 + println!(" Note: ATA driver postponed - RAM disk used instead"); 145 + } 146 + 111 147 /// Initialize the Heartwood's core systems 112 148 fn heartwood_init() { 113 149 unsafe { serial_out(b'A'); } // Before init sequence ··· 162 198 heartwood::eldarin::init(); 163 199 unsafe { serial_out(b'M'); } 164 200 println!(" ✓ Shell ready"); 201 + 202 + // Detect ATA drives and mount filesystem 203 + unsafe { serial_out(b'N'); } 204 + println!("◈ Detecting storage devices..."); 205 + detect_and_mount_storage(); 206 + unsafe { serial_out(b'O'); } 165 207 166 208 unsafe { serial_out(b'K'); } 167 209 println!("\n◈ Heartwood initialization complete!");
+36
heartwood/src/vfs/debug_cmd.rs
··· 1 + //! VFS Debug Command - shows mount status 2 + 3 + use crate::vfs::global as vfs_global; 4 + 5 + pub fn show_mount_status() { 6 + crate::println!("◈ VFS Mount Status"); 7 + crate::println!(); 8 + 9 + match vfs_global::get() { 10 + None => { 11 + crate::println!(" ✗ Global VFS not initialized"); 12 + crate::println!(" (This is a bug - VFS should initialize at boot)"); 13 + } 14 + Some(global_fs) => { 15 + crate::println!(" ✓ Global VFS initialized"); 16 + 17 + let fs_lock = global_fs.lock(); 18 + match &*fs_lock { 19 + None => { 20 + crate::println!(" ✗ No filesystem mounted"); 21 + crate::println!(); 22 + crate::println!(" Possible reasons:"); 23 + crate::println!(" - No ATA drive detected (check boot messages)"); 24 + crate::println!(" - FAT32 mount failed (disk not formatted?)"); 25 + crate::println!(" - QEMU not started with -hda disk.img"); 26 + } 27 + Some(fs) => { 28 + crate::println!(" ✓ Filesystem mounted!"); 29 + crate::println!(" Type: {}", fs.name()); 30 + crate::println!(); 31 + crate::println!(" Try: vfs-ls / to list root directory"); 32 + } 33 + } 34 + } 35 + } 36 + }
+44
heartwood/src/vfs/global.rs
··· 1 + //! Global VFS mount point 2 + //! 3 + //! Simple global filesystem for testing until proper VFS manager is implemented 4 + 5 + use super::FileSystem; 6 + use crate::mana_pool::InterruptSafeLock; 7 + use core::mem::MaybeUninit; 8 + use alloc::boxed::Box; 9 + 10 + /// Global mounted filesystem 11 + static mut GLOBAL_FS: MaybeUninit<InterruptSafeLock<Option<Box<dyn FileSystem>>>> = MaybeUninit::uninit(); 12 + static mut FS_INITIALIZED: bool = false; 13 + 14 + /// Initialize the global filesystem 15 + pub fn init() { 16 + unsafe { 17 + let fs_option: Option<Box<dyn FileSystem>> = None; 18 + let lock = InterruptSafeLock::new(fs_option); 19 + core::ptr::write(core::ptr::addr_of_mut!(GLOBAL_FS).cast(), lock); 20 + FS_INITIALIZED = true; 21 + } 22 + } 23 + 24 + /// Mount a filesystem as the global root 25 + pub fn mount(fs: Box<dyn FileSystem>) { 26 + unsafe { 27 + if !FS_INITIALIZED { 28 + init(); 29 + } 30 + let global_fs = &*core::ptr::addr_of!(GLOBAL_FS).cast::<InterruptSafeLock<Option<Box<dyn FileSystem>>>>(); 31 + let mut fs_lock = global_fs.lock(); 32 + *fs_lock = Some(fs); 33 + } 34 + } 35 + 36 + /// Get reference to global filesystem 37 + pub fn get() -> Option<&'static InterruptSafeLock<Option<Box<dyn FileSystem>>>> { 38 + unsafe { 39 + if !FS_INITIALIZED { 40 + return None; 41 + } 42 + Some(&*core::ptr::addr_of!(GLOBAL_FS).cast::<InterruptSafeLock<Option<Box<dyn FileSystem>>>>()) 43 + } 44 + }
+2
heartwood/src/vfs/mod.rs
··· 13 13 pub mod block_device; 14 14 pub mod fat32; 15 15 pub mod mock_fat32; 16 + pub mod global; 17 + pub mod debug_cmd; 16 18 17 19 #[cfg(test)] 18 20 mod tests;
isodir/boot/aethelos/heartwood.bin

This is a binary file and will not be displayed.

+1
serial.log
··· 1 + BSLSR12AB~b$%$%$%$%$%$%~VWG+@$%#E[~]D@VWG+@$%#E[~]D#VWG+@$%#E[~]DCVWG+@$%#E[~]DMNabcdeOPQRSDVWG+@$%#E[~]DEVWG+@$%#E[~]Dnxsu!FVWG+@$%#E[~]DGVWG+@$%#E[~]D1AabcdefghijklmBCDy3VWG+@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DHVWG+@$%#E[~]DIVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DM...mM....mM....mM....mM....mVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~^]DJVWG+@$%#E[~^]DLVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM........mMmM........mM........mM........mMVWG+@$%#E[~^]DNVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM....mM....mMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DOKVWG+@$%#E[~^]DVWG+@$%#E[~^]D3HXY!SI.P12345LCKVWG+@$%#E[~^]DP12345LCT+VWG+@$%#E[~^]D*VWG+@$%#E[~^]D1VWG+@$%#E[~^]D2VWG+@$%#E[~^]D3VWG+@$%#E[~^]D4VWG+@$%#E[~^]D5VWG+@$%#E[~^]D6VWG+@$%#E[~^]D7VWG+@$%#E[~^]D8VWG+@$%#E[~^]D9VWG+@$%#E[~^]D0VWG+@$%#E[~^]D!stmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DaVWG+@$%#MmMmMmMmMmMmMmMmMmMmMmMm@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DbVWG+@$%#@$%#@$%#E[~^]DcVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~^]DdVWG+@$%#@$%#@$%#E[~^]DeVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P1Mm2345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P1Mm2345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P1Mm2345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P1Mm2345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P1M.m2345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#@$%#@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCVWG+@$%#E[~]DR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~]DVWG+@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#@$%#@$%#@$%#@$%#@$%#@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#@$%#@$%#E[~]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!VWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6MmVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DVWG+@$%#E[~]DMmVWG+@$%#E[~]Dh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DVWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]DP12345LCR6yh.P12345LCR6P12345LCR6VWG+@$%#E[~]D!MmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmMmM....mM....mMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DMmMmMmMmMmMmMmMmMmMmMmVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#@$%#@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]DVWG+@$%#E[~^]D>VWG+@$%#E[~^]DP12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6P12345LCR6yh.P12345LCR6P12345LCR6