Compare commits

..
Author SHA1 Message Date
Aaron acb4a15e41 Fix file headers
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-07 19:40:18 +00:00
Aaron d3581eea2e update header
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2026-03-07 19:37:26 +00:00
Aaron 1fc00e3e7c chore: ignore lessons_learnt.md
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2026-03-07 19:33:57 +00:00
Aaron 2f837ace6e chore: remove lessons_learnt.md from tracking
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-07 19:33:40 +00:00
Aaron f8182b24b3 removed another bad file
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-07 19:24:59 +00:00
Aaron f0531ff861 Removed bad files
continuous-integration/drone/push Build is passing
2026-03-07 19:22:40 +00:00
Aaron 3d9c4cb49a feat: add processmanager.create to diskutil and notepad
continuous-integration/drone/push Build is passing
- diskutil: add proc_pid global, diskutil_entry idle proc, create process
  on launch with setWindowOwner, kill on close, zero proc_pid in init
- notepad: add pid field to TNotepadState, notepad_entry idle proc, create
  process on launch with setWindowOwner, kill pid in doCloseWindow
- both apps now appear in PS and are manageable via KILL/TERMINATE
2026-03-07 19:18:55 +00:00
Aaron 3a733b1559 feat: auto-mount boot drive to /boot; fix FAT32 deleted entry triple fault
continuous-integration/drone/push Build is passing
- Decode multiboot boot_device byte in storagemanager to identify boot device
- Add isBootDevice to TStorage_Device; propagate isBootDrive to volumes
- Create /boot VFS directory at init; mount boot volume there in auto_mount_volumes
- Fix getDirEntries skipping \-marked (deleted) FAT32 entries to prevent
  triple fault when navigating into a deleted directory via file picker
2026-03-07 18:58:32 +00:00
Aaron deb513c925 storage: fix VFS corruption, ISO9660 hang, OOM; add notepad, file picker, fdtable, GPT, async I/O
VFS fixes:
- GetDirectoryListing(otVDIRECTORY) now returns a heap-allocated snapshot
  instead of a raw live-tree pointer; FreeDirectoryListing no longer
  corrupts the VFS tree (fixes page fault on repeated navigation)
- volumeGetDirectories: guard LL_Size > 0 before loop to prevent uint32
  underflow (0-1 = 0xFFFFFFFF) causing 4B kalloc iterations -> OOM
- Free entry^.fileName and dirList in all branches (memory leak fix)

iso9660:
- equalsIgnoreCase: guard la=0 before loop (same uint32 underflow bug)
- readDirectoryEntries/resolvePath: add 65536/256-iter safety caps

storagemanager:
- Strip debug syslog calls that were allocating 6+ strings per I/O
  (hundreds of I/Os x 6 allocs exhausted the heap)

Process manager:
- Per-process FDTable and Cwd initialised on create, freed on reap
- proc_await: use pointer-indirection spin per lesson #6 (FPC caches
  non-volatile reads; raw while flag=0 returns immediately)
- graphicsrefresh: move LVGL handler from timer ISR (IF=0) to a
  dedicated process so LVGL callbacks can call blocking I/O

New units:
- fdtable.pas: per-process file descriptor table (fd_alloc/get/close)
- iorequest.pas: heap allocation helpers for TIORequest
- gpt.pas: GPT header/entry read + CRC validation
- filepicker.pas: reusable OS-level open/save file picker dialog
- notepad.pas: GUI text editor with selection, indent, save-as

Shell commands (diskcmd, partcmd, volcmd, diskutil):
- Route output to stdout_buf instead of syslog (lesson #4)
- diskutil: async add/remove/format partition; cache-based device display

Add Apache 2.0 license headers to storagemanager.pas, iso9660.pas,
fat32.pas, storagetest.pas

Lessons learnt: #9 VFS listing must return snapshot (not live pointer)
2026-03-07 18:58:32 +00:00
Aaron 789fb7971a getting ready 2026-03-07 18:57:38 +00:00
Aaron 4e3acd6af7 Storage system: AHCI, IDE rework, VFS, volume manager, flatfs, async IO, IOAPIC 2026-03-07 18:45:25 +00:00
admin 262d064b6d Merge pull request 'Fix: PS/2 mouse ISR blocking; convert USB polling & GFX refresh to processes; remove dead scheduler' (#48) from feature/ps2-mouse-fix into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #48
2026-03-07 00:40:20 +00:00
t3hn3rd 738e5828f6 Fix PS/2 mouse ISR blocking; convert USB polling & GFX refresh to processes; remove dead scheduler
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
PS/2 Mouse:
- Fix ISR spin-blocking by reading port $60 directly with inb() instead
  of calling mouse_read(), which uses mouse_wait_long (100k iterations)
  and would stall the interrupt handler waiting for the next packet byte.

Timer (PIT):
- Increase PIT frequency from ~1024 Hz to ~8 kHz (divisor 1193 -> 149)
  for more granular timer ticks.

Graphics Refresh:
- Replace timer-hook-driven rendering (driver/timers/graphicsrefresh)
  with a dedicated 'gfxd' process that runs a continuous render loop,
  keeping the vCPU active to avoid NEM/Hyper-V pause-loop descheduling.
- Move uidebug from driver/video/ to prog/.
- Update FPS calculation to account for 8 kHz tick rate.

USB Hotplug:
- Replace timer-hook-driven polling (driver/timers/usbhotplug) with a
  dedicated 'usbd' daemon process that sleeps 1s between poll cycles.
- Add bounds check in usbcore.usb_check_hotplug for empty HC list.

Cleanup:
- Remove old scheduler unit (superseded by processmanager/contextswitcher).
- Remove tss unit and tss.init() call from kernel.
- Remove unused syslog import from contextswitcher.
- Reduce BASE_QUANTUM from 8 to 5.
2026-03-07 00:29:38 +00:00
t3hn3rd 9fa1c859ac Merge pull request 'feature: preemptive process management & TCP/IP barebones' (#41) from feature/process-management into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #41
Reviewed-by: Aaron Hance <[email protected]>
2026-03-04 20:04:24 +00:00
63 changed files with 17379 additions and 3368 deletions
+1
View File
@@ -14,5 +14,6 @@ localenv.json
/lvgl/ /lvgl/
dockerout.txt dockerout.txt
AGENTS.md AGENTS.md
lessons_learnt.md
*.log *.log
/doc/*.md /doc/*.md
+7 -1
View File
@@ -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
+32
View File
@@ -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
---
Generated
+1
View File
@@ -0,0 +1 @@
Hello from the Asuro ISO!
+1 -4
View File
@@ -29,14 +29,11 @@ unit contextswitcher;
interface interface
uses uses
idt, isrmanager, processmanager, proctypes, util, syslog, tracer; idt, isrmanager, processmanager, proctypes, util, tracer;
{ Initialise: overwrite IDT gate 32 with our custom ISR. } { Initialise: overwrite IDT gate 32 with our custom ISR. }
procedure init; procedure init;
{ No idle ESP variable needed — idle is now a formal process (PID 0)
with its SavedESP managed like any other process. }
implementation implementation
{ ----------------------------------------------------------------------- { -----------------------------------------------------------------------
+31
View File
@@ -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.
+4 -1
View File
@@ -957,11 +957,14 @@ end;
procedure usb_check_hotplug; procedure usb_check_hotplug;
var var
i : uint32; i : uint32;
count: uint32;
hc : PUSBHCDriver; hc : PUSBHCDriver;
port : uint8; port : uint8;
begin begin
if HCList = nil then exit; if HCList = nil then exit;
for i := 0 to LL_Size(HCList) - 1 do begin count := LL_Size(HCList);
if count = 0 then exit;
for i := 0 to count - 1 do begin
hc := PUSBHCDriver(LL_Get(HCList, i)); hc := PUSBHCDriver(LL_Get(HCList, i));
if (hc <> nil) and hc^.PortChangePending then begin if (hc <> nil) and hc^.PortChangePending then begin
hc^.PortChangePending := false; hc^.PortChangePending := false;
+5 -1
View File
@@ -119,8 +119,12 @@ var
x32, y32 : sint32; x32, y32 : sint32;
r : pchar; r : pchar;
begin begin
{ mouse_wait(0) checks OBF with a short timeout (100 iterations).
When it returns true, data is ready — read it directly with inb($60).
Do NOT call mouse_read here: it uses mouse_wait_long (100k iterations)
and would spin-block the ISR if the next packet byte hasn't arrived yet. }
while mouse_wait(0) do begin while mouse_wait(0) do begin
b := mouse_read; b := inb($60);
if Cycle = 0 then begin if Cycle = 0 then begin
if (b AND $08) = $08 then begin if (b AND $08) = $08 then begin
Mouse_Byte[Cycle] := b; Mouse_Byte[Cycle] := b;
+24
View File
@@ -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
-85
View File
@@ -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
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More