ci: add self-hosted

This commit is contained in:
David Gonzalez Martin 2023-07-10 12:19:24 -06:00
parent deffd2ee8b
commit 4a2a4255b2
7 changed files with 116 additions and 51 deletions

View File

@ -28,13 +28,30 @@ jobs:
windows-latest, windows-latest,
] ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 15
steps: steps:
- uses: actions/checkout@v3 - name: Checkout
- uses: goto-bus-stop/setup-zig@v2 uses: actions/checkout@v3
- name: Set up Zig
uses: goto-bus-stop/setup-zig@v2
with: with:
version: master version: master
- name: Zig environment variables - name: Zig environment variables
run: zig env run: zig env
- name: Build test executables - name: Build test executables
run: zig build all_tests -Dci --verbose run: zig build all_tests -Dci --verbose
build_and_test:
runs-on: [self-hosted, Linux, X64]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Zig
uses: goto-bus-stop/setup-zig@v2
with:
version: master
- name: Zig environment variables
run: zig env
- name: Build test executables
run: zig build all_tests -Dci -Dci_native --verbose
- name: Test with QEMU
run: zig build test_all -Dci -Dci_native --verbose

View File

@ -37,6 +37,7 @@ const source_root_dir = "src";
const user_program_dir_path = "src/user/programs"; const user_program_dir_path = "src/user/programs";
var ci = false; var ci = false;
var ci_native = false;
var debug_user = false; var debug_user = false;
var debug_loader = false; var debug_loader = false;
var modules = Modules{}; var modules = Modules{};
@ -49,6 +50,7 @@ var options = Options{};
pub fn build(b_arg: *Build) !void { pub fn build(b_arg: *Build) !void {
b = b_arg; b = b_arg;
ci = b.option(bool, "ci", "CI mode") orelse false; ci = b.option(bool, "ci", "CI mode") orelse false;
ci_native = b.option(bool, "ci_native", "CI mode in self-hosted runner") orelse false;
debug_user = b.option(bool, "debug_user", "Debug user program") orelse false; debug_user = b.option(bool, "debug_user", "Debug user program") orelse false;
debug_loader = b.option(bool, "debug_loader", "Debug loader program") orelse false; debug_loader = b.option(bool, "debug_loader", "Debug loader program") orelse false;
const default_cfg_override = b.option([]const u8, "default", "Default configuration JSON file") orelse "config/default.json"; const default_cfg_override = b.option([]const u8, "default", "Default configuration JSON file") orelse "config/default.json";
@ -157,6 +159,7 @@ pub fn build(b_arg: *Build) !void {
root_project_path: []const u8, root_project_path: []const u8,
modules: []const ModuleID, modules: []const ModuleID,
c: ?C = null, c: ?C = null,
run_native: bool = true,
const C = struct { const C = struct {
include_paths: []const []const u8, include_paths: []const []const u8,
@ -190,6 +193,7 @@ pub fn build(b_arg: *Build) !void {
.link_libc = true, .link_libc = true,
.link_libcpp = false, .link_libcpp = false,
}, },
.run_native = false,
}, },
}; };
@ -222,12 +226,25 @@ pub fn build(b_arg: *Build) !void {
} }
} }
const run_test_step = b.addRunArtifact(test_exe);
//run_test_step.condition = .always; //run_test_step.condition = .always;
build_steps.test_all.dependOn(&run_test_step.step); const should_run = !ci_native or (ci_native and native_test.run_native);
build_steps.test_host.dependOn(&run_test_step.step); if (should_run) {
const run_test_step = b.addRunArtifact(test_exe);
build_steps.test_all.dependOn(&run_test_step.step);
build_steps.test_host.dependOn(&run_test_step.step);
}
} }
const ovmf_downloader = try addCompileStep(.{
.name = "ovmf_downloader",
.root_project_path = "src/host/ovmf_downloader",
.optimize_mode = .Debug,
.modules = &.{ .lib, .host },
.kind = .exe,
});
const ovmf_downloader_run_step = b.addRunArtifact(ovmf_downloader);
const ovmf_path = ovmf_downloader_run_step.addOutputFileArg("OVMF.fd");
{ {
var user_module_list = std.ArrayList(common.Module).init(b.allocator); var user_module_list = std.ArrayList(common.Module).init(b.allocator);
var user_program_dir = try std.fs.cwd().openIterableDir(user_program_dir_path, .{ .access_sub_paths = true }); var user_program_dir = try std.fs.cwd().openIterableDir(user_program_dir_path, .{ .access_sub_paths = true });
@ -461,6 +478,7 @@ pub fn build(b_arg: *Build) !void {
.is_debug = false, .is_debug = false,
.is_test = is_test, .is_test = is_test,
}, },
.ovmf_path = ovmf_path,
}); });
const runner_debug = try newRunnerRunArtifact(.{ const runner_debug = try newRunnerRunArtifact(.{
.configuration = configuration, .configuration = configuration,
@ -473,6 +491,7 @@ pub fn build(b_arg: *Build) !void {
.is_debug = true, .is_debug = true,
.is_test = is_test, .is_test = is_test,
}, },
.ovmf_path = ovmf_path,
}); });
if (is_test) { if (is_test) {
@ -572,9 +591,12 @@ fn newRunnerRunArtifact(arguments: struct {
cpu_driver: *CompileStep, cpu_driver: *CompileStep,
user_init: *CompileStep, user_init: *CompileStep,
qemu_options: QEMUOptions, qemu_options: QEMUOptions,
ovmf_path: FileSource,
}) !*RunStep { }) !*RunStep {
const runner = b.addRunArtifact(arguments.runner); const runner = b.addRunArtifact(arguments.runner);
var argument_parser = common.ArgumentParser.Runner{}; var argument_parser = common.ArgumentParser.Runner{};
while (argument_parser.next()) |argument_type| switch (argument_type) { while (argument_parser.next()) |argument_type| switch (argument_type) {
.configuration => inline for (common.fields(Configuration)) |field| runner.addArg(@tagName(@field(arguments.configuration, field.name))), .configuration => inline for (common.fields(Configuration)) |field| runner.addArg(@tagName(@field(arguments.configuration, field.name))),
.image_configuration_path => runner.addArg(common.ImageConfig.default_path), .image_configuration_path => runner.addArg(common.ImageConfig.default_path),
@ -586,6 +608,7 @@ fn newRunnerRunArtifact(arguments: struct {
.ci => runner.addArg(if (ci) "true" else "false"), .ci => runner.addArg(if (ci) "true" else "false"),
.debug_user => runner.addArg(if (debug_user) "true" else "false"), .debug_user => runner.addArg(if (debug_user) "true" else "false"),
.debug_loader => runner.addArg(if (debug_loader) "true" else "false"), .debug_loader => runner.addArg(if (debug_loader) "true" else "false"),
.ovmf_path => runner.addFileSourceArg(arguments.ovmf_path),
}; };
return runner; return runner;

View File

@ -97,7 +97,6 @@ const Filesystem = extern struct {
pub fn getFileSize(filesystem: *Filesystem, file_path: []const u8) !u32 { pub fn getFileSize(filesystem: *Filesystem, file_path: []const u8) !u32 {
const file = try filesystem.openFile(file_path); const file = try filesystem.openFile(file_path);
log.debug("File size", .{});
var file_info_buffer: [@sizeOf(uefi.FileInfo) + 0x100]u8 align(@alignOf(uefi.FileInfo)) = undefined; var file_info_buffer: [@sizeOf(uefi.FileInfo) + 0x100]u8 align(@alignOf(uefi.FileInfo)) = undefined;
var file_info_size = file_info_buffer.len; var file_info_size = file_info_buffer.len;
try uefi.Try(file.handle.getInfo(&uefi.FileInfo.guid, &file_info_size, &file_info_buffer)); try uefi.Try(file.handle.getInfo(&uefi.FileInfo.guid, &file_info_size, &file_info_buffer));
@ -112,25 +111,20 @@ const Filesystem = extern struct {
return Error.boot_services_exited; return Error.boot_services_exited;
} }
log.debug("opening file: {s}", .{file_path});
var file: *FileProtocol = undefined; var file: *FileProtocol = undefined;
var path_buffer: [256:0]u16 = undefined; var path_buffer: [256:0]u16 = undefined;
const length = try lib.unicode.utf8ToUtf16Le(&path_buffer, file_path); const length = try lib.unicode.utf8ToUtf16Le(&path_buffer, file_path);
path_buffer[length] = 0; path_buffer[length] = 0;
const path = path_buffer[0..length :0]; const path = path_buffer[0..length :0];
const uefi_path = if (path[0] == '/') path[1..] else path; const uefi_path = if (path[0] == '/') path[1..] else path;
log.debug("uefi path: {any}", .{uefi_path});
try uefi.Try(filesystem.root.open(&file, uefi_path, FileProtocol.efi_file_mode_read, 0)); try uefi.Try(filesystem.root.open(&file, uefi_path, FileProtocol.efi_file_mode_read, 0));
log.debug("Opened", .{});
const result = FileDescriptor{ const result = FileDescriptor{
.handle = file, .handle = file,
.path_size = @as(u32, @intCast(path.len * @sizeOf(u16))), .path_size = @as(u32, @intCast(path.len * @sizeOf(u16))),
}; };
log.debug("opened file: {s}", .{file_path});
return result; return result;
} }
@ -251,9 +245,7 @@ const Initialization = struct {
}, },
}, },
.framebuffer = blk: { .framebuffer = blk: {
log.debug("Locating GOP", .{});
const gop = try Protocol.locate(uefi.GraphicsOutputProtocol, boot_services); const gop = try Protocol.locate(uefi.GraphicsOutputProtocol, boot_services);
log.debug("Located GOP", .{});
const pixel_format_info: struct { const pixel_format_info: struct {
red_color_mask: bootloader.Framebuffer.ColorMask, red_color_mask: bootloader.Framebuffer.ColorMask,
@ -303,7 +295,6 @@ const Initialization = struct {
}, },
}; };
log.debug("Memory map size: {}", .{init.memory_map.size});
_ = boot_services.getMemoryMap(&init.memory_map.size, @as([*]MemoryDescriptor, @ptrCast(&init.memory_map.buffer)), &init.memory_map.key, &init.memory_map.descriptor_size, &init.memory_map.descriptor_version); _ = boot_services.getMemoryMap(&init.memory_map.size, @as([*]MemoryDescriptor, @ptrCast(&init.memory_map.buffer)), &init.memory_map.key, &init.memory_map.descriptor_size, &init.memory_map.descriptor_version);
init.memory_map.entry_count = @as(u32, @intCast(@divExact(init.memory_map.size, init.memory_map.descriptor_size))); init.memory_map.entry_count = @as(u32, @intCast(@divExact(init.memory_map.size, init.memory_map.descriptor_size)));
assert(init.memory_map.entry_count > 0); assert(init.memory_map.entry_count > 0);
@ -321,8 +312,6 @@ const Initialization = struct {
const expected_memory_map_descriptor_size = init.memory_map.descriptor_size; const expected_memory_map_descriptor_size = init.memory_map.descriptor_size;
const expected_memory_map_descriptor_version = init.memory_map.descriptor_version; const expected_memory_map_descriptor_version = init.memory_map.descriptor_version;
log.debug("Getting memory map before exiting boot services...", .{});
blk: while (init.memory_map.size < MemoryMap.buffer_len) : (init.memory_map.size += init.memory_map.descriptor_size) { blk: while (init.memory_map.size < MemoryMap.buffer_len) : (init.memory_map.size += init.memory_map.descriptor_size) {
uefi.Try(init.boot_services.getMemoryMap(&init.memory_map.size, @as([*]MemoryDescriptor, @ptrCast(&init.memory_map.buffer)), &init.memory_map.key, &init.memory_map.descriptor_size, &init.memory_map.descriptor_version)) catch continue; uefi.Try(init.boot_services.getMemoryMap(&init.memory_map.size, @as([*]MemoryDescriptor, @ptrCast(&init.memory_map.buffer)), &init.memory_map.key, &init.memory_map.descriptor_size, &init.memory_map.descriptor_version)) catch continue;
init.exited_boot_services = true; init.exited_boot_services = true;

View File

@ -481,6 +481,7 @@ pub const ArgumentParser = struct {
debug_user, debug_user,
debug_loader, debug_loader,
init, init,
ovmf_path,
}; };
pub const Result = struct { pub const Result = struct {
@ -494,6 +495,7 @@ pub const ArgumentParser = struct {
debug_user: bool, debug_user: bool,
debug_loader: bool, debug_loader: bool,
init: []const u8, init: []const u8,
ovmf_path: []const u8,
}; };
}; };
}; };

View File

@ -15,6 +15,9 @@ pub const cwd = fs.cwd;
pub const Dir = fs.Dir; pub const Dir = fs.Dir;
pub const basename = fs.path.basename; pub const basename = fs.path.basename;
pub const dirname = fs.path.dirname; pub const dirname = fs.path.dirname;
pub const realpathAlloc = fs.realpathAlloc;
pub const os = std.os;
const io = std.io; const io = std.io;
pub const getStdOut = std.io.getStdOut; pub const getStdOut = std.io.getStdOut;

View File

@ -0,0 +1,57 @@
const host = @import("host");
const Error = error{
wrong_arguments,
};
pub fn main() !void {
const allocator = @import("std").heap.page_allocator;
const arguments = try host.allocateArguments(allocator);
if (arguments.len != 2) {
return Error.wrong_arguments;
}
const ovmf_path = arguments[1];
const file_descriptor = blk: {
if (host.fs.openFileAbsolute(ovmf_path, .{})) |file_descriptor| {
break :blk file_descriptor;
} else |_| {
const url = "https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd";
const uri = try host.Uri.parse(url);
var http_client = host.http.Client{ .allocator = allocator };
defer http_client.deinit();
var request_headers = host.http.Headers{ .allocator = allocator };
defer request_headers.deinit();
var request = try http_client.request(.GET, uri, request_headers, .{});
defer request.deinit();
try request.start();
try request.wait();
if (request.response.status != .ok) {
return error.ResponseNotOk;
}
const content_length = request.response.content_length orelse {
return error.OutOfMemory;
};
const buffer = try allocator.alloc(u8, content_length);
const read_byte_count = try request.readAll(buffer);
if (read_byte_count != buffer.len) {
return error.OutOfMemory;
}
const ovmf_file_descriptor = try host.fs.createFileAbsolute(ovmf_path, .{});
try ovmf_file_descriptor.writeAll(buffer);
break :blk ovmf_file_descriptor;
}
};
file_descriptor.close();
}

View File

@ -21,6 +21,7 @@ const Error = error{
not_implemented, not_implemented,
architecture_not_supported, architecture_not_supported,
execution_environment_not_supported, execution_environment_not_supported,
ovmf_path_not_found,
}; };
pub fn main() anyerror!void { pub fn main() anyerror!void {
@ -44,6 +45,7 @@ pub fn main() anyerror!void {
var argument_debug_loader: ?bool = null; var argument_debug_loader: ?bool = null;
var argument_init_path: ?[]const u8 = null; var argument_init_path: ?[]const u8 = null;
var argument_index: usize = 0; var argument_index: usize = 0;
var argument_ovmf_path: ?[]const u8 = null;
while (argument_parser.next()) |argument_type| switch (argument_type) { while (argument_parser.next()) |argument_type| switch (argument_type) {
.disk_image_path => { .disk_image_path => {
@ -95,6 +97,10 @@ pub fn main() anyerror!void {
argument_init_path = arguments[argument_index]; argument_init_path = arguments[argument_index];
argument_index += 1; argument_index += 1;
}, },
.ovmf_path => {
argument_ovmf_path = arguments[argument_index];
argument_index += 1;
},
}; };
if (argument_index != arguments.len) return Error.wrong_argument_count; if (argument_index != arguments.len) return Error.wrong_argument_count;
@ -110,6 +116,7 @@ pub fn main() anyerror!void {
.debug_user = argument_debug_user orelse return Error.debug_user_not_found, .debug_user = argument_debug_user orelse return Error.debug_user_not_found,
.debug_loader = argument_debug_loader orelse return Error.debug_loader_not_found, .debug_loader = argument_debug_loader orelse return Error.debug_loader_not_found,
.init = argument_init_path orelse return Error.init_not_found, .init = argument_init_path orelse return Error.init_not_found,
.ovmf_path = argument_ovmf_path orelse return Error.ovmf_path_not_found,
}; };
}; };
@ -130,40 +137,7 @@ pub fn main() anyerror!void {
} }
switch (arguments_result.configuration.boot_protocol) { switch (arguments_result.configuration.boot_protocol) {
.uefi => { .uefi => try argument_list.appendSlice(&.{ "-bios", arguments_result.ovmf_path }),
const ovmf_path = "tools/OVMF.fd";
if (host.cwd().openFile(ovmf_path, .{})) |file_descriptor| {
file_descriptor.close();
} else |_| {
const url = "https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd";
const uri = try host.Uri.parse(url);
var http_client = host.http.Client{ .allocator = wrapped_allocator.zigUnwrap() };
defer http_client.deinit();
var request_headers = host.http.Headers{ .allocator = wrapped_allocator.zigUnwrap() };
defer request_headers.deinit();
var request = try http_client.request(.GET, uri, request_headers, .{});
defer request.deinit();
try request.start();
try request.wait();
if (request.response.status != .ok) return error.ResponseNotOk;
const content_length = request.response.content_length orelse return error.OutOfMemory;
const buffer = try wrapped_allocator.zigUnwrap().alloc(u8, content_length);
const read_byte_count = try request.readAll(buffer);
if (read_byte_count != buffer.len) {
return error.OutOfMemory;
}
try host.cwd().writeFile(ovmf_path, buffer);
}
try argument_list.appendSlice(&.{ "-bios", ovmf_path });
},
else => {}, else => {},
} }