+2
BOOT_AETHELOS.bat
+2
BOOT_AETHELOS.bat
aethelos-test.img
aethelos-test.img
This is a binary file and will not be displayed.
aethelos.iso
aethelos.iso
This is a binary file and will not be displayed.
+332
heartwood/src/drivers/ata.rs
+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(§or_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
+7
heartwood/src/drivers/mod.rs
+34
-61
heartwood/src/eldarin.rs
+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
+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
+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
+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
+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
+2
heartwood/src/vfs/mod.rs
isodir/boot/aethelos/heartwood.bin
isodir/boot/aethelos/heartwood.bin
This is a binary file and will not be displayed.
+1
serial.log
+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