Compare commits

..
Author SHA1 Message Date
t3hn3rd 035207442a Fix USB device speed reporting across host controllers
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
- Add a port-speed callback for UHCI, OHCI, EHCI, and xHCI
- Read root-device speed after reset during enumeration and hotplug
- Preserve hub-reported speeds for downstream devices
- Report SuperSpeed devices correctly instead of defaulting to Full Speed
2026-11-07 23:53:09 +00:00
Aaron 9d4323ca53 Merge pull request 'Automate boot unit inclusion with architecture-aware Moderne analysis' (#74) from feature/dangling-unit-resolution into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #74
2026-11-07 22:32:22 +00:00
t3hn3rd dd3bb1e016 Automate boot unit inclusion with architecture-aware Moderne analysis
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
- Replace boot.mgr's static unit list with generated dangling_units.inc
- Generate Pascal LSTs and run the dangling-unit recipe before compilation
- Exclude Wasuro, inactive architectures, and NOT_DANGLING units
- Add ASURO_ARCH selection with an x86 default
- Mark unfinished legacy units as NOT_DANGLING
- Inherit pinned Moderne tooling in the builder image
- Ensure Drone pulls the latest builder image
- Document the updated build pipeline in MkDocs

Validation:
- Full x86 ISO build and VirtualBox boot succeeded
- 1,133 kernel tests passed with no failures
- x86_64 build failed clearly due to unavailable sources
2026-11-07 21:49:06 +00:00
admin 7ed8012c7e Merge pull request 'feature/boot.mgr' (#71) from feature/boot.mgr into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #71
Reviewed-by: Aaron Hance <[email protected]>
2026-03-14 20:38:39 +00:00
t3hn3rd e7f7325c54 Fix unicode characters
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-14 20:02:25 +00:00
27 changed files with 184 additions and 116 deletions

No files matched your search

+1
View File
@@ -17,6 +17,7 @@ steps:
- name: compile - name: compile
image: t3hn3rd/asuro-build:latest image: t3hn3rd/asuro-build:latest
pull: always
depends_on: depends_on:
- build-image - build-image
commands: commands:
+4
View File
@@ -20,3 +20,7 @@ wasuro
src/core/core.version.pas src/core/core.version.pas
site/* site/*
!site/.gitkeep !site/.gitkeep
/src/boot/dangling_units.inc
/lib/dangling/
.moderne
CLAUDE.md
+3 -3
View File
@@ -1,4 +1,5 @@
FROM ubuntu:latest ARG RECIPES_IMAGE=t3hn3rd/moderne-asuro-recipes:0.1.1@sha256:eaf54188053511dad9c620a8fb98b0f50c41770cd49a0b3d71a0538386522011
FROM ${RECIPES_IMAGE}
VOLUME ["/code"] VOLUME ["/code"]
@@ -7,7 +8,7 @@ RUN dpkg --add-architecture i386
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
curl dos2unix wget git make nasm binutils xorriso grub-pc-bin gcc gcc-multilib \ curl dos2unix wget git make nasm binutils xorriso grub-pc-bin gcc gcc-multilib \
python3 python3-pip python3-pil && \ python3 python3-pip python3-pil && \
apt-get clean my room apt-get clean && rm -rf /var/lib/apt/lists/*
RUN pip3 install --no-cache-dir --break-system-packages "mkdocs>=1.6,<2" mkdocs-material RUN pip3 install --no-cache-dir --break-system-packages "mkdocs>=1.6,<2" mkdocs-material
@@ -20,6 +21,5 @@ RUN curl -sL https://sourceforge.net/projects/freepascal/files/Linux/$FPC_VERSIO
ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver ADD https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver /usr/bin/semver
RUN chmod +x /usr/bin/semver RUN chmod +x /usr/bin/semver
WORKDIR /code WORKDIR /code
RUN find . -type f -print0 | xargs -0 dos2unix
ENTRYPOINT ["/bin/bash", "-c"] ENTRYPOINT ["/bin/bash", "-c"]
CMD ["find toolchain -name '*.sh' -exec dos2unix {} + 2>/dev/null; find toolchain -name '*.sh' -exec chmod +x {} +; bash toolchain/compile.sh"] CMD ["find toolchain -name '*.sh' -exec dos2unix {} + 2>/dev/null; find toolchain -name '*.sh' -exec chmod +x {} +; bash toolchain/compile.sh"]
+8
View File
@@ -0,0 +1,8 @@
**/.git
**/.gradle
**/build
**/.moderne
wasuro
site
lib
release
+45
View File
@@ -0,0 +1,45 @@
# Automatic boot-unit inclusion
Run the usual `docker compose build builder` and `docker compose run builder`
from Asuro. Only this repository is required. Compose and Drone use the same
Dockerfile and repository build context, producing `t3hn3rd/asuro-build:latest`.
The Dockerfile inherits the published `t3hn3rd/moderne-asuro-recipes:0.1.1` image,
pinned by digest. It already includes Java, Moderne CLI, the Pascal LST generator,
and the registered recipe. The Asuro layer installs FPC and the kernel build tools.
To upgrade tooling, publish the upstream images first and update `RECIPES_IMAGE`
in the Dockerfile to the new tag and digest. Local tooling image testing can use
`docker compose build --build-arg RECIPES_IMAGE=<local-tag> builder`.
`ASURO_ARCH` selects the source architecture, defaulting to `x86`. For example:
```sh
export ASURO_ARCH=x86
docker compose run --rm builder
```
Compose forwards this variable to the builder; Drone inherits it from its compile
environment. Only `src/arch/$ASURO_ARCH` is added to FPC's unit search paths.
Other architecture folders are excluded from LST generation and from the recipe's
dependency graph and results. Common units outside `src/arch` remain eligible.
The selected architecture folder must exist. This source selection does not
change the existing i386 compiler target, assembly stub, or linker settings;
an x86_64 port still needs those platform-specific changes.
`compile_dangling.sh` runs after Wasuro synchronization and before FPC. It copies
only `src/` and `compat/` into an isolated temporary analysis repository, generates
LSTs with rewrite-pascal, runs the standalone Moderne recipe, exports its
datatable, and writes `src/boot/dangling_units.inc`. Wasuro is not parsed.
Datatable conversion is provided by the standalone project's Java exporter.
Parse errors, recipe failures, and malformed datatables stop the build. The
generated include is ignored by Git and removed before each generation attempt.
Use `{$DEFINE NOT_DANGLING}` near a unit declaration to exclude an experimental
or legacy unit from automatic inclusion. It can still be referenced normally.
This is a file-level marker; conditional definitions are not evaluated. The
analysis follows both interface and implementation uses, without expanding
includes or evaluating conditional compilation.
Moderne runs through its CLI normally; any license or tenant configuration
required by your CLI installation must be provided to the container separately.
No host credentials are copied into the image.
+3
View File
@@ -1,5 +1,8 @@
services: services:
builder: builder:
image: t3hn3rd/asuro-build:latest
build: . build: .
environment:
ASURO_ARCH: ${ASURO_ARCH:-x86}
volumes: volumes:
- .:/code - .:/code
+1
View File
@@ -283,6 +283,7 @@ nav:
- Version Generation: toolchain/compile_vergen.md - Version Generation: toolchain/compile_vergen.md
- LVGL Compilation: toolchain/compile_lvgl.md - LVGL Compilation: toolchain/compile_lvgl.md
- Wasuro Pull: toolchain/compile_wasuro.md - Wasuro Pull: toolchain/compile_wasuro.md
- Automatic Boot Units: toolchain/dangling_units.md
- Source List: toolchain/compile_sourcelist.md - Source List: toolchain/compile_sourcelist.md
- Source Compilation: toolchain/compile_sources.md - Source Compilation: toolchain/compile_sources.md
- Checksum: toolchain/compile_checksum.md - Checksum: toolchain/compile_checksum.md
+2 -1
View File
@@ -28,7 +28,8 @@ We welcome everyone to give building/breaking/fixing/shooting Asuro a go, feel f
4. Install Git for Windows. 4. Install Git for Windows.
5. Install VSCode & the listed plugins. 5. Install VSCode & the listed plugins.
6. Install VirtualBox (v7+). 6. Install VirtualBox (v7+).
7. Clone this repository. 7. Clone this repository. The builder inherits the published Moderne/Pascal
tooling image; see [boot-unit generation](doc/toolchain/dangling_units.md).
8. Run the following command in the root of the repo to build the docker image: 8. Run the following command in the root of the repo to build the docker image:
```powershell ```powershell
docker compose build builder docker compose build builder
+2
View File
@@ -19,6 +19,8 @@
} }
unit arch.x86.isr.tmr1; unit arch.x86.isr.tmr1;
{$DEFINE NOT_DANGLING} { Unused legacy timer ISR; not part of the kernel boot sequence. }
interface interface
uses uses
@@ -19,6 +19,8 @@
} }
unit arch.x86.proc.loader; unit arch.x86.proc.loader;
{$DEFINE NOT_DANGLING} { Unimplemented process-loader stub. }
interface interface
implementation; implementation;
+1 -1
View File
@@ -276,7 +276,7 @@ function fpc_mod_int64(d, n: int64): int64; compilerproc;
function fpc_mod_qword(d, n: qword): qword; compilerproc; function fpc_mod_qword(d, n: qword): qword; compilerproc;
function fpc_div_qword(d, n: qword): qword; compilerproc; function fpc_div_qword(d, n: qword): qword; compilerproc;
{ Memory allocation compilerprocs – delegate to core.version heap (memory.heap) } { Memory allocation compilerprocs - delegate to core.version heap (memory.heap) }
function fpc_getmem(size: PtrUInt): Pointer; compilerproc; function fpc_getmem(size: PtrUInt): Pointer; compilerproc;
procedure fpc_freemem(p: Pointer); compilerproc; procedure fpc_freemem(p: Pointer); compilerproc;
+3 -101
View File
@@ -71,107 +71,9 @@ procedure run;
implementation implementation
uses uses
io.syslog, boot.splash, io.syslog, boot.splash
{$INCLUDE dangling_units.inc}
// Silo units that must be included here to compile ;
driver.storage.boot,
test,
core,
app.wasm,
driver.storage.ctl.ahci,
core.enc.base64,
core.panic,
driver.video.bga,
arch.x86.bda,
arch.x86.panic,
core.ds.cfifo,
core.ds.cfifols,
core.ds.circ,
core.gfx.color,
arch.x86.proc.sched,
arch.x86.cpu,
driver.video.desktop,
driver.video.doublebuffer,
driver.mgr,
driver.net.dev.e1000,
driver.bus.usb.ehci,
driver.storage.fs.fat32,
arch.x86.fault,
core.ds.fifo,
driver.storage.fs.mgr,
driver.storage.fs.flatfs,
core.gfx.fonts,
arch.x86.gdt,
driver.video.gpu,
svc.gfxd,
core.ds.hashmap,
arch.x86.idt,
arch.x86.isr.ioapic,
arch.x86.irq,
driver.storage.fs.iso9660,
arch.x86.isr,
arch.x86.isr.mgr,
driver.hid.keyboard,
core.ds.lifo,
core.ds.lists,
memory.heap,
driver.video.lvgl,
core.ds.maxh,
core.enc.md5,
core.ds.minh,
driver.hid.mouse,
arch.x86.multiboot,
driver.net,
driver.bus.usb.ohci,
app.partcmd,
driver.bus.pci,
arch.x86.memory.physical,
core.ds.prio,
proc.mgr,
app.mgr,
driver.hid.ps2.keyboard,
driver.hid.ps2.mouse,
core.rand,
driver.timer.rtc,
driver.io.serial,
io.stdio,
driver.storage.mgr,
driver.storage.test,
core.strings,
driver.exp.testdriver,
proc.testprocs,
arch.x86.isr.tmr0,
debug.tracer,
driver.bus.usb.uhci,
app.uidebug,
driver.bus.usb,
driver.hid.usb.keyboard,
driver.hid.usb.mouse,
driver.storage.ctl.usb,
driver.bus.usb.core,
svc.usbd,
driver.bus.usb.hub,
driver.bus.usb.types,
core.util,
arch.x86.util,
arch.x86.v86,
driver.video.vesa,
driver.storage.vfs,
driver.video,
arch.x86.memory.virtual,
core.enc.fnv1a,
core.enc.djb2,
core.ds.bloom,
app.volcmd,
driver.storage.vol.mgr,
app.vterminal,
wasm,
wasm.vm.io,
wasm.test,
wasm.test.framework,
driver.video.windows,
driver.bus.usb.xhci,
core.fmt.json;
type type
{ Resolved execution order — indices into Entries[] } { Resolved execution order — indices into Entries[] }
+5 -2
View File
@@ -247,8 +247,7 @@ begin
if (status AND $01) <> 0 then begin if (status AND $01) <> 0 then begin
io.syslog.log('driver.bus.usb Core', 'Device detected on port '); io.syslog.log('driver.bus.usb Core', 'Device detected on port ');
io.syslog.writeintln(port); io.syslog.writeintln(port);
{ Determine speed from status bits - HC specific, { Root-port speed is resolved by enumerate_device after reset. }
default to full-speed for now }
speed := USB_SPEED_FULL; speed := USB_SPEED_FULL;
enumerate_device(hc, port, speed, nil, port); enumerate_device(hc, port, speed, nil, port);
end; end;
@@ -656,6 +655,10 @@ begin
end; end;
end; end;
{ Speed is valid after reset. Hub children retain the hub-reported speed. }
if (parentHub = nil) and (hc^.fnPortSpeed <> nil) then
speed := hc^.fnPortSpeed(hc, port);
{ Step 2: Create device at address 0 } { Step 2: Create device at address 0 }
dev := PUSBDevice(kalloc(sizeof(TUSBDevice))); dev := PUSBDevice(kalloc(sizeof(TUSBDevice)));
dev^.Address := 0; dev^.Address := 0;
@@ -783,6 +783,13 @@ end;
{ ========================= Port Reset ========================= } { ========================= Port Reset ========================= }
function ehci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8;
begin
{ Successful EHCI root resets retain only high-speed devices;
full/low-speed devices are handed to a companion controller. }
ehci_port_speed := USB_SPEED_HIGH;
end;
function ehci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; function ehci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean;
var var
priv : PEHCI_PrivData; priv : PEHCI_PrivData;
@@ -1558,6 +1565,7 @@ begin
hc.fnPoll := TUSBHCPoll(@ehci_poll); hc.fnPoll := TUSBHCPoll(@ehci_poll);
hc.fnPortReset := TUSBHCPortReset(@ehci_port_reset); hc.fnPortReset := TUSBHCPortReset(@ehci_port_reset);
hc.fnPortStatus := TUSBHCPortStatus(@ehci_port_status); hc.fnPortStatus := TUSBHCPortStatus(@ehci_port_status);
hc.fnPortSpeed := TUSBHCPortSpeed(@ehci_port_speed);
{ Reset the controller } { Reset the controller }
if not ehci_reset(@hc) then begin if not ehci_reset(@hc) then begin
@@ -602,6 +602,14 @@ end;
{ ========================= Port Reset ========================= } { ========================= Port Reset ========================= }
function ohci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8;
begin
if (ohci_port_status(hc, port) AND OHCI_PORT_LSDA) <> 0 then
ohci_port_speed := USB_SPEED_LOW
else
ohci_port_speed := USB_SPEED_FULL;
end;
function ohci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; function ohci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean;
var var
priv : POHCI_PrivData; priv : POHCI_PrivData;
@@ -1257,6 +1265,7 @@ begin
hc.fnPoll := TUSBHCPoll(@ohci_poll); hc.fnPoll := TUSBHCPoll(@ohci_poll);
hc.fnPortReset := TUSBHCPortReset(@ohci_port_reset); hc.fnPortReset := TUSBHCPortReset(@ohci_port_reset);
hc.fnPortStatus := TUSBHCPortStatus(@ohci_port_status); hc.fnPortStatus := TUSBHCPortStatus(@ohci_port_status);
hc.fnPortSpeed := TUSBHCPortSpeed(@ohci_port_speed);
{ Reset the controller } { Reset the controller }
if not ohci_reset(@hc) then begin if not ohci_reset(@hc) then begin
@@ -261,6 +261,8 @@ type
TUSBHCPoll = procedure(hc : PUSBHCDriver); TUSBHCPoll = procedure(hc : PUSBHCDriver);
TUSBHCPortReset = function(hc : PUSBHCDriver; port : uint8) : boolean; TUSBHCPortReset = function(hc : PUSBHCDriver; port : uint8) : boolean;
TUSBHCPortStatus = function(hc : PUSBHCDriver; port : uint8) : uint32; TUSBHCPortStatus = function(hc : PUSBHCDriver; port : uint8) : uint32;
{ Return USB_SPEED_* after root-port reset has completed. }
TUSBHCPortSpeed = function(hc : PUSBHCDriver; port : uint8) : uint8;
{ ---- HC Driver Record ---- } { ---- HC Driver Record ---- }
@@ -283,6 +285,7 @@ type
fnPoll : TUSBHCPoll; fnPoll : TUSBHCPoll;
fnPortReset : TUSBHCPortReset; fnPortReset : TUSBHCPortReset;
fnPortStatus : TUSBHCPortStatus; fnPortStatus : TUSBHCPortStatus;
fnPortSpeed : TUSBHCPortSpeed;
end; end;
{ ========================= Utility Functions ========================= } { ========================= Utility Functions ========================= }
@@ -429,6 +432,7 @@ begin
hc^.fnPoll := nil; hc^.fnPoll := nil;
hc^.fnPortReset := nil; hc^.fnPortReset := nil;
hc^.fnPortStatus := nil; hc^.fnPortStatus := nil;
hc^.fnPortSpeed := nil;
end; end;
pop_trace; pop_trace;
end; end;
@@ -453,6 +453,14 @@ end;
{ ========================= Port Reset ========================= } { ========================= Port Reset ========================= }
function uhci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8;
begin
if (uhci_port_status(hc, port) AND UHCI_PORT_LSDA) <> 0 then
uhci_port_speed := USB_SPEED_LOW
else
uhci_port_speed := USB_SPEED_FULL;
end;
function uhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; function uhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean;
var var
priv : PUHCI_PrivData; priv : PUHCI_PrivData;
@@ -976,6 +984,7 @@ begin
hc.fnPoll := TUSBHCPoll(@uhci_poll); hc.fnPoll := TUSBHCPoll(@uhci_poll);
hc.fnPortReset := TUSBHCPortReset(@uhci_port_reset); hc.fnPortReset := TUSBHCPortReset(@uhci_port_reset);
hc.fnPortStatus := TUSBHCPortStatus(@uhci_port_status); hc.fnPortStatus := TUSBHCPortStatus(@uhci_port_status);
hc.fnPortSpeed := TUSBHCPortSpeed(@uhci_port_speed);
{ Reset the controller } { Reset the controller }
if not uhci_reset(@hc) then begin if not uhci_reset(@hc) then begin
@@ -1142,6 +1142,12 @@ begin
pop_trace; pop_trace;
end; end;
function xhci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8;
begin
xhci_port_speed := xhci_map_speed(
(xhci_port_status(hc, port) AND XHCI_PORTSC_SPEED_MASK) SHR XHCI_PORTSC_SPEED_SHIFT);
end;
function xhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; function xhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean;
var var
priv : PXHCI_PrivData; priv : PXHCI_PrivData;
@@ -2095,6 +2101,7 @@ begin
hc.fnPoll := TUSBHCPoll(@xhci_poll); hc.fnPoll := TUSBHCPoll(@xhci_poll);
hc.fnPortReset := TUSBHCPortReset(@xhci_port_reset); hc.fnPortReset := TUSBHCPortReset(@xhci_port_reset);
hc.fnPortStatus := TUSBHCPortStatus(@xhci_port_status); hc.fnPortStatus := TUSBHCPortStatus(@xhci_port_status);
hc.fnPortSpeed := TUSBHCPortSpeed(@xhci_port_speed);
{ Reset the controller } { Reset the controller }
if not xhci_reset(@hc) then begin if not xhci_reset(@hc) then begin
@@ -19,6 +19,8 @@
} }
unit driver.storage.ctl.ide.ata; unit driver.storage.ctl.ide.ata;
{$DEFINE NOT_DANGLING} { Part of the unfinished legacy IDE stack. }
interface interface
uses uses
@@ -24,6 +24,8 @@
unit driver.storage.ctl.ide.atapi; unit driver.storage.ctl.ide.atapi;
{$DEFINE NOT_DANGLING} { Nonfunctional legacy ATAPI driver. }
interface interface
uses uses
Loaded 20 of 27 files, more files were not shown because too many files have changed in this diff. Show more