diff --git a/doc/planning/x86_64.md b/doc/planning/x86_64.md index 6322d9f3..a46ec125 100644 --- a/doc/planning/x86_64.md +++ b/doc/planning/x86_64.md @@ -5,7 +5,7 @@ The x86-64 target boots into Pascal with exception handling, physical/virtual allocation, the shared heap, PIC/PIT interrupts and tested kernel-context preemption. Fatal faults report over COM1. -This is a bootstrap kernel, not the complete Asuro desktop or storage stack. +The native desktop, terminal, storage, E1000 networking and WASM runtime now run. The existing x86 target remains the default. ## Architecture boundaries and reuse @@ -59,7 +59,7 @@ target's objects. The x86 compiler search path excludes `src/arch/x86_64`. Use VirtualBox for runtime validation. With the configured Asuro VM stopped, select `Asuro-x86_64.iso` as its optical medium, then start it through the normal VM workflow and read `C:\Temp\asuro.log`. Restore the original optical medium -after testing. The bootstrap does not access storage controllers or disks. +after testing. The normal image enumerates storage and mounts attached filesystems; boot checks read attached disks without writing them. Expected serial output: @@ -71,7 +71,7 @@ PASS: INT3 frame, GPRs, RFLAGS, x87/SSE and IRETQ PASS: page-fault error code, CR2 and IRETQ recovery EXCEPTION_TESTS_PASSED=0000000000000002 EXCEPTION_TESTS_FAILED=0000000000000000 -ASURO x86_64: bootstrap complete; interrupts disabled +ASURO x86_64: desktop ready ``` An early single `C` means CPUID/long-mode support is unavailable; `B` means an @@ -132,8 +132,7 @@ Rebuild without `ASURO_BOOT_TEST` after testing to restore the normal image. this state policy before enabling those features. - IRQ0 is enabled during timer and context tests, then masked before the final halt. PIC acknowledgement and spurious IRQ7/15 handling are implemented. - General driver hooks, APIC/SMP, Pascal unit-init - dispatch remain future work. + General driver hooks and APIC/SMP remain future work. - The low identity map is temporary. It is not a final process address-space design and does not enforce page-level W^X. New heap mappings use 4 KiB pages at `0xFFFF800000000000`, spanning up to 16 GiB with NX when supported. @@ -145,7 +144,7 @@ Rebuild without `ASURO_BOOT_TEST` after testing to restore the normal image. | Area | Existing assumptions / next work | |---|---| -| Runtime | Keep compiler metadata shared; implement required x86-64 helpers and initialization dispatch as consumers are ported. | +| Runtime | Keep compiler metadata shared; initialization dispatch is shared; implement further x86-64 helpers as consumers are ported. | | Common kernel entry | `src/asuro.pas` currently imports x86 units; separate common boot sequencing from architecture setup before sharing full initialization. | | Exceptions | IDT/TSS, IST stacks, normalized frames, diagnostics, and tested `iretq` paths are implemented. NMI/MC injection, user transitions, guard pages, and general IRQ dispatch remain. | | ABI | Bootstrap interrupt alignment and x87/SSE preservation are tested. Audit red-zone assumptions for each added compiler/library and extend preservation before enabling AVX or lazy-FPU switching. | @@ -334,8 +333,7 @@ implementations. Native scalar widths live in each selected system unit. `arch.x86.startup` now registers heap/process/console startup with the boot manager. `arch.x86.console` owns VERSION/TIME/REBOOT commands and their driver dependencies. The x86-64 bootstrap retains its explicit startup sequence. -Unused working-directory wrappers moved from `io.stdio` into `io.directory`, -which explicitly depends on VFS. Existing in-repository callers need no changes. +Unused working-directory wrappers were removed; directory operations belong to VFS. Existing `DEBUG_LMM` allocator guards and architecture-local fault-injection build flags remain; these are feature/test options, not architecture selection. @@ -367,3 +365,215 @@ the configured assembly entry is linked first to preserve the Multiboot header. Initialization-table, icon, LVGL, version, and checksum generation use target settings too. Full i386 and x86-64 builds and VirtualBox boot checks validate this pipeline; the i386 boot includes normal mounts and existing storage tests. + +## Shared unit initialization + +Both system units now use `arch/common/system.init.inc` to dispatch the +build-generated INITFINAL table. The x86-64 profile enables the existing +`initcalls` stage, whose packed records use native procedure-pointer widths. +An initialization guard prevents repeat or reentrant dispatch. This also removes +the duplicated table walks from the i386 runtime. + +Initializers may set globals or register boot work; they must not require heap, +hardware setup, or dependency ordering. The existing generator enumerates symbols +in object-file order, so actual subsystem startup remains explicitly sequenced +on x86-64 and dependency-ordered by boot.mgr on i386. The full boot manager remains i386-only; the x86-64 composition now starts +the shared storage services explicitly (see storage integration below). + +Validation: x86-64 build and 64 MiB VirtualBox boot passed, including a real +Pascal initialization section checked after two calls to system.init. The full +i386 build and VirtualBox boot also passed, with 54 initialization entries, +normal volume mounts, and zero failures in the reported regression suites. + +## Shared filesystem foundations + +The shared FNV-1a hashes, hash map, managed/string lists, path syntax, and +filesystem registry now compile and run in long mode. String-list slots hold +native pointers; hash inputs and memory-copy addresses no longer truncate to +32 bits. Hash replacement preserves the entry count, rehashing links each item +in constant time, and container allocation failures leave published state intact. +Linked-list insertion supports the end position and string splitting shares one +implementation with rollback on allocation failure. + +`driver.storage.path` provides caller-owned absolute and normalized paths without +volume or driver dependencies. VFS delegates to this implementation on i386. +Normalization scans into one allocated output buffer, handling repeated slashes, +dot segments, and parent traversal without climbing above root. It is lexical; +symlink resolution remains VFS work. + +The filesystem registry uses native record copies, handles empty registries, +and traverses linked records directly for linear searches/probes. Its boot +registration lives in arch.x86.startup; x86-64 initializes it explicitly. +Registry tests invoke an identify callback using heap-backed volume/driver +records and restore the existing registry after the test. + +New shared checks: 9 FNV-1a, 47 hash-map, 8 list, 15 path, and 9 registry checks. +These foundation checks preceded the storage integration described below. + +The shared contiguous FIFO and I/O request pool also run on x86-64. Queue +addresses and byte-size calculations use native widths, capacity growth checks +for overflow/allocation failure, and zero-sized elements are rejected. Request +pool initialization and free-list changes use arch.platform.cpu IRQ exclusion. +Pool node recovery uses the actual request-field offset instead of assuming a +pointer-sized prefix. The bounded, heap-backed pool retains its existing +512-request capacity and lifetime. + +The 6 GiB VirtualBox run passes 22 CFIFO and 4 request-pool checks in addition +to the filesystem-foundation suites. Tests cover queue compaction/growth, +native pointer payloads, request-pool exhaustion/reuse, and callback/data copies. +Hardware storage validation is covered by the subsequent integration below. + +Final validation for this batch: both target builds pass. The x86-64 VirtualBox +bootstrap passes at 64 MiB; the 6 GiB run also passes the above-4-GiB physical +memory check. i386 reaches idle with all 114 shared foundation checks passing, +all 130 VFS checks passing, normal ISO9660/FAT32/EXT2 mounts, and zero failures +in the reported storage/controller suites. VM RAM and optical media are restored +and the VM is powered off. Logs remain in bin/x86_64/ (ignored). + +## Shared storage integration + +The x86-64 boot now starts PCI, AHCI, the shared storage request manager, volume +manager, VFS, ISO9660, FAT32 and EXT2. Boot registration belongs to target startup +units. Shared code uses build-selected CPU, memory, timer and interrupt adapters; +there are no CPU conditionals or duplicated filesystem implementations. + +AHCI command lists and FIS buffers use native virtual addresses and full physical +addresses. Each command table fits within one physical page. PRDs translate every +4 KiB page, coalesce contiguous physical runs and retain upper address bits. +Controllers lacking 64-bit DMA reject inaccessible structures and buffers rather +than truncating addresses. Unsupported 32-bit-only controllers do not yet have +bounce-buffer support. The descriptor count remains bounded at 32. + +PCI driver callbacks receive persistent device records rather than stack locals. +Multifunction probing visits functions 1 through 7. IRQ/timer callbacks use the +existing i386 interrupt infrastructure or the x86-64 PIC dispatch implementation. +MMIO currently uses the low 4 GiB mapping; this is not general high-BAR support. + +VFS, filesystem buffers, volume slots and controller references preserve native +pointer widths. EXT2's worker starts before blocking filesystem operations, with +scheduler interrupts enabled. Filesystem registration follows the i386 probe +order so stale FAT signatures do not take precedence over EXT2 identification. +FAT32 now falls back to the space required by a write when optional preallocation +cannot fit, instead of incorrectly returning disk-full. + +VirtualBox validation at 64 MiB and 6 GiB passes: + +- 130 shared VFS checks and 34 AHCI checks. +- 123 storage metadata/filesystem checks, including heap-backed FAT32 and EXT2 + format, file creation, cross-block write, close/reopen, unaligned read-back, + persisted size and volume cleanup. No attached disk is written by these tests. +- Actual ISO9660, FAT32 and EXT2 mounts through the AHCI controller. +- A 4096-byte VFS read of the ISO's ELF64 kernel with header validation. +- At 6 GiB, sector reads into physical RAM above 4 GiB compared byte-for-byte + against ordinary-buffer reads from every attached storage device. + +The boot harness requires the new failure counters and content-read marker; a +high-memory run must also complete the high-DMA comparison. Evidence is saved in +`bin/x86_64/boot-none-64.log` and `bin/x86_64/boot-none-6144.log`. + +This completes the tested AHCI/filesystem path, not the entire OS port. The +x86-64 image now continues into the desktop and shared application startup. Remaining USB controllers still require porting and validation. Disk LBAs +and file sizes retain the existing storage API's 32-bit limits. + +Final i386 regression also passes: the complete image reaches idle with 123 +metadata/filesystem checks, 130 VFS checks, 34 AHCI checks and the existing USB, +controller, storage and core suites reporting zero failures. Early-boot tests +use private filesystem descriptors with synchronous transfer hooks; scheduled +x86-64 tests keep the normal async hooks and exercise the EXT2 worker. The final +6 GiB x86-64 image passes the same 123 checks and the high-DMA comparison. +VirtualBox is powered off with its original 2048 MiB RAM and Asuro.iso restored. + +## USB core and OHCI bring-up + +The shared USB types, descriptor parsing, controller/device registry and hub +logic now use native pointers and platform adapters. Aligned allocations store +a native-width allocation header and reject invalid alignment and size overflow. +Device-list slots retain full pointers, empty-list loops are bounded, and failed +controller registration rolls back its allocation. Tests isolate registry state +under IRQ exclusion and verify that their allocations are returned. + +OHCI runs in the x86-64 VirtualBox image. Its hardware ED/TD prefix stays 16 bytes; +software links and cleanup pointers use native widths. Controller MMIO and IRQ +routing use the existing platform adapters. DMA buffers and descriptor pages +must fit below 4 GiB; inaccessible buffers fail submission without truncation. +There is no OHCI high-memory bounce-buffer support yet. Schedule allocation must +succeed before the controller enters the operational state. + +A 6 GiB VirtualBox boot starts OHCI, resets its port and enumerates the configured +USB device (VID 80EE, PID 0030). At that stage, USB class-driver input/storage, UHCI, EHCI and xHCI +were not part of the long-mode boot. That established real control transfers, +not full USB feature parity. The boot harness requires successful enumeration as +well as the USB type/core/hub/OHCI test failure counters. + +Validation after the OHCI changes: both target builds and VirtualBox boots pass. +The x86-64 runs at 64 MiB and 6 GiB report 55 USB type checks, 55 core checks, +44 hub checks and 91 OHCI checks with zero failures, plus real device enumeration. +The i386 boot reaches idle with the existing storage, USB/HID and core suites +passing. Original VM RAM and optical media are restored and the VM is off. + +## USB class drivers and stable storage registration + +The shared mass-storage, boot keyboard and boot mouse drivers now compile for +both targets through the platform adapters. The mouse receives bounds from the +video subsystem; i386 startup supplies the optional PS/2 keyboard-disable hook. +USB class registration stays in architecture startup composition. + +Boot work after scheduler initialization runs in a normal process. Running it on +the idle context starved initialization once the persistent USB worker started. +Storage device records now have stable heap addresses behind native pointer +slots: registering a fifth disk previously moved the by-value registry and left +mounted volumes pointing at freed records. Registry publication and lookup exclude +interrupts. ISO9660 now stops on failed sector reads instead of parsing empty data. + +VirtualBox checks pass at 64 MiB and 6 GiB: 40 mass-storage protocol tests, 62 +keyboard tests and 33 mouse tests, plus the existing USB/core/OHCI and storage +suites. The existing USB disk serves a read-only sector-zero request through OHCI, +and the AHCI kernel-file read passes before and after USB registration. The 6 GiB +run also compares high-physical-memory reads against normal buffers. No USB writes +are used. The full i386 image builds and reaches idle with its suites passing. + +Temporarily enabling VirtualBox USB keyboard and mouse binds both class drivers +alongside the disk. This validates attachment, not injected input: boot-protocol +requests returned failure and the existing drivers continued. Report delivery, +hot unplug, USB writes and UHCI/EHCI/xHCI remain unvalidated in long mode. The image now continues into the graphical desktop. +## Native desktop, networking and applications + +The normal image runs the shared LVGL desktop and application manager. Both +architectures use the same application registrations; architecture startup retains +CPU/BIOS-specific commands. PS/2 mouse and keyboard drive the terminal, including +paced and burst input. Live BGA switching to 1280x800 and subsequent terminal input +pass in VirtualBox. The LVGL lock hands ownership to queued waiters, and framebuffer +flush stays inside that lock so mode changes cannot release a buffer during use. + +E1000 uses native MMIO mappings, platform IRQ routing and owned DMA buffers. +VirtualBox NAT tests obtained a DHCP lease and received ping replies at 6 GiB; +DHCP also passed at 64 MiB. This does not establish complete TCP protocol coverage. + +The WASM bridge resolves its context from the current process, initializes a +suspended process before publishing it, and releases partially loaded contexts on +failure. Native WASI proc_exit tests pass, and /disk/ram/hello prints Hello, World! +in the terminal. The external runtime's fixed VM stacks exceed the available RAM +in the 64 MiB configuration; launch is rejected before allocating those stacks. +MEMINFO uses platform physical-byte counters and reports RAM above 4 GiB. + +Both target builds pass. The i386 image reaches idle with its suites reporting +zero failures. Native boots at 64 MiB and 6 GiB reach the interactive desktop; +the high-memory run also passes AHCI DMA comparisons above 4 GiB. MD5SUM of abc +matches 900150983CD24FB0D6963F7D28E17F72. VM test settings are restored afterward. + +Full feature parity is still outstanding: UHCI/EHCI/xHCI, USB report delivery and +hot unplug, broader network workloads, and full interactive application coverage. +OHCI still rejects DMA addresses above its 32-bit hardware limit rather than +providing bounce buffers. These limits must not be described as a finished port. + +Follow-up interactive checks pass with VirtualBox USB keyboard and mouse: the +mouse opens Terminal and paced/burst keyboard commands produce the expected +output. SET_PROTOCOL warnings remain, but report delivery is now demonstrated. +Files, Notepad and Disk Utility also open successfully; Files lists root entries, +and Disk Utility lists AHCI and USB devices. This checks startup and display, +not destructive disk operations or every editor/file-management workflow. + +The application check exposed a duplicate core.strings.helpers unit shadowing +the native implementation. Removing the stale copy fixes the Files sorting fault +without changing compiler search rules. Low-memory WASM launch now displays the +handler's memory error, and a subsequent terminal command succeeds. diff --git a/src/app/app.mgr.pas b/src/app/app.mgr.pas index 348dbdd6..fa78125c 100644 --- a/src/app/app.mgr.pas +++ b/src/app/app.mgr.pas @@ -23,10 +23,9 @@ unit app.mgr; interface uses - boot.mgr, debug.tracer, io.stdio, proc.mgr, //progs - app.base64, app.md5sum, app.dhclient, app.vbeinfo, app.testcmd, app.ping, app.meminfo, app.setres, app.iotest, + app.base64, app.md5sum, app.dhclient, app.testcmd, app.ping, app.meminfo, app.setres, //drivers driver.storage.ctl.ram, driver.mgr, //network @@ -35,8 +34,6 @@ uses driver.storage.filedispatch, //wasm app.wasm.runner, - app.divzero, - app.bsod, app.vterminal; { Initialize all baked-in programs } @@ -47,7 +44,6 @@ implementation uses core.version, //command provider units - arch.x86.cpu, app.diskcmd, driver.bus.usb.core, app.diskutil, app.notepad, app.partcmd, app.volcmd, app.filebrowser; @@ -56,16 +52,10 @@ begin debug.tracer.push_trace('app.mgr.init'); { Register commands from provider units } - io.stdio.registerCommand('CPU', @arch.x86.cpu.Terminal_Command_CPU, 'CPU Info.'); io.stdio.registerCommand('DEV', @driver.mgr.terminal_command_dev, 'Driver Management Interface.'); io.stdio.registerCommand('PS', @proc.mgr.terminal_command_ps, 'List running processes.'); io.stdio.registerCommand('KILL', @proc.mgr.terminal_command_kill, 'Force-kill a process by PID.'); io.stdio.registerCommand('TERMINATE', @proc.mgr.terminal_command_terminate, 'Gracefully terminate a process by PID.'); - io.stdio.registerCommand('ARP', @driver.net.proto.arp.terminal_command_arp, 'Get ARP Table.'); - io.stdio.registerCommand('IFCONFIG', @driver.net.proto.ipv4.terminal_command_ifconfig, 'Configure Network Settings.'); - io.stdio.registerCommand('TCPCONNECT', @driver.net.proto.tcp.terminal_command_tcpconnect, 'Connect to a TCP host and send Hello World.'); - io.stdio.registerCommand('TCPLISTEN', @driver.net.proto.tcp.terminal_command_tcplisten, 'Listen on a TCP port and log received data.'); - io.stdio.registerCommand('TCPHTTP', @driver.net.proto.tcp.terminal_command_tcphttp, 'Send HTTP GET to a host IP (port 80 default).'); io.stdio.registerCommand('USB', @driver.bus.usb.core.terminal_command_usb, 'driver.bus.usb subsystem information.'); { File dispatch — must init before apps that register handlers } @@ -81,21 +71,15 @@ begin app.md5sum.init(); app.base64.init(); app.dhclient.init(); - app.vbeinfo.init(); app.testcmd.init(); app.ping.init(); app.meminfo.init(); { WASM & remaining apps } app.wasm.runner.init(); app.setres.init(); - app.divzero.init(); - app.bsod.init(); app.vterminal.init; app.filebrowser.init(); - app.iotest.init(); end; -Initialization - boot.mgr.registerBoot('app.mgr', @init, 'Program Manager', BOOT_MGR_BARRIER_LATE); end. \ No newline at end of file diff --git a/src/arch/x86/arch.x86.startup.pas b/src/arch/x86/arch.x86.startup.pas index ff9fd6a0..fd29a1ad 100644 --- a/src/arch/x86/arch.x86.startup.pas +++ b/src/arch/x86/arch.x86.startup.pas @@ -12,12 +12,109 @@ { Compose shared services with the i386 boot manager and platform commands. } unit arch.x86.startup; + interface + implementation -uses boot.mgr, memory.heap, proc.mgr, io.stdio, arch.x86.console; +uses + app.mgr, app.vbeinfo, app.divzero, app.bsod, app.iotest, arch.x86.cpu, + driver.net, + driver.video.desktop, driver.timer.rtc, svc.gfxd, + app.uidebug, + driver.video.bga, driver.video, driver.video.gpu, driver.video.vesa, + driver.video.doublebuffer, driver.video.lvgl, + driver.hid.usb.keyboard, + driver.hid.usb.mouse, + driver.hid.ps2.keyboard, driver.hid.ps2.mouse, + driver.storage.ctl.usb, + driver.storage.metatest, + driver.mgr, + driver.bus.pci, + driver.storage.ctl.ahci, + driver.storage.mgr, + driver.storage.vfs, + driver.storage.vol.mgr, + driver.storage.fs.flatfs, + driver.storage.fs.iso9660, + driver.storage.fs.ext2, + driver.storage.fs.fat32, + driver.io.serial, + io.syslog, + debug.tracer, + driver.storage.fs.mgr, + boot.mgr, + memory.heap, + proc.mgr, + io.stdio, + arch.x86.console; + +procedure initApps; +begin + app.mgr.init; + io.stdio.registerCommand('CPU', @arch.x86.cpu.Terminal_Command_CPU, 'CPU Info.'); + app.vbeinfo.init; + app.divzero.init; + app.bsod.init; + app.iotest.init; +end; + procedure consoleInit; -begin io.stdio.init; arch.x86.console.init; end; +begin + io.stdio.init; + arch.x86.console.init; +end; +procedure lateInit(); +begin + driver.video.vesa.init(@driver.video.register); + driver.video.doublebuffer.init(@driver.video.register); + + io.syslog.logln('VIDEO', 'VESA Enable.'); + driver.video.enable('VESA'); + + io.syslog.logln('VIDEO', 'Double Buffer Enable.'); + driver.video.enable('BASIC_DOUBLE_BUFFER'); + + { Initialize LVGL early so the boot.splash screen can use it } + io.syslog.logln('VIDEO', 'LVGL: INIT BEGIN.'); + lvgl_init(driver.video.frontBufferWidth, driver.video.frontBufferHeight); + io.syslog.logln('VIDEO', 'LVGL: INIT END.'); +end; + initialization + boot.mgr.registerBoot('app.mgr', @initApps, 'Program Manager', BOOT_MGR_BARRIER_LATE); + boot.mgr.registerBoot('driver.video.bga', @driver.video.bga.init, 'BGA Display Driver Initialization', 'driver.video'); + boot.mgr.registerBoot('driver.net', @driver.net.init, 'Net Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('driver.hid.ps2.keyboard', @driver.hid.ps2.keyboard.init, 'PS/2 Keyboard Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('driver.hid.ps2.mouse', @driver.hid.ps2.mouse.init, 'PS/2 Mouse Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('proc.desktop', @driver.video.desktop.init, 'Initialize Desktop', 'boot.splash.teardown'); + boot.mgr.registerBoot('svc.gfxd', @svc.gfxd.init, 'GFX Daemon', BOOT_MGR_BARRIER_LATE); + boot.mgr.registerBoot('driver.timer.rtc', @driver.timer.rtc.init, 'Real Time Clock Driver', 'arch.x86.fault'); + boot.mgr.registerBoot('driver.video', @driver.video.init, 'Video Driver Initialization', 'driver.video.gpu'); + boot.mgr.registerBoot('driver.video.gpu', @driver.video.gpu.init, 'GPU Framework', BOOT_MGR_BARRIER_EARLY); + boot.mgr.registerBoot('driver.video_late', @lateInit, 'Video Driver Late Initialization', 'driver.video.*'); + driver.video.lvgl.onDebugToggle := @app.uidebug.toggle; + driver.hid.usb.keyboard.onAttach := @driver.hid.ps2.keyboard.disable; + boot.mgr.registerBoot('driver.hid.usb.keyboard', @driver.hid.usb.keyboard.init, 'USB Keyboard Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('driver.hid.usb.mouse', @driver.hid.usb.mouse.init, 'USB Mouse Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('driver.storage.ctl.usb', @driver.storage.ctl.usb.init, 'USB Mass Storage Driver', BOOT_MGR_BARRIER_DEVICE); + boot.mgr.registerBoot('driver.storage.metatest', @driver.storage.metatest.init, 'Storage Metadata Tests', BOOT_MGR_BARRIER_MID); + boot.mgr.registerBoot('driver.mgr', @driver.mgr.init, 'Driver Manager Initialization', BOOT_MGR_BARRIER_MID); + boot.mgr.registerBoot('driver.bus.pci', @driver.bus.pci.Init, 'PCI Bus Driver', BOOT_MGR_BARRIER_BUS_LATE); + boot.mgr.registerBoot('driver.storage.ctl.ahci', @driver.storage.ctl.ahci.init, 'AHCI Controller', 'driver.storage.fs.*'); + boot.mgr.registerBoot('driver.storage.mgr', @driver.storage.mgr.init, 'Storage Manager', 'driver.storage.vfs'); + boot.mgr.registerBoot('driver.storage.vfs', @driver.storage.vfs.init, 'Virtual File System', BOOT_MGR_BARRIER_STORAGE); + boot.mgr.registerBoot('driver.storage.vol.mount', @driver.storage.vfs.auto_mount_volumes, 'Mount Storage Volumes', BOOT_MGR_BARRIER_LATE); + boot.mgr.registerBoot('driver.storage.vol.mgr', @driver.storage.vol.mgr.init, 'Volume Manager', 'driver.storage.mgr*'); + boot.mgr.registerBoot('driver.storage.fs.flatfs', @driver.storage.fs.flatfs.init, 'FlatFS Filesystem', 'driver.storage.fs.mgr'); + boot.mgr.registerBoot('driver.storage.fs.iso9660', @driver.storage.fs.iso9660.Init, 'IS9660 File System', 'driver.storage.fs.mgr'); + boot.mgr.registerBoot('driver.storage.fs.ext2',@driver.storage.fs.ext2.init,'Ext2 Filesystem','driver.storage.fs.mgr'); + boot.mgr.registerBoot('driver.storage.ext2.worker',@driver.storage.fs.ext2.StartWorker,'Ext2 I/O Worker','proc.mgr'); + boot.mgr.registerBoot('driver.storage.fs.fat32', @driver.storage.fs.fat32.init, 'FAT32 Filesystem', 'driver.storage.fs.mgr'); + boot.mgr.registerBoot('driver.io.serial', @driver.io.serial.init, 'Serial Interface', 'immediate'); + boot.mgr.registerBoot('io.syslog', @io.syslog.init, 'Syslog Interface', 'driver.io.serial'); + boot.mgr.registerBoot('debug.tracer.freeze', @debug.tracer.freeze, 'Debug Tracer Freeze', 'io.syslog' ); + boot.mgr.registerBoot('debug.tracer', @debug.tracer.init, 'Debug Tracer Initialization', 'io.stdio' ); + boot.mgr.registerBoot('driver.storage.fs.mgr', @driver.storage.fs.mgr.init, 'Filesystem Manager', 'driver.storage.vol.mgr'); boot.mgr.registerBoot('memory.heap', @memory.heap.init, 'Heap Memory Manager', 'arch.*.memory.*'); boot.mgr.registerBoot('io.stdio', @consoleInit, 'Standard I/O Abstraction', BOOT_MGR_BARRIER_EARLY); boot.mgr.registerBoot('proc.mgr', @proc.mgr.init, 'Process Manager', 'driver.storage.fs*'); diff --git a/src/arch/x86_64/arch.x86_64.boot.pas b/src/arch/x86_64/arch.x86_64.boot.pas index 4012b9de..98d8726c 100644 --- a/src/arch/x86_64/arch.x86_64.boot.pas +++ b/src/arch/x86_64/arch.x86_64.boot.pas @@ -18,8 +18,61 @@ procedure kmain(info: pointer; magic: uint32); cdecl; implementation -uses io.stdio, core.strings, driver.storage.fdtable, arch.x86_64.proc.sched, proc.mgr, arch.x86_64.context, arch.x86_64.irq, memory.heap, debug.early, arch.x86_64.debug, arch.x86_64.isr, boot.multiboot, - arch.x86_64.memory.physical, arch.x86_64.memory.virtual; +uses + app.mgr, + driver.net, app.wasm.runner, + driver.hid.ps2.keyboard, driver.hid.ps2.mouse, + driver.video.desktop, driver.timer.rtc, svc.gfxd, app.uidebug, + driver.video.lvgl, + driver.video.bga, driver.video, driver.video.gpu, driver.video.doublebuffer, + core.gfx.color, arch.platform.memory, + proc.types, + driver.hid.usb.keyboard, + driver.hid.usb.mouse, + driver.storage.ctl.usb, + driver.bus.usb.types, + driver.bus.usb.core, + driver.bus.usb.hub, + driver.bus.usb.ohci, + driver.storage.metatest, + driver.storage.types, + arch.common.legacyirq, + driver.mgr, + driver.bus.pci, + driver.storage.ctl.ahci, + driver.storage.fs.fat32, + driver.storage.fs.ext2, + driver.storage.vfs, + driver.storage.mgr, + driver.storage.vol.mgr, + driver.storage.fs.iso9660, + io.syslog, + driver.io.serial, + debug.tracer, + core.ds.cfifo, + driver.storage.iorequest, + driver.storage.path, + driver.storage.fs.mgr, + core.ds.lists, + core.ds.hashmap, + core.enc.fnv1a, + io.stdio, + core.strings, + driver.storage.fdtable, + arch.x86_64.proc.sched, + proc.mgr, + arch.x86_64.context, + arch.x86_64.irq, + memory.heap, + debug.early, + arch.x86_64.debug, + arch.x86_64.isr, + boot.multiboot, + arch.x86_64.memory.physical, + arch.x86_64.memory.virtual; + +var + initializationCount: uint32; function long_mode_active: boolean; assembler; nostackframe; asm @@ -29,12 +82,201 @@ asm and eax, 1 end; +procedure test_high_dma; +var + address: PtrUInt; + frame, oldFrame: uint64; + device: PStorage_Device; + reference: puint8; + i, j, count: uint32; + ok: boolean; +begin + frame := arch.x86_64.memory.physical.alloc_high; + if frame = 0 then begin + puts('SKIP: no high physical frame for DMA test'#13#10); + exit; + end; + address := arch.x86_64.memory.virtual.allocate_region(1); + if address = 0 then begin + arch.x86_64.memory.physical.free_page(frame); + puts('FAIL: DMA test mapping allocation'#13#10); + exit; + end; + if not unmap_page(address, oldFrame) then bootstrap_halt; + arch.x86_64.memory.physical.free_page(oldFrame); + if not map_page(address, frame, true) then bootstrap_halt; + reference := puint8(kalloc(4096)); + ok := reference <> nil; + count := driver.storage.mgr.get_device_count; + if count = 0 then ok := false; + if ok then + for i := 0 to count - 1 do begin + device := driver.storage.mgr.get_device(i); + if (device^.sectorSize = 0) or (device^.sectorSize > 4096) then begin + ok := false; + break; + end; + if (storage_read(device, 0, 1, puint32(reference)) <> eNone) or + (storage_read(device, 0, 1, puint32(address)) <> eNone) then begin + ok := false; + break; + end; + for j := 0 to device^.sectorSize - 1 do + if reference[j] <> puint8(address)[j] then ok := false; + end; + if reference <> nil then kfree(void(reference)); + if not release_region(address, 1) then ok := false; + if ok then + puts('PASS: AHCI DMA above 4 GiB matches every disk sector'#13#10) + else + puts('FAIL: AHCI DMA above 4 GiB'#13#10); +end; + +procedure test_storage_read; +var + handle: TFileHandle; + error: TError; + buffer: puint8; + bytes: uint32; +begin + buffer := puint8(kalloc(4096)); + if buffer = nil then begin + puts('FAIL: storage read buffer allocation'#13#10); + exit; + end; + handle := driver.storage.vfs.OpenFile('/disk/ISOIMAGE/boot/asuro.bin', omRead, @error); + if error = eNone then begin + bytes := driver.storage.vfs.ReadFile(handle, 0, buffer, 4096); + if (bytes = 4096) and (buffer[0] = $7F) and + (buffer[1] = ord('E')) and (buffer[2] = ord('L')) and + (buffer[3] = ord('F')) and (buffer[4] = 2) then + puts('PASS: VFS reads ELF64 kernel through AHCI'#13#10) + else + puts('FAIL: VFS kernel file contents'#13#10); + driver.storage.vfs.CloseFile(handle); + end else + puts('FAIL: VFS opens kernel file'#13#10); + kfree(void(buffer)); +end; + +procedure test_usb_read; +var + device: PStorage_Device; + buffer: puint32; + attempt, i, count: uint32; +begin + device := nil; + for attempt := 0 to 499 do begin + count := driver.storage.mgr.get_device_count; + if count > 0 then + for i := 0 to count - 1 do + if driver.storage.mgr.get_device(i)^.controller = ControllerUSB then + device := driver.storage.mgr.get_device(i); + if device <> nil then break; + proc.mgr.proc_sleep_ms(10); + end; + if device = nil then begin + puts('SKIP: no USB storage device registered'#13#10); + exit; + end; + buffer := puint32(kalloc(device^.sectorSize)); + if buffer = nil then begin + puts('FAIL: USB read buffer allocation'#13#10); + exit; + end; + if storage_read(device, 0, 1, buffer) = eNone then + puts('PASS: USB mass storage reads sector zero through OHCI'#13#10) + else + puts('FAIL: USB mass storage sector read'#13#10); + kfree(void(buffer)); +end; + +procedure init_video(info: Pmultiboot_info_t); +var + framebuffer: pointer; + bytes: SizeUInt; +begin + if (info^.flags and (1 shl 12) = 0) or + (info^.framebuffer_bpp <> 32) or + (info^.framebuffer_width = 0) or (info^.framebuffer_height = 0) or + (info^.framebuffer_pitch < uint64(info^.framebuffer_width) * 4) then begin + puts('FAIL: boot framebuffer geometry'#13#10); + exit; + end; + bytes := SizeUInt(info^.framebuffer_pitch) * info^.framebuffer_height; + framebuffer := arch.platform.memory.mapDevice(info^.framebuffer_addr, bytes); + if framebuffer = nil then begin + puts('FAIL: boot framebuffer mapping'#13#10); + exit; + end; + driver.video.gpu.init; + driver.video.init; + driver.video.doublebuffer.init(@driver.video.register); + driver.video.reinit(PtrUInt(framebuffer), info^.framebuffer_width, + info^.framebuffer_height, info^.framebuffer_pitch, info^.framebuffer_bpp); + driver.video.DrawString(32, 32, 'Asuro x86-64', core.gfx.color.white); + driver.video.Flush; + driver.video.lvgl.lvgl_init(info^.framebuffer_width, info^.framebuffer_height); + driver.video.lvgl.lvgl_handler; + driver.video.Flush; + puts('PASS: native framebuffer and double buffer initialized'#13#10); +end; + +procedure finish_boot(ctx: PProcessContext); +begin + driver.storage.metatest.RunTests(true); + driver.video.bga.init; + driver.net.init; + driver.bus.pci.init; + driver.storage.vfs.auto_mount_volumes; + test_storage_read; + driver.hid.ps2.mouse.init; + driver.hid.ps2.keyboard.init; + driver.hid.usb.keyboard.onAttach := @driver.hid.ps2.keyboard.disable; + driver.bus.usb.core.init; + driver.bus.usb.hub.init; + driver.storage.ctl.usb.init; + driver.hid.usb.keyboard.init; + driver.hid.usb.mouse.init; + driver.bus.usb.ohci.load; + test_usb_read; + test_storage_read; + test_high_dma; + driver.timer.rtc.init; + driver.video.lvgl.onDebugToggle := @app.uidebug.toggle; + driver.video.desktop.init; + app.mgr.init; + app.wasm.runner.UnitTest; + driver.video.lvgl.lvgl_handler; + driver.video.Flush; + {$ifdef ASURO_TEST_UD} + arch.x86_64.isr.testFatal(6); + {$endif} + {$ifdef ASURO_TEST_PF} + arch.x86_64.isr.testFatal(14); + {$endif} + {$ifdef ASURO_TEST_DF} + arch.x86_64.isr.testFatal(8); + {$endif} + svc.gfxd.init; + puts('ASURO x86_64: desktop ready'#13#10); +end; + procedure kmain(info: pointer; magic: uint32); cdecl; [public, alias: 'kmain']; var wide: PtrUInt; begin + boot.multiboot.multibootinfo := Pmultiboot_info_t(info); arch.x86_64.debug.init; arch.x86_64.isr.init; + io.syslog.init; + system.init; + system.init; + if initializationCount <> 1 then begin + puts('FAIL: unit initialization dispatch'#13#10); + bootstrap_halt; + end; + puts('PASS: native unit initialization runs once'#13#10); puts('ASURO x86_64: entered Pascal'#13#10); if (magic <> $2BADB002) or (info = nil) then begin puts('FAIL: Multiboot handoff'#13#10); @@ -58,7 +300,21 @@ begin arch.x86_64.memory.virtual.UnitTest; memory.heap.init; memory.heap.UnitTest; + driver.bus.usb.types.UnitTest; + driver.bus.usb.core.UnitTest; + driver.bus.usb.hub.UnitTest; + driver.hid.usb.keyboard.UnitTest; + driver.hid.usb.mouse.UnitTest; + driver.bus.usb.ohci.UnitTest; core.strings.UnitTest; + core.enc.fnv1a.UnitTest; + core.ds.hashmap.UnitTest; + core.ds.lists.TestAllLists; + core.ds.cfifo.UnitTest; + driver.storage.iorequest.UnitTest; + driver.storage.path.UnitTest; + driver.storage.fs.mgr.UnitTest; + driver.storage.fs.mgr.init; io.stdio.init; arch.x86_64.irq.init; arch.x86_64.irq.UnitTest; @@ -67,17 +323,36 @@ begin proc.mgr.init; arch.x86_64.proc.sched.init; arch.x86_64.proc.sched.UnitTest; - {$ifdef ASURO_TEST_UD} - arch.x86_64.isr.testFatal(6); - {$endif} - {$ifdef ASURO_TEST_PF} - arch.x86_64.isr.testFatal(14); - {$endif} - {$ifdef ASURO_TEST_DF} - arch.x86_64.isr.testFatal(8); - {$endif} - puts('ASURO x86_64: bootstrap complete; interrupts disabled'#13#10); - bootstrap_halt; + driver.storage.mgr.init; + driver.storage.vol.mgr.init; + driver.storage.fs.iso9660.init; + driver.storage.fs.ext2.init; + driver.storage.fs.fat32.init; + driver.storage.fs.ext2.StartWorker; + driver.storage.vfs.init; + driver.storage.vfs.auto_mount_volumes; + driver.storage.vfs.UnitTest; + driver.storage.ctl.ahci.UnitTest; + driver.storage.ctl.usb.UnitTest; + init_video(Pmultiboot_info_t(info)); + driver.mgr.init; + driver.storage.ctl.ahci.init; + if proc.mgr.create('bootstrap', @finish_boot, nil, 1) = nil then begin + puts('FAIL: bootstrap process allocation'#13#10); + bootstrap_halt; + end; + arch.common.legacyirq.masks($FE, $FF); + asm + sti + end; + while true do begin + asm + hlt + end; + end; end; +initialization + inc(initializationCount); + end. diff --git a/src/test/test.pas b/src/test/test.pas index 3f239a19..f0e10898 100644 --- a/src/test/test.pas +++ b/src/test/test.pas @@ -29,6 +29,9 @@ implementation uses core.strings, + core.ds.lists, + core.ds.hashmap, + driver.storage.iorequest, driver.storage.path, driver.storage.fs.mgr, app.diskutil, driver.bus.usb.types, driver.bus.usb.core, @@ -69,6 +72,11 @@ procedure runAllTests(); begin { Run unit tests } core.strings.UnitTest; + core.ds.lists.TestAllLists; + core.ds.hashmap.UnitTest; + driver.storage.iorequest.UnitTest; + driver.storage.path.UnitTest; + driver.storage.fs.mgr.UnitTest; app.diskutil.UnitTest; driver.bus.usb.types.UnitTest; driver.bus.usb.core.UnitTest; diff --git a/toolchain/targets/x86_64.sh b/toolchain/targets/x86_64.sh index a1165d66..bce58839 100644 --- a/toolchain/targets/x86_64.sh +++ b/toolchain/targets/x86_64.sh @@ -13,12 +13,12 @@ PASCAL_COMPILER=ppcx64 PASCAL_ENTRY="$ARCH_SOURCE_ROOT/arch.$ASURO_ARCH.boot.pas" PASCAL_OPTIONS=(-O2) -C_TARGET_OPTIONS=(-m64) +C_TARGET_OPTIONS=(-m64 -mno-red-zone) NASM_FORMAT=elf64 LD_FORMAT=elf_x86_64 LINKER_SCRIPT="$TARGET_TOOLCHAIN_DIR/linker.script" -# The bootstrap does not depend on the desktop or hosted runtime. -BUILD_STEPS=(stub sources link isogen) +# Native desktop and runtime sources follow the selected entry unit's dependencies. +BUILD_STEPS=(stub vergen lvgl sources initcalls link isogen) case "${ASURO_BOOT_TEST:-none}" in none) ;; ud|pf|df) PASCAL_OPTIONS+=("-dASURO_TEST_${ASURO_BOOT_TEST^^}") ;; diff --git a/toolchain/x86_64/test_boot.ps1 b/toolchain/x86_64/test_boot.ps1 index 8bb650d8..d4b66a67 100644 --- a/toolchain/x86_64/test_boot.ps1 +++ b/toolchain/x86_64/test_boot.ps1 @@ -13,6 +13,10 @@ # Run from the workspace root after building the selected ASURO_BOOT_TEST. # Restore temporary optical medium and optional RAM changes after the test. param( + [string[]]$TerminalCommands = @(), + [string[]]$OpenPrograms = @(), + [switch]$NetworkInput, + [switch]$DesktopInput, [ValidateSet('none', 'ud', 'pf', 'df')][string]$Test = 'none', [ValidateRange(0, 8192)][int]$MemoryMB = 0, [string]$Controller = 'AHCI', @@ -42,21 +46,57 @@ if ($originalMedium -eq 'none') { $originalMedium = 'emptydrive' } $evidence = Join-Path (Get-Location) 'bin\x86_64' New-Item -ItemType Directory -Path $evidence -Force | Out-Null $originalMemory = [int](($state | Where-Object { $_ -match '^memory=' }) -replace '^memory=', '') +$originalNetwork = (($state | Where-Object { $_ -match '^nic1=' }) -replace '^nic1=', '').Trim('"') if ($originalMemory -le 0) { throw 'Cannot identify original VM RAM size.' } +function Open-DesktopProgram($mouse, [string]$name) { + $mouse.PutMouseEvent(-2000, -2000, 0, 0, 0) + Start-Sleep -Milliseconds 200 + $mouse.PutMouseEvent(240, 0, 0, 0, 0) + for ($step = 0; $step -lt 12; $step++) { + $mouse.PutMouseEvent(0, 100, 0, 0, 0) + Start-Sleep -Milliseconds 100 + } + $mouse.PutMouseEvent(0, -32, 0, 0, 0) + Start-Sleep -Milliseconds 200 + $mouse.PutMouseEvent(0, 0, 0, 0, 1) + Start-Sleep -Milliseconds 200 + $mouse.PutMouseEvent(0, 0, 0, 0, 0) + & VBoxManage.exe controlvm $vm keyboardputstring $name + Start-Sleep -Seconds 1 + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 1 +} $started = $false try { + if ($NetworkInput) { + & VBoxManage.exe modifyvm $vm --nic1 nat + if ($LASTEXITCODE -ne 0) { throw 'Cannot set test NAT network.' } + Start-Sleep -Milliseconds 600 + } if ($MemoryMB -ne 0) { & VBoxManage.exe modifyvm $vm --memory $MemoryMB if ($LASTEXITCODE -ne 0) { throw 'Cannot set test RAM size.' } + Start-Sleep -Milliseconds 600 } & VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $isoPath if ($LASTEXITCODE -ne 0) { throw 'Cannot attach bootstrap ISO.' } - & .\virtualbox-wrapper.ps1 -command up -Headless -NoMonitor - if ($LASTEXITCODE -ne 0) { throw 'Cannot start test VM.' } - $started = $true + # VBoxSVC releases configuration sessions asynchronously. + Start-Sleep -Milliseconds 500 + for ($attempt = 0; $attempt -lt 5; $attempt++) { + $launchOutput = & .\virtualbox-wrapper.ps1 -command up -Headless -NoMonitor 2>&1 + if ($LASTEXITCODE -eq 0) { + $started = $true + break + } + if (($launchOutput -join "`n") -notmatch 'already locked') { + throw "Cannot start test VM: $launchOutput" + } + Start-Sleep -Seconds 1 + } + if (-not $started) { throw "VirtualBox session remained locked: $launchOutput" } $deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds) $output = '' - $marker = if ($Test -eq 'none') { 'bootstrap complete; interrupts disabled' } else { 'HALTED: exception diagnostics complete' } + $marker = if ($Test -eq 'none') { 'desktop ready' } else { 'HALTED: exception diagnostics complete' } do { if (Test-Path -LiteralPath $serialPath) { $output = Get-Content -LiteralPath $serialPath -Raw @@ -68,18 +108,82 @@ try { & VBoxManage.exe debugvm $vm getregisters rip rsp cs cr0 cr2 cr3 cr4 efer tr | Set-Content -LiteralPath (Join-Path $evidence "registers-$Test-$MemoryMB.log") if ($LASTEXITCODE -ne 0) { throw 'Cannot capture CPU registers.' } + if (($DesktopInput -or $NetworkInput -or $TerminalCommands.Count -gt 0 -or $OpenPrograms.Count -gt 0) -and $Test -eq 'none' -and $output.Contains($marker)) { + $vbox = New-Object -ComObject VirtualBox.VirtualBox + $session = New-Object -ComObject VirtualBox.Session + $machine = $vbox.FindMachine($vm) + $machine.LockMachine($session, 1) + try { + Start-Sleep -Seconds 1 + $mouse = $session.Console.Mouse + Open-DesktopProgram $mouse 'Terminal' + $mouse.PutMouseEvent(100, -400, 0, 0, 0) + Start-Sleep -Milliseconds 200 + $mouse.PutMouseEvent(0, 0, 0, 0, 1) + Start-Sleep -Milliseconds 200 + $mouse.PutMouseEvent(0, 0, 0, 0, 0) + Start-Sleep -Seconds 1 + foreach ($character in 'echo native64'.ToCharArray()) { + & VBoxManage.exe controlvm $vm keyboardputstring ([string]$character) + Start-Sleep -Milliseconds 150 + } + Start-Sleep -Seconds 2 + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 3 + & VBoxManage.exe controlvm $vm keyboardputstring 'echo burst64' + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 3 + foreach ($command in $TerminalCommands) { + & VBoxManage.exe controlvm $vm keyboardputstring $command + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 3 + } + if ($NetworkInput) { + & VBoxManage.exe controlvm $vm keyboardputstring 'dhclient' + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 5 + & VBoxManage.exe controlvm $vm keyboardputstring 'ifconfig' + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 2 + & VBoxManage.exe controlvm $vm keyboardputstring 'ping 10.0.2.2' + & VBoxManage.exe controlvm $vm keyboardputscancode 1c 9c + Start-Sleep -Seconds 12 + } + foreach ($program in $OpenPrograms) { + Open-DesktopProgram $mouse $program + Start-Sleep -Seconds 3 + $safeName = $program -replace '[^A-Za-z0-9]', '-' + & VBoxManage.exe controlvm $vm screenshotpng (Join-Path $evidence "app-$safeName-$MemoryMB.png") + if ($LASTEXITCODE -ne 0) { throw "Cannot capture $program." } + } + } finally { + $session.UnlockMachine() + } + } + & VBoxManage.exe controlvm $vm screenshotpng (Join-Path $evidence "screen-$Test-$MemoryMB.png") + $output = Get-Content -LiteralPath $serialPath -Raw + $output | Set-Content -LiteralPath (Join-Path $evidence "boot-$Test-$MemoryMB.log") Write-Output $output if (-not $output -or -not $output.Contains($marker) -or $output.Contains('FAIL:')) { throw 'Boot did not reach its expected completion marker.' } - foreach ($required in @('EXCEPTION_TESTS_PASSED=0000000000000002', 'EXCEPTION_TESTS_FAILED=0000000000000000', - 'PMM_TESTS_FAILED=0000000000000000', 'VMM_TESTS_FAILED=0000000000000000', + if ($Test -eq 'none' -and $output.Contains('HALTED:')) { + throw 'The kernel halted after starting the desktop.' + } + foreach ($required in @('PASS: native unit initialization runs once', 'EXCEPTION_TESTS_PASSED=0000000000000002', 'EXCEPTION_TESTS_FAILED=0000000000000000', + 'PASS: VFS reads ELF64 kernel through AHCI', 'VFS_TESTS_FAILED=0000000000000000', + 'STORMETA_TESTS_FAILED=0000000000000000', 'AHCI_TESTS_FAILED=0000000000000000', 'USBTYPES_TESTS_FAILED=0000000000000000', 'USBCORE_TESTS_FAILED=0000000000000000', + 'USBMSC_TESTS_FAILED=0000000000000000', 'USBKEYBOARD_TESTS_FAILED=0000000000000000', 'USBMOUSE_TESTS_FAILED=0000000000000000', 'USBHUB_TESTS_FAILED=0000000000000000', 'OHCI_TESTS_FAILED=0000000000000000', + 'Device enumerated at address 1', 'IOREQ_TESTS_FAILED=0000000000000000', 'CFIFO_TESTS_FAILED=0000000000000000', 'FSMGR_TESTS_FAILED=0000000000000000', 'PATH_TESTS_FAILED=0000000000000000', 'FNV1A_TESTS_FAILED=0000000000000000', 'HASHMAP_TESTS_FAILED=0000000000000000', 'LISTS_TESTS_FAILED=0000000000000000', 'PMM_TESTS_FAILED=0000000000000000', 'VMM_TESTS_FAILED=0000000000000000', 'HEAP_TESTS_FAILED=0000000000000000', 'IRQ_TESTS_FAILED=0000000000000000', 'CONTEXT_TESTS_FAILED=0000000000000000', 'PROCESS_TESTS_FAILED=0000000000000000', 'FD_TESTS_FAILED=0000000000000000', 'STRINGS_TESTS_FAILED=0000000000000000', 'STDIO_TESTS_FAILED=0000000000000000')) { if (-not $output.Contains($required)) { throw "Missing check: $required" } } - if ($MemoryMB -gt 4096 -and $output.Contains('SKIP: no available physical RAM above 4 GiB')) { + if ($MemoryMB -gt 4096 -and -not $output.Contains('PASS: AHCI DMA above 4 GiB matches every disk sector')) { throw 'High physical memory test was skipped.' } + if ($NetworkInput -and -not $output.Contains('Process ACK.')) { + throw 'Network test did not receive a DHCP acknowledgement.' + } if ($Test -ne 'none') { $vector = @{ud = '6'; pf = 'E'; df = '8'}[$Test] $errorCode = if ($Test -eq 'pf') { '2' } else { '0' } @@ -105,8 +209,14 @@ try { & VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $originalMedium if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original optical medium.' } if ($MemoryMB -ne 0) { + Start-Sleep -Milliseconds 500 & VBoxManage.exe modifyvm $vm --memory $originalMemory if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original VM RAM size.' } } + if ($NetworkInput) { + Start-Sleep -Milliseconds 600 + & VBoxManage.exe modifyvm $vm --nic1 $originalNetwork + if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original network mode.' } + } } }