Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a733b1559 | ||
|
|
deb513c925 | ||
|
|
789fb7971a | ||
|
|
4e3acd6af7 | ||
|
|
262d064b6d |
No files matched your search
+157
File diff suppressed because it is too large.
Load diff
+7
-1
@@ -4,4 +4,10 @@ echo "======================="
|
|||||||
echo " "
|
echo " "
|
||||||
echo "Compiling FPC Sources..."
|
echo "Compiling FPC Sources..."
|
||||||
echo " "
|
echo " "
|
||||||
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/include/* -Fusrc/driver/* -Fusrc/driver/net/* -Fusrc/driver/bus/* -Fusrc/driver/bus/usb/* -Fusrc/driver/hid/* src/kernel.pas
|
# Build -Fu flags for all directories under src/ and wasuro/
|
||||||
|
FU_PATHS="-Fusrc -Fuwasuro"
|
||||||
|
for dir in $(find src wasuro -type d 2>/dev/null); do
|
||||||
|
FU_PATHS="$FU_PATHS -Fu$dir"
|
||||||
|
done
|
||||||
|
|
||||||
|
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/kernel.pas
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#Flat filesystem
|
||||||
|
|
||||||
|
A super simple filesystem for asuro. Folders are emulated in filenames.
|
||||||
|
|
||||||
|
Starts with disk info sector, sector 0 of volume
|
||||||
|
|
||||||
|
---
|
||||||
|
#### disk info
|
||||||
|
|
||||||
|
jmp2boot : ubit24;
|
||||||
|
OEMName : array[0..7] of char;
|
||||||
|
version : uint16 // numerical version of filesystem
|
||||||
|
sectorCount : uint16;
|
||||||
|
fileCount : uint16
|
||||||
|
signature : uint32 = 0x0B00B1E5
|
||||||
|
|
||||||
|
|
||||||
|
the Rest of the sector is reserved
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Starting from sector 1 is the file table. Table size is determined by entry size (64) * fileCount
|
||||||
|
|
||||||
|
---
|
||||||
|
####File entry
|
||||||
|
|
||||||
|
name : array[0..59] of char //file name max 60 chars
|
||||||
|
fileStart : 16bit // start sector of data
|
||||||
|
fileSize : 16bit // data size in sectors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Binary file not shown.
Generated
+1
@@ -0,0 +1 @@
|
|||||||
|
Hello from the Asuro ISO!
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Lessons Learnt
|
||||||
|
|
||||||
|
## 1. File Pickers Must Be Proper Reusable OS Components
|
||||||
|
Inline pickers hacked into app code are broken and not reusable. Build file pickers as a standalone unit (`filepicker.pas`) that any program can call via a callback.
|
||||||
|
|
||||||
|
## 2. All Errors Need Visible In-App Feedback
|
||||||
|
Never use `syslog.logln` as the only error output. Always show the user a dialog, msgbox, or status bar message. Syslog is supplemental only.
|
||||||
|
|
||||||
|
## 4. Shell Command Output Goes to stdout_buf, Not syslog
|
||||||
|
Use `stdio.bufWriteStr(stdout_buf, ...)` for all shell command output. `syslog` is for kernel diagnostics only.
|
||||||
|
|
||||||
|
## 5. Unit Test Convention
|
||||||
|
New subsystem units get a `procedure UnitTest` (called at boot from kernel.pas) and a `procedure init` that registers a CLI command so tests can be re-run at runtime. Tests use a nested `Assert(condition, name)` that increments `passed`/`failed` and logs failures via `syslog.logln`. At-boot tests must not do disk I/O — only test in-memory/virtual structures.
|
||||||
|
|
||||||
|
## 6. ISR-Visible Spin-Wait Flags Must Use Pointer Dereferencing
|
||||||
|
FPC has no `volatile` keyword. Any `while flag = 0 do asm hlt end` loop where `flag` is set by an ISR will hang forever because FPC hoists the load into a register before the loop and never re-reads memory. Always access the flag through a pointer: `while puint32(@flag)^ = 0 do proc_yield()`. This applies everywhere in the kernel that spins waiting for ISR-written state (e.g. `submit_io_wait`, `proc_await`-style loops, DMA done flags).
|
||||||
|
|
||||||
|
## 7. Never Spawn a Process Per I/O Operation
|
||||||
|
Spawning a new kernel process for each FAT32 read/write/dir operation is pure overhead: process creation (kalloc 8 KB stack, fake IRET frame, DList insertion), an extra context switch, and a double-wait (VFS spins on the worker, worker spins on AHCI). Instead, submit the I/O directly and park the calling process via `psAwaiting` until the AHCI ISR fires the completion callback — zero extra processes, zero wasted scheduler ticks.
|
||||||
|
|
||||||
|
## 8. Use psAwaiting to Park a Process Pending Async I/O (not proc_yield spin)
|
||||||
|
The correct way to block a process on an async I/O result is: (1) set up a completion callback that sets `State := psReady` then `Done := 1`, (2) atomically check if the operation is already done (under CLI) and set `CurrentProcess^.State := psAwaiting` if not, (3) spin on `Done` via `puint32(@wait.Done)^` per Lesson #6 with `asm hlt end` inside the loop. The process is removed from the runnable set while hardware works. **Do NOT call `proc_await` from `submit_io_wait`** — `proc_await` spins on `CurrentProcess^.State = psAwaiting` without pointer indirection and FPC caches the value in a register, causing it to return immediately before the I/O completes. The calling code then reads garbage from the DMA buffer, causing invalid pointer dereferences and page faults.
|
||||||
|
|
||||||
|
## 9. VFS GetDirectoryListing Must Return a Snapshot, Not a Live Tree Reference
|
||||||
|
`GetDirectoryListing` for `otVDIRECTORY` nodes previously returned `PHashMap(Obj^.Reference)` — a direct pointer into the live VFS tree. When callers called `FreeDirectoryListing` on the returned map, it freed the live VFSObjects and their name strings, destroying the VFS tree. Any subsequent `GetObjectFromPath` call would then dereference the trashed memory and page fault. **Fix**: always return a heap-allocated snapshot copy of the directory (new `PHashMap`, new `PVFSObject` entries with `stringCopy`'d keys). `FreeDirectoryListing` can then safely own and free the snapshot without touching the live tree. The rule: any function that returns a `PHashMap` to a caller who will call `FreeDirectoryListing` must allocate a fresh map — never return a raw interior pointer to a live data structure.
|
||||||
|
|
||||||
|
## 10. Never Call Synchronous Disk I/O From an LVGL Timer or Event Callback
|
||||||
|
LVGL timer callbacks (`lv_timer_create`) and event callbacks run synchronously inside the LVGL render loop. Calling any function that parks the current process waiting for disk I/O (e.g. `vfs.FileSize`, `vfs.OpenFile`, `vfs.ReadFile`) from inside a timer or event callback will hang the entire UI — the process blocks mid-callback and the LVGL loop never resumes. All disk I/O that must occur in a UI context must either: (a) use the async VFS API (`OpenFileAsync`, `WriteFileAsync`) with a completion callback that triggers a deferred LVGL update, or (b) be deferred to a dedicated worker process that signals back via a flag the UI can poll. `GetDirectoryListingFrom` is the one bulk exception — it was already present in the original picker and works because it loads into a snapshot synchronously as a single operation; per-file calls like `FileSize` in a loop are the problem.
|
||||||
|
|
||||||
|
## 11. Never Allocate Large Arrays as Local Variables in Deep Kernel Call Chains
|
||||||
|
Local variables are stack-allocated in Pascal. Kernel processes have a fixed, limited stack (≈8 KB). In deep LVGL callback chains (kernel → LVGL render loop → timer callback → app code), there may only be a few KB of usable stack remaining by the time app code executes. Declaring local arrays larger than ~200–400 bytes (e.g. `array[0..255] of pchar` = 1024 bytes) inside any procedure that runs in this context will silently overflow the stack, corruptung adjacent memory and causing a page fault with a garbled call trace. **Rule**: any local variable array larger than ~128 bytes in a UI callback or procedure called from one must be moved to the heap with `kalloc`/`kfree`. The corruption pattern is a page fault with a call stack full of completely unrelated function names.
|
||||||
|
|
||||||
|
## 12. Pascal Silently Ignores Everything After `end.` — Dead Code Masquerades as Live Code
|
||||||
|
FPC compiles everything up to and including the first `end.` and silently discards the rest of the file. If a file is partially rewritten by prepending a new implementation but the old implementation is not deleted, the old code survives after `end.`. Forward declarations resolve to the **last** implementation before `end.` — so if the new code was added before the old `end.` but the old procedures were in the "dead" zone they have no effect. However the reverse is dangerous: if the old `end.` was replaced/removed and the new code placed before it, the old procedures in the dead zone still compile to nothing but pollute the source. **Rule**: after any large-scale replacement of a Pascal unit, explicitly check where `end.` falls with a text search and PowerShell-truncate the file at the first `end.`. Never assume a multi-step replacement tool correctly removed all old code — always verify with `Select-String -Pattern "^end\.$"`.
|
||||||
|
|
||||||
|
## 13. `for i := 0 to uint32_count - 1` Wraps to 4 Billion When Count is Zero
|
||||||
|
In Free Pascal, `uint32` arithmetic wraps: if `dir_count` is `uint32` and equals `0`, then `dir_count - 1 = 0xFFFFFFFF`. A `for i := 0 to dir_count - 1 do` loop with zero count does NOT skip — it runs 4 billion iterations, immediately accessing invalid memory and page faulting. FPC does not emit a warning for this. **Rule**: always guard `uint32`-bounded for loops: `if count > 0 then for i := 0 to count - 1 do`. Alternatively, use `sint32` for loop counters that might legitimately be zero.
|
||||||
|
|
||||||
|
## 14. FAT32 Deleted Entries ($E5) Must Be Filtered in getDirEntries
|
||||||
|
When a FAT32 directory entry is deleted, `fileName[0]` is overwritten with `$E5` but the rest of the entry (including the cluster pointer) remains intact on disk. `getDirEntries` must explicitly skip entries where `fileName[0] = char($E5)` — stopping only at `char(0)` (end-of-directory) is not enough. If `$E5` entries are returned to callers, they appear in directory listings with a garbage first character, and navigating into them follows a stale/freed cluster chain, which causes reads into arbitrary memory or FAT data, leading to a triple fault. Fix location: the `while i < maxEntries` loop in `fat32.getDirEntries`.
|
||||||
+585
File diff suppressed because it is too large.
Load diff
@@ -91,6 +91,7 @@ function getDeviceInfo(class_code : uint8; subclass_code : uint8; prog_if : uint
|
|||||||
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
|
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
|
||||||
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
|
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
|
||||||
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
|
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
|
||||||
|
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@@ -442,4 +443,34 @@ begin
|
|||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
//Enable device inturrupts and set bus master
|
||||||
|
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
|
||||||
|
var
|
||||||
|
addr : uint32;
|
||||||
|
cmd : uint32;
|
||||||
|
begin
|
||||||
|
push_trace('PCI.enableDevice');
|
||||||
|
|
||||||
|
addr := ($1 shl 31);
|
||||||
|
addr := addr or (bus shl 16);
|
||||||
|
addr := addr or ((slot) shl 11);
|
||||||
|
addr := addr or ((func) shl 8);
|
||||||
|
addr := addr or ($04 and $FC);
|
||||||
|
|
||||||
|
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||||
|
cmd := inl(PCI_CONFIG_DATA_PORT);
|
||||||
|
cmd := cmd or PCI_COMMAND_MEM_SPACE;
|
||||||
|
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
||||||
|
cmd := cmd or (3 shl 1);
|
||||||
|
|
||||||
|
//enable interrupts, remove disable interrupt bit maybe
|
||||||
|
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
||||||
|
// cmd := cmd and not (1 shl 9);
|
||||||
|
|
||||||
|
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||||
|
outl(PCI_CONFIG_DATA_PORT, cmd);
|
||||||
|
|
||||||
|
pop_trace;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
@@ -21,6 +21,29 @@ unit drivertypes;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
const
|
||||||
|
PCI_CONFIG_ADDRESS_PORT = $0CF8;
|
||||||
|
PCI_CONFIG_DATA_PORT = $0CFC;
|
||||||
|
|
||||||
|
PCI_COMMAND_IO_SPACE = $0001;
|
||||||
|
PCI_COMMAND_MEM_SPACE = $0002;
|
||||||
|
PCI_COMMAND_BUS_MASTER = $0004;
|
||||||
|
PCI_COMMAND_SPECIAL_CYC = $0008;
|
||||||
|
PCI_COMMAND_MEM_WRITE = $0010;
|
||||||
|
PCI_COMMAND_VGA_PALETTE = $0020;
|
||||||
|
PCI_COMMAND_PARITY = $0040;
|
||||||
|
PCI_COMMAND_WAIT = $0080;
|
||||||
|
PCI_COMMAND_SERR = $0100;
|
||||||
|
PCI_COMMAND_FAST_BACK = $0200;
|
||||||
|
PCI_COMMAND_INT_DISABLE = $0400;
|
||||||
|
PCI_COMMAND_SERR_ENABLE = $8000;
|
||||||
|
|
||||||
|
PCI_CAP_ID_MSI = $05;
|
||||||
|
|
||||||
|
// Bits in the MSI Control register (16-bit):
|
||||||
|
MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0
|
||||||
|
MSI_CONTROL_64BIT = 1 shl 7; // Bit 7
|
||||||
|
MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking)
|
||||||
type
|
type
|
||||||
|
|
||||||
PPCI_Device = ^TPCI_Device;
|
PPCI_Device = ^TPCI_Device;
|
||||||
@@ -44,6 +67,7 @@ type
|
|||||||
address1 : uint32;
|
address1 : uint32;
|
||||||
address2 : uint32;
|
address2 : uint32;
|
||||||
address3 : uint32;
|
address3 : uint32;
|
||||||
|
|
||||||
address4 : uint32;
|
address4 : uint32;
|
||||||
address5 : uint32;
|
address5 : uint32;
|
||||||
CIS_pointer : uint32;
|
CIS_pointer : uint32;
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,58 @@
|
|||||||
|
# AHCI Driver Notes
|
||||||
|
|
||||||
|
## Pre-scheduling / Process Kill Hazards
|
||||||
|
|
||||||
|
### 1. Dangling DMA Buffer (critical)
|
||||||
|
When a process is killed, its `kalloc`'d buffers get freed. But the AHCI hardware
|
||||||
|
is still DMA'ing into that physical memory. The DMA write lands on whatever now
|
||||||
|
occupies that memory, silently corrupting the kernel heap or another process.
|
||||||
|
|
||||||
|
**Fix:** Before freeing a process's memory, either:
|
||||||
|
- Wait for all its pending AHCI slots to drain (`cmd_issue` bits clear), or
|
||||||
|
- Issue a port reset to abort in-flight commands, *then* free memory.
|
||||||
|
|
||||||
|
### 2. Dangling Completion Callback / Userdata Pointer (critical)
|
||||||
|
In `storage_read`/`storage_write`, the completion callback writes to `@done` —
|
||||||
|
a **stack-local variable**. If the scheduler preempts or kills the process while
|
||||||
|
it's in the `hlt` loop, that stack frame is gone. The ISR fires and writes to a
|
||||||
|
dangling stack address, corrupting whatever now uses that stack page.
|
||||||
|
|
||||||
|
**Fix:** The `done` flag and completion context must be heap-allocated (or in a
|
||||||
|
kernel-owned structure that outlives the process). A per-request struct like:
|
||||||
|
```pascal
|
||||||
|
type TPendingIO = record
|
||||||
|
done : uint32;
|
||||||
|
ownerPID : uint32; { skip delivery if process is dead }
|
||||||
|
end;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Command Slot Leak
|
||||||
|
If a process is killed with pending I/O, `pending[slot].inUse` stays `true`
|
||||||
|
forever. Eventually all 32 slots fill up and the device becomes unusable.
|
||||||
|
|
||||||
|
**Fix:** When killing a process, scan all AHCI devices for `pending[]` entries
|
||||||
|
belonging to that process, and either:
|
||||||
|
- Let the hardware finish but null out the completion callback (ISR just frees slot), or
|
||||||
|
- Abort the command (port reset) and clear the slot.
|
||||||
|
|
||||||
|
### 4. Interrupt-Disabled Preemption
|
||||||
|
The `asm sti` before the `hlt` loop is fine, but if the timer fires during setup
|
||||||
|
(between `readCallbackAsync(...)` and `asm sti`), the process could be switched
|
||||||
|
out with interrupts in an unexpected state. `hlt` is also not preemption-safe.
|
||||||
|
|
||||||
|
**Fix:** Move to a proper wait-queue/sleep mechanism instead of `hlt`.
|
||||||
|
|
||||||
|
## Recommended Path Forward
|
||||||
|
Implement a small **I/O request queue** owned by the kernel (not the process stack):
|
||||||
|
1. Allocate a request struct
|
||||||
|
2. Put it on a per-device queue
|
||||||
|
3. ISR completes it
|
||||||
|
4. Process kill walks the queue and cancels entries for that PID
|
||||||
|
|
||||||
|
## Other Bugs Fixed (2026-03-03)
|
||||||
|
- **vtop mask bug:** `$FFFFFF` (24-bit) → `$3FFFFF` (22-bit) for 4MB page offset
|
||||||
|
- **find_cmd_slot:** Now checks `pending[].inUse` in addition to `cmd_issue` bit
|
||||||
|
- **Missing lba5:** Both `send_read_dma_async` and `send_write_dma_async` now write all 48 LBA bits
|
||||||
|
- **IOAPIC routing:** PCI interrupts routed through IOAPIC so AHCI interrupts actually reach the CPU
|
||||||
|
- **LAPIC EOI:** `ISR_N` now sends LAPIC EOI for IOAPIC-delivered interrupts
|
||||||
|
- **PxIS pre-clear removed:** No longer blanket-clears port interrupt status before issuing commands (was eating other slots' completions)
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
// Copyright 2021 Aaron Hance
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
{
|
|
||||||
Drivers->Storage->ATA_ISR - Primary ATA IRQ.
|
|
||||||
|
|
||||||
@author(Aaron Hance <[email protected]>)
|
|
||||||
}
|
|
||||||
unit ATA_ISR;
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses
|
|
||||||
util,
|
|
||||||
syslog,
|
|
||||||
isr_types,
|
|
||||||
isrmanager,
|
|
||||||
IDT;
|
|
||||||
|
|
||||||
procedure register();
|
|
||||||
procedure hook(hook_method : uint32);
|
|
||||||
procedure unhook(hook_method : uint32);
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
var
|
|
||||||
Hooks : Array[1..MAX_HOOKS] of pp_hook_method;
|
|
||||||
|
|
||||||
procedure Main(); interrupt;
|
|
||||||
var
|
|
||||||
i : integer;
|
|
||||||
|
|
||||||
begin
|
|
||||||
CLI;
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) <> 0 then Hooks[i](void($00000000));
|
|
||||||
end;
|
|
||||||
syslog.writestringln('Disk Operation Complete');
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure register();
|
|
||||||
begin
|
|
||||||
memset(uint32(@Hooks[0]), 0, sizeof(pp_hook_method)*MAX_HOOKS);
|
|
||||||
//isrmanager.registerISR(76, @Main);
|
|
||||||
//IDT.set_gate(76, uint32(@Main), $08, ISR_RING_0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure hook(hook_method : uint32);
|
|
||||||
var
|
|
||||||
i : uint32;
|
|
||||||
|
|
||||||
begin
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) = hook_method then exit;
|
|
||||||
end;
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
if uint32(Hooks[i]) = 0 then begin
|
|
||||||
Hooks[i]:= pp_hook_method(hook_method);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure unhook(hook_method : uint32);
|
|
||||||
var
|
|
||||||
i : uint32;
|
|
||||||
begin
|
|
||||||
for i:=0 to MAX_HOOKS-1 do begin
|
|
||||||
If uint32(Hooks[i]) = hook_method then Hooks[i]:= nil;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
|
||||||
@@ -22,14 +22,17 @@ unit asfs;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
storagemanagement,
|
syslog,
|
||||||
util,
|
|
||||||
lmemorymanager,
|
|
||||||
strings,
|
|
||||||
lists,
|
lists,
|
||||||
tracer,
|
lmemorymanager,
|
||||||
|
rtc,
|
||||||
serial,
|
serial,
|
||||||
rtc;
|
storagemanagement,
|
||||||
|
storagemanager,
|
||||||
|
strings,
|
||||||
|
stdio,
|
||||||
|
tracer,
|
||||||
|
util;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@@ -98,7 +101,7 @@ begin
|
|||||||
filesystemRecord^.endOfData := filesystemRecord.sectorsPerTable;
|
filesystemRecord^.endOfData := filesystemRecord.sectorsPerTable;
|
||||||
//filesystemRecord.volumeLabel := config^
|
//filesystemRecord.volumeLabel := config^
|
||||||
|
|
||||||
disk^.writecallback(disk, start, 1, buffer);
|
storagemanager.storage_write(disk, start, 1, buffer);
|
||||||
memset(uint32(buffer), 0, disk^.sectorSize);
|
memset(uint32(buffer), 0, disk^.sectorSize);
|
||||||
|
|
||||||
fileEntry := PFileEntry(buffer)[0];
|
fileEntry := PFileEntry(buffer)[0];
|
||||||
@@ -111,7 +114,7 @@ begin
|
|||||||
fileEntry^.attributes := 0;
|
fileEntry^.attributes := 0;
|
||||||
fileEntry^.location := 1;
|
fileEntry^.location := 1;
|
||||||
|
|
||||||
disk^.writecallback(disk, start + 1, 1, buffer);
|
storagemanager.storage_write(disk, start + 1, 1, buffer);
|
||||||
|
|
||||||
|
|
||||||
end;
|
end;
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,120 @@
|
|||||||
|
{
|
||||||
|
Driver->Storage->FilesystemManager - Filesystem driver registry and routing.
|
||||||
|
|
||||||
|
Filesystem drivers (FAT32, FlatFS, etc.) register themselves here.
|
||||||
|
When VolumeManager discovers a volume, FilesystemManager probes it
|
||||||
|
against all registered filesystem drivers to detect the filesystem type.
|
||||||
|
|
||||||
|
@author(Aaron Hance <[email protected]>)
|
||||||
|
}
|
||||||
|
unit filesystemmanager;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
lists,
|
||||||
|
lmemorymanager,
|
||||||
|
storagetypes,
|
||||||
|
strings,
|
||||||
|
tracer,
|
||||||
|
util;
|
||||||
|
|
||||||
|
var
|
||||||
|
filesystems : PLinkedListBase;
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
procedure register_filesystem(filesystem : PFilesystem);
|
||||||
|
function get_filesystem_count() : uint32;
|
||||||
|
function get_filesystem(index : uint32) : PFilesystem;
|
||||||
|
function find_filesystem_by_name(name : pchar) : PFilesystem;
|
||||||
|
function find_filesystem_by_id(system_id : uint8) : PFilesystem;
|
||||||
|
procedure probe_volume(volume : PStorage_Volume);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
begin
|
||||||
|
push_trace('FilesystemManager.init');
|
||||||
|
filesystems := LL_New(sizeof(TFilesystem));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure register_filesystem(filesystem : PFilesystem);
|
||||||
|
var
|
||||||
|
elm : void;
|
||||||
|
begin
|
||||||
|
push_trace('FilesystemManager.register_filesystem');
|
||||||
|
|
||||||
|
elm := LL_Add(filesystems);
|
||||||
|
memcpy(uint32(filesystem), uint32(elm), sizeof(TFilesystem));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_filesystem_count() : uint32;
|
||||||
|
begin
|
||||||
|
get_filesystem_count := LL_Size(filesystems);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function get_filesystem(index : uint32) : PFilesystem;
|
||||||
|
begin
|
||||||
|
if index < LL_Size(filesystems) then
|
||||||
|
get_filesystem := PFilesystem(LL_Get(filesystems, index))
|
||||||
|
else
|
||||||
|
get_filesystem := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function find_filesystem_by_name(name : pchar) : PFilesystem;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
fs : PFilesystem;
|
||||||
|
begin
|
||||||
|
push_trace('FilesystemManager.find_filesystem_by_name');
|
||||||
|
find_filesystem_by_name := nil;
|
||||||
|
|
||||||
|
for i := 0 to LL_Size(filesystems) - 1 do begin
|
||||||
|
fs := PFilesystem(LL_Get(filesystems, i));
|
||||||
|
if stringEquals(fs^.sName, name) then begin
|
||||||
|
find_filesystem_by_name := fs;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function find_filesystem_by_id(system_id : uint8) : PFilesystem;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
fs : PFilesystem;
|
||||||
|
begin
|
||||||
|
push_trace('FilesystemManager.find_filesystem_by_id');
|
||||||
|
find_filesystem_by_id := nil;
|
||||||
|
|
||||||
|
for i := 0 to LL_Size(filesystems) - 1 do begin
|
||||||
|
fs := PFilesystem(LL_Get(filesystems, i));
|
||||||
|
if fs^.system_id = system_id then begin
|
||||||
|
find_filesystem_by_id := fs;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure probe_volume(volume : PStorage_Volume);
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
fs : PFilesystem;
|
||||||
|
begin
|
||||||
|
push_trace('FilesystemManager.probe_volume.enter');
|
||||||
|
|
||||||
|
{ Try each registered filesystem's identify callback against this volume }
|
||||||
|
for i := 0 to LL_Size(filesystems) - 1 do begin
|
||||||
|
fs := PFilesystem(LL_Get(filesystems, i));
|
||||||
|
if fs^.identifyCallback <> nil then begin
|
||||||
|
push_trace('FilesystemManager.probe_volume.tryFS');
|
||||||
|
if fs^.identifyCallback(volume) then begin
|
||||||
|
volume^.filesystem := fs;
|
||||||
|
push_trace('FilesystemManager.probe_volume.found');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
push_trace('FilesystemManager.probe_volume.exit');
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Loaded 20 of 57 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user