diff --git a/src/c/c.zig b/src/c/c.zig index 5b86936..ce5b93e 100644 --- a/src/c/c.zig +++ b/src/c/c.zig @@ -335,7 +335,7 @@ export fn sdfgen_irq_ioapic_create(ioapic: u64, pin: u64, c_trigger: [*c]binding log.err("failed to create IOAPIC IRQ at chip {}, pin {}, vector {}: invalid polarity '{}'", .{ ioapic, pin, vector, c_polarity.* }); allocator.destroy(irq); return null; - } + }, }; options.polarity = polarity; } @@ -535,14 +535,16 @@ export fn sdfgen_channel_add(c_sdf: *align(8) anyopaque, c_ch: *align(8) anyopaq sdf.addChannel(ch.*); } -export fn sdfgen_sddf_timer(c_sdf: *align(8) anyopaque, c_device: ?*align(8) anyopaque, driver: *align(8) anyopaque) *anyopaque { +export fn sdfgen_sddf_timer(c_sdf: *align(8) anyopaque, c_device: ?*align(8) anyopaque, driver: *align(8) anyopaque, virt: *align(8) anyopaque) *anyopaque { const sdf: *SystemDescription = @ptrCast(c_sdf); const timer = allocator.create(sddf.Timer) catch @panic("OOM"); timer.* = sddf.Timer.init( allocator, sdf, if (c_device) |raw| @ptrCast(raw) else null, - @ptrCast(driver) + @ptrCast(driver), + @ptrCast(virt), + .{}, ); return timer; @@ -596,7 +598,7 @@ export fn sdfgen_sddf_serial(c_sdf: *align(8) anyopaque, c_device: ?*align(8) an } const serial = allocator.create(sddf.Serial) catch @panic("OOM"); serial.* = sddf.Serial.init(allocator, sdf, if (c_device) |raw| @ptrCast(raw) else null, @ptrCast(driver), @ptrCast(virt_tx), options) catch |e| { - log.err("failed to initialiase serial system: {any}", .{ e }); + log.err("failed to initialiase serial system: {any}", .{e}); allocator.destroy(serial); return null; }; @@ -726,12 +728,11 @@ export fn sdfgen_sddf_gpio_serialise_config(system: *align(8) anyopaque, output_ return true; } - export fn sdfgen_sddf_blk(c_sdf: *align(8) anyopaque, c_device: ?*align(8) anyopaque, driver: *align(8) anyopaque, virt: *align(8) anyopaque) ?*anyopaque { const sdf: *SystemDescription = @ptrCast(c_sdf); const blk = allocator.create(sddf.Blk) catch @panic("OOM"); blk.* = sddf.Blk.init(allocator, sdf, if (c_device) |raw| @ptrCast(raw) else null, @ptrCast(driver), @ptrCast(virt), .{}) catch |e| { - log.err("failed to initialiase blk system: {any}", .{ e }); + log.err("failed to initialiase blk system: {any}", .{e}); allocator.destroy(blk); return null; }; diff --git a/src/data.zig b/src/data.zig index 372d4b7..080001f 100644 --- a/src/data.zig +++ b/src/data.zig @@ -281,11 +281,23 @@ pub const Resources = struct { pub const Timer = struct { const MAGIC: [5]u8 = MAGIC_START ++ .{0x6}; - pub const Client = extern struct { magic: [5]u8 = MAGIC, + time_page: Region, + virt_id: u8, + }; + + pub const Virt = extern struct { + magic: [5]u8 = MAGIC, + time_page: Region, driver_id: u8, }; + + pub const Driver = extern struct { + magic: [5]u8 = MAGIC, + time_page: Region, + virt_id: u8, + }; }; pub const Gpu = struct { diff --git a/src/python/module.py b/src/python/module.py index f646345..b872de8 100644 --- a/src/python/module.py +++ b/src/python/module.py @@ -1104,14 +1104,15 @@ def __init__( self, sdf: SystemDescription, device: Optional[DeviceTree.Node], - driver: SystemDescription.ProtectionDomain + driver: SystemDescription.ProtectionDomain, + virt: SystemDescription.ProtectionDomain ) -> None: if device is None: device_obj = None else: device_obj = device._obj - self._obj: c_void_p = libsdfgen.sdfgen_sddf_timer(sdf._obj, device_obj, driver._obj) + self._obj: c_void_p = libsdfgen.sdfgen_sddf_timer(sdf._obj, device_obj, driver._obj, virt._obj) def add_client(self, client: SystemDescription.ProtectionDomain): ret = libsdfgen.sdfgen_sddf_timer_add_client(self._obj, client._obj) diff --git a/src/sddf/timer.zig b/src/sddf/timer.zig index 08eaa90..655ce84 100644 --- a/src/sddf/timer.zig +++ b/src/sddf/timer.zig @@ -24,9 +24,15 @@ pub const Timer = struct { sdf: *SystemDescription, /// Protection Domain that will act as the driver for the timer driver: *Pd, + virt: *Pd, /// Device Tree node for the timer device device: ?*dtb.Node, device_res: ConfigResources.Device, + /// Current time page + time_page_size: usize, + /// Config structs + driver_config: ConfigResources.Timer.Driver, + virt_config: ConfigResources.Timer.Virt, /// Client PDs serviced by the timer driver clients: std.array_list.Managed(*Pd), client_configs: std.array_list.Managed(ConfigResources.Timer.Client), @@ -35,17 +41,24 @@ pub const Timer = struct { pub const Error = SystemError; - pub fn init(allocator: Allocator, sdf: *SystemDescription, device: ?*dtb.Node, driver: *Pd) Timer { - // First we have to set some properties on the driver. It is currently our policy that every timer - // driver should be passive. - driver.passive = true; + pub const Options = struct { + time_page_size: usize = 0x1000, + }; + + pub fn init(allocator: Allocator, sdf: *SystemDescription, device: ?*dtb.Node, driver: *Pd, virt: *Pd, options: Options) Timer { + // Virt should be passive + virt.passive = true; return .{ .allocator = allocator, .sdf = sdf, .driver = driver, + .virt = virt, .device = device, .device_res = std.mem.zeroInit(ConfigResources.Device, .{}), + .time_page_size = options.time_page_size, + .driver_config = std.mem.zeroInit(ConfigResources.Timer.Driver, .{}), + .virt_config = std.mem.zeroInit(ConfigResources.Timer.Virt, .{}), .clients = std.array_list.Managed(*Pd).init(allocator), .client_configs = std.array_list.Managed(ConfigResources.Timer.Client).init(allocator), }; @@ -67,8 +80,17 @@ pub const Timer = struct { log.err("invalid timer client, same name as driver '{s}", .{client.name}); return Error.InvalidClient; } + if (std.mem.eql(u8, client.name, system.virt.name)) { + log.err("invalid timer client, same name as virt'{s}", .{client.name}); + return Error.InvalidClient; + } const client_priority = if (client.priority) |priority| priority else Pd.DEFAULT_PRIORITY; + const virt_priority = if (system.virt.priority) |priority| priority else Pd.DEFAULT_PRIORITY; const driver_priority = if (system.driver.priority) |priority| priority else Pd.DEFAULT_PRIORITY; + if (client_priority >= virt_priority) { + log.err("invalid timer client '{s}', virt '{s}' must have greater priority than client", .{ client.name, system.virt.name }); + return Error.InvalidClient; + } if (client_priority >= driver_priority) { log.err("invalid timer client '{s}', driver '{s}' must have greater priority than client", .{ client.name, system.driver.name }); return Error.InvalidClient; @@ -77,22 +99,73 @@ pub const Timer = struct { system.client_configs.append(std.mem.zeroInit(ConfigResources.Timer.Client, .{})) catch @panic("Could not add client to Timer"); } + pub fn connectDriver(system: *Timer, mr_time_page: Mr) void { + var sdf = system.sdf; + var driver = system.driver; + var virt = system.virt; + + // Create all the MRs between the driver and virtualiser + + sdf.addMemoryRegion(mr_time_page); + + const driver_map_time_page = Map.create(mr_time_page, driver.getMapVaddr(&mr_time_page), .rw, .{}); + driver.addMap(driver_map_time_page); + + const virt_map_time_page = Map.create(mr_time_page, virt.getMapVaddr(&mr_time_page), .r, .{}); + virt.addMap(virt_map_time_page); + + const ch = Channel.create(system.driver, system.virt, .{ + // virt must be able to ppc to driver, not notify. + .pp = .b, + .pd_b_notify = false, + }) catch unreachable; + sdf.addChannel(ch); + + system.driver_config = .{ + .time_page = .createFromMap(driver_map_time_page), + .virt_id = ch.pd_a_id, + }; + + system.virt_config = .{ + .time_page = .createFromMap(virt_map_time_page), + .driver_id = ch.pd_b_id, + }; + } + + pub fn connectClient(system: *Timer, client: *Pd, i: usize, mr_time_page: Mr) void { + var sdf = system.sdf; + const virt = system.virt; + + // system.virt_config.num_clients += 1; + + const client_time_page_map = Map.create(mr_time_page, client.getMapVaddr(&mr_time_page), .r, .{}); + client.addMap(client_time_page_map); + + // Create a channel between the virtualiser and client + const ch = Channel.create(virt, client, .{ + .pp = .b, + .pd_b_notify = false, + }) catch unreachable; + sdf.addChannel(ch); + + system.client_configs.items[i] = .{ + .virt_id = ch.pd_b_id, + .time_page = .createFromMap(client_time_page_map), + }; + } + pub fn connect(system: *Timer) !void { - // The driver must be passive - std.debug.assert(system.driver.passive.?); + const allocator = system.allocator; + // The virt must be passive + std.debug.assert(system.virt.passive.?); + const mr_time_page = Mr.create(allocator, "time_page", system.time_page_size, .{}); if (system.device) |dtb_node| { try sddf.createDriver(system.sdf, system.driver, dtb_node, .timer, &system.device_res); } + system.connectDriver(mr_time_page); for (system.clients.items, 0..) |client, i| { - const ch = Channel.create(system.driver, client, .{ - // Client needs to be able to PPC into driver - .pp = .b, - // Client does not need to notify driver - .pd_b_notify = false, - }) catch unreachable; - system.sdf.addChannel(ch); - system.client_configs.items[i].driver_id = ch.pd_b_id; + system.connectClient(client, i, mr_time_page); } system.connected = true; @@ -105,6 +178,8 @@ pub const Timer = struct { const device_res_data_name = fmt(allocator, "{s}_device_resources", .{system.driver.name}); try data.serialize(allocator, system.device_res, prefix, device_res_data_name); + try data.serialize(allocator, system.driver_config, prefix, "timer_driver"); + try data.serialize(allocator, system.virt_config, prefix, "timer_virt"); for (system.clients.items, 0..) |client, i| { const data_name = fmt(allocator, "timer_client_{s}", .{client.name});