1 Commits
Author SHA1 Message Date
Daniel Samson 198767bb30 igpu: WIP 2026-07-30 03:53:34 +01:00
110 changed files with 1570 additions and 2859 deletions
-173
View File
@@ -1,173 +0,0 @@
//! The danos build API (docs/build-packages-plan.md): the one shared recipe
//! for building a user-space binary. A binary package's build.zig names its
//! binary and EXACTLY the modules its source imports — the moral equivalent
//! of a C file's include list — and `userBinary` resolves each name from the
//! library domain package that exports it. Nothing is pre-wired: an @import
//! the package did not declare is a compile error, and a domain none of the
//! imports come from never appears in the package's manifest. The only
//! implicit dependency is the kernel package, because the shared root shim
//! (root.zig, user.ld) lives there and itself reaches start + logging.
//!
//! Consumers declare this package in their build.zig.zon (as "build-support")
//! and @import its build.zig from their own build.zig; nothing is compiled
//! from this package itself — it exports build-time functions only.
const std = @import("std");
pub fn build(b: *std.Build) void {
_ = b; // nothing to build: this package exports build-time functions only
}
/// The freestanding x86-64 target every danos binary (kernel and user) is
/// built for. SSE2 is part of the x86_64 baseline and UEFI leaves it enabled
/// at handoff, so we keep it: disabling it forces soft-float and makes the
/// compiler unable to encode the vector ops that std's formatting/runtime
/// still emit.
pub fn freestandingTarget(b: *std.Build) std.Build.ResolvedTarget {
return b.resolveTargetQuery(.{
.cpu_arch = .x86_64,
.os_tag = .freestanding,
.abi = .none,
});
}
/// Which library domain package exports each importable module — the one
/// name -> home table. When a domain grows a module, it gets a row here; a
/// binary naming a module whose home is missing from its own build.zig.zon
/// fails loudly at dependency resolution.
const ModuleHome = struct { name: []const u8, home: []const u8 };
const module_homes = [_]ModuleHome{
// library/kernel — the userspace private-ABI library, split by concern.
.{ .name = "abi", .home = "kernel" },
.{ .name = "system-call", .home = "kernel" },
.{ .name = "ipc", .home = "kernel" },
.{ .name = "time", .home = "kernel" },
.{ .name = "thread", .home = "kernel" },
.{ .name = "logging", .home = "kernel" },
.{ .name = "process", .home = "kernel" },
.{ .name = "file-system", .home = "kernel" },
.{ .name = "memory", .home = "kernel" },
.{ .name = "service", .home = "kernel" },
.{ .name = "start", .home = "kernel" },
// library/device — driver-side libraries + the flat reference data.
.{ .name = "mmio", .home = "device" },
.{ .name = "acpi-ids", .home = "device" },
.{ .name = "device-abi", .home = "device" },
.{ .name = "aml", .home = "device" },
.{ .name = "usb-abi", .home = "device" },
.{ .name = "usb-ids", .home = "device" },
.{ .name = "usb", .home = "device" },
.{ .name = "driver", .home = "device" },
.{ .name = "block", .home = "device" },
.{ .name = "pci", .home = "device" },
.{ .name = "pci-class", .home = "device" },
.{ .name = "device-registry", .home = "device" },
// library/client — userspace service clients.
.{ .name = "display-client", .home = "client" },
.{ .name = "input-client", .home = "client" },
// library/protocol — the wire protocols.
.{ .name = "vfs-protocol", .home = "protocol" },
.{ .name = "input-protocol", .home = "protocol" },
.{ .name = "block-protocol", .home = "protocol" },
.{ .name = "usb-transfer-protocol", .home = "protocol" },
.{ .name = "device-manager-protocol", .home = "protocol" },
.{ .name = "display-protocol", .home = "protocol" },
.{ .name = "scanout-protocol", .home = "protocol" },
.{ .name = "power-protocol", .home = "protocol" },
// library/csv — the /etc/*.csv helpers.
.{ .name = "csv", .home = "csv" },
// library/xkeyboard-config — keycode -> keysym/character tables.
.{ .name = "xkeyboard-config", .home = "xkeyboard-config" },
};
fn moduleHome(name: []const u8) ?[]const u8 {
for (module_homes) |entry| {
if (std.mem.eql(u8, entry.name, name)) return entry.home;
}
return null;
}
/// What `userBinary` needs to know about one user binary.
pub const UserBinaryOptions = struct {
name: []const u8,
/// The program's own source file — it becomes the `program` module the
/// root shim imports; a program only defines `pub fn main`.
root_source_file: std.Build.LazyPath,
/// Exactly the modules the program's source @imports (directly or through
/// its same-directory files) — no more, no less. Order is free; sorted
/// reads best. An undeclared @import fails the compile; a declared name no
/// domain exports fails the build graph with a pointer to module_homes.
imports: []const []const u8,
/// Built multi-threaded (`single_threaded = false`) so real atomics/TLS
/// work — required before a binary may call `Thread.spawn`
/// (docs/threading.md). Threads are a deliberate per-binary opt-in.
threaded: bool = false,
};
/// Build one user-space binary the same way for every program (init, the
/// services, the drivers): freestanding, ReleaseSmall, `.large` code model
/// (the image base is above 4 GiB — smaller models emit 32-bit relocations
/// that can't reach), linked with the shared user link script. Pinned to
/// LLVM + LLD so the script's PHDRS (segment permissions) are authoritative —
/// the kernel's W^X user-ELF loader requires exact perms.
///
/// The compilation root is not the program's own file but the shared shim
/// (the kernel package's root.zig), which supplies the root declarations
/// (`main` re-export, panic handler, `_start` pull) so a program only defines
/// `pub fn main`. The program's file becomes the `program` module the shim
/// imports; reach it through `programModule` to add per-binary non-library
/// modules (compile-time options).
pub fn userBinary(b: *std.Build, options: UserBinaryOptions) *std.Build.Step.Compile {
const kernel = b.dependency("kernel", .{});
var imports: std.ArrayListUnmanaged(std.Build.Module.Import) = .empty;
for (options.imports) |name| {
const home = moduleHome(name) orelse @panic(b.fmt(
"no library domain exports a module named '{s}' — if a domain grew it, add its row to module_homes in build-support/build.zig",
.{name},
));
const dependency = if (std.mem.eql(u8, home, "kernel")) kernel else b.dependency(home, .{});
imports.append(b.allocator, .{ .name = name, .module = dependency.module(name) }) catch @panic("OOM");
}
// Settings (target, optimize, code model, ...) live on the root module
// only; the program module inherits them.
const program_module = b.createModule(.{
.root_source_file = options.root_source_file,
.imports = imports.items,
});
const exe = b.addExecutable(.{
.name = options.name,
.root_module = b.createModule(.{
.root_source_file = kernel.path("root.zig"),
.target = freestandingTarget(b),
.optimize = .ReleaseSmall,
.code_model = .large,
.single_threaded = !options.threaded, // a threaded binary needs real atomics/TLS
.sanitize_c = .off,
.stack_check = false,
.stack_protector = false,
// The root shim itself imports only start (_start + panic) and
// logging (std_options) — straight from the kernel package, so a
// program's own import list stays exactly its own.
.imports = &.{
.{ .name = "start", .module = kernel.module("start") },
.{ .name = "logging", .module = kernel.module("logging") },
.{ .name = "program", .module = program_module },
},
}),
});
exe.setLinkerScript(kernel.path("user.ld"));
exe.entry = .{ .symbol_name = "_start" };
exe.image_base = 0x7000_0000_0000;
exe.use_llvm = true;
exe.use_lld = true;
return exe;
}
/// The `program` module of a binary built by `userBinary` — the module rooted
/// at the program's own source file. Per-binary non-library modules (an
/// addOptions build_options) go here, not on the root shim: module imports
/// are not transitive, so an import added to the root would be invisible to
/// the program's code.
pub fn programModule(exe: *std.Build.Step.Compile) *std.Build.Module {
return exe.root_module.import_table.get("program").?;
}
-8
View File
@@ -1,8 +0,0 @@
.{
.name = .build_support,
.version = "0.0.0",
.fingerprint = 0xad91962994f4be41, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{""},
}
+930 -141
View File
File diff suppressed because it is too large Load Diff
+8 -43
View File
@@ -32,48 +32,6 @@
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
// The danos build API — the shared user-binary recipe every build file
// (root and per-binary packages) consumes (docs/build-packages-plan.md).
.@"build-support" = .{ .path = "build-support" },
// The library domains, each a package exporting its modules.
.kernel = .{ .path = "library/kernel" },
.device = .{ .path = "library/device" },
.client = .{ .path = "library/client" },
.protocol = .{ .path = "library/protocol" },
.csv = .{ .path = "library/csv" },
.@"xkeyboard-config" = .{ .path = "library/xkeyboard-config" },
// Binary packages (phase 2), consumed as artifacts for the boot image.
.@"pci-bus" = .{ .path = "system/drivers/pci-bus" },
.init = .{ .path = "system/services/init" },
.fat = .{ .path = "system/services/fat" },
.display = .{ .path = "system/services/display" },
.@"display-demo" = .{ .path = "system/services/display-demo" },
.@"device-manager" = .{ .path = "system/services/device-manager" },
.input = .{ .path = "system/services/input" },
.logger = .{ .path = "system/services/logger" },
// The discovery pair and the /test fixtures are lazy: only what a
// given build actually ships gets its build file loaded and compiled
// (-Ddiscovery picks one of the pair; -Dtest-case pulls the fixtures).
.acpi = .{ .path = "system/services/acpi", .lazy = true },
.fdt = .{ .path = "system/services/fdt", .lazy = true },
.@"ps2-bus" = .{ .path = "system/drivers/ps2-bus" },
.@"usb-xhci-bus" = .{ .path = "system/drivers/usb-xhci-bus" },
.@"usb-hid" = .{ .path = "system/drivers/usb-hid" },
.@"usb-storage" = .{ .path = "system/drivers/usb-storage" },
.@"virtio-gpu" = .{ .path = "system/drivers/virtio-gpu" },
.@"vfs-test" = .{ .path = "test/system/services/vfs-test", .lazy = true },
.@"fat-test" = .{ .path = "test/system/services/fat-test", .lazy = true },
.@"shared-memory-server" = .{ .path = "test/system/services/shared-memory-server", .lazy = true },
.@"shared-memory-client" = .{ .path = "test/system/services/shared-memory-client", .lazy = true },
.@"crash-test" = .{ .path = "test/system/services/crash-test", .lazy = true },
.@"device-list" = .{ .path = "test/system/services/device-list", .lazy = true },
.@"pci-cap-test" = .{ .path = "test/system/services/pci-cap-test", .lazy = true },
.@"iommu-fault-test" = .{ .path = "test/system/services/iommu-fault-test", .lazy = true },
.@"input-source" = .{ .path = "test/system/services/input-source", .lazy = true },
.@"input-test" = .{ .path = "test/system/services/input-test", .lazy = true },
.@"args-echo" = .{ .path = "test/system/services/args-echo", .lazy = true },
.@"process-test" = .{ .path = "test/system/services/process-test", .lazy = true },
.@"thread-test" = .{ .path = "test/system/services/thread-test", .lazy = true },
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
//.example = .{
// // When updating this field to a new URL, be sure to delete the corresponding
@@ -112,5 +70,12 @@
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{""},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
// For example...
//"LICENSE",
//"README.md",
},
}
-166
View File
@@ -1,166 +0,0 @@
//! Boot-image assembly (docs/build-packages-plan.md, phase 3): everything
//! between "here are the built binaries" and "here is a bootable volume".
//! The FHS-shaped zig-out install tree, the boot manifest, the boot capsule,
//! the FAT32 USB image (+ its serial-enabled twin for the QEMU run steps),
//! and the release ISO — with their check steps. The root build.zig decides
//! WHAT ships (the bundled list); this file owns HOW it becomes an image.
const std = @import("std");
/// One user binary and its FHS home on the boot volume (and in zig-out).
pub const BundledBinary = struct { path: []const u8, binary: std.Build.LazyPath };
pub const Options = struct {
/// The installed/flashable kernel (serial follows the root -Dserial).
kernel: *std.Build.Step.Compile,
/// The serial-enabled kernel variant the `run-x86-64` image boots.
kernel_serial: *std.Build.Step.Compile,
/// The UEFI loader (BOOTX64).
efi: *std.Build.Step.Compile,
/// Every user binary and data file at its FHS path.
bundled: []const BundledBinary,
};
/// Wire up the install tree, both FAT32 boot images, the release ISO, and the
/// check steps. Returns the serial-enabled FAT image for the QEMU run steps.
pub fn addImageSteps(b: *std.Build, options: Options) std.Build.LazyPath {
// Everything installs into a FHS-shaped zig-out: it IS the danos filesystem *and*
// the boot volume. Each binary lands at its addressed, leaf-collapsed path — the
// kernel at zig-out/system/kernel (from system/kernel/kernel.zig), init at
// zig-out/system/services/init, and so on (see docs/README.md). The bootloader
// then loads these FHS paths off the volume.
const kernel_install = b.addInstallArtifact(options.kernel, .{ .dest_dir = .{ .override = .{ .custom = "system" } } });
b.getInstallStep().dependOn(&kernel_install.step);
// UEFI firmware requires the removable-media loader at exactly \EFI\BOOT\BOOTX64.efi,
// so that path is fixed by the firmware (it is /boot's EFI stub, conceptually).
const efi_install = b.addInstallArtifact(options.efi, .{ .dest_dir = .{ .override = .{ .custom = "EFI/BOOT" } } });
b.getInstallStep().dependOn(&efi_install.step);
// The boot manifest: the FHS path of every bundled binary, one per line. The
// EFI loader reads THIS by name and opens each listed path by name — FAT
// name lookup is case-insensitive and firmware-portable, unlike directory
// ENUMERATION, whose returned names vary by firmware (bare 8.3 entries come
// back uppercase on some FAT drivers). The tree walk remains only as the
// loader's fallback for hand-assembled sticks without a manifest.
var manifest_text: std.ArrayListUnmanaged(u8) = .empty;
for (options.bundled) |item| {
manifest_text.append(b.allocator, '/') catch @panic("OOM");
manifest_text.appendSlice(b.allocator, item.path) catch @panic("OOM");
manifest_text.append(b.allocator, '\n') catch @panic("OOM");
}
const manifest_files = b.addWriteFiles();
const manifest_file = manifest_files.add("manifest", manifest_text.items);
const manifest_install = b.addInstallFileWithDir(manifest_file, .prefix, "system/manifest");
b.getInstallStep().dependOn(&manifest_install.step);
// The boot capsule: the same bundled list packed into ONE file (v2
// initial_ramdisk format), because a single open + sequential read is the
// only firmware file I/O shape that is fast everywhere — a per-file tree
// walk measured MINUTES on real firmware. The loader tries this first,
// then the manifest, then the walk; the running system cannot tell the
// difference (it always receives the same in-RAM table). Derived from the
// tree in the same build graph, so the two cannot drift.
const mk_capsule = b.addSystemCommand(&.{"python3"});
mk_capsule.addFileArg(b.path("tools/pack-system-image.py"));
const capsule_img = mk_capsule.addOutputFileArg("system.img");
for (options.bundled) |item| {
mk_capsule.addArg(item.path);
mk_capsule.addFileArg(item.binary);
}
const capsule_install = b.addInstallFile(capsule_img, "boot/system.img");
b.getInstallStep().dependOn(&capsule_install.step);
// Install every bundled binary to its FHS home, so zig-out is a true image of
// the filesystem — the same tree make-fat-image.py lays out on the boot volume.
for (options.bundled) |item| {
const install = b.addInstallFileWithDir(item.binary, .prefix, item.path);
b.getInstallStep().dependOn(&install.step);
}
// --- danos-usb.img: the bootable FAT32 USB image ---
// Format a real FAT32 image (the in-repo Python builder, no external tools)
// holding the EFI stub, the kernel, and the whole /system tree of user
// binaries at their FHS paths. QEMU presents this image as a USB mass-storage
// device the guest boots from (see run-x86-64 and the test harness), and the
// danos fat driver mounts the same image at /mnt/usb.
const fat_image = addBootImage(b, options.kernel.getEmittedBin(), options.efi.getEmittedBin(), manifest_file, capsule_img, options.bundled);
const fat_image_install = b.addInstallFile(fat_image, "danos-usb.img");
b.getInstallStep().dependOn(&fat_image_install.step);
// The image `run-x86-64` boots: identical to the flashable one but with the
// serial log sink compiled in, so a developer always gets the machine-readable
// log captured to serial0 — without baking serial into the image users flash.
// Built lazily (only when `run-x86-64` is requested), and never installed.
const fat_image_serial = addBootImage(b, options.kernel_serial.getEmittedBin(), options.efi.getEmittedBin(), manifest_file, capsule_img, options.bundled);
// `zig build check-fat-image` — validate the produced image is a real FAT32
// with the EFI stub present (the builder's own --verify, no external tools).
const check_fat = b.addSystemCommand(&.{"python3"});
check_fat.addFileArg(b.path("tools/make-fat-image.py"));
check_fat.addArg("--verify");
check_fat.addFileArg(fat_image);
const check_fat_step = b.step("check-fat-image", "Verify the FAT32 USB image is valid and bootable");
check_fat_step.dependOn(&check_fat.step);
// --- release-x86-64: danos-x86-64.iso, the flashable release image ---
// Wrap the FAT32 boot volume in a hybrid ISO (the in-repo Python builder
// again, no xorriso/isohybrid): an ISO9660 whose El Torito EFI boot entry
// and MBR ESP partition entry both point at the embedded FAT image. One
// file then boots every way release media is consumed — flashed raw to a
// USB stick with Etcher or dd, or burned to optical media — while
// danos-usb.img stays the raw superfloppy QEMU and the test harness boot.
const mk_iso = b.addSystemCommand(&.{"python3"});
mk_iso.addFileArg(b.path("tools/make-iso-image.py"));
const iso_image = mk_iso.addOutputFileArg("danos-x86-64.iso");
mk_iso.addFileArg(fat_image);
const iso_install = b.addInstallFile(iso_image, "danos-x86-64.iso");
const release_step = b.step("release-x86-64", "Build the flashable x86-64 release ISO (zig-out/danos-x86-64.iso; flash with Etcher or dd)");
release_step.dependOn(&iso_install.step);
// `zig build check-iso-image` — the ISO builder's own --verify (mirroring
// check-fat-image): the MBR partition, the El Torito catalog, and the
// embedded FAT32 image must all agree.
const check_iso = b.addSystemCommand(&.{"python3"});
check_iso.addFileArg(b.path("tools/make-iso-image.py"));
check_iso.addArg("--verify");
check_iso.addFileArg(iso_image);
const check_iso_step = b.step("check-iso-image", "Verify the release ISO is a valid hybrid (MBR ESP partition + El Torito EFI entry)");
check_iso_step.dependOn(&check_iso.step);
return fat_image_serial;
}
/// Assemble the bootable FAT32 image (the in-repo Python builder) holding the
/// EFI stub, the kernel, and every user binary at its FHS path — the volume's
/// /system tree IS the system image; the EFI loader walks it at boot and builds
/// the in-RAM initial_ramdisk from it. Factored so the serial-enabled
/// `run-x86-64` variant can bundle its own serial kernel while sharing the
/// loader and user tree (the loader's boot breadcrumbs and init's heartbeat both
/// follow the top-level -Dserial). Returns the image's LazyPath.
fn addBootImage(
b: *std.Build,
kernel_bin: std.Build.LazyPath,
efi_bin: std.Build.LazyPath,
manifest: std.Build.LazyPath,
capsule: std.Build.LazyPath,
bundled: []const BundledBinary,
) std.Build.LazyPath {
const mk_fat = b.addSystemCommand(&.{"python3"});
mk_fat.addFileArg(b.path("tools/make-fat-image.py"));
const fat_image = mk_fat.addOutputFileArg("danos-usb.img");
mk_fat.addArg("64"); // MiB
mk_fat.addArg("EFI/BOOT/BOOTX64.efi");
mk_fat.addFileArg(efi_bin);
mk_fat.addArg("system/kernel");
mk_fat.addFileArg(kernel_bin);
mk_fat.addArg("system/manifest");
mk_fat.addFileArg(manifest);
mk_fat.addArg("boot/system.img");
mk_fat.addFileArg(capsule);
for (bundled) |item| {
mk_fat.addArg(item.path);
mk_fat.addFileArg(item.binary);
}
return fat_image;
}
-176
View File
@@ -1,176 +0,0 @@
//! The QEMU run steps (docs/build-packages-plan.md, phase 3): `run-x86-64`
//! boots the serial-enabled FAT image via UEFI/OVMF; `run-x86-64-gpu` adds a
//! virtio-gpu adapter for the native-present display path. OVMF firmware is
//! probed across distro/OS layouts (-Dovmf-code / -Dovmf-vars override).
const std = @import("std");
/// Wire up the `run-x86-64` and `run-x86-64-gpu` steps around the given
/// serial-enabled boot image (the guest boots that self-contained image
/// attached as USB storage, not the installed FHS zig-out).
pub fn addRunSteps(b: *std.Build, fat_image_serial: std.Build.LazyPath) void {
// Firmware lives in different places per OS/distro, so probe the known
// layouts (Architecture, Debian/Ubuntu, Fedora, macOS Homebrew) and use the first
// that exists. Override with -Dovmf-code / -Dovmf-vars if yours is elsewhere.
const ovmf_code = b.option(
[]const u8,
"ovmf-code",
"Path to the OVMF_CODE firmware image",
) orelse firstExisting(b.graph.io, &.{
"/usr/share/edk2/x64/OVMF_CODE.4m.fd", // Architecture
"/usr/share/OVMF/OVMF_CODE_4M.fd", // Debian/Ubuntu
"/usr/share/OVMF/OVMF_CODE.fd", // older Debian/Ubuntu
"/usr/share/edk2-ovmf/x64/OVMF_CODE.fd", // Fedora
"/opt/homebrew/share/qemu/edk2-x86_64-code.fd", // macOS Homebrew (Apple Silicon)
"/usr/local/share/qemu/edk2-x86_64-code.fd", // macOS Homebrew (Intel)
});
const ovmf_vars = b.option(
[]const u8,
"ovmf-vars",
"Path to the OVMF_VARS firmware image (a writable copy is made)",
) orelse firstExisting(b.graph.io, &.{
"/usr/share/edk2/x64/OVMF_VARS.4m.fd", // Architecture
"/usr/share/OVMF/OVMF_VARS_4M.fd", // Debian/Ubuntu
"/usr/share/OVMF/OVMF_VARS.fd", // older Debian/Ubuntu
"/usr/share/edk2-ovmf/x64/OVMF_VARS.fd", // Fedora
"/opt/homebrew/share/qemu/edk2-i386-vars.fd", // macOS Homebrew (Apple Silicon)
"/usr/local/share/qemu/edk2-i386-vars.fd", // macOS Homebrew (Intel)
});
// The firmware needs to write NVRAM, so give it a writable copy of the vars.
const vars_copy = b.addSystemCommand(&.{ "cp", "-f", ovmf_vars });
const vars_out = vars_copy.addOutputFileArg("OVMF_VARS.4m.fd");
// Capture the guest's serial0 (danos's machine-readable log) to the qemu-test
// scratch area — a dev/host artifact, kept out of the FHS boot volume we mount.
// (/var/log/system is reserved for the kernel's own logging system later.) One
// timestamped file per run.
const log_dir = b.fmt("{s}/qemu-test", .{b.install_path});
const make_log_dir = b.addSystemCommand(&.{ "mkdir", "-p", log_dir });
// --- run-x86-64: boot the x86-64 kernel in QEMU via UEFI/OVMF ---
const run_efi = b.addSystemCommand(&.{
"qemu-system-x86_64",
"-device",
"qemu-xhci,id=xhci",
"-device",
"usb-mouse,bus=xhci.0",
"-device",
"usb-kbd,bus=xhci.0",
"-machine",
"q35",
"-m",
"128M",
"-drive",
b.fmt("if=pflash,format=raw,readonly=on,file={s}", .{ovmf_code}),
});
run_efi.addArg("-drive");
run_efi.addPrefixedFileArg("if=pflash,format=raw,file=", vars_out);
// Boot off the FAT32 USB image: a mass-storage device on the same xHCI bus as
// the keyboard and mouse. OVMF finds \EFI\BOOT\BOOTX64.efi on it and boots.
// The serial-enabled variant, so serial0 carries the log for this dev boot.
run_efi.addArg("-drive");
run_efi.addPrefixedFileArg("if=none,id=bootusb,format=raw,file=", fat_image_serial);
run_efi.addArgs(&.{
"-device",
"usb-storage,bus=xhci.0,drive=bootusb,removable=on,bootindex=0",
"-net",
"none",
// Emulated display advertising 1280x720 as its native (EDID preferred)
// resolution, so the kernel's native-resolution switch has something to
// find. `-vga none` avoids a second, default adapter.
"-vga",
"none",
"-device",
"VGA,edid=on,xres=1280,yres=720",
});
const serial_log = b.fmt("{s}/run-x86-64-serial0-{s}.log", .{ log_dir, timestamp(b) });
run_efi.addArgs(&.{ "-serial", b.fmt("file:{s}", .{serial_log}) });
// We boot the self-contained `fat_image_serial` (added as a file arg above, so
// it's already a dependency) — not the installed FHS zig-out — so `run-x86-64`
// builds only the serial kernel, never the flashable one. Just make the serial
// scratch dir first.
run_efi.step.dependOn(&make_log_dir.step);
const run_efi_step = b.step("run-x86-64", "Boot the x86-64 kernel in QEMU (UEFI/OVMF); serial0 is logged to zig-out/qemu-test/run-x86-64-serial0-<timestamp>.log");
run_efi_step.dependOn(&run_efi.step);
// --- run-x86-64-gpu: the same boot plus a virtio-gpu adapter ---
// The VGA device still supplies the boot (GOP) framebuffer the compositor starts
// on; the virtio-gpu function is discovered by the device-manager stack, its
// driver announces a shared scanout, and the compositor upgrades off the GOP
// floor to fenced, tear-free native presents (docs/display-v2.md).
// This is the interactive twin of the `display-native` test case, and 512M
// matches it (the whole driver stack + the compositor's surfaces at once).
// QEMU shows one head per adapter: pick the virtio-gpu head in the View menu
// to watch the native output.
const run_gpu = b.addSystemCommand(&.{
"qemu-system-x86_64",
"-device",
"qemu-xhci,id=xhci",
"-device",
"usb-mouse,bus=xhci.0",
"-device",
"usb-kbd,bus=xhci.0",
"-machine",
"q35",
"-m",
"512M",
"-drive",
b.fmt("if=pflash,format=raw,readonly=on,file={s}", .{ovmf_code}),
});
run_gpu.addArg("-drive");
run_gpu.addPrefixedFileArg("if=pflash,format=raw,file=", vars_out);
run_gpu.addArg("-drive");
run_gpu.addPrefixedFileArg("if=none,id=bootusb,format=raw,file=", fat_image_serial);
run_gpu.addArgs(&.{
"-device",
"usb-storage,bus=xhci.0,drive=bootusb,removable=on,bootindex=0",
"-net",
"none",
"-vga",
"none",
"-device",
"VGA,edid=on,xres=1280,yres=720",
"-device",
"virtio-gpu-pci",
});
const gpu_serial_log = b.fmt("{s}/run-x86-64-gpu-serial0-{s}.log", .{ log_dir, timestamp(b) });
run_gpu.addArgs(&.{ "-serial", b.fmt("file:{s}", .{gpu_serial_log}) });
run_gpu.step.dependOn(&make_log_dir.step);
const run_gpu_step = b.step("run-x86-64-gpu", "Boot in QEMU with a virtio-gpu adapter: the compositor upgrades to fenced (tear-free) native presents; watch the virtio-gpu head in QEMU's View menu");
run_gpu_step.dependOn(&run_gpu.step);
}
/// Return the first path in `candidates` that exists on the build host, else the
/// first candidate as a fallback so a missing-firmware error still names a
/// concrete (and, by convention, the primary) path. Used to locate OVMF firmware
/// across distro/OS layouts without configuration.
fn firstExisting(io: std.Io, candidates: []const []const u8) []const u8 {
for (candidates) |path| {
std.Io.Dir.accessAbsolute(io, path, .{}) catch continue;
return path;
}
return candidates[0];
}
/// A UTC timestamp like "20260708-153045", for naming a per-run artifact so
/// repeated runs don't clobber each other's logs. Resolved when `zig build`
/// runs, which is moments before QEMU launches.
fn timestamp(b: *std.Build) []const u8 {
const ns = std.Io.Clock.now(.real, b.graph.io).nanoseconds;
const secs: u64 = @intCast(@divFloor(ns, std.time.ns_per_s));
const es = std.time.epoch.EpochSeconds{ .secs = secs };
const yd = es.getEpochDay().calculateYearDay();
const md = yd.calculateMonthDay();
const ds = es.getDaySeconds();
return b.fmt("{d:0>4}{d:0>2}{d:0>2}-{d:0>2}{d:0>2}{d:0>2}", .{
yd.year,
md.month.numeric(),
@as(u32, md.day_index) + 1,
ds.getHoursIntoDay(),
ds.getMinutesIntoHour(),
ds.getSecondsIntoMinute(),
});
}
+4 -15
View File
@@ -55,7 +55,9 @@ rather than restate it. Roughly in the order things happen at runtime:
15. **[drivers.md](device-driver-development/drivers.md) — writing a driver.** The payoff: a driver is an
ordinary ring-3 process that claims a device, maps its registers, and **sleeps
until its hardware interrupts it**. The claim is the capability; `irq_ack` is the
unmask.
unmask. The condensed version: the
[new-driver checklist](device-driver-development/new-driver-checklist.md) —
the minimum steps from boot-log line to mapped registers.
16. **[driver-model.md](device-driver-development/driver-model.md) — buses, classes and host controllers.** How
real driver stacks factor into three shapes and how families share code. The
three primitives it proposed are long since built (M13 capability passing,
@@ -263,20 +265,9 @@ test/ → /test the test tree: the QEMU harness (qemu_test.py, h
system/services/ beside the on-image test fixtures — vfs-test/ thread-test/
crash-test/ … — whose repo path IS their boot-volume path
(/test/system/services/<name>)
build-support/ the danos build API (build-time only, nothing on the image):
the shared user-binary recipe + default-import wiring every
build file consumes (docs/build-packages-plan.md)
build/ root-build helpers: image assembly (images.zig) + the QEMU
run steps (qemu.zig)
tools/ host-side build scripts
```
**Builds are packages** (docs/build-packages-plan.md): each `library/` domain owns a
`build.zig`/`build.zig.zon` exporting its modules (with a standalone `zig build test`),
every binary directory is a ~15-line package build, and the root `build.zig`
orchestrates — the kernel + loader, what ships, and the aggregate test step — with
image assembly in `build/images.zig` and the QEMU run steps in `build/qemu.zig`.
**Wire protocols live in `library/protocol/`**, one module per directory
(`library/protocol/vfs/vfs-protocol.zig` is the `vfs-protocol` module), imported by module
name. A protocol is the seam between a low-level driver and the higher-level service it
@@ -331,7 +322,5 @@ exception in [coding-standards.md](coding-standards.md) applies to that seam.
| System services (init, the `fat` filesystem, the device-manager) | `system/services/` |
| Device drivers, one sub-project each (`pci-bus`, `ps2-bus`, `usb-xhci-bus` bus drivers) | `system/drivers/` |
| On-image test fixtures for the QEMU cases (`vfs-test`, `crash-test`, `thread-test`, …) → `/test/system/services` | `test/system/services/` |
| Build orchestration (kernel + loader, what ships, the aggregate test step) | `build.zig` (root; the shared user-binary recipe is `build-support/`, and each `library/` domain + binary package carries its own `build.zig`) |
| Image assembly + `release-x86-64` (the flashable ISO) | `build/images.zig` |
| `run-x86-64` / `run-x86-64-gpu` (QEMU/OVMF) | `build/qemu.zig` |
| Build + `run-x86-64` (QEMU/OVMF) + `release-x86-64` (the flashable ISO) | `build.zig` |
| QEMU integration test harness | `test/qemu_test.py` |
-177
View File
@@ -1,177 +0,0 @@
# Plan: packages — hierarchical builds for libraries and binaries
**Status: complete** (branch `claude/build-packages-plan-174144`). Phase 0
(`build-support`), phase 1 (all six library domains), phase 2 (every binary —
the pci-bus pilot first, then services, drivers, and test fixtures in waves;
multi-binary directories like ps2-bus and usb-hid are one package exporting
several artifacts, and the acpi/fdt discovery pair each export an artifact
named "discovery" that the root's -Ddiscovery picks between), and phase 3 (the
root split into `build/images.zig` + `build/qemu.zig`; the root `build.zig` is
~460 lines of orchestration, down from ~1,250). Every phase landed green: unit
tests, the QEMU suite at parity with main, boot-image file list unchanged.
The `lazyDependency` payoff (What-this-buys #4) is in too: the /test fixtures
and the unselected discovery package are lazy — a build loads and compiles
only what it ships. And imports are exact: the pre-wired default set is gone;
every binary names precisely the modules its source imports and carries only
those domains in its manifest (rule 1 below).
## Why
`build.zig` was ~1,250 lines, growing by three hand-written stanzas per binary;
at a driver per device family that does not scale. More fundamentally: in one
monolithic build every binary compiles against library *source*, so a library
interface break is silently absorbed by whoever edits everything in one commit —
the interface never has to be honest. danos is about isolation; the build should
mirror it.
A **package** here is a build-time unit only — a directory owning a `build.zig`
(recipe: what it exports, how to test it) and a `build.zig.zon` (manifest: name
+ dependencies). Binaries remain fully static freestanding ELFs; packages change
who declares what, not what links to what. Source code is untouched: `@import`
uses module names (`"pci"`, `"service"`) exactly as today — only build files
know where anything lives.
## Target shape
```
build-support/ package: the danos build API (userBinary(), defaultImports(), targets)
library/kernel/ package "kernel": modules abi, ipc, service, memory, process, logging, time, ... (depends on protocol)
library/device/ package "device": modules driver, pci, usb-abi, model, ... (depends on kernel, protocol, csv)
library/protocol/ package "protocol": the wire protocols
library/client/ package "client" (depends on kernel, protocol)
library/csv/ package "csv"
library/xkeyboard-config/ package "xkeyboard-config"
system/services/<name>/ one package per binary: ~15-line build.zig + zon
system/drivers/<name>/ one package per binary
build.zig (root) orchestrator: dependency() per binary, image assembly, QEMU, test steps
```
The three shared contracts: `boot-handoff` stays a root module (only the
loader↔kernel pair speaks it); `abi` is exported by the kernel package from
`../../system/abi.zig` (the source stays with the kernel; userspace's one view
of it lives in the package, so every consumer names the same module instance);
`device-abi` is exported by device. Reaching outside the package root means the
kernel package is valid only as an in-repo path dependency — it could never be
fetched by hash — which is fine: path dependencies are the only way any of
these packages is consumed.
Rules:
- **Imports are exact and per binary.** A binary's build.zig names precisely
the modules its source `@import`s — the moral equivalent of a C file's
include list — and its zon names only the domains those modules come from
(plus `build-support` and `kernel`, which is implicit in every binary: the
root shim and user link script live there). Nothing is pre-wired: an
undeclared `@import` is a compile error, and build-support's one
module-to-domain table (`module_homes`) resolves each name. Availability
never meant bloat — Zig only compiles what a program actually imports — but
exactness makes the declared interface honest and machine-checked.
- **Modules export source, not artifacts** — each consumer compiles libraries
with its own flags, so per-binary optimization choices keep working; Zig's
cache deduplicates.
- **Zon paths are relative and that is accepted.** Binaries sit exactly three
levels deep, so the `../../../` prefix is a constant idiom; a library-domain
move is a rare, already-breaking event fixed by one sed across manifests, and
a stale path fails loudly before anything compiles.
- **Cross-cutting build changes live in `build-support` only** — that is the
contract that keeps per-binary build files declarative.
## What this buys
1. Library interfaces become machine-checked: a consumer can only import what
it declared — per binary, down to the single module — and each domain's zon
declares what it needs (claim-before-touch, applied to source). A keyboard
driver carries `xkeyboard-config` in its manifest; nothing else does.
2. Each library domain gets a standalone `zig build test` — runtime-library
stability testing in isolation.
3. Adding a binary = adding a directory (source + two small files), not editing
three places in a 1,250-line file.
4. `lazyDependency` lets an image target build only what it ships: the /test
fixtures resolve only under -Dtest-case, and only the -Ddiscovery-selected
discovery package ever loads.
## Phases
Each phase ends green: `zig build test` passes (88/88 QEMU) and the boot
image's file list is unchanged. Byte-identical binaries are expected but not
required (module reorganization can perturb symbol order); file list is the
hard gate.
**Phase 0 — `build-support`.** Extract `addUserBinary`/`addThreadedUserBinary`,
the freestanding target setup, and the default-import wiring into the
`build-support` package. Root build consumes it; nothing else moves. This is
the cross-cutting-change home, so it lands first.
**Phase 1 — library domains become packages.** In dependency order: `protocol`
and `csv` (the roots) → `kernel` (depends on protocol: file-system speaks
vfs-protocol) → `device`, `client`; `xkeyboard-config` stands alone. Each gets
build.zig + zon + a standalone test step (client's is empty until its modules
grow host tests — kept for uniformity, since the root aggregate depends on
every domain's test step). The root build swaps its `createModule` calls for
`b.dependency("<domain>").module("<name>")`. **No binary moves in this phase**
— the root build is the pilot consumer, which proves the packages without
touching 30 binaries.
**Phase 2 — binaries become packages, in waves.** The template was shaken out
by the pci-bus pilot (see Status). Wave A: services (done). Wave B: the
remaining drivers (done). Wave C: test fixtures (done). Root build shrank to
orchestration per wave. init's `-Dserial` heartbeat flag rides a dependency
option; a directory with several binaries (ps2-bus, usb-hid) is one package
exporting several artifacts.
**Phase 3 — root cleanup (done).** What remained of the root build split into
`build/images.zig` (the FHS install tree, boot manifest + capsule, FAT32
images, release ISO, check steps) and `build/qemu.zig` (the run steps + OVMF
probing), imported by a short root `build.zig`.
**Afterwards** (outside this plan): the intel-uhd-graphics-750 driver is
(re)created as a greenfield package. The new-driver checklist's build step
(docs/device-driver-development/new-driver-checklist.md, step 2) is already
rewritten against the package template.
## Execution notes (the finished shape)
- The shared recipe lives in `build-support/build.zig`: `userBinary` (what
every binary package calls, resolving each named import through the
`module_homes` table) and `programModule` (for per-binary addOptions
modules). The `start` root shim and `user.ld` are named through the kernel
package (Dependency.path).
- Adding a binary = adding a directory with source + a ~15-line build.zig +
zon (copy any existing binary package, e.g.
`system/drivers/pci-bus/build.zig`) listing exactly the modules the source
imports and the domains they come from, then one dependency + one bundled
entry in the root build.zig and one zon line.
- The boot-tree array in the root (search `"etc/init.csv"` or
`.getEmittedBin()`) is the image file list — the authoritative comparison
target for any future build change.
- Package unit tests live in each package's own `test` step; the root
aggregate depends on every test-bearing package's step, so `zig build test`
at the root still runs everything.
Verification per phase:
- Unit tests: `zig build test`.
- QEMU integration suite: `python3 test/qemu_test.py` (docs/testing.md; the
full suite, all cases must pass).
- Image file list: the boot-tree array is the source of truth — snapshot it
(paths only) before phase 0 and diff after each phase; `zig build
check-fat-image` must also stay green.
Context a fresh session should read first: this doc, docs/testing.md,
docs/coding-standards.md (kebab-case names, no abbreviations), and the
`userBinary`/`userBinaryFromImports` bodies in build-support/build.zig. Commit
style: no Co-Authored-By trailers.
## Risks / notes
- Zig version churn: the package API (`b.dependency`, zon schema) has moved
between releases; the work pins against the repo's current Zig and any
upgrade lands separately, never mid-phase.
- The QEMU size-check tests hardcode source paths (e.g. virtio-gpu protocol
struct sizes) — they moved into their binaries' packages with their waves,
discharging the carry-along obligation.
- Doc updates ride each phase: docs/README.md (repo layout + source map),
docs/device-driver-development/new-driver-checklist.md (step 2) and
devices-csv.md ("Adding a driver"), and the docs that cite the build recipe
(driver-model.md, threading.md, system-requirements.md) reference build
shapes that keep changing.
@@ -96,15 +96,7 @@ in different namespaces — against the right `bus` column.
## Adding a driver
(The step-by-step walkthrough with a worked example is
[new-driver-checklist.md](new-driver-checklist.md).)
1. Create `system/drivers/<name>/` with the driver source plus a ~15-line
package `build.zig` + `build.zig.zon` (copy an existing driver package,
e.g. `system/drivers/pci-bus/`; per-driver extras go through
`build_support.programModule`). Then bundle it at `/system/drivers/<name>`:
one dependency + one bundled entry in the root `build.zig`, one line in the
root `build.zig.zon`.
1. Build the driver binary and bundle it at `/system/drivers/<name>` (build.zig).
2. Add a row to `etc/devices.csv` naming the identity it binds and its full path.
No device-manager change is required — the registry is the seam.
@@ -20,10 +20,9 @@ Read [display.md](display.md) first for the *why*; this is the *what* and the *o
Follow [coding-standards.md](../coding-standards.md): spell out non-acronym abbreviations in
full, kebab-case file names, no `Co-Authored-By` trailers on commits. New user binaries
go through build-support's shared user-binary recipe and get packed into the
initial-ramdisk; protocols are modules exported by the `library/protocol` package.
(This section predates the build-packages split; see
[build-packages-plan.md](../build-packages-plan.md) for the current build shape.)
go through `addUserBinary` in [build.zig](../../build.zig) and get packed into the
initial-ramdisk; protocols are `b.addModule("…-protocol", …)` and imported into the
`runtime` module.
## How to verify along the way
@@ -18,11 +18,9 @@ lands on its own and ends in a **verifiable gate** — shaped for a `/loop` run,
Follow [coding-standards.md](../coding-standards.md): spell out non-acronym abbreviations,
kebab-case file names, no `Co-Authored-By` trailers. New user binaries go through
build-support's shared user-binary recipe and get packed into the initial-ramdisk;
protocols are modules exported by the `library/protocol` package; new syscalls extend
[abi.zig](../../system/abi.zig) `SystemCall` + a `library/kernel` wrapper.
(This section predates the build-packages split; see
[build-packages-plan.md](../build-packages-plan.md) for the current build shape.)
`addUserBinary` and get packed into the initial-ramdisk; protocols are
`b.addModule("…-protocol", …)` imported into `runtime`; new syscalls extend
[abi.zig](../../system/abi.zig) `SystemCall` + a `library/runtime` wrapper.
## How to verify along the way
+1 -1
View File
@@ -29,7 +29,7 @@ which one you're holding decides what you can do.
- **The PCI class-0x03 device is the raw controller** — BARs, config space, registers,
IO ports. It is what you actually *own* after boot. On QEMU's emulated adapter
([`-device VGA,edid=on`](../../build/qemu.zig), the Bochs VBE/DISPI model) the `base` GOP handed
([`-device VGA,edid=on`](../../build.zig), the Bochs VBE/DISPI model) the `base` GOP handed
you *is* that device's linear-framebuffer BAR — the same physical memory, seen through
a different door. On a real discrete GPU, GOP's `base` is an aperture inside the GPU's
VRAM BAR. danos already decodes this device
+7 -11
View File
@@ -138,17 +138,13 @@ a higher-level service (block ↔ filesystem, a scanout driver ↔ the composito
private wire to its *hardware* — virtio-gpu's command set — is not that; it stays a
driver-private file, like the virtio-pci transport beside it.
The build side of this has since landed: every binary owns a package whose
~15-line `build.zig` names EXACTLY the modules its source imports — the moral
equivalent of a C file's include list — and the shared recipe in
[`build-support/build.zig`](../../build-support/build.zig) (`userBinary`)
resolves each name from the library domain that exports it (kernel's concern
modules, the device driver libraries, the service clients, the protocols). An
undeclared `@import` is a compile error, and a domain none of the imports come
from never appears in the binary's manifest — a keyboard driver declares
`xkeyboard-config`; nothing else does (see
[build-packages-plan.md](../build-packages-plan.md)). That's the *entire*
mechanism — Zig modules already give you everything else.
The build side of this has since landed: [`addUserBinary`](build.zig) injects the
default modules — the library/kernel concern modules (`ipc`, `memory`, `process`, `time`,
`logging`, `file-system`, `thread`, `service`), the device/service clients (`driver`,
`block`, `display`, `input`), plus `mmio`, `xkeyboard-config`, `acpi-ids` — into every user
binary, and per-binary extras — protocol modules, bus logic — are added with
`programModule(exe).addImport(...)`. That's the *entire* mechanism — Zig modules
already give you everything else.
The discipline that makes this work: **a class driver must not import a bus's *hardware*
logic module.** `usb-hid` imports `usb` (the transfer client) and `input-protocol`, never
+3 -1
View File
@@ -4,7 +4,9 @@ In a monolithic kernel a driver is a function call away from everything: it runs
ring 0, dereferences any physical address, and its interrupt handler *is* the ISR. In
danos a driver is **an ordinary ring-3 process**. It has its own address space, it
can crash without taking the kernel with it, and — the point of this document — it
can be restarted ([resilience](../os-development/resilience.md)).
can be restarted ([resilience](../os-development/resilience.md)). This document is
the reasoning; the condensed do-this-then-that version is the
[new-driver checklist](new-driver-checklist.md).
That leaves three questions the kernel has to answer, because a process can't answer
them for itself:
@@ -1,218 +0,0 @@
# New driver: the minimum steps
The shortest path from "a device shows up in the boot log" to "my process is
running with its registers mapped". This is the checklist; the reasoning behind
every step lives in [Writing a driver](drivers.md), the matching rules in
[devices.csv](devices-csv.md), and interrupts in
[device interrupts](device-interrupts.md).
Worked example throughout: the Intel UHD 750 iGPU, which the boot log reports as
```
pci-bus: 0:2.0 bus=pci base=03 class=00 prog_if=00 vendor=8086 device=4C8A ...
```
## 1. Create the source file
`system/drivers/<name>/<name>.zig` — kebab-case, abbreviations spelled out
([coding standards](../coding-standards.md)). The directory name, the binary
name, and the `devices.csv` driver path must all agree; a mismatch fails
silently (the device-manager logs the spawn failure, nothing else happens).
The complete minimal driver — claims its device, logs every resource, maps the
register window, then sleeps in the harness loop:
```zig
//! /system/drivers/intel-uhd-graphics-750 — spawned by the device manager with
//! the device-tree id as argv[1]; claims that device and no other.
const std = @import("std");
const device = @import("driver");
const ipc = @import("ipc");
const memory = @import("memory");
const process = @import("process");
const service = @import("service");
/// No protocol yet: the kernel's IPC ceiling (MESSAGE_MAXIMUM) sizes the buffers.
const message_maximum = 256;
var controller_id: u64 = 0;
var register_base: usize = 0;
fn initialise(endpoint: ipc.Handle) bool {
_ = endpoint; // needed later, for irq binding and timers
if (!device.claim(controller_id)) {
std.log.err("unable to claim device {d}", .{controller_id});
return false;
}
// Fetch our own descriptor back for the device's resources.
const buffer = memory.allocator().alloc(device.DeviceDescriptor, 64) catch return false;
defer memory.allocator().free(buffer);
const total = device.enumerate(buffer);
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == controller_id) break d;
} else {
std.log.err("device {d} not in the device tree", .{controller_id});
return false;
};
// Log every resource BEFORE choosing one (see step 5).
var register_index: u64 = 0;
for (descriptor.resources[0..@intCast(descriptor.resource_count)], 0..) |resource, index| {
std.log.info("resource {d}: kind={d} start=0x{x} len=0x{x}", .{
index, resource.kind, resource.start, resource.len,
});
// The 16 MiB window is GTTMMADR, the register BAR (this device also has
// a 256 MiB memory BAR, GMADR — "first memory resource" would be wrong).
if (resource.kind == @intFromEnum(device.ResourceKind.memory) and
resource.len == 16 * 1024 * 1024) register_index = index;
}
if (register_index == 0) {
std.log.err("register BAR not found", .{});
return false;
}
register_base = device.mmioMap(controller_id, register_index) orelse {
std.log.err("mmio_map failed", .{});
return false;
};
std.log.info("registers mapped at 0x{x}", .{register_base});
return true;
}
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?ipc.Handle) usize {
_ = message;
_ = reply;
_ = sender;
_ = capability;
return 0; // no protocol yet; the zero-length ping is answered by the harness
}
pub fn main(init: process.Init) void {
const argument = init.arguments.get(1) orelse {
std.log.err("missing device id (argv[1])", .{});
return;
};
controller_id = std.fmt.parseInt(u64, argument, 10) catch {
std.log.err("malformed device id '{s}'", .{argument});
return;
};
service.run(message_maximum, .{
.init = initialise,
.on_message = onMessage,
// .on_notification only once an IRQ or timer is bound
});
}
```
`claim` is the capability gate: MMIO mapping, DMA grants, and IRQ binding all
require it, and it pins the IOMMU domain to this process
([drivers.md — claim before touch](drivers.md#the-capability-claim-before-touch)).
## 2. Create the build package and register it in the root build
The driver directory is its own build package
([build-packages-plan.md](../build-packages-plan.md)): a ~15-line `build.zig`
plus a `build.zig.zon` beside the source. Copy both from an existing driver —
`system/drivers/pci-bus/` is the template — and adjust the name, root source
file, and the import list. The list names EXACTLY the modules the driver's
source `@import`s (the moral equivalent of its include list; an undeclared
import is a compile error):
```zig
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "intel-uhd-graphics-750",
.root_source_file = b.path("intel-uhd-graphics-750.zig"),
.imports = &.{ "driver", "ipc", "memory", "process", "service" },
});
b.installArtifact(exe);
}
```
The zon declares `build-support`, `kernel` (implicit in every binary: the root
shim lives there), and the homes of the listed imports — for the minimal
driver above that is kernel alone plus `device` (for `driver`); add
`protocol`, `client`, ... only when an import comes from them (again, copy
pci-bus's zon and adjust). For the `.fingerprint` field, leave the copied
value in place and `zig build` will reject it and suggest the fresh one to
paste.
Then three one-liners in the root build register the package: the dependency
and a row in the boot-tree array in `build.zig` (search for
`virtio_gpu_package` to land in the right places),
```zig
const intel_uhd_graphics_750_exe = b.dependency("intel-uhd-graphics-750", .{}).artifact("intel-uhd-graphics-750");
```
```zig
.{ .path = "system/drivers/intel-uhd-graphics-750", .binary = intel_uhd_graphics_750_exe.getEmittedBin() },
```
and the path entry in the root `build.zig.zon`:
```zig
.@"intel-uhd-graphics-750" = .{ .path = "system/drivers/intel-uhd-graphics-750" },
```
Without the boot-tree row the binary never reaches the image and the
device-manager has nothing to spawn. (The package also builds standalone:
`cd system/drivers/intel-uhd-graphics-750 && zig build`.)
## 3. Add the match rule to `etc/devices.csv`
One row: bus, class triplet, vendor/device, driver path. **Copy the class
triplet from the pci-bus boot log line, not from another row** — for the iGPU
above the correct rule is
```
pci, 03, 00, 00, 8086, 4C8A, *, *, /system/drivers/intel-uhd-graphics-750
```
Field-by-field rules and the most-specific-wins policy: [devices.csv](devices-csv.md).
The registry is authoritative: an unmatched device is logged unbound, never
guessed — so a wrong nibble here means the driver simply never starts.
## 4. First contact: read, predict, verify
Before writing any register, read one whose value you can predict from state
the firmware already programmed (for a display controller: the pipe source
size of the live mode). Registers are volatile loads at `register_base +
offset`, where `offset` is what the device's manual lists:
```zig
fn read32(offset: usize) u32 {
return @as(*volatile u32, @ptrFromInt(register_base + offset)).*;
}
```
A matching read proves the whole chain — CSV match, spawn, claim, BAR choice,
mapping — with zero risk to the hardware.
## 5. Verify the plumbing
- `zig build test` still passes.
- On the image: `/var/log/<boot-stamp>/system/services/device-manager.log`
shows `spawned <name> for device <N>`, and
`/var/log/<boot-stamp>/system/drivers/<name>.log` holds the resource list and
your first read.
- If the driver did not spawn, diagnose in this order: binary on the image
(step 2) → CSV row matches the log line exactly (step 3) → path identical in
both (step 1).
## Later, when the device needs them
- **Interrupts**: MSI/MSI-X via the `pci` module, delivered as notifications to
`on_notification` — see [device interrupts](device-interrupts.md) and the
xHCI driver's `setupMsi` (QEMU trap documented there: enable MSI-X before
unmasking the device's own interrupt-enable bit).
- **DMA**: grant-backed buffers, bounded by the IOMMU domain established at
claim time ([driver model](driver-model.md)).
- **Children**: a bus driver publishes what it finds via `device_register`
([drivers.md — publishing children](drivers.md#publishing-children-device_register)).
- **A protocol**: replace `message_maximum` with the protocol's own maximum and
dispatch on the operation word in `onMessage` — every service under
`system/services/` is an example.
+2 -3
View File
@@ -24,9 +24,8 @@ EFI/BOOT/BOOTX64.efi <- the "removable media" default for x86-64
```
The boot volume is **FHS-shaped** (see the repository-layout note in
[README.md](../README.md)): the root `build.zig` compiles `boot/efi.zig` (built
for the `uefi` target) and `build/images.zig` places it at
`EFI/BOOT/BOOTX64.efi` — the one path UEFI firmware fixes — and lays
[README.md](../README.md)): `build.zig` installs `boot/efi.zig` (built for the `uefi`
target) at `EFI/BOOT/BOOTX64.efi` — the one path UEFI firmware fixes — and lays
the rest out by FHS path: the kernel at `system/kernel`, init at
`system/services/init`, the pre-packed boot capsule at `boot/system.img`
([system-image.md](system-image.md)).
+5 -6
View File
@@ -22,12 +22,11 @@ lands on its own and ends in a **verifiable gate** — shaped for a `/loop` run,
## Conventions
Follow [coding-standards.md](../coding-standards.md): spell out non-acronym abbreviations,
kebab-case file names, no `Co-Authored-By` trailers. New user binaries are
packages whose build.zig calls `build_support.userBinary` (with `.threaded =
true` where a binary spawns threads) and get packed into the initial-ramdisk;
new syscalls extend [abi.zig](../../system/abi.zig) `SystemCall` + a
`library/kernel` wrapper; test services live beside the code they exercise and
register a `ServiceId` if they must be looked up.
kebab-case file names, no `Co-Authored-By` trailers. New user binaries go through
`addUserBinary` (with the new `threaded` flag where a binary spawns threads) and get
packed into the initial-ramdisk; new syscalls extend [abi.zig](../../system/abi.zig)
`SystemCall` + a `library/runtime` wrapper; test services live beside the code they
exercise and register a `ServiceId` if they must be looked up.
## How to verify along the way
+6 -8
View File
@@ -61,10 +61,9 @@ runtime — rebuilt in lockstep — knows the mapping.
backend would either bake danos syscall numbers into std (breaking ABI privacy and
renumbering) or fork std to route back through the runtime — a permanent rebase
cost that buys nothing the native type doesn't.
2. **Our user binaries are built `single_threaded = true`** (the shared recipe in
[build-support/build.zig](../../build-support/build.zig)), which compiles threading
out entirely and makes atomics and TLS single-threaded. Threads need this flipped
per binary regardless.
2. **Our user binaries are built `single_threaded = true`** ([build.zig](../../build.zig)
`addUserBinary`), which compiles threading out entirely and makes atomics and TLS
single-threaded. Threads need this flipped per binary regardless.
So we take the *shape* of `std.Thread`, not the *type*. The cost of replicating the
surface (spawn/join/Mutex/Condition) is small; the cost of the std type is the ABI
@@ -237,10 +236,9 @@ see the intro). Two scoped pieces, as built:
### Build: multi-threaded codegen, opt-in
A binary opts in with `.threaded = true` in its package's
`build_support.userBinary` call — the shared recipe in build-support then builds it
`single_threaded = false` — so atomics
and (later) TLS are real. Threads and atomics are unsound in a `single_threaded` image,
A binary opts in by being added with `addThreadedUserBinary` — as `addUserBinary`,
but the shared implementation builds it `single_threaded = false` — so atomics and
(later) TLS are real. Threads and atomics are unsound in a `single_threaded` image,
so a binary must opt in **before** it may call `Thread.spawn`. Everyone else
stays single-threaded and lean.
+3 -3
View File
@@ -95,9 +95,9 @@ hypervisor configured for UEFI firmware and an xHCI USB controller.
| Requirement | Detail | Source |
|---|---|---|
| **x86-64, 64-bit only** | Kernel and loader are built exclusively for `x86_64`; the loader rejects any non-x86-64 kernel ELF (`error.WrongArchitecture`). | `build-support/build.zig` (`freestandingTarget`), `boot/efi.zig:622` |
| **x86-64, 64-bit only** | Kernel and loader are built exclusively for `x86_64`; the loader rejects any non-x86-64 kernel ELF (`error.WrongArchitecture`). | `build.zig:481`, `boot/efi.zig:622` |
| **Long mode + PAE + NX** | AP trampoline sets `CR4.PAE`, `EFER.LME`, `EFER.NXE`; NX is used in kernel page-table entries. | `system/kernel/architecture/x86_64/trampoline.s:62` |
| **SSE / SSE2** | Baseline: the compiler emits SSE for ordinary struct copies. Trampoline enables `CR4.OSFXSR` + `OSXMMEXCPT` and clears `CR0.EM`. | `build-support/build.zig` (`freestandingTarget`), `trampoline.s:62` |
| **SSE / SSE2** | Baseline: the compiler emits SSE for ordinary struct copies. Trampoline enables `CR4.OSFXSR` + `OSXMMEXCPT` and clears `CR0.EM`. | `build.zig:477`, `trampoline.s:62` |
| **`syscall` / `sysret`** | Primary user↔kernel entry path. `EFER.SCE` enabled; `STAR`/`LSTAR`/`SFMASK` programmed per core. (`int 0x80` exists as a parallel gate.) | `architecture/x86_64/per-cpu.zig:71`, `isr.s:196` |
| **Local APIC (xAPIC)** | LAPIC accessed via MMIO at `0xFEE00000`. LAPIC ID read as a `u8` — classic xAPIC. **x2APIC is not supported** (no MSR path). | `apic.zig:67`, `apic.zig:646` |
| **CPUID + RDTSC** | CPUID leaf `0x15` for TSC frequency; RDTSC is the monotonic clock. | `apic.zig:333`, `apic.zig:113` |
@@ -108,7 +108,7 @@ hypervisor configured for UEFI firmware and an xHCI USB controller.
- **UEFI only.** A custom UEFI application loader is installed to
`\EFI\BOOT\BOOTX64.efi`. There is **no BIOS, multiboot, or limine** path. The
loader tolerates UEFI Class-3 machines with no legacy PIC/PIT.
(`build/images.zig` — the EFI/BOOT install — and `boot/efi.zig`)
(`build.zig:246`, `boot/efi.zig`)
- **ACPI is the hardware-discovery mechanism.** The RSDP is taken from the UEFI
configuration table (ACPI 2.0 GUID preferred, 1.0 fallback). Without a valid
RSDP there is **no device discovery** — no SMP, no IOAPIC routing, no PCI/USB.
+1 -3
View File
@@ -12,9 +12,7 @@ There are two layers:
`system/abi.zig`, `library/device/model/device-abi.zig`) now spans ~26 modules:
protocol and on-wire definitions (VFS, USB, virtio-gpu), the FAT engine, the
display compositor, PS/2 and HID decoding, the kernel log ring, and the
runtime's `time`/`thread` — the list is distributed across the library-domain
and binary packages' own `test` steps, which the root `zig build test`
aggregates (docs/build-packages-plan.md).
runtime's `time`/`thread` — the full list is the test step in `build.zig`.
These compile for the host and run natively.
- **QEMU integration tests** (`python3 test/qemu_test.py`) — boot the real kernel
and check its behaviour. This is the interesting part.
+339
View File
@@ -0,0 +1,339 @@
Vendor ID,Device ID,Graphics Family,GPU Name
0x8086,0x0152,HD Graphics,Xeon E3-1200 v2/3rd Gen Core GT1
0x8086,0x0155,HD Graphics,Xeon E3-1200 v2/3rd Gen Core
0x8086,0x0156,HD Graphics,Ivy Bridge mobile GT1
0x8086,0x0157,HD Graphics,Ivy Bridge mobile GT1
0x8086,0x015a,HD Graphics,Xeon E3-1200 v2/Ivy Bridge
0x8086,0x0162,HD Graphics,Ivy Bridge GT2 (HD Graphics 4000)
0x8086,0x0166,HD Graphics,Ivy Bridge mobile GT2 (HD Graphics 4000)
0x8086,0x016a,HD Graphics,Xeon E3-1200 v2/3rd Gen Core GT3
0x8086,0x0402,HD Graphics,Xeon E3-1200 v3/4th Gen Core GT1
0x8086,0x0406,HD Graphics,Haswell GT1
0x8086,0x040a,HD Graphics,Xeon E3-1200 v3 GT1
0x8086,0x040b,HD Graphics,Haswell GT1
0x8086,0x040e,HD Graphics,Haswell GT1
0x8086,0x0412,HD Graphics,Xeon E3-1200 v3/4th Gen Core GT2
0x8086,0x0416,HD Graphics,4th Gen Core GT2
0x8086,0x041a,HD Graphics,Xeon E3-1200 v3 GT2
0x8086,0x041b,HD Graphics,Haswell GT2
0x8086,0x041e,HD Graphics,4th Gen Core Family GT2
0x8086,0x0422,HD Graphics,Haswell GT3
0x8086,0x0426,HD Graphics,Haswell GT3
0x8086,0x042a,HD Graphics,Haswell GT3
0x8086,0x042b,HD Graphics,Haswell GT3
0x8086,0x042e,HD Graphics,Haswell GT3
0x8086,0x0a02,HD Graphics,Haswell-ULT GT1
0x8086,0x0a06,HD Graphics,Haswell-ULT GT1
0x8086,0x0a0a,HD Graphics,Haswell-ULT GT1
0x8086,0x0a0b,HD Graphics,Haswell-ULT GT1
0x8086,0x0a0e,HD Graphics,Haswell-ULT GT1
0x8086,0x0a12,HD Graphics,Haswell-ULT GT2
0x8086,0x0a16,HD Graphics,Haswell-ULT GT2
0x8086,0x0a1a,HD Graphics,Haswell-ULT GT2
0x8086,0x0a1b,HD Graphics,Haswell-ULT GT2
0x8086,0x0a1e,HD Graphics,Haswell-ULT GT2
0x8086,0x0a22,HD Graphics,Haswell-ULT GT2
0x8086,0x0a26,HD Graphics,Haswell-ULT GT2
0x8086,0x0a2a,HD Graphics,Haswell-ULT GT2
0x8086,0x0a2b,HD Graphics,Haswell-ULT GT2
0x8086,0x0a2e,HD Graphics,Haswell-ULT GT2
0x8086,0x0d02,Iris Pro Graphics,Crystal Well GT1
0x8086,0x0d06,Iris Pro Graphics,Crystal Well GT2
0x8086,0x0d0a,Iris Pro Graphics,Crystal Well GT2
0x8086,0x0d0b,Iris Pro Graphics,Crystal Well GT2
0x8086,0x0d0e,Iris Pro Graphics,Crystal Well GT2
0x8086,0x0d12,Iris Pro Graphics,Crystal Well GT3 (Iris Pro 5200)
0x8086,0x0d16,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d1a,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d1b,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d1e,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d22,Iris Pro Graphics,Crystal Well (Iris Pro 5200)
0x8086,0x0d26,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d2a,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d2b,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d2e,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d32,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d36,Iris Pro Graphics,Crystal Well GT3
0x8086,0x0d3a,Iris Pro Graphics,Crystal Well GT3
0x8086,0x1602,HD Graphics,Broadwell-U GT1
0x8086,0x1606,HD Graphics,Broadwell-U GT1
0x8086,0x160a,HD Graphics,Broadwell-U GT1
0x8086,0x160b,HD Graphics,Broadwell-U GT1
0x8086,0x160d,HD Graphics,Broadwell-U GT1
0x8086,0x160e,HD Graphics,Broadwell-U GT1
0x8086,0x1612,HD Graphics,Broadwell-H GT2 (HD Graphics 5600)
0x8086,0x1616,HD Graphics,Broadwell-U GT2 (HD Graphics 5500)
0x8086,0x161a,HD Graphics,Broadwell-U GT2
0x8086,0x161b,HD Graphics,Broadwell-U GT2
0x8086,0x161d,HD Graphics,Broadwell-U GT2
0x8086,0x161e,HD Graphics,Broadwell-Y GT2 (HD Graphics 5300)
0x8086,0x1622,Iris Pro Graphics,Broadwell-DT/H GT3 (Iris Pro 6200)
0x8086,0x1626,HD Graphics,Broadwell-U GT3 (HD Graphics 6000)
0x8086,0x162a,Iris Pro Graphics,Broadwell-DT GT3 (Iris Pro P6300)
0x8086,0x162b,Iris Graphics,Broadwell-U GT3 (Iris 6100)
0x8086,0x162d,HD Graphics,Broadwell-U GT3
0x8086,0x162e,HD Graphics,Broadwell-U GT3
0x8086,0x1632,HD Graphics,Broadwell-U GT3
0x8086,0x1636,HD Graphics,Broadwell-U GT3
0x8086,0x163a,HD Graphics,Broadwell-U GT3
0x8086,0x163b,HD Graphics,Broadwell-U GT3
0x8086,0x163d,HD Graphics,Broadwell-U GT3
0x8086,0x163e,HD Graphics,Broadwell-U GT3
0x8086,0x1902,HD Graphics,Skylake-S GT1 (HD Graphics 510)
0x8086,0x1906,HD Graphics,Skylake-U GT1 (HD Graphics 510)
0x8086,0x190a,HD Graphics,Skylake-DT GT1
0x8086,0x190b,HD Graphics,Skylake GT1 (HD Graphics 510)
0x8086,0x190e,HD Graphics,Skylake GT1
0x8086,0x1912,HD Graphics,Skylake-S GT2 (HD Graphics 530)
0x8086,0x1913,HD Graphics,Skylake GT2
0x8086,0x1915,HD Graphics,Skylake GT2
0x8086,0x1916,HD Graphics,Skylake-U GT2 (HD Graphics 520)
0x8086,0x1917,HD Graphics,Skylake GT2
0x8086,0x191a,HD Graphics,Skylake GT2
0x8086,0x191b,HD Graphics,Skylake-H GT2 (HD Graphics 530)
0x8086,0x191d,HD Graphics,Skylake-DT/H GT2 (HD Graphics P530)
0x8086,0x191e,HD Graphics,Skylake-Y GT2 (HD Graphics 515)
0x8086,0x1921,HD Graphics,Skylake GT2 (HD Graphics 520)
0x8086,0x1923,HD Graphics,Skylake GT2 (HD Graphics 535)
0x8086,0x1926,Iris Graphics,Skylake-U GT3 (Iris Graphics 540)
0x8086,0x1927,Iris Graphics,Skylake-U GT3 (Iris Graphics 550)
0x8086,0x192a,Iris Graphics,Skylake GT3
0x8086,0x192b,Iris Graphics,Skylake GT3 (Iris Graphics 555)
0x8086,0x192d,Iris Graphics,Skylake-H GT3 (Iris Graphics P555)
0x8086,0x1932,Iris Pro Graphics,Skylake GT4 (Iris Pro 580)
0x8086,0x193a,Iris Pro Graphics,Skylake-H GT4 (Iris Pro P580)
0x8086,0x193b,Iris Pro Graphics,Skylake-H GT4 (Iris Pro 580)
0x8086,0x193d,Iris Pro Graphics,Skylake-H GT4 (Iris Pro P580)
0x8086,0x1a84,UHD Graphics,Skylake-DT
0x8086,0x1a85,UHD Graphics,Skylake-DT
0x8086,0x5902,HD Graphics,Kaby Lake-S GT1 (HD Graphics 610)
0x8086,0x5906,HD Graphics,Kaby Lake-U GT1 (HD Graphics 610)
0x8086,0x5908,HD Graphics,Kaby Lake GT1
0x8086,0x590a,HD Graphics,Kaby Lake GT1
0x8086,0x590b,HD Graphics,Kaby Lake GT1 (HD Graphics 610)
0x8086,0x590e,HD Graphics,Kaby Lake GT1
0x8086,0x5912,HD Graphics,Kaby Lake-S GT2 (HD Graphics 630)
0x8086,0x5913,HD Graphics,Kaby Lake GT2
0x8086,0x5915,HD Graphics,Kaby Lake GT2
0x8086,0x5916,HD Graphics,Kaby Lake-U GT2 (HD Graphics 620)
0x8086,0x5917,UHD Graphics,Kaby Lake-R GT2 (UHD Graphics 620)
0x8086,0x591a,HD Graphics,Kaby Lake GT2
0x8086,0x591b,HD Graphics,Kaby Lake-H GT2 (HD Graphics 630)
0x8086,0x591c,UHD Graphics,Kaby Lake GT2 (UHD Graphics 615)
0x8086,0x591d,HD Graphics,Kaby Lake-DT GT2 (HD Graphics P630)
0x8086,0x591e,HD Graphics,Kaby Lake-Y GT2 (HD Graphics 615)
0x8086,0x5921,HD Graphics,Kaby Lake GT2 (HD Graphics 620)
0x8086,0x5923,HD Graphics,Kaby Lake GT2 (HD Graphics 635)
0x8086,0x5926,Iris Plus Graphics,Kaby Lake-U GT3 (Iris Plus 640)
0x8086,0x5927,Iris Plus Graphics,Kaby Lake-U GT3 (Iris Plus 650)
0x8086,0x592a,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x592b,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x5932,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x593a,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x593b,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x593d,Iris Plus Graphics,Kaby Lake GT3
0x8086,0x5a40,Intel Graphics,Apollolake
0x8086,0x5a41,Intel Graphics,Apollolake
0x8086,0x5a42,Intel Graphics,Apollolake
0x8086,0x5a44,Intel Graphics,Apollolake
0x8086,0x5a49,Intel Graphics,Apollolake
0x8086,0x5a4a,Intel Graphics,Apollolake
0x8086,0x5a4c,Intel Graphics,Apollolake
0x8086,0x5a50,Intel Graphics,Apollolake
0x8086,0x5a51,Intel Graphics,Apollolake
0x8086,0x5a52,Intel Graphics,Apollolake
0x8086,0x5a54,Intel Graphics,Apollolake
0x8086,0x5a59,Intel Graphics,Apollolake
0x8086,0x5a5a,Intel Graphics,Apollolake
0x8086,0x5a5c,Intel Graphics,Apollolake
0x8086,0x5a71,Intel Graphics,Apollolake
0x8086,0x5a79,Intel Graphics,Apollolake
0x8086,0x5a84,HD Graphics,Apollo Lake GT1 (HD Graphics 505)
0x8086,0x5a85,HD Graphics,Apollo Lake GT1 (HD Graphics 500)
0x8086,0x3184,UHD Graphics,GeminiLake (UHD Graphics 605)
0x8086,0x3185,UHD Graphics,GeminiLake (UHD Graphics 600)
0x8086,0x3e90,UHD Graphics,Coffee Lake-S GT1 (UHD Graphics 610)
0x8086,0x3e91,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics 630)
0x8086,0x3e92,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics 630)
0x8086,0x3e93,UHD Graphics,Coffee Lake-S GT1 (UHD Graphics 610)
0x8086,0x3e94,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics P630)
0x8086,0x3e96,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics P630)
0x8086,0x3e98,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics 630)
0x8086,0x3e99,UHD Graphics,Coffee Lake GT2
0x8086,0x3e9a,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics P630)
0x8086,0x3e9b,UHD Graphics,Coffee Lake-H GT2 (UHD Graphics 630)
0x8086,0x3e9c,UHD Graphics,Coffee Lake-S GT1 (UHD Graphics 610)
0x8086,0x3ea0,UHD Graphics,Whiskey Lake-U GT2 (UHD Graphics 620)
0x8086,0x3ea1,UHD Graphics,Whiskey Lake-U GT1 (UHD Graphics 610)
0x8086,0x3ea2,UHD Graphics,Whiskey Lake GT1
0x8086,0x3ea3,UHD Graphics,Whiskey Lake GT1
0x8086,0x3ea4,UHD Graphics,Whiskey Lake GT1
0x8086,0x3ea5,Iris Plus Graphics,Coffee Lake-U GT3e (Iris Plus 655)
0x8086,0x3ea6,Iris Plus Graphics,Coffee Lake-U GT3 (Iris Plus 645)
0x8086,0x3ea7,Iris Plus Graphics,Whiskey Lake GT3
0x8086,0x3ea8,Iris Plus Graphics,Coffee Lake-U GT3 (Iris Plus 655)
0x8086,0x3ea9,UHD Graphics,Coffee Lake-U GT2 (UHD Graphics 620)
0x8086,0x87c0,UHD Graphics,9th Gen Core (UHD Graphics 617)
0x8086,0x87ca,UHD Graphics,9th Gen Core (UHD Graphics 617)
0x8086,0x8a50,Iris Plus Graphics,Ice Lake Gen1
0x8086,0x8a51,Iris Plus Graphics,Ice Lake GT2 (Iris Plus G7)
0x8086,0x8a52,Iris Plus Graphics,Ice Lake GT2 (Iris Plus G7)
0x8086,0x8a53,Iris Plus Graphics,Ice Lake GT2 (Iris Plus G7)
0x8086,0x8a54,Iris Plus Graphics,Ice Lake GT2
0x8086,0x8a56,Iris Plus Graphics,Ice Lake GT1 (Iris Plus G1)
0x8086,0x8a57,Iris Plus Graphics,Ice Lake GT1
0x8086,0x8a58,UHD Graphics,Ice Lake-Y GT1 (UHD Graphics G1)
0x8086,0x8a59,UHD Graphics,Ice Lake GT1
0x8086,0x8a5a,Iris Plus Graphics,Ice Lake GT4 (Iris Plus G4)
0x8086,0x8a5b,Iris Plus Graphics,Ice Lake GT4
0x8086,0x8a5c,Iris Plus Graphics,Ice Lake GT4 (Iris Plus G4)
0x8086,0x8a5d,Iris Plus Graphics,Ice Lake GT4
0x8086,0x8a70,Iris Plus Graphics,Ice Lake
0x8086,0x8a71,Iris Plus Graphics,Ice Lake
0x8086,0x9a40,Iris Xe Graphics,Tiger Lake-UP4 GT2
0x8086,0x9a49,Iris Xe Graphics,Tiger Lake-LP GT2
0x8086,0x9a59,Iris Xe Graphics,Tiger Lake GT2
0x8086,0x9a60,UHD Graphics,Tiger Lake-H GT1
0x8086,0x9a68,UHD Graphics,Tiger Lake-H GT1
0x8086,0x9a70,UHD Graphics,Tiger Lake-H GT1
0x8086,0x9a78,UHD Graphics,Tiger Lake-LP GT2 (UHD Graphics G4)
0x8086,0x9ac0,Iris Xe Graphics,Tiger Lake
0x8086,0x9ac9,Iris Xe Graphics,Tiger Lake
0x8086,0x9ad9,Iris Xe Graphics,Tiger Lake
0x8086,0x9af8,Iris Xe Graphics,Tiger Lake
0x8086,0x9b21,UHD Graphics,Comet Lake-U GT2 (UHD Graphics 620)
0x8086,0x9b41,UHD Graphics,Comet Lake-U GT2
0x8086,0x9ba0,UHD Graphics,Comet Lake GT1
0x8086,0x9ba2,UHD Graphics,Comet Lake GT1
0x8086,0x9ba4,UHD Graphics,Comet Lake-H GT1 (UHD Graphics 610)
0x8086,0x9ba5,UHD Graphics,Comet Lake GT1
0x8086,0x9ba8,UHD Graphics,Comet Lake-S GT1 (UHD Graphics 610)
0x8086,0x9baa,UHD Graphics,Comet Lake GT1
0x8086,0x9bab,UHD Graphics,Comet Lake GT1
0x8086,0x9bac,UHD Graphics,Comet Lake GT1
0x8086,0x9bc0,UHD Graphics,Comet Lake GT2
0x8086,0x9bc2,UHD Graphics,Comet Lake GT2
0x8086,0x9bc4,UHD Graphics,Comet Lake-H GT2
0x8086,0x9bc5,UHD Graphics,Comet Lake-S GT2 (UHD Graphics 630)
0x8086,0x9bc6,UHD Graphics,Comet Lake-S GT2 (UHD Graphics P630)
0x8086,0x9bc8,UHD Graphics,Comet Lake-S GT2 (UHD Graphics 630)
0x8086,0x9bca,UHD Graphics,Comet Lake GT2
0x8086,0x9bcb,UHD Graphics,Comet Lake GT2
0x8086,0x9bcc,UHD Graphics,Comet Lake GT2
0x8086,0x9be6,UHD Graphics,Comet Lake-S GT2 (UHD Graphics P630)
0x8086,0x9bf6,UHD Graphics,Coffee Lake-S GT2 (UHD Graphics P630)
0x8086,0x4555,UHD Graphics,Elkhart Lake GT2 (UHD Graphics Gen11 16EU)
0x8086,0x4571,UHD Graphics,Elkhart Lake GT2 (UHD Graphics Gen11 32EU)
0x8086,0x4500,Intel Graphics,Elkhart Lake GT1
0x8086,0x4541,Intel Graphics,Elkhart Lake GT1
0x8086,0x4551,Intel Graphics,Elkhart Lake GT1
0x8086,0x4557,Intel Graphics,Elkhart Lake GT1
0x8086,0x4570,Intel Graphics,Elkhart Lake GT1
0x8086,0x4c80,Intel Graphics,Rocket Lake
0x8086,0x4c8a,UHD Graphics,Rocket Lake-S GT1 (UHD Graphics 750)
0x8086,0x4c8b,UHD Graphics,Rocket Lake-S GT1 (UHD Graphics 730)
0x8086,0x4c8c,Intel Graphics,Rocket Lake GT1
0x8086,0x4c90,UHD Graphics,Rocket Lake-S GT1 (UHD Graphics P750)
0x8086,0x4c9a,UHD Graphics,Rocket Lake-S
0x8086,0x4e51,Intel Graphics,Jasper Lake GT1
0x8086,0x4e55,UHD Graphics,Jasper Lake
0x8086,0x4e57,Intel Graphics,Jasper Lake GT1
0x8086,0x4e61,UHD Graphics,Jasper Lake
0x8086,0x4e71,UHD Graphics,Jasper Lake
0x8086,0x4626,Intel Graphics,Alder Lake-P GT1
0x8086,0x4628,UHD Graphics,Alder Lake-UP3 GT2
0x8086,0x462a,Intel Graphics,Alder Lake-P GT1
0x8086,0x4680,UHD Graphics,Alder Lake-S GT1 (UHD Graphics 770)
0x8086,0x4681,Intel Graphics,Alder Lake-S GT1
0x8086,0x4682,UHD Graphics,Alder Lake-S GT1 (UHD Graphics 730)
0x8086,0x4683,Intel Graphics,Alder Lake-S GT1
0x8086,0x4688,UHD Graphics,Alder Lake-HX GT1 (UHD Graphics 770)
0x8086,0x4689,Intel Graphics,Alder Lake-HX GT1
0x8086,0x468a,Intel Graphics,Alder Lake-S
0x8086,0x468b,Intel Graphics,Alder Lake-S
0x8086,0x4690,UHD Graphics,Alder Lake-S GT1 (UHD Graphics 770)
0x8086,0x4691,Intel Graphics,Alder Lake-S GT1
0x8086,0x4692,UHD Graphics,Alder Lake-S GT1 (UHD Graphics 730)
0x8086,0x4693,UHD Graphics,Alder Lake-S GT1 (UHD Graphics 710)
0x8086,0x46a0,Intel Graphics,Alder Lake-P GT2
0x8086,0x46a1,UHD Graphics,Alder Lake-P GT1
0x8086,0x46a2,Intel Graphics,Alder Lake-P GT1
0x8086,0x46a3,UHD Graphics,Alder Lake-P GT1
0x8086,0x46a6,Iris Xe Graphics,Alder Lake-P GT2
0x8086,0x46a8,Iris Xe Graphics,Alder Lake-UP3 GT2
0x8086,0x46aa,Iris Xe Graphics,Alder Lake-UP4 GT2
0x8086,0x46b0,Iris Xe Graphics,Alder Lake-P
0x8086,0x46b1,Iris Xe Graphics,Alder Lake-P
0x8086,0x46b2,Intel Graphics,Alder Lake-P GT1
0x8086,0x46b3,UHD Graphics,Alder Lake-UP3 GT1
0x8086,0x46c0,Intel Graphics,Alder Lake-M GT1
0x8086,0x46c1,Iris Xe Graphics,Alder Lake-M
0x8086,0x46c2,Intel Graphics,Alder Lake-M GT1
0x8086,0x46c3,UHD Graphics,Alder Lake-UP4 GT1
0x8086,0x46d0,UHD Graphics,Alder Lake-N
0x8086,0x46d1,UHD Graphics,Alder Lake-N
0x8086,0x46d2,UHD Graphics,Alder Lake-N
0x8086,0x46d3,Intel Graphics,Alder Lake-N
0x8086,0x46d4,Intel Graphics,Alder Lake-N
0x8086,0x7d40,Intel Graphics,Meteor Lake-M
0x8086,0x7d41,Intel Graphics,Arrow Lake-U
0x8086,0x7d45,Intel Graphics,Meteor Lake-P
0x8086,0x7d51,Arc Pro Graphics,Arrow Lake-P (Arc Pro 130T/140T)
0x8086,0x7d55,Intel Arc Graphics,Meteor Lake-P
0x8086,0x7d60,Intel Graphics,Meteor Lake-M
0x8086,0x7d67,Intel Graphics,Arrow Lake-S
0x8086,0x7dd1,Intel Graphics,Arrow Lake-P
0x8086,0x7dd5,Intel Graphics,Meteor Lake-P
0x8086,0xa720,UHD Graphics,Raptor Lake-P
0x8086,0xa721,UHD Graphics,Raptor Lake-P
0x8086,0xa780,UHD Graphics,Raptor Lake-S GT1 (UHD Graphics 770)
0x8086,0xa781,UHD Graphics,Raptor Lake-S
0x8086,0xa782,UHD Graphics,Raptor Lake-S
0x8086,0xa783,UHD Graphics,Raptor Lake-S
0x8086,0xa788,UHD Graphics,Raptor Lake-S
0x8086,0xa789,UHD Graphics,Raptor Lake-S
0x8086,0xa78a,UHD Graphics,Raptor Lake-S
0x8086,0xa78b,UHD Graphics,Raptor Lake-S
0x8086,0xa7a0,Iris Xe Graphics,Raptor Lake-P
0x8086,0xa7a1,Iris Xe Graphics,Raptor Lake-P
0x8086,0xa7a8,UHD Graphics,Raptor Lake-P
0x8086,0xa7a9,UHD Graphics,Raptor Lake-P
0x8086,0xa7aa,Intel Graphics,Raptor Lake-P
0x8086,0xa7ab,Intel Graphics,Raptor Lake-P
0x8086,0xa7ac,Intel Graphics,Raptor Lake-U
0x8086,0xa7ad,Intel Graphics,Raptor Lake-U
0x8086,0xb640,Intel Graphics,Arrow Lake-H
0x8086,0x4905,Iris Xe MAX Graphics,DG1
0x8086,0x4906,Iris Xe Graphics,DG1
0x8086,0x4907,Intel Graphics,DG1 Server
0x8086,0x4908,Iris Xe Graphics,DG1
0x8086,0x4909,Iris Xe MAX Graphics,DG1 (Iris Xe MAX 100)
0x8086,0x5690,Arc Graphics,DG2 (Arc A770M)
0x8086,0x5691,Arc Graphics,DG2 (Arc A730M)
0x8086,0x5692,Arc Graphics,DG2 (Arc A550M)
0x8086,0x5693,Arc Graphics,DG2 (Arc A370M)
0x8086,0x5694,Arc Graphics,DG2 (Arc A350M)
0x8086,0x5695,Iris Xe MAX Graphics,DG2 (Iris Xe MAX A200M)
0x8086,0x5696,Arc Graphics,DG2 (Arc A570M)
0x8086,0x5697,Arc Graphics,DG2 (Arc A530M)
0x8086,0x5698,Arc Graphics,DG2 (Arc Xe Graphics)
0x8086,0x56a0,Arc Graphics,DG2 (Arc A770)
0x8086,0x56a1,Arc Graphics,DG2 (Arc A750)
0x8086,0x56a2,Arc Graphics,DG2 (Arc A580)
0x8086,0x56a3,Arc Graphics,DG2 (Arc Xe Graphics)
0x8086,0x56a4,Arc Graphics,DG2 (Arc Xe Graphics)
0x8086,0x56a5,Arc Graphics,DG2 (Arc A380)
0x8086,0x56a6,Arc Graphics,DG2 (Arc A310)
0x8086,0x56b0,Arc Pro Graphics,DG2 (Arc Pro A30M)
0x8086,0x56b1,Arc Pro Graphics,DG2 (Arc Pro A40/A50)
0x8086,0x56b2,Arc Pro Graphics,DG2 (Arc Pro A60M)
0x8086,0x56b3,Arc Pro Graphics,DG2 (Arc Pro A60)
0x8086,0x56ba,Arc Graphics,DG2 (Arc A380E)
0x8086,0x56bb,Arc Graphics,DG2 (Arc A310E)
0x8086,0x56bc,Arc Graphics,DG2 (Arc A370E)
0x8086,0x56bd,Arc Graphics,DG2 (Arc A350E)
0x8086,0x56be,Arc Graphics,DG2 (Arc A750E)
0x8086,0x56bf,Arc Graphics,DG2 (Arc A580E)
0x8086,0x56c0,Arc Graphics,DG2 (Data Center GPU Flex 170)
0x8086,0x56c1,Arc Graphics,DG2 (Data Center GPU Flex 140)
0x8086,0x56c2,Arc Graphics,DG2 (Data Center GPU Flex 170V)
1 Vendor ID Device ID Graphics Family GPU Name
2 0x8086 0x0152 HD Graphics Xeon E3-1200 v2/3rd Gen Core GT1
3 0x8086 0x0155 HD Graphics Xeon E3-1200 v2/3rd Gen Core
4 0x8086 0x0156 HD Graphics Ivy Bridge mobile GT1
5 0x8086 0x0157 HD Graphics Ivy Bridge mobile GT1
6 0x8086 0x015a HD Graphics Xeon E3-1200 v2/Ivy Bridge
7 0x8086 0x0162 HD Graphics Ivy Bridge GT2 (HD Graphics 4000)
8 0x8086 0x0166 HD Graphics Ivy Bridge mobile GT2 (HD Graphics 4000)
9 0x8086 0x016a HD Graphics Xeon E3-1200 v2/3rd Gen Core GT3
10 0x8086 0x0402 HD Graphics Xeon E3-1200 v3/4th Gen Core GT1
11 0x8086 0x0406 HD Graphics Haswell GT1
12 0x8086 0x040a HD Graphics Xeon E3-1200 v3 GT1
13 0x8086 0x040b HD Graphics Haswell GT1
14 0x8086 0x040e HD Graphics Haswell GT1
15 0x8086 0x0412 HD Graphics Xeon E3-1200 v3/4th Gen Core GT2
16 0x8086 0x0416 HD Graphics 4th Gen Core GT2
17 0x8086 0x041a HD Graphics Xeon E3-1200 v3 GT2
18 0x8086 0x041b HD Graphics Haswell GT2
19 0x8086 0x041e HD Graphics 4th Gen Core Family GT2
20 0x8086 0x0422 HD Graphics Haswell GT3
21 0x8086 0x0426 HD Graphics Haswell GT3
22 0x8086 0x042a HD Graphics Haswell GT3
23 0x8086 0x042b HD Graphics Haswell GT3
24 0x8086 0x042e HD Graphics Haswell GT3
25 0x8086 0x0a02 HD Graphics Haswell-ULT GT1
26 0x8086 0x0a06 HD Graphics Haswell-ULT GT1
27 0x8086 0x0a0a HD Graphics Haswell-ULT GT1
28 0x8086 0x0a0b HD Graphics Haswell-ULT GT1
29 0x8086 0x0a0e HD Graphics Haswell-ULT GT1
30 0x8086 0x0a12 HD Graphics Haswell-ULT GT2
31 0x8086 0x0a16 HD Graphics Haswell-ULT GT2
32 0x8086 0x0a1a HD Graphics Haswell-ULT GT2
33 0x8086 0x0a1b HD Graphics Haswell-ULT GT2
34 0x8086 0x0a1e HD Graphics Haswell-ULT GT2
35 0x8086 0x0a22 HD Graphics Haswell-ULT GT2
36 0x8086 0x0a26 HD Graphics Haswell-ULT GT2
37 0x8086 0x0a2a HD Graphics Haswell-ULT GT2
38 0x8086 0x0a2b HD Graphics Haswell-ULT GT2
39 0x8086 0x0a2e HD Graphics Haswell-ULT GT2
40 0x8086 0x0d02 Iris Pro Graphics Crystal Well GT1
41 0x8086 0x0d06 Iris Pro Graphics Crystal Well GT2
42 0x8086 0x0d0a Iris Pro Graphics Crystal Well GT2
43 0x8086 0x0d0b Iris Pro Graphics Crystal Well GT2
44 0x8086 0x0d0e Iris Pro Graphics Crystal Well GT2
45 0x8086 0x0d12 Iris Pro Graphics Crystal Well GT3 (Iris Pro 5200)
46 0x8086 0x0d16 Iris Pro Graphics Crystal Well GT3
47 0x8086 0x0d1a Iris Pro Graphics Crystal Well GT3
48 0x8086 0x0d1b Iris Pro Graphics Crystal Well GT3
49 0x8086 0x0d1e Iris Pro Graphics Crystal Well GT3
50 0x8086 0x0d22 Iris Pro Graphics Crystal Well (Iris Pro 5200)
51 0x8086 0x0d26 Iris Pro Graphics Crystal Well GT3
52 0x8086 0x0d2a Iris Pro Graphics Crystal Well GT3
53 0x8086 0x0d2b Iris Pro Graphics Crystal Well GT3
54 0x8086 0x0d2e Iris Pro Graphics Crystal Well GT3
55 0x8086 0x0d32 Iris Pro Graphics Crystal Well GT3
56 0x8086 0x0d36 Iris Pro Graphics Crystal Well GT3
57 0x8086 0x0d3a Iris Pro Graphics Crystal Well GT3
58 0x8086 0x1602 HD Graphics Broadwell-U GT1
59 0x8086 0x1606 HD Graphics Broadwell-U GT1
60 0x8086 0x160a HD Graphics Broadwell-U GT1
61 0x8086 0x160b HD Graphics Broadwell-U GT1
62 0x8086 0x160d HD Graphics Broadwell-U GT1
63 0x8086 0x160e HD Graphics Broadwell-U GT1
64 0x8086 0x1612 HD Graphics Broadwell-H GT2 (HD Graphics 5600)
65 0x8086 0x1616 HD Graphics Broadwell-U GT2 (HD Graphics 5500)
66 0x8086 0x161a HD Graphics Broadwell-U GT2
67 0x8086 0x161b HD Graphics Broadwell-U GT2
68 0x8086 0x161d HD Graphics Broadwell-U GT2
69 0x8086 0x161e HD Graphics Broadwell-Y GT2 (HD Graphics 5300)
70 0x8086 0x1622 Iris Pro Graphics Broadwell-DT/H GT3 (Iris Pro 6200)
71 0x8086 0x1626 HD Graphics Broadwell-U GT3 (HD Graphics 6000)
72 0x8086 0x162a Iris Pro Graphics Broadwell-DT GT3 (Iris Pro P6300)
73 0x8086 0x162b Iris Graphics Broadwell-U GT3 (Iris 6100)
74 0x8086 0x162d HD Graphics Broadwell-U GT3
75 0x8086 0x162e HD Graphics Broadwell-U GT3
76 0x8086 0x1632 HD Graphics Broadwell-U GT3
77 0x8086 0x1636 HD Graphics Broadwell-U GT3
78 0x8086 0x163a HD Graphics Broadwell-U GT3
79 0x8086 0x163b HD Graphics Broadwell-U GT3
80 0x8086 0x163d HD Graphics Broadwell-U GT3
81 0x8086 0x163e HD Graphics Broadwell-U GT3
82 0x8086 0x1902 HD Graphics Skylake-S GT1 (HD Graphics 510)
83 0x8086 0x1906 HD Graphics Skylake-U GT1 (HD Graphics 510)
84 0x8086 0x190a HD Graphics Skylake-DT GT1
85 0x8086 0x190b HD Graphics Skylake GT1 (HD Graphics 510)
86 0x8086 0x190e HD Graphics Skylake GT1
87 0x8086 0x1912 HD Graphics Skylake-S GT2 (HD Graphics 530)
88 0x8086 0x1913 HD Graphics Skylake GT2
89 0x8086 0x1915 HD Graphics Skylake GT2
90 0x8086 0x1916 HD Graphics Skylake-U GT2 (HD Graphics 520)
91 0x8086 0x1917 HD Graphics Skylake GT2
92 0x8086 0x191a HD Graphics Skylake GT2
93 0x8086 0x191b HD Graphics Skylake-H GT2 (HD Graphics 530)
94 0x8086 0x191d HD Graphics Skylake-DT/H GT2 (HD Graphics P530)
95 0x8086 0x191e HD Graphics Skylake-Y GT2 (HD Graphics 515)
96 0x8086 0x1921 HD Graphics Skylake GT2 (HD Graphics 520)
97 0x8086 0x1923 HD Graphics Skylake GT2 (HD Graphics 535)
98 0x8086 0x1926 Iris Graphics Skylake-U GT3 (Iris Graphics 540)
99 0x8086 0x1927 Iris Graphics Skylake-U GT3 (Iris Graphics 550)
100 0x8086 0x192a Iris Graphics Skylake GT3
101 0x8086 0x192b Iris Graphics Skylake GT3 (Iris Graphics 555)
102 0x8086 0x192d Iris Graphics Skylake-H GT3 (Iris Graphics P555)
103 0x8086 0x1932 Iris Pro Graphics Skylake GT4 (Iris Pro 580)
104 0x8086 0x193a Iris Pro Graphics Skylake-H GT4 (Iris Pro P580)
105 0x8086 0x193b Iris Pro Graphics Skylake-H GT4 (Iris Pro 580)
106 0x8086 0x193d Iris Pro Graphics Skylake-H GT4 (Iris Pro P580)
107 0x8086 0x1a84 UHD Graphics Skylake-DT
108 0x8086 0x1a85 UHD Graphics Skylake-DT
109 0x8086 0x5902 HD Graphics Kaby Lake-S GT1 (HD Graphics 610)
110 0x8086 0x5906 HD Graphics Kaby Lake-U GT1 (HD Graphics 610)
111 0x8086 0x5908 HD Graphics Kaby Lake GT1
112 0x8086 0x590a HD Graphics Kaby Lake GT1
113 0x8086 0x590b HD Graphics Kaby Lake GT1 (HD Graphics 610)
114 0x8086 0x590e HD Graphics Kaby Lake GT1
115 0x8086 0x5912 HD Graphics Kaby Lake-S GT2 (HD Graphics 630)
116 0x8086 0x5913 HD Graphics Kaby Lake GT2
117 0x8086 0x5915 HD Graphics Kaby Lake GT2
118 0x8086 0x5916 HD Graphics Kaby Lake-U GT2 (HD Graphics 620)
119 0x8086 0x5917 UHD Graphics Kaby Lake-R GT2 (UHD Graphics 620)
120 0x8086 0x591a HD Graphics Kaby Lake GT2
121 0x8086 0x591b HD Graphics Kaby Lake-H GT2 (HD Graphics 630)
122 0x8086 0x591c UHD Graphics Kaby Lake GT2 (UHD Graphics 615)
123 0x8086 0x591d HD Graphics Kaby Lake-DT GT2 (HD Graphics P630)
124 0x8086 0x591e HD Graphics Kaby Lake-Y GT2 (HD Graphics 615)
125 0x8086 0x5921 HD Graphics Kaby Lake GT2 (HD Graphics 620)
126 0x8086 0x5923 HD Graphics Kaby Lake GT2 (HD Graphics 635)
127 0x8086 0x5926 Iris Plus Graphics Kaby Lake-U GT3 (Iris Plus 640)
128 0x8086 0x5927 Iris Plus Graphics Kaby Lake-U GT3 (Iris Plus 650)
129 0x8086 0x592a Iris Plus Graphics Kaby Lake GT3
130 0x8086 0x592b Iris Plus Graphics Kaby Lake GT3
131 0x8086 0x5932 Iris Plus Graphics Kaby Lake GT3
132 0x8086 0x593a Iris Plus Graphics Kaby Lake GT3
133 0x8086 0x593b Iris Plus Graphics Kaby Lake GT3
134 0x8086 0x593d Iris Plus Graphics Kaby Lake GT3
135 0x8086 0x5a40 Intel Graphics Apollolake
136 0x8086 0x5a41 Intel Graphics Apollolake
137 0x8086 0x5a42 Intel Graphics Apollolake
138 0x8086 0x5a44 Intel Graphics Apollolake
139 0x8086 0x5a49 Intel Graphics Apollolake
140 0x8086 0x5a4a Intel Graphics Apollolake
141 0x8086 0x5a4c Intel Graphics Apollolake
142 0x8086 0x5a50 Intel Graphics Apollolake
143 0x8086 0x5a51 Intel Graphics Apollolake
144 0x8086 0x5a52 Intel Graphics Apollolake
145 0x8086 0x5a54 Intel Graphics Apollolake
146 0x8086 0x5a59 Intel Graphics Apollolake
147 0x8086 0x5a5a Intel Graphics Apollolake
148 0x8086 0x5a5c Intel Graphics Apollolake
149 0x8086 0x5a71 Intel Graphics Apollolake
150 0x8086 0x5a79 Intel Graphics Apollolake
151 0x8086 0x5a84 HD Graphics Apollo Lake GT1 (HD Graphics 505)
152 0x8086 0x5a85 HD Graphics Apollo Lake GT1 (HD Graphics 500)
153 0x8086 0x3184 UHD Graphics GeminiLake (UHD Graphics 605)
154 0x8086 0x3185 UHD Graphics GeminiLake (UHD Graphics 600)
155 0x8086 0x3e90 UHD Graphics Coffee Lake-S GT1 (UHD Graphics 610)
156 0x8086 0x3e91 UHD Graphics Coffee Lake-S GT2 (UHD Graphics 630)
157 0x8086 0x3e92 UHD Graphics Coffee Lake-S GT2 (UHD Graphics 630)
158 0x8086 0x3e93 UHD Graphics Coffee Lake-S GT1 (UHD Graphics 610)
159 0x8086 0x3e94 UHD Graphics Coffee Lake-S GT2 (UHD Graphics P630)
160 0x8086 0x3e96 UHD Graphics Coffee Lake-S GT2 (UHD Graphics P630)
161 0x8086 0x3e98 UHD Graphics Coffee Lake-S GT2 (UHD Graphics 630)
162 0x8086 0x3e99 UHD Graphics Coffee Lake GT2
163 0x8086 0x3e9a UHD Graphics Coffee Lake-S GT2 (UHD Graphics P630)
164 0x8086 0x3e9b UHD Graphics Coffee Lake-H GT2 (UHD Graphics 630)
165 0x8086 0x3e9c UHD Graphics Coffee Lake-S GT1 (UHD Graphics 610)
166 0x8086 0x3ea0 UHD Graphics Whiskey Lake-U GT2 (UHD Graphics 620)
167 0x8086 0x3ea1 UHD Graphics Whiskey Lake-U GT1 (UHD Graphics 610)
168 0x8086 0x3ea2 UHD Graphics Whiskey Lake GT1
169 0x8086 0x3ea3 UHD Graphics Whiskey Lake GT1
170 0x8086 0x3ea4 UHD Graphics Whiskey Lake GT1
171 0x8086 0x3ea5 Iris Plus Graphics Coffee Lake-U GT3e (Iris Plus 655)
172 0x8086 0x3ea6 Iris Plus Graphics Coffee Lake-U GT3 (Iris Plus 645)
173 0x8086 0x3ea7 Iris Plus Graphics Whiskey Lake GT3
174 0x8086 0x3ea8 Iris Plus Graphics Coffee Lake-U GT3 (Iris Plus 655)
175 0x8086 0x3ea9 UHD Graphics Coffee Lake-U GT2 (UHD Graphics 620)
176 0x8086 0x87c0 UHD Graphics 9th Gen Core (UHD Graphics 617)
177 0x8086 0x87ca UHD Graphics 9th Gen Core (UHD Graphics 617)
178 0x8086 0x8a50 Iris Plus Graphics Ice Lake Gen1
179 0x8086 0x8a51 Iris Plus Graphics Ice Lake GT2 (Iris Plus G7)
180 0x8086 0x8a52 Iris Plus Graphics Ice Lake GT2 (Iris Plus G7)
181 0x8086 0x8a53 Iris Plus Graphics Ice Lake GT2 (Iris Plus G7)
182 0x8086 0x8a54 Iris Plus Graphics Ice Lake GT2
183 0x8086 0x8a56 Iris Plus Graphics Ice Lake GT1 (Iris Plus G1)
184 0x8086 0x8a57 Iris Plus Graphics Ice Lake GT1
185 0x8086 0x8a58 UHD Graphics Ice Lake-Y GT1 (UHD Graphics G1)
186 0x8086 0x8a59 UHD Graphics Ice Lake GT1
187 0x8086 0x8a5a Iris Plus Graphics Ice Lake GT4 (Iris Plus G4)
188 0x8086 0x8a5b Iris Plus Graphics Ice Lake GT4
189 0x8086 0x8a5c Iris Plus Graphics Ice Lake GT4 (Iris Plus G4)
190 0x8086 0x8a5d Iris Plus Graphics Ice Lake GT4
191 0x8086 0x8a70 Iris Plus Graphics Ice Lake
192 0x8086 0x8a71 Iris Plus Graphics Ice Lake
193 0x8086 0x9a40 Iris Xe Graphics Tiger Lake-UP4 GT2
194 0x8086 0x9a49 Iris Xe Graphics Tiger Lake-LP GT2
195 0x8086 0x9a59 Iris Xe Graphics Tiger Lake GT2
196 0x8086 0x9a60 UHD Graphics Tiger Lake-H GT1
197 0x8086 0x9a68 UHD Graphics Tiger Lake-H GT1
198 0x8086 0x9a70 UHD Graphics Tiger Lake-H GT1
199 0x8086 0x9a78 UHD Graphics Tiger Lake-LP GT2 (UHD Graphics G4)
200 0x8086 0x9ac0 Iris Xe Graphics Tiger Lake
201 0x8086 0x9ac9 Iris Xe Graphics Tiger Lake
202 0x8086 0x9ad9 Iris Xe Graphics Tiger Lake
203 0x8086 0x9af8 Iris Xe Graphics Tiger Lake
204 0x8086 0x9b21 UHD Graphics Comet Lake-U GT2 (UHD Graphics 620)
205 0x8086 0x9b41 UHD Graphics Comet Lake-U GT2
206 0x8086 0x9ba0 UHD Graphics Comet Lake GT1
207 0x8086 0x9ba2 UHD Graphics Comet Lake GT1
208 0x8086 0x9ba4 UHD Graphics Comet Lake-H GT1 (UHD Graphics 610)
209 0x8086 0x9ba5 UHD Graphics Comet Lake GT1
210 0x8086 0x9ba8 UHD Graphics Comet Lake-S GT1 (UHD Graphics 610)
211 0x8086 0x9baa UHD Graphics Comet Lake GT1
212 0x8086 0x9bab UHD Graphics Comet Lake GT1
213 0x8086 0x9bac UHD Graphics Comet Lake GT1
214 0x8086 0x9bc0 UHD Graphics Comet Lake GT2
215 0x8086 0x9bc2 UHD Graphics Comet Lake GT2
216 0x8086 0x9bc4 UHD Graphics Comet Lake-H GT2
217 0x8086 0x9bc5 UHD Graphics Comet Lake-S GT2 (UHD Graphics 630)
218 0x8086 0x9bc6 UHD Graphics Comet Lake-S GT2 (UHD Graphics P630)
219 0x8086 0x9bc8 UHD Graphics Comet Lake-S GT2 (UHD Graphics 630)
220 0x8086 0x9bca UHD Graphics Comet Lake GT2
221 0x8086 0x9bcb UHD Graphics Comet Lake GT2
222 0x8086 0x9bcc UHD Graphics Comet Lake GT2
223 0x8086 0x9be6 UHD Graphics Comet Lake-S GT2 (UHD Graphics P630)
224 0x8086 0x9bf6 UHD Graphics Coffee Lake-S GT2 (UHD Graphics P630)
225 0x8086 0x4555 UHD Graphics Elkhart Lake GT2 (UHD Graphics Gen11 16EU)
226 0x8086 0x4571 UHD Graphics Elkhart Lake GT2 (UHD Graphics Gen11 32EU)
227 0x8086 0x4500 Intel Graphics Elkhart Lake GT1
228 0x8086 0x4541 Intel Graphics Elkhart Lake GT1
229 0x8086 0x4551 Intel Graphics Elkhart Lake GT1
230 0x8086 0x4557 Intel Graphics Elkhart Lake GT1
231 0x8086 0x4570 Intel Graphics Elkhart Lake GT1
232 0x8086 0x4c80 Intel Graphics Rocket Lake
233 0x8086 0x4c8a UHD Graphics Rocket Lake-S GT1 (UHD Graphics 750)
234 0x8086 0x4c8b UHD Graphics Rocket Lake-S GT1 (UHD Graphics 730)
235 0x8086 0x4c8c Intel Graphics Rocket Lake GT1
236 0x8086 0x4c90 UHD Graphics Rocket Lake-S GT1 (UHD Graphics P750)
237 0x8086 0x4c9a UHD Graphics Rocket Lake-S
238 0x8086 0x4e51 Intel Graphics Jasper Lake GT1
239 0x8086 0x4e55 UHD Graphics Jasper Lake
240 0x8086 0x4e57 Intel Graphics Jasper Lake GT1
241 0x8086 0x4e61 UHD Graphics Jasper Lake
242 0x8086 0x4e71 UHD Graphics Jasper Lake
243 0x8086 0x4626 Intel Graphics Alder Lake-P GT1
244 0x8086 0x4628 UHD Graphics Alder Lake-UP3 GT2
245 0x8086 0x462a Intel Graphics Alder Lake-P GT1
246 0x8086 0x4680 UHD Graphics Alder Lake-S GT1 (UHD Graphics 770)
247 0x8086 0x4681 Intel Graphics Alder Lake-S GT1
248 0x8086 0x4682 UHD Graphics Alder Lake-S GT1 (UHD Graphics 730)
249 0x8086 0x4683 Intel Graphics Alder Lake-S GT1
250 0x8086 0x4688 UHD Graphics Alder Lake-HX GT1 (UHD Graphics 770)
251 0x8086 0x4689 Intel Graphics Alder Lake-HX GT1
252 0x8086 0x468a Intel Graphics Alder Lake-S
253 0x8086 0x468b Intel Graphics Alder Lake-S
254 0x8086 0x4690 UHD Graphics Alder Lake-S GT1 (UHD Graphics 770)
255 0x8086 0x4691 Intel Graphics Alder Lake-S GT1
256 0x8086 0x4692 UHD Graphics Alder Lake-S GT1 (UHD Graphics 730)
257 0x8086 0x4693 UHD Graphics Alder Lake-S GT1 (UHD Graphics 710)
258 0x8086 0x46a0 Intel Graphics Alder Lake-P GT2
259 0x8086 0x46a1 UHD Graphics Alder Lake-P GT1
260 0x8086 0x46a2 Intel Graphics Alder Lake-P GT1
261 0x8086 0x46a3 UHD Graphics Alder Lake-P GT1
262 0x8086 0x46a6 Iris Xe Graphics Alder Lake-P GT2
263 0x8086 0x46a8 Iris Xe Graphics Alder Lake-UP3 GT2
264 0x8086 0x46aa Iris Xe Graphics Alder Lake-UP4 GT2
265 0x8086 0x46b0 Iris Xe Graphics Alder Lake-P
266 0x8086 0x46b1 Iris Xe Graphics Alder Lake-P
267 0x8086 0x46b2 Intel Graphics Alder Lake-P GT1
268 0x8086 0x46b3 UHD Graphics Alder Lake-UP3 GT1
269 0x8086 0x46c0 Intel Graphics Alder Lake-M GT1
270 0x8086 0x46c1 Iris Xe Graphics Alder Lake-M
271 0x8086 0x46c2 Intel Graphics Alder Lake-M GT1
272 0x8086 0x46c3 UHD Graphics Alder Lake-UP4 GT1
273 0x8086 0x46d0 UHD Graphics Alder Lake-N
274 0x8086 0x46d1 UHD Graphics Alder Lake-N
275 0x8086 0x46d2 UHD Graphics Alder Lake-N
276 0x8086 0x46d3 Intel Graphics Alder Lake-N
277 0x8086 0x46d4 Intel Graphics Alder Lake-N
278 0x8086 0x7d40 Intel Graphics Meteor Lake-M
279 0x8086 0x7d41 Intel Graphics Arrow Lake-U
280 0x8086 0x7d45 Intel Graphics Meteor Lake-P
281 0x8086 0x7d51 Arc Pro Graphics Arrow Lake-P (Arc Pro 130T/140T)
282 0x8086 0x7d55 Intel Arc Graphics Meteor Lake-P
283 0x8086 0x7d60 Intel Graphics Meteor Lake-M
284 0x8086 0x7d67 Intel Graphics Arrow Lake-S
285 0x8086 0x7dd1 Intel Graphics Arrow Lake-P
286 0x8086 0x7dd5 Intel Graphics Meteor Lake-P
287 0x8086 0xa720 UHD Graphics Raptor Lake-P
288 0x8086 0xa721 UHD Graphics Raptor Lake-P
289 0x8086 0xa780 UHD Graphics Raptor Lake-S GT1 (UHD Graphics 770)
290 0x8086 0xa781 UHD Graphics Raptor Lake-S
291 0x8086 0xa782 UHD Graphics Raptor Lake-S
292 0x8086 0xa783 UHD Graphics Raptor Lake-S
293 0x8086 0xa788 UHD Graphics Raptor Lake-S
294 0x8086 0xa789 UHD Graphics Raptor Lake-S
295 0x8086 0xa78a UHD Graphics Raptor Lake-S
296 0x8086 0xa78b UHD Graphics Raptor Lake-S
297 0x8086 0xa7a0 Iris Xe Graphics Raptor Lake-P
298 0x8086 0xa7a1 Iris Xe Graphics Raptor Lake-P
299 0x8086 0xa7a8 UHD Graphics Raptor Lake-P
300 0x8086 0xa7a9 UHD Graphics Raptor Lake-P
301 0x8086 0xa7aa Intel Graphics Raptor Lake-P
302 0x8086 0xa7ab Intel Graphics Raptor Lake-P
303 0x8086 0xa7ac Intel Graphics Raptor Lake-U
304 0x8086 0xa7ad Intel Graphics Raptor Lake-U
305 0x8086 0xb640 Intel Graphics Arrow Lake-H
306 0x8086 0x4905 Iris Xe MAX Graphics DG1
307 0x8086 0x4906 Iris Xe Graphics DG1
308 0x8086 0x4907 Intel Graphics DG1 Server
309 0x8086 0x4908 Iris Xe Graphics DG1
310 0x8086 0x4909 Iris Xe MAX Graphics DG1 (Iris Xe MAX 100)
311 0x8086 0x5690 Arc Graphics DG2 (Arc A770M)
312 0x8086 0x5691 Arc Graphics DG2 (Arc A730M)
313 0x8086 0x5692 Arc Graphics DG2 (Arc A550M)
314 0x8086 0x5693 Arc Graphics DG2 (Arc A370M)
315 0x8086 0x5694 Arc Graphics DG2 (Arc A350M)
316 0x8086 0x5695 Iris Xe MAX Graphics DG2 (Iris Xe MAX A200M)
317 0x8086 0x5696 Arc Graphics DG2 (Arc A570M)
318 0x8086 0x5697 Arc Graphics DG2 (Arc A530M)
319 0x8086 0x5698 Arc Graphics DG2 (Arc Xe Graphics)
320 0x8086 0x56a0 Arc Graphics DG2 (Arc A770)
321 0x8086 0x56a1 Arc Graphics DG2 (Arc A750)
322 0x8086 0x56a2 Arc Graphics DG2 (Arc A580)
323 0x8086 0x56a3 Arc Graphics DG2 (Arc Xe Graphics)
324 0x8086 0x56a4 Arc Graphics DG2 (Arc Xe Graphics)
325 0x8086 0x56a5 Arc Graphics DG2 (Arc A380)
326 0x8086 0x56a6 Arc Graphics DG2 (Arc A310)
327 0x8086 0x56b0 Arc Pro Graphics DG2 (Arc Pro A30M)
328 0x8086 0x56b1 Arc Pro Graphics DG2 (Arc Pro A40/A50)
329 0x8086 0x56b2 Arc Pro Graphics DG2 (Arc Pro A60M)
330 0x8086 0x56b3 Arc Pro Graphics DG2 (Arc Pro A60)
331 0x8086 0x56ba Arc Graphics DG2 (Arc A380E)
332 0x8086 0x56bb Arc Graphics DG2 (Arc A310E)
333 0x8086 0x56bc Arc Graphics DG2 (Arc A370E)
334 0x8086 0x56bd Arc Graphics DG2 (Arc A350E)
335 0x8086 0x56be Arc Graphics DG2 (Arc A750E)
336 0x8086 0x56bf Arc Graphics DG2 (Arc A580E)
337 0x8086 0x56c0 Arc Graphics DG2 (Data Center GPU Flex 170)
338 0x8086 0x56c1 Arc Graphics DG2 (Data Center GPU Flex 140)
339 0x8086 0x56c2 Arc Graphics DG2 (Data Center GPU Flex 170V)
+1
View File
@@ -25,6 +25,7 @@
#
# bus base class prog_if vendor device subsystem hid driver
pci, 0C, 03, 30, *, *, *, *, /system/drivers/usb-xhci-bus
pci, 03, 00, 00, 8086, 4C8A, *, *, /system/drivers/intel-uhd-graphics-750
pci, 03, 80, *, 1AF4, 1050, *, *, /system/drivers/virtio-gpu
usb, 03, 01, 01, *, *, *, *, /system/drivers/usb-hid-keyboard
usb, 03, 01, 02, *, *, *, *, /system/drivers/usb-hid-mouse
1 # /etc/devices.csv — the device→driver registry.
25 #
26 # bus base class prog_if vendor device subsystem hid driver
27 pci, 0C, 03, 30, *, *, *, *, /system/drivers/usb-xhci-bus
28 pci, 03, 00, 00, 8086, 4C8A, *, *, /system/drivers/intel-uhd-graphics-750
29 pci, 03, 80, *, 1AF4, 1050, *, *, /system/drivers/virtio-gpu
30 usb, 03, 01, 01, *, *, *, *, /system/drivers/usb-hid-keyboard
31 usb, 03, 01, 02, *, *, *, *, /system/drivers/usb-hid-mouse
-38
View File
@@ -1,38 +0,0 @@
//! The "client" library domain (library/client): userspace-service clients —
//! they talk to services over IPC, not to the kernel. Client modules end in
//! `-client` the way wire protocols end in `-protocol`, so a service, its
//! protocol, and its client never share a name (`display` the service,
//! `display-protocol` the wire contract, `display-client` a program's view).
const std = @import("std");
pub fn build(b: *std.Build) void {
const kernel = b.dependency("kernel", .{});
const protocol = b.dependency("protocol", .{});
const ipc = kernel.module("ipc");
const time = kernel.module("time");
_ = b.addModule("display-client", .{
.root_source_file = b.path("display/display-client.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "display-protocol", .module = protocol.module("display-protocol") },
},
});
_ = b.addModule("input-client", .{
.root_source_file = b.path("input/input-client.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "input-protocol", .module = protocol.module("input-protocol") },
},
});
// Standalone `zig build test`, kept for uniformity across the domains (the
// root aggregate depends on every domain's test step). The clients have no
// host-runnable unit tests yet — they are thin IPC conversation wrappers —
// so the step is empty until one grows some.
_ = b.step("test", "Run the client unit tests (none yet)");
}
-13
View File
@@ -1,13 +0,0 @@
.{
.name = .client,
.version = "0.0.0",
.fingerprint = 0xc74404553e73d4ff, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// The clients converse over ipc with time-bounded waits.
.kernel = .{ .path = "../kernel" },
// Each client speaks its service's wire protocol.
.protocol = .{ .path = "../protocol" },
},
.paths = .{""},
}
-20
View File
@@ -1,20 +0,0 @@
//! The "csv" library domain: shared CSV helpers (comment stripping, field
//! iteration) for the /etc/*.csv config files — the device registry and the
//! init service list both parse them.
const std = @import("std");
pub fn build(b: *std.Build) void {
_ = b.addModule("csv", .{ .root_source_file = b.path("csv.zig") });
// Standalone `zig build test` for this domain alone; the root build keeps
// its aggregate test step.
const test_step = b.step("test", "Run the csv unit tests");
const csv_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("csv.zig"),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(csv_tests).step);
}
-8
View File
@@ -1,8 +0,0 @@
.{
.name = .csv,
.version = "0.0.0",
.fingerprint = 0x8a4525791f4e5b6, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{""},
}
-137
View File
@@ -1,137 +0,0 @@
//! The "device" library domain (library/device): what a driver author imports.
//! The flat reference data (device-abi, pci-class, acpi-ids, usb-abi, usb-ids),
//! typed MMIO access, the driver-side client libraries (driver, pci, usb,
//! block), the AML interpreter, and the data-driven device registry.
const std = @import("std");
pub fn build(b: *std.Build) void {
const kernel = b.dependency("kernel", .{});
const protocol = b.dependency("protocol", .{});
const csv = b.dependency("csv", .{});
const abi = kernel.module("abi");
const system_call = kernel.module("system-call");
const ipc = kernel.module("ipc");
const time = kernel.module("time");
// The devices sub-project's public interface (the flat wire types),
// importable by user space, unlike the kernel-internal device model it
// also feeds (system/kernel/device-model.zig).
const device_abi = b.addModule("device-abi", .{
.root_source_file = b.path("model/device-abi.zig"),
});
// PCI class-code decoding (class/subclass/prog-IF -> names). Pure reference
// data, shared by kernel discovery and any user-space PCI tool.
const pci_class = b.addModule("pci-class", .{
.root_source_file = b.path("pci/pci-class.zig"),
});
// ACPI/PnP hardware-ID (_HID) names — the flat analog of pci-class.
_ = b.addModule("acpi-ids", .{
.root_source_file = b.path("acpi/acpi-ids.zig"),
});
// The AML interpreter, a build module so the ring-3 acpi service can run
// the same parser the kernel does (docs/discovery.md). Pure Zig, no kernel
// imports — one source, two builds.
_ = b.addModule("aml", .{
.root_source_file = b.path("acpi/aml/aml.zig"),
});
// The USB device-framework wire ABI (chapter-9 set-up packets, standard +
// class requests, descriptors) and the USB class-code taxonomy.
const usb_abi = b.addModule("usb-abi", .{
.root_source_file = b.path("usb/usb-abi.zig"),
});
const usb_ids = b.addModule("usb-ids", .{
.root_source_file = b.path("usb/usb-ids.zig"),
});
// Typed volatile MMIO register access + memory-ordering barriers, for
// drivers on top of an mmio_map grant. Depends only on `builtin`.
const mmio = b.addModule("mmio", .{
.root_source_file = b.path("mmio/mmio.zig"),
});
// The driver author's interface: device access + the device-manager hello
// handshake, folded together.
const driver = b.addModule("driver", .{
.root_source_file = b.path("driver/driver.zig"),
.imports = &.{
.{ .name = "abi", .module = abi },
.{ .name = "device-abi", .module = device_abi },
.{ .name = "system-call", .module = system_call },
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "device-manager-protocol", .module = protocol.module("device-manager-protocol") },
},
});
// A device driver's view of its claimed PCI function: config-space header
// fields, BAR decode + map, capability walks (legacy + extended), MSI/MSI-X
// programming, power state, and function-level reset — the generic PCI
// mechanics every leaf PCI driver used to re-derive inline.
_ = b.addModule("pci", .{
.root_source_file = b.path("pci/pci.zig"),
.imports = &.{
.{ .name = "driver", .module = driver },
.{ .name = "mmio", .module = mmio },
.{ .name = "pci-class", .module = pci_class },
.{ .name = "time", .module = time },
},
});
// The USB class-driver transfer client: open a device on the xHCI bus and
// drive it (control / interrupt / bulk). Re-exports usb-abi / usb-ids as
// usb.abi / usb.ids for a single USB import.
_ = b.addModule("usb", .{
.root_source_file = b.path("usb/usb.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "usb-transfer-protocol", .module = protocol.module("usb-transfer-protocol") },
.{ .name = "usb-abi", .module = usb_abi },
.{ .name = "usb-ids", .module = usb_ids },
},
});
// The block-device client — a device type, so it lives here.
_ = b.addModule("block", .{
.root_source_file = b.path("block/block.zig"),
.imports = &.{
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
.{ .name = "block-protocol", .module = protocol.module("block-protocol") },
},
});
// The device registry: parse /etc/devices.csv into match rules and bind a
// reported device to a driver. Pure logic (no hardware, no syscalls), so it
// unit-tests on the host; the device manager imports it.
_ = b.addModule("device-registry", .{
.root_source_file = b.path("registry/device-registry.zig"),
.imports = &.{.{ .name = "csv", .module = csv.module("csv") }},
});
// Standalone `zig build test` for this domain alone; the root build keeps
// its aggregate test step.
const test_step = b.step("test", "Run the device library unit tests");
for ([_][]const u8{
"model/device-abi.zig", // wire-type sizes
"pci/pci-class.zig", // class/subclass/prog-IF name decoding
"acpi/acpi-ids.zig", // _HID name decoding
"acpi/aml/aml.zig", // AML parse + interpret, incl. Notify dispatch
"usb/usb-abi.zig", // wire sizes + bit packings + set-up packet encodings
"usb/usb-ids.zig", // class/subclass/protocol code assignments
"mmio/mmio.zig", // barriers assemble + registers round-trip
}) |root| {
const device_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(device_tests).step);
}
// The registry needs its csv import wired, so it doesn't fit the loop.
const registry_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("registry/device-registry.zig"),
.target = b.resolveTargetQuery(.{}),
.imports = &.{.{ .name = "csv", .module = csv.module("csv") }},
}),
});
test_step.dependOn(&b.addRunArtifact(registry_tests).step);
}
-15
View File
@@ -1,15 +0,0 @@
.{
.name = .device,
.version = "0.0.0",
.fingerprint = 0x92fb68eace23a4f, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// driver/block/usb/pci build on the kernel library's concern modules.
.kernel = .{ .path = "../kernel" },
// driver speaks device-manager-protocol; block/usb their transfer protocols.
.protocol = .{ .path = "../protocol" },
// device-registry parses /etc/devices.csv with the shared csv helpers.
.csv = .{ .path = "../csv" },
},
.paths = .{""},
}
-104
View File
@@ -1,104 +0,0 @@
//! The "kernel" library domain (library/kernel): the userspace private-ABI
//! library (kernel32-style), split by concern into directly-importable
//! modules. The graph is a DAG: memory depends on thread (heap needs
//! Thread.Mutex), and thread does its own raw mmap so there is no cycle.
//!
//! This package also exports `abi` — the kernel <-> user contract (SystemCall
//! numbers, mmap prot flags, page_size). Its source lives with the kernel in
//! system/abi.zig, outside this directory, but userspace's one view of it is
//! exported here so every consumer names the same module instance. Reaching
//! outside the package root means this package is valid only as an in-repo
//! path dependency (never fetchable by hash) — fine, since path dependencies
//! are the only way danos packages are consumed.
//!
//! The root shim (root.zig) and the user link script (user.ld) are plain
//! files, not modules; build-support reaches them through this package's
//! directory (Dependency.path).
const std = @import("std");
pub fn build(b: *std.Build) void {
const protocol = b.dependency("protocol", .{});
const abi = b.addModule("abi", .{
.root_source_file = b.path("../../system/abi.zig"),
});
const system_call = b.addModule("system-call", .{
.root_source_file = b.path("system-call.zig"),
.imports = &.{.{ .name = "abi", .module = abi }},
});
const ipc = b.addModule("ipc", .{
.root_source_file = b.path("ipc.zig"),
.imports = &.{ .{ .name = "abi", .module = abi }, .{ .name = "system-call", .module = system_call } },
});
const time = b.addModule("time", .{
.root_source_file = b.path("time.zig"),
.imports = &.{.{ .name = "system-call", .module = system_call }},
});
const thread = b.addModule("thread", .{
.root_source_file = b.path("thread.zig"),
.imports = &.{ .{ .name = "abi", .module = abi }, .{ .name = "system-call", .module = system_call } },
});
const logging = b.addModule("logging", .{
.root_source_file = b.path("logging.zig"),
.imports = &.{ .{ .name = "abi", .module = abi }, .{ .name = "system-call", .module = system_call } },
});
const process = b.addModule("process", .{
.root_source_file = b.path("process.zig"),
.imports = &.{
.{ .name = "abi", .module = abi },
.{ .name = "system-call", .module = system_call },
.{ .name = "ipc", .module = ipc },
.{ .name = "time", .module = time },
},
});
_ = b.addModule("file-system", .{
.root_source_file = b.path("file-system.zig"),
.imports = &.{
.{ .name = "abi", .module = abi },
.{ .name = "system-call", .module = system_call },
.{ .name = "ipc", .module = ipc },
.{ .name = "vfs-protocol", .module = protocol.module("vfs-protocol") },
},
});
_ = b.addModule("memory", .{
.root_source_file = b.path("memory/memory.zig"),
.imports = &.{
.{ .name = "abi", .module = abi },
.{ .name = "system-call", .module = system_call },
.{ .name = "ipc", .module = ipc },
.{ .name = "thread", .module = thread },
},
});
_ = b.addModule("service", .{
.root_source_file = b.path("service.zig"),
.imports = &.{
.{ .name = "abi", .module = abi },
.{ .name = "ipc", .module = ipc },
.{ .name = "process", .module = process },
},
});
_ = b.addModule("start", .{
.root_source_file = b.path("start.zig"),
.imports = &.{ .{ .name = "process", .module = process }, .{ .name = "logging", .module = logging } },
});
// Standalone `zig build test` for this domain alone; the root build keeps
// its aggregate test step. time and thread pull in the syscall wrappers,
// which need the `abi` module; their danos seams fall back to host
// primitives off the danos target, so they run with real host threads.
const test_step = b.step("test", "Run the kernel library unit tests");
for ([_][]const u8{
"time.zig", // Instant/Duration arithmetic
"thread.zig", // Mutex/Condition/RwLock/WaitGroup state machines
}) |root| {
const kernel_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(root),
.target = b.resolveTargetQuery(.{}),
.imports = &.{.{ .name = "abi", .module = abi }},
}),
});
test_step.dependOn(&b.addRunArtifact(kernel_tests).step);
}
}
-11
View File
@@ -1,11 +0,0 @@
.{
.name = .kernel,
.version = "0.0.0",
.fingerprint = 0x5dd29aab36503453, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// file-system speaks the VFS wire protocol.
.protocol = .{ .path = "../protocol" },
},
.paths = .{""},
}
-46
View File
@@ -1,46 +0,0 @@
//! The "protocol" library domain: the wire protocols — each service's public
//! interface, exposed as its own module (docs/driver-model.md). Both sides of
//! every conversation depend on the contract by name; neither reaches into the
//! other's files. Pure flat wire types: no protocol module imports anything.
//!
//! vfs-protocol : the VFS server <-> the file layer (unistd/stdio)
//! input-protocol : the input fan-out service <-> sources + subscribers
//! block-protocol : a filesystem <-> a block driver (usb-storage)
//! usb-transfer-protocol : a USB class driver <-> the xHCI bus driver
//! device-manager-protocol : the device manager <-> drivers + discovery
//! display-protocol : the compositor's client-facing surface
//! scanout-protocol : the compositor -> a native scanout driver (docs/display-v2.md)
//! power-protocol : system power's domain-named surface (docs/power.md)
const std = @import("std");
pub fn build(b: *std.Build) void {
for ([_]struct { name: []const u8, root: []const u8 }{
.{ .name = "vfs-protocol", .root = "vfs/vfs-protocol.zig" },
.{ .name = "input-protocol", .root = "input/input-protocol.zig" },
.{ .name = "block-protocol", .root = "block/block-protocol.zig" },
.{ .name = "usb-transfer-protocol", .root = "usb-transfer/usb-transfer-protocol.zig" },
.{ .name = "device-manager-protocol", .root = "device-manager/device-manager-protocol.zig" },
.{ .name = "display-protocol", .root = "display/display-protocol.zig" },
.{ .name = "scanout-protocol", .root = "scanout/scanout-protocol.zig" },
.{ .name = "power-protocol", .root = "power/power-protocol.zig" },
}) |protocol| {
_ = b.addModule(protocol.name, .{ .root_source_file = b.path(protocol.root) });
}
// Standalone `zig build test` for this domain alone; the root build keeps
// its aggregate test step.
const test_step = b.step("test", "Run the protocol unit tests");
for ([_][]const u8{
"vfs/vfs-protocol.zig", // NodeKind / DirectoryEntry sizes + op values
"display/display-protocol.zig", // pack(): native pixel encoding per format
}) |root| {
const protocol_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(protocol_tests).step);
}
}
-8
View File
@@ -1,8 +0,0 @@
.{
.name = .protocol,
.version = "0.0.0",
.fingerprint = 0xc8c0bc4c4d551283, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{""},
}
-31
View File
@@ -1,31 +0,0 @@
//! The "xkeyboard-config" library domain: keyboard layouts compiled from the
//! X11 xkeyboard-config database into native Zig (keycode + modifiers ->
//! keysym/character). The `layouts` tables are generated by
//! tools/make-xkeyboard-config.py; `xkeyboard-config` is the hand-written API
//! over them.
const std = @import("std");
pub fn build(b: *std.Build) void {
const layouts = b.addModule("layouts", .{
.root_source_file = b.path("generated/layouts.zig"),
});
_ = b.addModule("xkeyboard-config", .{
.root_source_file = b.path("xkeyboard-config.zig"),
.imports = &.{.{ .name = "layouts", .module = layouts }},
});
// Standalone `zig build test` for this domain alone; the root build keeps
// its aggregate test step. The keycode->character assertions are the
// end-to-end proof that the xkb-data -> generator -> Zig-lookup pipeline
// is correct.
const test_step = b.step("test", "Run the xkeyboard-config unit tests");
const xkb_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("xkeyboard-config.zig"),
.target = b.resolveTargetQuery(.{}),
.imports = &.{.{ .name = "layouts", .module = layouts }},
}),
});
test_step.dependOn(&b.addRunArtifact(xkb_tests).step);
}
-8
View File
@@ -1,8 +0,0 @@
.{
.name = .xkeyboard_config,
.version = "0.0.0",
.fingerprint = 0xea5abe82f08b6eae, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{""},
}
@@ -0,0 +1,82 @@
//! /system/drivers/intel-uhd-graphics-750 — spawned by the device manager with
//! the device-tree id as argv[1]; claims that device and no other.
const std = @import("std");
const device = @import("driver");
const ipc = @import("ipc");
const memory = @import("memory");
const process = @import("process");
const service = @import("service");
/// No protocol yet: the kernel's IPC ceiling (MESSAGE_MAXIMUM) sizes the buffers.
const message_maximum = 256;
var controller_id: u64 = 0;
var register_base: usize = 0;
fn initialise(endpoint: ipc.Handle) bool {
_ = endpoint; // needed later, for irq binding and timers
if (!device.claim(controller_id)) {
std.log.err("unable to claim device {d}", .{controller_id});
return false;
}
// Fetch our own descriptor back for the device's resources.
const buffer = memory.allocator().alloc(device.DeviceDescriptor, 64) catch return false;
defer memory.allocator().free(buffer);
const total = device.enumerate(buffer);
const descriptor = for (buffer[0..@min(total, buffer.len)]) |d| {
if (d.id == controller_id) break d;
} else {
std.log.err("device {d} not in the device tree", .{controller_id});
return false;
};
// Log every resource BEFORE choosing one (see step 5).
var register_index: u64 = 0;
for (descriptor.resources[0..@intCast(descriptor.resource_count)], 0..) |resource, index| {
std.log.info("resource {d}: kind={d} start=0x{x} len=0x{x}", .{
index, resource.kind, resource.start, resource.len,
});
// The 16 MiB window is GTTMMADR, the register BAR (this device also has
// a 256 MiB memory BAR, GMADR — "first memory resource" would be wrong).
if (resource.kind == @intFromEnum(device.ResourceKind.memory) and
resource.len == 16 * 1024 * 1024) register_index = index;
}
if (register_index == 0) {
std.log.err("register BAR not found", .{});
return false;
}
register_base = device.mmioMap(controller_id, register_index) orelse {
std.log.err("mmio_map failed", .{});
return false;
};
std.log.info("registers mapped at 0x{x}", .{register_base});
return true;
}
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?ipc.Handle) usize {
_ = message;
_ = reply;
_ = sender;
_ = capability;
return 0; // no protocol yet; the zero-length ping is answered by the harness
}
pub fn main(init: process.Init) void {
const argument = init.arguments.get(1) orelse {
std.log.err("missing device id (argv[1])", .{});
return;
};
controller_id = std.fmt.parseInt(u64, argument, 10) catch {
std.log.err("malformed device id '{s}'", .{argument});
return;
};
service.run(message_maximum, .{
.init = initialise,
.on_message = onMessage,
// .on_notification only once an IRQ or timer is bound
});
}
-18
View File
@@ -1,18 +0,0 @@
//! The pci-bus driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "pci-bus",
.root_source_file = b.path("pci-bus.zig"),
.imports = &.{
"device-manager-protocol", "driver", "ipc", "logging", "memory", "pci-class",
"process", "service",
},
});
b.installArtifact(exe);
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .pci_bus,
.version = "0.0.0",
.fingerprint = 0x283fca121f0bb145, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-50
View File
@@ -1,50 +0,0 @@
//! The ps2-bus driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const ps2_bus_exe = build_support.userBinary(b, .{
.name = "ps2-bus",
.root_source_file = b.path("ps2-bus.zig"),
.imports = &.{ "acpi-ids", "driver", "ipc", "logging", "memory", "process", "service", "time" },
});
b.installArtifact(ps2_bus_exe);
const ps2_keyboard_exe = build_support.userBinary(b, .{
.name = "ps2-keyboard",
.root_source_file = b.path("keyboard.zig"),
.imports = &.{
"acpi-ids", "driver", "input-client", "input-protocol", "ipc", "logging", "memory",
"process", "time", "xkeyboard-config",
},
});
b.installArtifact(ps2_keyboard_exe);
const ps2_mouse_exe = build_support.userBinary(b, .{
.name = "ps2-mouse",
.root_source_file = b.path("mouse.zig"),
.imports = &.{
"acpi-ids", "driver", "input-client", "input-protocol", "ipc", "logging", "memory",
"process", "time",
},
});
b.installArtifact(ps2_mouse_exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the ps2-bus unit tests");
for ([_][]const u8{
"scancode.zig", // set-2 decode + keyboard state machine
"mouse-packet.zig", // 3-byte mouse packet assembly
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-18
View File
@@ -1,18 +0,0 @@
.{
.name = .ps2_bus,
.version = "0.0.0",
.fingerprint = 0x642a365353bf7de9, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
.@"xkeyboard-config" = .{ .path = "../../../library/xkeyboard-config" },
},
.paths = .{""},
}
+1 -1
View File
@@ -19,7 +19,7 @@ const device = @import("driver");
const ipc = @import("ipc");
const process = @import("process");
const time = @import("time");
const input = @import("input-client");
const input = @import("input");
const memory = @import("memory");
const logging = @import("logging");
const xkb = @import("xkeyboard-config");
+1 -1
View File
@@ -19,7 +19,7 @@ const device = @import("driver");
const ipc = @import("ipc");
const process = @import("process");
const time = @import("time");
const input = @import("input-client");
const input = @import("input");
const memory = @import("memory");
const logging = @import("logging");
const ps2 = @import("ps2-library.zig");
-42
View File
@@ -1,42 +0,0 @@
//! The usb-hid driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const usb_hid_keyboard_exe = build_support.userBinary(b, .{
.name = "usb-hid-keyboard",
.root_source_file = b.path("keyboard.zig"),
.imports = &.{
"driver", "input-client", "input-protocol", "ipc", "logging", "process", "service",
"usb", "usb-abi", "xkeyboard-config",
},
});
b.installArtifact(usb_hid_keyboard_exe);
const usb_hid_mouse_exe = build_support.userBinary(b, .{
.name = "usb-hid-mouse",
.root_source_file = b.path("mouse.zig"),
.imports = &.{
"driver", "input-client", "input-protocol", "ipc", "logging", "process", "service",
"usb", "usb-abi",
},
});
b.installArtifact(usb_hid_mouse_exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the usb-hid unit tests");
for ([_][]const u8{
"hid-report.zig", // HID boot-report keyboard/mouse decode
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-18
View File
@@ -1,18 +0,0 @@
.{
.name = .usb_hid,
.version = "0.0.0",
.fingerprint = 0x66328b738fffff01, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
.@"xkeyboard-config" = .{ .path = "../../../library/xkeyboard-config" },
},
.paths = .{""},
}
+1 -1
View File
@@ -18,7 +18,7 @@ const std = @import("std");
const ipc = @import("ipc");
const process = @import("process");
const service = @import("service");
const input = @import("input-client");
const input = @import("input");
const device_manager = @import("driver");
const logging = @import("logging");
const usb = @import("usb");
+1 -1
View File
@@ -14,7 +14,7 @@ const std = @import("std");
const ipc = @import("ipc");
const process = @import("process");
const service = @import("service");
const input = @import("input-client");
const input = @import("input");
const device_manager = @import("driver");
const logging = @import("logging");
const usb = @import("usb");
-33
View File
@@ -1,33 +0,0 @@
//! The usb-storage driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "usb-storage",
.root_source_file = b.path("usb-storage.zig"),
.imports = &.{
"block-protocol", "driver", "ipc", "logging", "memory", "process", "service",
"time", "usb",
},
});
b.installArtifact(exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the usb-storage unit tests");
for ([_][]const u8{
"bulk-only-transport.zig", // CBW/CSW wrapper sizes
"scsi.zig", // SCSI CDB encodings (big-endian)
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .usb_storage,
.version = "0.0.0",
.fingerprint = 0xce09fdc4c50bb4fe, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-19
View File
@@ -1,19 +0,0 @@
//! The usb-xhci-bus driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "usb-xhci-bus",
.root_source_file = b.path("usb-xhci-bus.zig"),
.imports = &.{
"device-manager-protocol", "driver", "input-client", "ipc", "logging", "memory",
"mmio", "pci", "process", "service", "time", "usb-abi", "usb-ids",
"usb-transfer-protocol",
},
});
b.installArtifact(exe);
}
-17
View File
@@ -1,17 +0,0 @@
.{
.name = .usb_xhci_bus,
.version = "0.0.0",
.fingerprint = 0x46d21373f05f6b20, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
+1 -1
View File
@@ -19,7 +19,7 @@ const ipc = @import("ipc");
const process = @import("process");
const service = @import("service");
const time = @import("time");
const input = @import("input-client");
const input = @import("input");
const device_manager = @import("driver");
const memory = @import("memory");
const logging = @import("logging");
-33
View File
@@ -1,33 +0,0 @@
//! The virtio-gpu driver as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "virtio-gpu",
.root_source_file = b.path("virtio-gpu.zig"),
.imports = &.{
"display-protocol", "driver", "ipc", "logging", "memory", "mmio", "pci", "process",
"scanout-protocol", "service", "time",
},
});
b.installArtifact(exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the virtio-gpu unit tests");
for ([_][]const u8{
"virtio-gpu-protocol.zig", // virtio-gpu command struct sizes
"virtio-pci.zig", // virtio 1.0 PCI transport struct sizes
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .virtio_gpu,
.version = "0.0.0",
.fingerprint = 0xfb704899c18b9a23, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
+11 -6
View File
@@ -106,6 +106,12 @@ pub const PlatformInformation = struct {
/// INCLUDE_PCI_ALL (the catch-all unit; falls back to the first), or the AMD-Vi
/// IOMMU's control-register base from the first IVHD.
iommu_base: u64 = 0,
/// The unit's Version register (offset 0x00) — its low byte is major.minor;
/// reading it back nonzero confirms a real, mappable VT-d unit.
iommu_version: u32 = 0,
/// The unit's Capability register (offset 0x08): supported address widths, number
/// of domains, etc. Consumed by the IOMMU core when it enables translation.
iommu_capabilities: u64 = 0,
/// Whether the selected unit carries INCLUDE_PCI_ALL. False means every unit is
/// device-scoped (unusual) — the core still enables on the selected unit but
/// devices outside its scope remain untranslated.
@@ -496,7 +502,7 @@ fn handleTable(device_tree: *DeviceTree, hal: Hal, sdt_physical: u64) !void {
} else if (std.mem.eql(u8, &sig, &SPCR)) {
parseSpcr(header);
} else if (std.mem.eql(u8, &sig, &DMAR)) {
parseDmar(header);
parseDmar(hal, header);
} else if (std.mem.eql(u8, &sig, &IVRS)) {
parseIvrs(header);
} else if (std.mem.eql(u8, &sig, &SSDT)) {
@@ -816,7 +822,7 @@ const scope_path_offset = 6;
/// and records single-path endpoint RMRRs for the IOMMU core to pre-map before it
/// enables translation. Multi-hop RMRR scopes are skipped loudly: better a named gap
/// than a silent one.
fn parseDmar(header: *const SystemDescriptorTableHeader) void {
fn parseDmar(hal: Hal, header: *const SystemDescriptorTableHeader) void {
const base: [*]align(1) const u8 = @ptrCast(header);
const total: usize = header.length;
@@ -834,14 +840,13 @@ fn parseDmar(header: *const SystemDescriptorTableHeader) void {
const replace = !platform_information.iommu_present or
(include_all and !platform_information.iommu_include_all);
if (replace) {
// Table facts only: the unit's registers are the IOMMU
// backend's business (it maps and validates them at
// detect) — discovery records where they live, never
// reads them.
if (platform_information.iommu_present) platform_information.iommu_extra_units += 1;
const regs = hal.mapMmio(register_base, abi.page_size, true);
platform_information.iommu_present = true;
platform_information.iommu_base = register_base;
platform_information.iommu_include_all = include_all;
platform_information.iommu_version = @as(*const volatile u32, @ptrFromInt(regs + 0x00)).*;
platform_information.iommu_capabilities = @as(*const volatile u64, @ptrFromInt(regs + 0x08)).*;
} else {
platform_information.iommu_extra_units += 1;
}
@@ -17,11 +17,6 @@ const io = @import("io.zig");
const smp = @import("smp.zig");
const pcpu = @import("per-cpu.zig");
/// The x86-64 IOMMU backends (Intel VT-d, AMD-Vi) behind their dispatch
/// surface — the architecture-neutral IOMMU core (system/kernel/iommu.zig)
/// reaches the hardware only through this.
pub const iommu = @import("iommu.zig");
/// The saved register/trap frame passed to a fault handler.
pub const CpuState = idt.CpuState;
@@ -1,77 +0,0 @@
//! x86-64 IOMMU backends, behind the architecture boundary: Intel VT-d
//! (iommu-intel.zig) and AMD-Vi (iommu-amd.zig). The architecture-neutral
//! core (system/kernel/iommu.zig) owns the domain table and the shared
//! page-table walker; it hands this file the firmware discovery facts and an
//! environment (frame allocation + the log sink, injected the same way
//! enablePaging receives its frame hooks), and gets back a hardware vtable.
//! A new architecture supplies its own unit (ARM: the SMMU) from its own
//! directory with no core change.
const intel = @import("iommu-intel.zig");
const amd = @import("iommu-amd.zig");
/// What the platform's firmware tables reported: where the unit's registers
/// live, and which programming model its table implies (an IVRS table
/// describes AMD-Vi; a DMAR table describes Intel VT-d).
pub const Discovery = struct {
register_base: u64,
amd: bool,
};
/// What the backends need from the generic kernel, injected at detect so this
/// module never imports kernel internals: physical-frame allocation for the
/// hardware structures, and the kernel log sink (fault reports, warnings, the
/// enable banner).
pub const Environment = struct {
allocateFrame: *const fn () ?u64,
allocateContiguous: *const fn (count: usize, max_physical: u64) ?u64,
write: *const fn (bytes: []const u8) void,
};
/// The bit encodings and hardware operations a backend supplies to the shared
/// core. Entry helpers build the raw page-table entries for the backend's
/// format; the core walks the tree with them. The hardware ops act on a whole
/// domain (identified by its hardware domain id = core index + 1) or device
/// (by requester id / bdf).
pub const Backend = struct {
/// Number of page-table levels (3 or 4) the backend selected from hardware caps.
levels: u8,
/// Largest leaf the walker may emit: 4 KiB always, 2 MiB when the backend allows.
supports_huge_pages: bool,
/// Raw entry bits for a leaf mapping `physical` (with the given size), and for a
/// non-leaf entry pointing at `table_physical` at `level` (level counts down to 1
/// at the leaf's parent). `isPresent` tests a read-back entry.
makeLeaf: *const fn (physical: u64, huge: bool) u64,
makeTable: *const fn (table_physical: u64, level: u8) u64,
isPresent: *const fn (entry: u64) bool,
/// Flush a cache line holding IOMMU structures the hardware reads non-coherently
/// (VT-d with ECAP.C==0). A no-op where the unit snoops caches.
flushStructure: *const fn (address: usize) void,
/// Turn translation on (the core has already seeded any pre-claim domains)
/// and write the unit's identity lines to the log — the core follows with
/// the neutral posture lines.
enable: *const fn () void,
/// Point `bdf`'s translation structure at `domain` (hardware id) and invalidate the
/// context/device caches so the change takes effect.
attach: *const fn (bdf: u16, domain: u16, page_table_root: u64) void,
/// Return `bdf`'s translation structure to not-present + invalidate — all its DMA
/// faults afterward.
detach: *const fn (bdf: u16) void,
/// Invalidate cached translations for `domain` (after a map or unmap).
invalidateDomain: *const fn (domain: u16) void,
/// Pull pending faults out of the hardware, log them (rate-limited), return the
/// count seen this call.
faultDrain: *const fn () usize,
};
/// The injected kernel services, stored for the backends at detect time.
pub var environment: Environment = undefined;
/// Probe the discovered unit and return its vtable, or null when it is
/// unusable (the core stays fail-open and says so).
pub fn detect(discovery: Discovery, injected: Environment) ?Backend {
environment = injected;
return if (discovery.amd) amd.detect(discovery) else intel.detect(discovery);
}
@@ -1,6 +1,5 @@
//! AMD-Vi (AMD I/O Virtualization) backend for the IOMMU core, behind the
//! architecture boundary. The AMD analogue of iommu-intel.zig: it supplies
//! the architecture-neutral core's `Backend` vtable (iommu.zig beside this file)
//! system/kernel/iommu-amd.zig — AMD-Vi (AMD I/O Virtualization) backend for the IOMMU
//! core. The AMD analogue of iommu-intel.zig: it supplies the core's `Backend` vtable
//! with AMD-Vi's page-table entry bits and drives the device table, command buffer, and
//! event log.
//!
@@ -15,7 +14,10 @@
const std = @import("std");
const abi = @import("abi");
const boot_handoff = @import("boot-handoff");
const paging = @import("paging.zig");
const pmm = @import("pmm.zig");
const platform = @import("platform");
const architecture = @import("architecture");
const log = @import("log.zig");
const iommu = @import("iommu.zig");
const page_size = abi.page_size;
@@ -86,10 +88,10 @@ fn ram(physical: u64) [*]volatile u64 {
/// Map the register window, allocate the device table / command buffer / event log.
/// Returns the vtable, or null if the boot-time allocations fail.
pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
register_base = paging.mapMmio(discovery.register_base, 16 * 1024, true);
pub fn detect(info: platform.PlatformInformation) ?iommu.Backend {
register_base = architecture.mapMmio(info.iommu_base, 16 * 1024, true);
device_table = iommu.environment.allocateContiguous(device_table_pages, ~@as(u64, 0)) orelse return null;
device_table = pmm.allocContiguous(device_table_pages, ~@as(u64, 0)) orelse return null;
zero(device_table, device_table_pages); // all-zero DTE = V=0 = deny every device
command_buffer = allocZeroedFrame() orelse return null;
event_log = allocZeroedFrame() orelse return null;
@@ -98,7 +100,6 @@ pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
return iommu.Backend{
.levels = levels,
.supports_huge_pages = false, // 4 KiB leaves only (AMD superpage encoding deferred)
.enable = enable,
.makeLeaf = makeLeaf,
.makeTable = makeTable,
.isPresent = isPresent,
@@ -113,7 +114,7 @@ pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
/// Program the base registers and enable translation. The device table is already
/// zeroed (every device denied) except any entries `attach` wrote for RMRR/claimed
/// devices, so turning translation on blocks all other DMA and logs it.
fn enable() void {
pub fn enable() void {
write64(reg_device_table_base, (device_table & address_mask) | (device_table_pages - 1));
write64(reg_command_buffer_base, (command_buffer & address_mask) | (ring_length_code << 56));
write64(reg_event_log_base, (event_log & address_mask) | (ring_length_code << 56));
@@ -125,12 +126,6 @@ fn enable() void {
// Buffers first, then the master enable.
write64(reg_control, control_command_buffer_enable | control_event_log_enable);
write64(reg_control, control_command_buffer_enable | control_event_log_enable | control_iommu_enable);
iommu.environment.write("/system/kernel: iommu online (AMD-Vi) — UNTESTED on real AMD hardware (QEMU-verified only)\n");
var buffer: [48]u8 = undefined;
if (std.fmt.bufPrint(&buffer, " levels : {d} (48-bit)\n", .{levels})) |line|
iommu.environment.write(line)
else |_| {}
}
// --- Backend vtable ------------------------------------------------------------------
@@ -200,14 +195,13 @@ fn faultDrain() usize {
fn logFault(source: u16, address: u64) void {
if (fault_log_budget == 0) return;
fault_log_budget -= 1;
var buffer: [128]u8 = undefined;
if (std.fmt.bufPrint(&buffer, "DANOS-IOMMU-FAULT: bdf={x:0>2}:{x:0>2}.{d} addr=0x{x} reason=amd-io-page-fault\n", .{
log.print("DANOS-IOMMU-FAULT: bdf={x:0>2}:{x:0>2}.{d} addr=0x{x} reason=amd-io-page-fault\n", .{
source >> 8,
(source >> 3) & 0x1F,
source & 0x7,
address,
})) |line| iommu.environment.write(line) else |_| {}
if (fault_log_budget == 0) iommu.environment.write("DANOS-IOMMU-FAULT: (further faults suppressed)\n");
});
if (fault_log_budget == 0) log.write("DANOS-IOMMU-FAULT: (further faults suppressed)\n");
}
// --- command ring --------------------------------------------------------------------
@@ -246,7 +240,7 @@ fn completeAndWait() void {
if (spins > 100_000) {
if (!completion_warned) {
completion_warned = true;
iommu.environment.write("/system/kernel: AMD-Vi COMPLETION_WAIT store not observed — proceeding (QEMU processes commands synchronously)\n");
log.write("/system/kernel: AMD-Vi COMPLETION_WAIT store not observed — proceeding (QEMU processes commands synchronously)\n");
}
return;
}
@@ -254,7 +248,7 @@ fn completeAndWait() void {
}
fn allocZeroedFrame() ?u64 {
const frame = iommu.environment.allocateFrame() orelse return null;
const frame = pmm.alloc() orelse return null;
zero(frame, 1);
return frame;
}
@@ -1,7 +1,7 @@
//! Intel VT-d backend for the IOMMU core, behind the architecture boundary.
//! system/kernel/iommu-intel.zig — Intel VT-d backend for the IOMMU core.
//!
//! Provides the architecture-neutral core (system/kernel/iommu.zig) with the VT-d
//! hardware specifics behind the `Backend` vtable (iommu.zig beside this file): second-level page-table entry bits, the root/context table structure, the
//! Provides the core (iommu.zig) with the VT-d hardware specifics behind its `Backend`
//! vtable: second-level page-table entry bits, the root/context table structure, the
//! translation-enable and invalidation register sequences, and the fault drain. The
//! core owns the domain table and the page-table walk; this file owns the registers.
//!
@@ -15,7 +15,10 @@
const std = @import("std");
const abi = @import("abi");
const boot_handoff = @import("boot-handoff");
const paging = @import("paging.zig");
const pmm = @import("pmm.zig");
const platform = @import("platform");
const architecture = @import("architecture");
const log = @import("log.zig");
const iommu = @import("iommu.zig");
const page_size = abi.page_size;
@@ -63,7 +66,6 @@ const slpte_page_size: u64 = 1 << 7; // a 2 MiB leaf (== iommu.huge_leaf_bit)
const address_mask: u64 = 0x000F_FFFF_FFFF_F000;
var register_base: usize = 0;
var version: u32 = 0;
var capabilities: u64 = 0;
var extended_capabilities: u64 = 0;
var coherent: bool = true; // ECAP.C — whether clflush is unnecessary
@@ -95,15 +97,11 @@ fn tableAt(physical: u64) [*]volatile u64 {
}
/// Map the register window, read caps, pick the address width. Returns the vtable, or
/// null when the unit is not live or advertises no address width danos can drive.
pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
// Map 16 KiB: FRCD and IOTLB registers can sit past the first page (CAP.FRO /
// ECAP.IRO are 16-byte-unit offsets).
register_base = paging.mapMmio(discovery.register_base, 16 * 1024, true);
// The Version register's low byte is major.minor; reading it back nonzero is
// the live-mappable-unit sanity check (previously a kernel-test assertion).
version = read32(0x00);
if (version == 0) return null;
/// null when the unit advertises no address width danos can drive.
pub fn detect(info: platform.PlatformInformation) ?iommu.Backend {
// Remap 16 KiB: FRCD and IOTLB registers can sit past the first page (CAP.FRO /
// ECAP.IRO are 16-byte-unit offsets). Idempotent with the detection-time mapping.
register_base = architecture.mapMmio(info.iommu_base, 16 * 1024, true);
capabilities = read64(reg_cap);
extended_capabilities = read64(reg_ecap);
coherent = (extended_capabilities & ecap_coherent) != 0;
@@ -124,7 +122,6 @@ pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
return iommu.Backend{
.levels = levels,
.supports_huge_pages = true,
.enable = enable,
.makeLeaf = makeLeaf,
.makeTable = makeTable,
.isPresent = isPresent,
@@ -140,7 +137,7 @@ pub fn detect(discovery: iommu.Discovery) ?iommu.Backend {
/// and populated the RMRR domains (their context entries are live via `attach`), so at
/// this instant every OTHER device's context entry is not-present and will fault — which
/// for stale firmware bus-mastering is the desired evidence, not a bug.
fn enable() void {
pub fn enable() void {
write64(reg_rtaddr, root_table); // legacy mode (bits 11:10 = 00)
setGlobalCommand(gcmd_srtp);
spinStatus(gsts_rtps);
@@ -148,15 +145,6 @@ fn enable() void {
setGlobalCommand(gcmd_te);
spinStatus(gsts_tes);
gcmd_shadow |= gcmd_te;
iommu.environment.write("/system/kernel: iommu online (Intel VT-d)\n");
var buffer: [64]u8 = undefined;
if (std.fmt.bufPrint(&buffer, " version : 0x{x}\n", .{version})) |line|
iommu.environment.write(line)
else |_| {}
if (std.fmt.bufPrint(&buffer, " agaw : {d} levels\n", .{levels})) |line|
iommu.environment.write(line)
else |_| {}
}
// --- Backend vtable ------------------------------------------------------------------
@@ -253,17 +241,16 @@ fn faultDrain() usize {
fn logFault(source: u16, address: u64, reason: u8, is_read: bool) void {
if (fault_log_budget > 0) {
fault_log_budget -= 1;
var buffer: [128]u8 = undefined;
if (std.fmt.bufPrint(&buffer, "DANOS-IOMMU-FAULT: bdf={x:0>2}:{x:0>2}.{d} addr=0x{x} reason=0x{x} write={d}\n", .{
log.print("DANOS-IOMMU-FAULT: bdf={x:0>2}:{x:0>2}.{d} addr=0x{x} reason=0x{x} write={d}\n", .{
source >> 8,
(source >> 3) & 0x1F,
source & 0x7,
address,
reason,
@intFromBool(!is_read),
})) |line| iommu.environment.write(line) else |_| {}
});
if (fault_log_budget == 0)
iommu.environment.write("DANOS-IOMMU-FAULT: (further faults suppressed)\n");
log.write("DANOS-IOMMU-FAULT: (further faults suppressed)\n");
} else {
faults_suppressed += 1;
}
@@ -282,7 +269,7 @@ fn spinStatus(bit: u32) void {
while (read32(reg_gsts) & bit == 0) {
spins += 1;
if (spins > 10_000_000) {
iommu.environment.write("/system/kernel: WARNING VT-d status bit never set — translation may be incomplete\n");
log.write("/system/kernel: WARNING VT-d status bit never set — translation may be incomplete\n");
return;
}
}
@@ -319,7 +306,7 @@ fn iotlbOffset() usize {
}
fn allocZeroed() ?u64 {
const frame = iommu.environment.allocateFrame() orelse return null;
const frame = pmm.alloc() orelse return null;
const table = tableAt(frame);
var i: usize = 0;
while (i < 512) : (i += 1) table[i] = 0;
+104 -53
View File
@@ -1,6 +1,5 @@
//! system/kernel/iommu.zig — architecture-neutral IOMMU core: per-device DMA
//! translation domains over a backend the architecture module supplies
//! (x86-64: Intel VT-d or AMD-Vi, behind architecture/x86_64/iommu.zig).
//! system/kernel/iommu.zig — vendor-neutral IOMMU core: per-device DMA translation
//! domains over an Intel VT-d or AMD-Vi backend.
//!
//! The problem this closes: without an IOMMU, a claimed bus-mastering device can DMA to
//! ANY physical address, so a compromised or buggy driver reaches all of memory through
@@ -14,12 +13,11 @@
//! physical address they program into hardware; a domain simply makes that same
//! address the ONLY thing the device can reach. No IOVA allocator, and every
//! driver's register-programming code is untouched.
//! - **Architecture-neutral**: this file owns the domain table and a shared
//! 512-entry page-table walker; the architecture module's `Backend` vtable
//! supplies the hardware specifics — the entry-bit encodings, the
//! enable/invalidate register dances, and the fault drain — with the frame
//! allocator and log sink injected the other way.
//! - **Fail-open**: when no IOMMU is found, nothing activates and every entry point is a
//! - **Vendor-neutral**: this file owns the domain table and a shared 512-entry
//! page-table walker; a `Backend` vtable supplies the hardware specifics (VT-d in
//! iommu-intel.zig, AMD-Vi in iommu-amd.zig) — the entry-bit encodings, the
//! enable/invalidate register dances, and the fault drain.
//! - **Fail-open**: when no IOMMU is found, `kind == .none` and every entry point is a
//! success no-op, so callers in process.zig stay unconditional and behavior is
//! byte-for-byte the pre-IOMMU kernel. The boot log states the posture.
//!
@@ -31,18 +29,54 @@ const abi = @import("abi");
const boot_handoff = @import("boot-handoff");
const pmm = @import("pmm.zig");
const platform = @import("platform");
const architecture = @import("architecture");
const devices_broker = @import("devices-broker.zig");
const log = @import("log.zig");
const intel = @import("iommu-intel.zig");
const amd = @import("iommu-amd.zig");
const page_size: u64 = abi.page_size;
const page_mask: u64 = page_size - 1;
const huge_page_size: u64 = 2 * 1024 * 1024;
pub const Kind = enum { none, intel_vtd, amd_vi };
/// One domain per claimed PCI function. 64 mirrors devices-broker's device cap.
pub const maximum_domains = 64;
pub const invalid_domain: u16 = 0xFFFF;
/// The bit encodings and hardware operations a backend supplies to the shared core.
/// Entry helpers build the raw page-table entries for the backend's format; the core
/// walks the tree with them. The hardware ops act on a whole domain (identified by its
/// hardware domain id = core index + 1) or device (by requester id / bdf).
pub const Backend = struct {
/// Number of page-table levels (3 or 4) the backend selected from hardware caps.
levels: u8,
/// Largest leaf the walker may emit: 4 KiB always, 2 MiB when the backend allows.
supports_huge_pages: bool,
/// Raw entry bits for a leaf mapping `physical` (with the given size), and for a
/// non-leaf entry pointing at `table_physical` at `level` (level counts down to 1
/// at the leaf's parent). `isPresent` tests a read-back entry.
makeLeaf: *const fn (physical: u64, huge: bool) u64,
makeTable: *const fn (table_physical: u64, level: u8) u64,
isPresent: *const fn (entry: u64) bool,
/// Flush a cache line holding IOMMU structures the hardware reads non-coherently
/// (VT-d with ECAP.C==0). A no-op where the unit snoops caches.
flushStructure: *const fn (address: usize) void,
/// Point `bdf`'s translation structure at `domain` (hardware id) and invalidate the
/// context/device caches so the change takes effect.
attach: *const fn (bdf: u16, domain: u16, page_table_root: u64) void,
/// Return `bdf`'s translation structure to not-present + invalidate — all its DMA
/// faults afterward.
detach: *const fn (bdf: u16) void,
/// Invalidate cached translations for `domain` (after a map or unmap).
invalidateDomain: *const fn (domain: u16) void,
/// Pull pending faults out of the hardware, log them (rate-limited), return the
/// count seen this call.
faultDrain: *const fn () usize,
};
const Domain = struct {
in_use: bool = false,
owner: u32 = 0, // task that owns the attached device
@@ -51,44 +85,53 @@ const Domain = struct {
rmrr: bool = false, // a firmware reserved-region domain (persists across claims)
};
var active: bool = false;
var backend: architecture.iommu.Backend = undefined;
var kind: Kind = .none;
var backend: Backend = undefined;
var domains: [maximum_domains]Domain = .{Domain{}} ** maximum_domains;
pub fn kindOf() Kind {
return kind;
}
pub fn enabled() bool {
return active;
return kind != .none;
}
/// Detect the IOMMU (the architecture module probes the discovered unit and
/// returns its backend), pre-map firmware reserved regions, and enable
/// translation. Fail-open (nothing activates) when no usable unit exists — the
/// caller logs the posture. Must run after platform discovery and before any
/// user process starts.
/// Detect the IOMMU, pick a backend, pre-map firmware reserved regions, and enable
/// translation. Fail-open (kind stays .none) when no unit exists — the caller logs the
/// posture. Must run after platform discovery and before any user process starts.
pub fn init() void {
const info = platform.platformInformation();
if (!info.iommu_present) return;
// A present-but-unusable unit stays fail-open with a logged reason rather
// than half-enabling. The backend receives the kernel services it needs
// (frames, the log sink) here — it never imports kernel internals.
backend = architecture.iommu.detect(.{
.register_base = info.iommu_base,
.amd = info.iommu_is_amd,
}, .{
.allocateFrame = pmm.alloc,
.allocateContiguous = pmm.allocContiguous,
.write = log.write,
}) orelse {
log.write("/system/kernel: WARNING IOMMU present but unusable — staying fail-open\n");
if (!info.iommu_present) {
kind = .none;
return;
};
active = true;
}
// Pick the backend by vendor. A present-but-unusable unit stays fail-open with a
// logged reason rather than half-enabling.
if (info.iommu_is_amd) {
if (amd.detect(info)) |be| {
backend = be;
kind = .amd_vi;
} else {
kind = .none;
log.write("/system/kernel: WARNING AMD-Vi present but unusable — staying fail-open\n");
return;
}
} else {
if (intel.detect(info)) |be| {
backend = be;
kind = .intel_vtd;
} else {
kind = .none;
log.write("/system/kernel: WARNING IOMMU present but unusable — staying fail-open\n");
return;
}
}
// The translation structures start empty: every device is denied until its driver
// claims it (confineDevice gives it a private domain). PCI functions are enumerated
// post-boot by the ring-3 pci-bus driver, so there is nothing to attach at init.
// The backend writes its identity lines; the neutral posture lines follow.
backend.enable();
logPosture(info);
if (kind == .amd_vi) amd.enable() else intel.enable();
logEnabled(info);
}
/// Per-claimed-device record: its private domain, so a driver's death tears down
@@ -104,7 +147,7 @@ var confined: [maximum_domains]Confined = .{Confined{}} ** maximum_domains;
/// the claim back (a claim that can't be confined must not stand). No-op success when no
/// IOMMU exists (fail-open).
pub fn confineDevice(device_id: u64, bdf: u16, owner: u32) bool {
if (!active) return true;
if (kind == .none) return true;
if (device_id >= confined.len) return true; // unusual id; leave it to fail-open
const domain = domainCreate(owner, bdf) orelse return false;
@@ -131,14 +174,14 @@ fn confinedOf(device_id: u64) ?*Confined {
/// Map a DMA region into a specific claimed device's domain (the device owner binding a
/// granted buffer). false if the device is not confined. No-op success without an IOMMU.
pub fn mapForDevice(device_id: u64, physical: u64, len: u64) bool {
if (!active) return true;
if (kind == .none) return true;
const c = confinedOf(device_id) orelse return false;
return map(c.domain, physical, len);
}
/// Unmap a DMA region from a specific claimed device's domain. No-op if not confined.
pub fn unmapForDevice(device_id: u64, physical: u64, len: u64) void {
if (!active) return;
if (kind == .none) return;
const c = confinedOf(device_id) orelse return;
unmap(c.domain, physical, len);
}
@@ -146,7 +189,7 @@ pub fn unmapForDevice(device_id: u64, physical: u64, len: u64) void {
/// Map a region into every claimed device owned by `owner` — the auto-bind of a task's
/// own freshly-`dma_alloc`'d buffer into the devices it drives.
pub fn mapRegionForOwner(owner: u32, physical: u64, len: u64) void {
if (!active) return;
if (kind == .none) return;
for (&confined) |*c| {
if (c.active and c.owner == owner) _ = map(c.domain, physical, len);
}
@@ -157,7 +200,7 @@ pub fn mapRegionForOwner(owner: u32, physical: u64, len: u64) void {
/// use-after-free this prevents. Cross-device because a granted buffer may be bound in a
/// domain other than its owner's.
pub fn unmapRegionEverywhere(physical: u64, len: u64) void {
if (!active) return;
if (kind == .none) return;
for (&confined) |*c| {
if (c.active) unmap(c.domain, physical, len);
}
@@ -167,7 +210,7 @@ pub fn unmapRegionEverywhere(physical: u64, len: u64) void {
/// device, free the tables) so their DMA is blocked again and a restarted driver
/// re-claims cleanly. Runs BEFORE the broker claims and the DMA frames are released.
pub fn releaseAllOwnedBy(owner: u32) void {
if (!active) return;
if (kind == .none) return;
for (&confined) |*c| {
if (c.active and c.owner == owner) {
detachDevice(c.bdf);
@@ -180,7 +223,7 @@ pub fn releaseAllOwnedBy(owner: u32) void {
/// Allocate an empty domain (an empty top-level table). null when the table is full.
pub fn domainCreate(owner: u32, bdf: u16) ?u16 {
if (!active) return 0; // fail-open: a dummy id the no-op ops ignore
if (kind == .none) return 0; // fail-open: a dummy id the no-op ops ignore
for (&domains, 0..) |*d, index| {
if (d.in_use) continue;
const root = allocTable() orelse return null;
@@ -193,7 +236,7 @@ pub fn domainCreate(owner: u32, bdf: u16) ?u16 {
/// Free a domain's page-table frames and its slot. Precondition: no device attached
/// (detach first).
pub fn domainDestroy(domain: u16) void {
if (!active) return;
if (kind == .none) return;
const d = &domains[domain];
if (!d.in_use) return;
freeTables(d.page_table_root, backend.levels);
@@ -202,7 +245,7 @@ pub fn domainDestroy(domain: u16) void {
/// Attach `bdf`'s device to `domain` and pre-load any RMRR range recorded for it.
pub fn attachDevice(domain: u16, bdf: u16) void {
if (!active) return;
if (kind == .none) return;
const d = &domains[domain];
d.bdf = bdf;
backend.attach(bdf, hardwareId(domain), d.page_table_root);
@@ -210,7 +253,7 @@ pub fn attachDevice(domain: u16, bdf: u16) void {
/// Return `bdf`'s device to not-present + invalidate.
pub fn detachDevice(bdf: u16) void {
if (!active) return;
if (kind == .none) return;
backend.detach(bdf);
}
@@ -218,7 +261,7 @@ pub fn detachDevice(bdf: u16) void {
/// Unconditional domain-selective invalidation after every map — correct under VT-d
/// caching-mode and free otherwise.
pub fn map(domain: u16, physical: u64, len: u64) bool {
if (!active) return true;
if (kind == .none) return true;
const d = &domains[domain];
if (!d.in_use) return false;
if (!mapRange(d.page_table_root, physical, len)) return false;
@@ -230,7 +273,7 @@ pub fn map(domain: u16, physical: u64, len: u64) bool {
/// invalidation before the caller returns the frames to pmm — a stale IOTLB entry
/// pointing at a reallocated frame is the use-after-free this ordering prevents.
pub fn unmap(domain: u16, physical: u64, len: u64) void {
if (!active) return;
if (kind == .none) return;
const d = &domains[domain];
if (!d.in_use) return;
unmapRange(d.page_table_root, physical, len);
@@ -240,14 +283,14 @@ pub fn unmap(domain: u16, physical: u64, len: u64) void {
/// Poll the hardware for translation faults, log them, return the count. Called by the
/// IOMMU test case and opportunistically after a device detaches.
pub fn faultDrain() usize {
if (!active) return 0;
if (kind == .none) return 0;
return backend.faultDrain();
}
/// The physical address `virtual` maps to in `domain`, or null if unmapped — a test
/// helper that walks the domain's page tables (identity mappings return `virtual`).
pub fn translationOf(domain: u16, virtual: u64) ?u64 {
if (!active) return virtual;
if (kind == .none) return virtual;
const d = &domains[domain];
if (!d.in_use) return null;
var table = d.page_table_root;
@@ -382,16 +425,24 @@ fn isHugeLeaf(entry: u64) bool {
/// The size-bit the backends set on a 2 MiB leaf (VT-d SL-PTE PS bit 7; AMD encodes a
/// leaf as next-level 0, so the core marks huge leaves with this software bit — an
/// ignored bit in both formats — to tell them apart from table pointers when freeing).
const huge_leaf_bit: u64 = 1 << 7;
pub const huge_leaf_bit: u64 = 1 << 7;
fn hardwareId(domain: u16) u16 {
return domain + 1; // id 0 is reserved by both architectures
}
fn logPosture(info: platform.PlatformInformation) void {
fn logEnabled(info: platform.PlatformInformation) void {
if (kind == .amd_vi) {
log.write("/system/kernel: iommu online (AMD-Vi) — UNTESTED on real AMD hardware (QEMU-verified only)\n");
log.print(" levels : {d} (48-bit)\n", .{backend.levels});
return;
}
log.write("/system/kernel: iommu online (Intel VT-d)\n");
log.print(" version : 0x{x}\n", .{info.iommu_version});
log.print(" agaw : {d} levels\n", .{backend.levels});
log.print(" rmrr : {d} region(s) premapped\n", .{info.rmrr_count});
if (info.rmrr_skipped > 0)
log.print(" rmrr : WARNING {d} scope(s) skipped — a device keeps an unmapped firmware buffer\n", .{info.rmrr_skipped});
if (info.iommu_extra_units > 0)
log.print(" units : WARNING {d} other unit(s) — their scoped devices are NOT translated\n", .{info.iommu_extra_units});
log.print(" units : WARNING {d} other DRHD(s) — their scoped devices are NOT translated\n", .{info.iommu_extra_units});
}
+12 -25
View File
@@ -1253,10 +1253,11 @@ fn iommuTest() void {
const pinfo = platform.platformInformation();
check("IOMMU found in the firmware tables", pinfo.iommu_present);
check("IOMMU unit has a register base", pinfo.iommu_base != 0);
// The live-unit sanity (the version register reading back nonzero) now
// gates detect itself: an unusable unit stays fail-open, so `enabled()`
// below subsumes the old vendor-gated register check.
log("DANOS-IOMMU: base=0x{x}\n", .{pinfo.iommu_base});
// The VT-d version register is a live-unit sanity check; AMD-Vi (from IVRS) records
// no version, so gate it on the vendor.
if (!pinfo.iommu_is_amd)
check("VT-d version register reads back nonzero (real, mappable unit)", pinfo.iommu_version != 0);
log("DANOS-IOMMU: base=0x{x} version=0x{x} capabilities=0x{x}\n", .{ pinfo.iommu_base, pinfo.iommu_version, pinfo.iommu_capabilities });
// Translation was enabled at boot (kernel.zig: iommu.init before any driver claims
// a device). The blanket domain keeps every device identity-mapped, so DMA still
@@ -1969,20 +1970,15 @@ fn initTest(boot_information: *const BootInformation) void {
};
check("init loaded and spawned as a process", spawned);
// Wait (real time) until the LAST write is a heartbeat — proving init got
// through its boot chatter (heap ok, the /etc/init.csv lookup) and settled
// into its beat-and-sleep loop (~1 s between beats). Waiting on the text
// rather than a raw write count: the boot chatter alone satisfies a count,
// which is exactly the too-early check that used to fail here.
// Wait (real time) for at least two heartbeats — proving it runs, writes,
// and sleeps repeatedly (init sleeps ~1 s between beats).
scheduler.setPriority(1);
const prefix = "init: heartbeat";
const deadline = architecture.millis() + 8000;
var beat_ok = false;
while (!beat_ok and architecture.millis() < deadline) {
beat_ok = bufferHas(prefix);
scheduler.yield();
}
while (process.write_count < 2 and architecture.millis() < deadline) scheduler.yield();
scheduler.setPriority(4);
const prefix = "init: heartbeat";
const beat_ok = bufferHas(prefix);
check("init produced repeated heartbeats (>=2)", process.write_count >= 2);
check("heartbeat text arrived intact", beat_ok);
check("heartbeats came from user mode (CPL 3)", process.write_from_user);
@@ -2796,24 +2792,15 @@ fn initialRamdiskTest(boot_information: *const BootInformation) void {
process.write_count = 0;
process.write_from_user = false;
var programs: u32 = 0;
var spawned: u32 = 0;
var i: u32 = 0;
while (i < rd.count) : (i += 1) {
const item = rd.entry(i) orelse continue;
// The FHS boot tree ferries data files too (/etc/devices.csv,
// /etc/init.csv — served read-only by the kernel VFS, never spawned);
// only the /system and /test trees hold programs, so only those count
// toward the spawn-everything sweep.
const is_program = std.mem.startsWith(u8, item.name, "/system/") or
std.mem.startsWith(u8, item.name, "/test/");
if (!is_program) continue;
programs += 1;
if (process.spawnProcess(item.blob, 4, &.{item.name})) spawned += 1 else |err| {
log("DANOS-INITRD-ERR: {s}: {s}\n", .{ item.name, @errorName(err) });
}
}
check("every initial_ramdisk program spawned", programs >= 1 and spawned == programs);
check("every initial_ramdisk binary spawned", spawned == rd.count);
// Wait for the spawned programs to run and make syscalls (they write + sleep).
scheduler.setPriority(1);
-22
View File
@@ -1,22 +0,0 @@
//! The acpi service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
//!
//! The artifact is named "discovery": one swappable process per firmware
//! fills the ramdisk's neutral `discovery` slot (docs/discovery.md); the
//! root's -Ddiscovery picks this package or `fdt`.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "discovery",
.root_source_file = b.path("acpi.zig"),
.imports = &.{
"acpi-ids", "aml", "device-manager-protocol", "driver", "ipc", "logging", "memory",
"power-protocol", "process", "service", "time",
},
});
b.installArtifact(exe);
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .acpi,
.version = "0.0.0",
.fingerprint = 0xf31e9a0903256b64, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-18
View File
@@ -1,18 +0,0 @@
//! The device-manager service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "device-manager",
.root_source_file = b.path("device-manager.zig"),
.imports = &.{
"device-manager-protocol", "device-registry", "driver", "file-system", "ipc",
"logging", "memory", "process", "service", "time",
},
});
b.installArtifact(exe);
}
@@ -1,16 +0,0 @@
.{
.name = .device_manager,
.version = "0.0.0",
.fingerprint = 0x7092fc24905cd147, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-15
View File
@@ -1,15 +0,0 @@
//! The display-demo service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "display-demo",
.root_source_file = b.path("display-demo.zig"),
.imports = &.{ "display-client", "logging", "time" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .display_demo,
.version = "0.0.0",
.fingerprint = 0x5d2832e1e2880143, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
},
.paths = .{""},
}
@@ -11,7 +11,7 @@
//! is deliberately independent of the mouse.
const display = @import("display-client");
const display = @import("display");
const time = @import("time");
const logging = @import("logging");
pub fn main() void {
-33
View File
@@ -1,33 +0,0 @@
//! The display service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "display",
.root_source_file = b.path("display.zig"),
.imports = &.{
"display-client", "display-protocol", "driver", "input-client", "ipc", "logging",
"memory", "scanout-protocol", "service", "thread", "time",
},
.threaded = true, // real atomics/TLS (docs/threading.md)
});
b.installArtifact(exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the display unit tests");
for ([_][]const u8{
"compositor.zig", // Rect math + fill/composite/blit-tile
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-17
View File
@@ -1,17 +0,0 @@
.{
.name = .display,
.version = "0.0.0",
.fingerprint = 0xcd172a34b127a19, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
+2 -2
View File
@@ -17,11 +17,11 @@
const std = @import("std");
const ipc = @import("ipc");
const input = @import("input-client");
const input = @import("input");
const Thread = @import("thread").Thread;
const service = @import("service");
const time = @import("time");
const display = @import("display-client");
const display = @import("display");
const memory = @import("memory");
const logging = @import("logging");
const compositor = @import("compositor.zig");
-33
View File
@@ -1,33 +0,0 @@
//! The fat service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "fat",
.root_source_file = b.path("fat.zig"),
.imports = &.{
"block", "file-system", "ipc", "logging", "memory", "process", "service", "time",
"vfs-protocol",
},
});
b.installArtifact(exe);
// Standalone `zig build test`; the root aggregate depends on this step.
const test_step = b.step("test", "Run the fat unit tests");
for ([_][]const u8{
"on-disk.zig", // FAT on-disk struct sizes + type detection
"engine.zig", // FAT read/write over a RAM-backed image
}) |test_root| {
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path(test_root),
.target = b.resolveTargetQuery(.{}),
}),
});
test_step.dependOn(&b.addRunArtifact(unit_tests).step);
}
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .fat,
.version = "0.0.0",
.fingerprint = 0x98958143ecfe1636, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.device = .{ .path = "../../../library/device" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-20
View File
@@ -1,20 +0,0 @@
//! The fdt service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
//!
//! The artifact is named "discovery" like acpi's: the Raspberry Pis hand over
//! a flattened device tree, and the aarch64 target flips the root's
//! -Ddiscovery default when it lands (docs/arm.md). A placeholder until the
//! ARM bring-up.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "discovery",
.root_source_file = b.path("fdt.zig"),
.imports = &.{ "process" },
});
b.installArtifact(exe);
}
-14
View File
@@ -1,14 +0,0 @@
.{
.name = .fdt,
.version = "0.0.0",
.fingerprint = 0xe5e27506c7fc2eea, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
},
.paths = .{""},
}
-28
View File
@@ -1,28 +0,0 @@
//! init (PID 1) as a binary package (docs/build-packages-plan.md): this file
//! names the binary and EXACTLY the modules its source imports — the shared
//! recipe and the module-to-domain map live in build-support. The root build
//! consumes the artifact for the boot image and forwards its -Dserial here.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "init",
.root_source_file = b.path("init.zig"),
.imports = &.{
"csv", "file-system", "ipc", "logging", "memory", "power-protocol",
"process", "time",
},
});
// init reads the same `serial` flag the kernel does: its liveness heartbeat
// is a serial/test-build diagnostic (the QEMU harness's init tests assert
// on it, and -Dserial images emit it), so a flashable image runs a purely
// event-driven PID 1 that wakes only for real work. The root build forwards
// its top-level -Dserial as this dependency option.
const serial = b.option(bool, "serial", "Compile the serial liveness heartbeat in (forwarded from the root -Dserial)") orelse false;
const init_options = b.addOptions();
init_options.addOption(bool, "serial", serial);
build_support.programModule(exe).addImport("build_options", init_options.createModule());
b.installArtifact(exe);
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .init,
.version = "0.0.0",
.fingerprint = 0xc674e474eeeced43, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.csv = .{ .path = "../../../library/csv" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
-15
View File
@@ -1,15 +0,0 @@
//! The input service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "input",
.root_source_file = b.path("input.zig"),
.imports = &.{ "input-client", "input-protocol", "ipc", "logging", "process", "service" },
});
b.installArtifact(exe);
}
-16
View File
@@ -1,16 +0,0 @@
.{
.name = .input,
.version = "0.0.0",
.fingerprint = 0xd82832d7113ed94e, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
.client = .{ .path = "../../../library/client" },
.protocol = .{ .path = "../../../library/protocol" },
},
.paths = .{""},
}
+1 -1
View File
@@ -23,7 +23,7 @@ const std = @import("std");
const ipc = @import("ipc");
const process = @import("process");
const service = @import("service");
const input = @import("input-client");
const input = @import("input");
const logging = @import("logging");
const input_protocol = @import("input-protocol");
-15
View File
@@ -1,15 +0,0 @@
//! The logger service as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "logger",
.root_source_file = b.path("logger.zig"),
.imports = &.{ "file-system", "ipc", "logging", "service", "time" },
});
b.installArtifact(exe);
}
-14
View File
@@ -1,14 +0,0 @@
.{
.name = .logger,
.version = "0.0.0",
.fingerprint = 0x987e13f37b0eaea2, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../build-support" },
.kernel = .{ .path = "../../../library/kernel" },
},
.paths = .{""},
}
-15
View File
@@ -1,15 +0,0 @@
//! The args-echo test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "args-echo",
.root_source_file = b.path("args-echo.zig"),
.imports = &.{ "logging", "process" },
});
b.installArtifact(exe);
}
@@ -1,14 +0,0 @@
.{
.name = .args_echo,
.version = "0.0.0",
.fingerprint = 0xcc0ad94cf777eeb, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
},
.paths = .{""},
}
-15
View File
@@ -1,15 +0,0 @@
//! The crash-test test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "crash-test",
.root_source_file = b.path("crash-test.zig"),
.imports = &.{ "device-manager-protocol", "driver", "ipc", "logging", "process", "time" },
});
b.installArtifact(exe);
}
@@ -1,16 +0,0 @@
.{
.name = .crash_test,
.version = "0.0.0",
.fingerprint = 0x611122f815277984, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.device = .{ .path = "../../../../library/device" },
.protocol = .{ .path = "../../../../library/protocol" },
},
.paths = .{""},
}
@@ -1,15 +0,0 @@
//! The device-list test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "device-list",
.root_source_file = b.path("device-list.zig"),
.imports = &.{ "device-manager-protocol", "ipc", "logging", "time" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .device_list,
.version = "0.0.0",
.fingerprint = 0xcdf12d2276a06cb1, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.protocol = .{ .path = "../../../../library/protocol" },
},
.paths = .{""},
}
-15
View File
@@ -1,15 +0,0 @@
//! The fat-test test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "fat-test",
.root_source_file = b.path("fat-test.zig"),
.imports = &.{ "file-system", "logging", "process", "time" },
});
b.installArtifact(exe);
}
@@ -1,14 +0,0 @@
.{
.name = .fat_test,
.version = "0.0.0",
.fingerprint = 0x8dac87d9dc3aabca, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
},
.paths = .{""},
}
@@ -1,15 +0,0 @@
//! The input-source test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "input-source",
.root_source_file = b.path("input-source.zig"),
.imports = &.{ "input-client", "logging", "process", "time" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .input_source,
.version = "0.0.0",
.fingerprint = 0x933ef62ed7d33db7, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.client = .{ .path = "../../../../library/client" },
},
.paths = .{""},
}
@@ -11,7 +11,7 @@
//! decoded hardware is a follow-up (see docs/input.md).
const std = @import("std");
const input = @import("input-client");
const input = @import("input");
const process = @import("process");
const time = @import("time");
const logging = @import("logging");
-15
View File
@@ -1,15 +0,0 @@
//! The input-test test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "input-test",
.root_source_file = b.path("input-test.zig"),
.imports = &.{ "input-client", "logging" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .input_test,
.version = "0.0.0",
.fingerprint = 0x9b12c53bde4d070e, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.client = .{ .path = "../../../../library/client" },
},
.paths = .{""},
}
@@ -7,7 +7,7 @@
//! device classes to one subscription — source -> service -> subscriber, per device.
const std = @import("std");
const input = @import("input-client");
const input = @import("input");
const logging = @import("logging");
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
@@ -1,15 +0,0 @@
//! The iommu-fault-test test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "iommu-fault-test",
.root_source_file = b.path("iommu-fault-test.zig"),
.imports = &.{ "driver", "logging", "mmio", "pci", "pci-class", "time" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .iommu_fault_test,
.version = "0.0.0",
.fingerprint = 0xd7ec3a4e1a61696c, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.device = .{ .path = "../../../../library/device" },
},
.paths = .{""},
}
@@ -1,15 +0,0 @@
//! The pci-cap-test test fixture as a binary package (docs/build-packages-plan.md):
//! this file names the binary and EXACTLY the modules its source imports —
//! the shared recipe and the module-to-domain map live in build-support.
const std = @import("std");
const build_support = @import("build-support");
pub fn build(b: *std.Build) void {
const exe = build_support.userBinary(b, .{
.name = "pci-cap-test",
.root_source_file = b.path("pci-cap-test.zig"),
.imports = &.{ "driver", "ipc", "logging", "mmio", "pci", "pci-class", "time" },
});
b.installArtifact(exe);
}
@@ -1,15 +0,0 @@
.{
.name = .pci_cap_test,
.version = "0.0.0",
.fingerprint = 0x2d4f027d811c3953, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0",
.dependencies = .{
// build-support supplies the shared recipe; kernel is implicit in
// every binary (the root shim + link script live there). The rest
// are exactly the homes of this binary's declared imports.
.@"build-support" = .{ .path = "../../../../build-support" },
.kernel = .{ .path = "../../../../library/kernel" },
.device = .{ .path = "../../../../library/device" },
},
.paths = .{""},
}

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