diff --git a/build-support/build.zig b/build-support/build.zig index 449f27b..474c9b0 100644 --- a/build-support/build.zig +++ b/build-support/build.zig @@ -113,3 +113,78 @@ pub fn userBinaryFromImports(b: *std.Build, options: UserBinaryOptions) *std.Bui pub fn programModule(exe: *std.Build.Step.Compile) *std.Build.Module { return exe.root_module.import_table.get("program").?; } + +/// The library domain packages a user binary's default import set draws from. +/// A binary package declares these in its build.zig.zon under exactly these +/// dependency names (kernel, device, client, xkeyboard-config) and resolves +/// them with `domains`. Path dependencies deduplicate by resolved location, +/// so every binary and the root build share one instance of each module. +pub const Domains = struct { + kernel: *std.Build.Dependency, + device: *std.Build.Dependency, + client: *std.Build.Dependency, + xkeyboard_config: *std.Build.Dependency, +}; + +/// Resolve the four default-set domain packages by their conventional +/// dependency names — the one-liner for a binary package's build fn. +pub fn domains(b: *std.Build) Domains { + return .{ + .kernel = b.dependency("kernel", .{}), + .device = b.dependency("device", .{}), + .client = b.dependency("client", .{}), + .xkeyboard_config = b.dependency("xkeyboard-config", .{}), + }; +} + +/// What `userBinary` needs to know about one user binary. The domain wiring +/// (default imports, root shim, link script, target) is derived. +pub const DomainUserBinaryOptions = struct { + name: []const u8, + /// The program's own source file — it becomes the `program` module. + root_source_file: std.Build.LazyPath, + domains: Domains, + /// See UserBinaryOptions.threaded. + threaded: bool = false, +}; + +/// Build one user binary against the domain packages' default import set — +/// the library/kernel concern modules (ipc, memory, process, time, logging, +/// file-system, ...), the device/service clients (driver, block, display, +/// input), mmio, acpi-ids, and xkeyboard-config. Per-binary extras go through +/// `programModule(exe).addImport`. This is THE recipe a binary package's +/// build.zig calls; the root shim and user link script come from the kernel +/// domain package's directory. +pub fn userBinary(b: *std.Build, options: DomainUserBinaryOptions) *std.Build.Step.Compile { + const kernel = options.domains.kernel; + const device = options.domains.device; + const client = options.domains.client; + const default_imports = [_]std.Build.Module.Import{ + .{ .name = "mmio", .module = device.module("mmio") }, + .{ .name = "xkeyboard-config", .module = options.domains.xkeyboard_config.module("xkeyboard-config") }, + .{ .name = "acpi-ids", .module = device.module("acpi-ids") }, + .{ .name = "system-call", .module = kernel.module("system-call") }, + .{ .name = "ipc", .module = kernel.module("ipc") }, + .{ .name = "memory", .module = kernel.module("memory") }, + .{ .name = "process", .module = kernel.module("process") }, + .{ .name = "thread", .module = kernel.module("thread") }, + .{ .name = "time", .module = kernel.module("time") }, + .{ .name = "logging", .module = kernel.module("logging") }, + .{ .name = "file-system", .module = kernel.module("file-system") }, + .{ .name = "service", .module = kernel.module("service") }, + .{ .name = "start", .module = kernel.module("start") }, + .{ .name = "driver", .module = device.module("driver") }, + .{ .name = "block", .module = device.module("block") }, + .{ .name = "display", .module = client.module("display") }, + .{ .name = "input", .module = client.module("input") }, + }; + return userBinaryFromImports(b, .{ + .name = options.name, + .root_source_file = options.root_source_file, + .shim_source_file = kernel.path("root.zig"), + .linker_script = kernel.path("user.ld"), + .target = freestandingTarget(b), + .default_imports = &default_imports, + .threaded = options.threaded, + }); +} diff --git a/build.zig b/build.zig index 298d429..d05f904 100644 --- a/build.zig +++ b/build.zig @@ -467,11 +467,10 @@ pub fn build(b: *std.Build) void { const shared_memory_server_exe = addUserBinary(b, kernel_target, &default_imports, "shared-memory-server", "test/system/services/shared-memory-server/shared-memory-server.zig"); const shared_memory_client_exe = addUserBinary(b, kernel_target, &default_imports, "shared-memory-client", "test/system/services/shared-memory-client/shared-memory-client.zig"); const fat_test_exe = addUserBinary(b, kernel_target, &default_imports, "fat-test", "test/system/services/fat-test/fat-test.zig"); - const pci_bus_exe = addUserBinary(b, kernel_target, &default_imports, "pci-bus", "system/drivers/pci-bus/pci-bus.zig"); - programModule(pci_bus_exe).addImport("device-manager-protocol", device_manager_protocol_module); - // The PCI bus driver decodes each function's class triple to human names in its - // boot log (class/subclass/prog-IF), so pull in the shared pci-class reference. - programModule(pci_bus_exe).addImport("pci-class", pci_class_module); + // The first binary package (docs/build-packages-plan.md, phase 2): pci-bus + // builds itself against the domain packages; the root build just takes the + // artifact for the boot image. + const pci_bus_exe = b.dependency("pci-bus", .{}).artifact("pci-bus"); // A test fixture, not a real driver: hellos to the device manager, then faults — // what the driver-restart scenario drives the crash-loop cap with. const crash_test_exe = addUserBinary(b, kernel_target, &default_imports, "crash-test", "test/system/services/crash-test/crash-test.zig"); diff --git a/build.zig.zon b/build.zig.zon index 03e00a6..b80f6ad 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -42,6 +42,8 @@ .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" }, // See `zig fetch --save ` for a command-line interface for adding dependencies. //.example = .{ // // When updating this field to a new URL, be sure to delete the corresponding diff --git a/system/drivers/pci-bus/build.zig b/system/drivers/pci-bus/build.zig new file mode 100644 index 0000000..6456182 --- /dev/null +++ b/system/drivers/pci-bus/build.zig @@ -0,0 +1,20 @@ +//! The pci-bus driver as a binary package (docs/build-packages-plan.md, +//! phase 2): this file names only what is specific to pci-bus — the shared +//! recipe and the default-import wiring live in build-support. The root build +//! consumes the artifact for the boot image. + +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"), + .domains = build_support.domains(b), + }); + // The bus driver reports discovered functions to the device manager, and + // decodes each function's class triple to human names in its boot log. + build_support.programModule(exe).addImport("device-manager-protocol", b.dependency("protocol", .{}).module("device-manager-protocol")); + build_support.programModule(exe).addImport("pci-class", b.dependency("device", .{}).module("pci-class")); + b.installArtifact(exe); +} diff --git a/system/drivers/pci-bus/build.zig.zon b/system/drivers/pci-bus/build.zig.zon new file mode 100644 index 0000000..ade4cfa --- /dev/null +++ b/system/drivers/pci-bus/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .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" = .{ .path = "../../../build-support" }, + .kernel = .{ .path = "../../../library/kernel" }, + .device = .{ .path = "../../../library/device" }, + .client = .{ .path = "../../../library/client" }, + .@"xkeyboard-config" = .{ .path = "../../../library/xkeyboard-config" }, + .protocol = .{ .path = "../../../library/protocol" }, + }, + .paths = .{""}, +}