Merge pull request #249 from ZystemOS/feature/pci

Initial PCI interface
This commit is contained in:
Edward Dean 2020-10-12 11:53:42 +01:00 committed by GitHub
commit 39b857df5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 677 additions and 147 deletions

View file

@ -9,6 +9,7 @@ const irq = @import("irq.zig");
const isr = @import("isr.zig"); const isr = @import("isr.zig");
const paging = @import("paging.zig"); const paging = @import("paging.zig");
const pic = @import("pic.zig"); const pic = @import("pic.zig");
const pci = @import("pci.zig");
const pit = @import("pit.zig"); const pit = @import("pit.zig");
const rtc = @import("rtc.zig"); const rtc = @import("rtc.zig");
const serial = @import("serial.zig"); const serial = @import("serial.zig");
@ -25,6 +26,9 @@ const TTY = @import("../../tty.zig").TTY;
const Keyboard = @import("../../keyboard.zig").Keyboard; const Keyboard = @import("../../keyboard.zig").Keyboard;
const MemProfile = mem.MemProfile; const MemProfile = mem.MemProfile;
/// The type of a device.
pub const Device = pci.PciDeviceInfo;
/// The virtual end of the kernel code. /// The virtual end of the kernel code.
extern var KERNEL_VADDR_END: *u32; extern var KERNEL_VADDR_END: *u32;
@ -101,42 +105,67 @@ pub const MEMORY_BLOCK_SIZE: usize = paging.PAGE_SIZE_4KB;
/// The default stack size of a task. Currently this is set to a page size. /// The default stack size of a task. Currently this is set to a page size.
pub const STACK_SIZE: u32 = MEMORY_BLOCK_SIZE / @sizeOf(u32); pub const STACK_SIZE: u32 = MEMORY_BLOCK_SIZE / @sizeOf(u32);
///
/// Assembly to write to a given port with a byte of data.
///
/// Arguments:
/// IN port: u16 - The port to write to.
/// IN data: u8 - The byte of data that will be sent.
///
pub fn outb(port: u16, data: u8) void {
asm volatile ("outb %[data], %[port]"
:
: [port] "{dx}" (port),
[data] "{al}" (data)
);
}
/// ///
/// Assembly that reads data from a given port and returns its value. /// Assembly that reads data from a given port and returns its value.
/// ///
/// Arguments: /// Arguments:
/// IN port: u16 - The port to read data from. /// IN comptime Type: type - The type of the data. This can only be u8, u16 or u32.
/// IN port: u16 - The port to read data from.
/// ///
/// Return: u8 /// Return: Type
/// The data that the port returns. /// The data that the port returns.
/// ///
pub fn inb(port: u16) u8 { pub fn in(comptime Type: type, port: u16) Type {
return asm volatile ("inb %[port], %[result]" return switch (Type) {
: [result] "={al}" (-> u8) u8 => asm volatile ("inb %[port], %[result]"
: [port] "N{dx}" (port) : [result] "={al}" (-> Type)
); : [port] "N{dx}" (port)
),
u16 => asm volatile ("inw %[port], %[result]"
: [result] "={ax}" (-> Type)
: [port] "N{dx}" (port)
),
u32 => asm volatile ("inl %[port], %[result]"
: [result] "={eax}" (-> Type)
: [port] "N{dx}" (port)
),
else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(Type)),
};
}
///
/// Assembly to write to a given port with a give type of data.
///
/// Arguments:
/// IN port: u16 - The port to write to.
/// IN data: anytype - The data that will be sent This must be a u8, u16 or u32 type.
///
pub fn out(port: u16, data: anytype) void {
switch (@TypeOf(data)) {
u8 => asm volatile ("outb %[data], %[port]"
:
: [port] "{dx}" (port),
[data] "{al}" (data)
),
u16 => asm volatile ("outw %[data], %[port]"
:
: [port] "{dx}" (port),
[data] "{ax}" (data)
),
u32 => asm volatile ("outl %[data], %[port]"
:
: [port] "{dx}" (port),
[data] "{eax}" (data)
),
else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(@TypeOf(data))),
}
} }
/// ///
/// Force the CPU to wait for an I/O operation to compete. Use port 0x80 as this is unused. /// Force the CPU to wait for an I/O operation to compete. Use port 0x80 as this is unused.
/// ///
pub fn ioWait() void { pub fn ioWait() void {
outb(0x80, 0); out(0x80, @as(u8, 0));
} }
/// ///
@ -516,6 +545,10 @@ pub fn initTaskStack(entry_point: usize, allocator: *Allocator) Allocator.Error!
return ret; return ret;
} }
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
return pci.getDevices(allocator);
}
/// ///
/// Initialise the architecture /// Initialise the architecture
/// ///

View file

@ -139,9 +139,9 @@ pub const RtcRegister = enum {
/// ///
inline fn selectRegister(reg: u8, comptime disable_nmi: bool) void { inline fn selectRegister(reg: u8, comptime disable_nmi: bool) void {
if (disable_nmi) { if (disable_nmi) {
arch.outb(ADDRESS, reg | NMI_BIT); arch.out(ADDRESS, reg | NMI_BIT);
} else { } else {
arch.outb(ADDRESS, reg); arch.out(ADDRESS, reg);
} }
} }
@ -152,7 +152,7 @@ inline fn selectRegister(reg: u8, comptime disable_nmi: bool) void {
/// IN data: u8 - The data to write to the selected register. /// IN data: u8 - The data to write to the selected register.
/// ///
inline fn writeRegister(data: u8) void { inline fn writeRegister(data: u8) void {
arch.outb(DATA, data); arch.out(DATA, data);
} }
/// ///
@ -162,7 +162,7 @@ inline fn writeRegister(data: u8) void {
/// The value in the selected register. /// The value in the selected register.
/// ///
inline fn readRegister() u8 { inline fn readRegister() u8 {
return arch.inb(DATA); return arch.in(u8, DATA);
} }
/// ///
@ -240,7 +240,7 @@ test "selectRegister" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_A }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_A });
const reg = STATUS_REGISTER_A; const reg = STATUS_REGISTER_A;
@ -251,7 +251,7 @@ test "selectRegister no NMI" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_A | NMI_BIT }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_A | NMI_BIT });
const reg = STATUS_REGISTER_A; const reg = STATUS_REGISTER_A;
@ -262,7 +262,7 @@ test "writeRegister" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ DATA, @as(u8, 0xAA) }); arch.addTestParams("out", .{ DATA, @as(u8, 0xAA) });
const data = @as(u8, 0xAA); const data = @as(u8, 0xAA);
@ -273,7 +273,7 @@ test "readRegister" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("inb", .{ DATA, @as(u8, 0x55) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x55) });
const expected = @as(u8, 0x55); const expected = @as(u8, 0x55);
const actual = readRegister(); const actual = readRegister();
@ -285,8 +285,8 @@ test "selectAndReadRegister NMI" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C });
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
arch.addConsumeFunction("ioWait", arch.mock_ioWait); arch.addConsumeFunction("ioWait", arch.mock_ioWait);
const reg = STATUS_REGISTER_C; const reg = STATUS_REGISTER_C;
@ -301,8 +301,8 @@ test "selectAndReadRegister no NMI" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT });
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
arch.addConsumeFunction("ioWait", arch.mock_ioWait); arch.addConsumeFunction("ioWait", arch.mock_ioWait);
const reg = STATUS_REGISTER_C; const reg = STATUS_REGISTER_C;
@ -317,7 +317,7 @@ test "selectAndWriteRegister NMI" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C, DATA, @as(u8, 0x88) }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C, DATA, @as(u8, 0x88) });
arch.addConsumeFunction("ioWait", arch.mock_ioWait); arch.addConsumeFunction("ioWait", arch.mock_ioWait);
const reg = STATUS_REGISTER_C; const reg = STATUS_REGISTER_C;
@ -330,7 +330,7 @@ test "selectAndWriteRegister no NMI" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT, DATA, @as(u8, 0x88) }); arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT, DATA, @as(u8, 0x88) });
arch.addConsumeFunction("ioWait", arch.mock_ioWait); arch.addConsumeFunction("ioWait", arch.mock_ioWait);
const reg = STATUS_REGISTER_C; const reg = STATUS_REGISTER_C;
@ -358,8 +358,8 @@ test "readRtcRegister" {
.CENTURY => REGISTER_CENTURY, .CENTURY => REGISTER_CENTURY,
}; };
arch.addTestParams("outb", .{ ADDRESS, r }); arch.addTestParams("out", .{ ADDRESS, r });
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
const expected = @as(u8, 0x44); const expected = @as(u8, 0x44);
const actual = readRtcRegister(reg); const actual = readRtcRegister(reg);
@ -383,8 +383,8 @@ test "readStatusRegister NMI" {
.C => STATUS_REGISTER_C, .C => STATUS_REGISTER_C,
}; };
arch.addTestParams("outb", .{ ADDRESS, r }); arch.addTestParams("out", .{ ADDRESS, r });
arch.addTestParams("inb", .{ DATA, @as(u8, 0x78) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x78) });
const expected = @as(u8, 0x78); const expected = @as(u8, 0x78);
const actual = readStatusRegister(reg, false); const actual = readStatusRegister(reg, false);
@ -408,8 +408,8 @@ test "readStatusRegister no NMI" {
.C => STATUS_REGISTER_C, .C => STATUS_REGISTER_C,
}; };
arch.addTestParams("outb", .{ ADDRESS, r | NMI_BIT }); arch.addTestParams("out", .{ ADDRESS, r | NMI_BIT });
arch.addTestParams("inb", .{ DATA, @as(u8, 0x78) }); arch.addTestParams("in", .{ DATA, @as(u8, 0x78) });
const expected = @as(u8, 0x78); const expected = @as(u8, 0x78);
const actual = readStatusRegister(reg, true); const actual = readStatusRegister(reg, true);
@ -433,7 +433,7 @@ test "writeStatusRegister NMI" {
.C => STATUS_REGISTER_C, .C => STATUS_REGISTER_C,
}; };
arch.addTestParams("outb", .{ ADDRESS, r, DATA, @as(u8, 0x43) }); arch.addTestParams("out", .{ ADDRESS, r, DATA, @as(u8, 0x43) });
const data = @as(u8, 0x43); const data = @as(u8, 0x43);
writeStatusRegister(reg, data, false); writeStatusRegister(reg, data, false);
@ -455,7 +455,7 @@ test "writeStatusRegister no NMI" {
.C => STATUS_REGISTER_C, .C => STATUS_REGISTER_C,
}; };
arch.addTestParams("outb", .{ ADDRESS, r | NMI_BIT, DATA, @as(u8, 0x43) }); arch.addTestParams("out", .{ ADDRESS, r | NMI_BIT, DATA, @as(u8, 0x43) });
const data = @as(u8, 0x43); const data = @as(u8, 0x43);
writeStatusRegister(reg, data, true); writeStatusRegister(reg, data, true);

View file

@ -32,7 +32,7 @@ var on_print_screen = false;
/// The byte waiting in the keyboard buffer /// The byte waiting in the keyboard buffer
/// ///
fn readKeyboardBuffer() u8 { fn readKeyboardBuffer() u8 {
return arch.inb(0x60); return arch.in(u8, 0x60);
} }
/// ///

359
src/kernel/arch/x86/pci.zig Normal file
View file

@ -0,0 +1,359 @@
const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const expectEqual = std.testing.expectEqual;
const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path;
const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
const logger = std.log.scoped(.pci);
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
/// The port address for selecting a 32bit register in the PCI configuration space.
const CONFIG_ADDRESS: u16 = 0x0CF8;
/// The port address for read/writing to the selected address.
const CONFIG_DATA: u16 = 0x0CFC;
/// The register offsets for PCI. Currently there is no check for valid register offsets for the
/// header type. The names are self explanatory. Further information can be found here:
/// https://wiki.osdev.org/PCI.
const PciRegisters = enum(u8) {
VenderId = 0x00,
DeviceId = 0x02,
Command = 0x04,
Status = 0x06,
RevisionId = 0x08,
ProgrammingInterface = 0x09,
Subclass = 0x0A,
ClassCode = 0x0B,
CacheLineSize = 0x0C,
LatencyTimer = 0x0D,
HeaderType = 0x0E,
BIST = 0x0F,
// The next set of registers are for the 0x00 (standard) header.
// This currently uses only the common registers above that are available to all header types.
BaseAddr0 = 0x10,
BaseAddr1 = 0x14,
BaseAddr2 = 0x18,
BaseAddr3 = 0x1C,
BaseAddr4 = 0x20,
BaseAddr5 = 0x24,
CardbusCISPtr = 0x28,
SubsystemVenderId = 0x2C,
SubsystemId = 0x2E,
ExpansionROMBaseAddr = 0x30,
CapabilitiesPtr = 0x34,
InterruptLine = 0x3C,
InterruptPin = 0x3D,
MinGrant = 0x3E,
MaxLatency = 0x3F,
///
/// Get the type the represents the width of the register. This can be either u8, u16 or u32.
///
/// Argument:
/// IN comptime pci_reg: PciRegisters - The register to get the width for.
///
/// Return: type
/// The width type.
///
pub fn getWidth(comptime pci_reg: PciRegisters) type {
return switch (pci_reg) {
.RevisionId, .ProgrammingInterface, .Subclass, .ClassCode, .CacheLineSize, .LatencyTimer, .HeaderType, .BIST, .InterruptLine, .InterruptPin, .MinGrant, .MaxLatency, .CapabilitiesPtr => u8,
.VenderId, .DeviceId, .Command, .Status, .SubsystemVenderId, .SubsystemId => u16,
.BaseAddr0, .BaseAddr1, .BaseAddr2, .BaseAddr3, .BaseAddr4, .BaseAddr5, .CardbusCISPtr, .ExpansionROMBaseAddr => u32,
};
}
};
/// The PCI address used for sending to the address port.
const PciAddress = packed struct {
register_offset: u8,
function: u3,
device: u5,
bus: u8,
reserved: u7 = 0,
enable: u1 = 1,
};
/// A PCI device. This will be unique to a bus and device number.
const PciDevice = struct {
/// The bus on which the device is on
bus: u8,
/// The device number.
device: u5,
const Self = @This();
///
/// Get the PCI address for this device and for a function and register.
///
/// Argument:
/// IN self: Self - This device.
/// IN function: u3 - The function.
/// IN comptime pci_reg: PciRegisters - The register.
///
/// Return: PciAddress
/// The PCI address that can be used to read the register offset for this device and function.
///
pub fn getAddress(self: Self, function: u3, comptime pci_reg: PciRegisters) PciAddress {
return PciAddress{
.bus = self.bus,
.device = self.device,
.function = function,
.register_offset = @enumToInt(pci_reg),
};
}
///
/// Read the configuration register data from this device, function and register. PCI configure
/// reads will return a u32 value, but the register may not be u32 is size so this will return
/// the correctly typed value depending on the size of the register.
///
/// Argument:
/// IN self: Self - This device.
/// IN function: u3 - The function.
/// IN comptime pci_reg: PciRegisters - The register.
///
/// Return: PciRegisters.getWidth()
/// Depending on the register, the type of the return value maybe u8, u16 or u32. See
/// PciRegisters.getWidth().
///
pub fn configReadData(self: Self, function: u3, comptime pci_reg: PciRegisters) pci_reg.getWidth() {
const address = self.getAddress(function, pci_reg);
// Last 2 bits of offset must be zero
// This is because we are requesting a integer (4 bytes) and cannot request a
// single byte that isn't 4 bytes aligned
// Write the address
arch.out(CONFIG_ADDRESS, @bitCast(u32, address) & 0xFFFFFFFC);
// Read the data
const result = arch.in(u32, CONFIG_DATA);
// Return the size the user wants
const shift = switch (pci_reg.getWidth()) {
u8 => (@intCast(u5, address.register_offset & 0x3)) * 8,
u16 => (@intCast(u5, address.register_offset & 0x2)) * 8,
u32 => 0,
else => @compileError("Invalid read size. Only u8, u16 and u32 allowed."),
};
return @truncate(pci_reg.getWidth(), (result >> shift));
}
test "configReadData u8" {
arch.initTest();
defer arch.freeTest();
// The bus, device and function values can be any value as we are testing the shifting and masking
// Have chosen bus = 0, device = 1 and function = 2.
// We only change the register as they will have different but widths.
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .RevisionId)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// RevisionId is a u8 width, offset 0
const res = device.configReadData(2, .RevisionId);
expectEqual(res, 0x12);
}
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .ProgrammingInterface)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// ProgrammingInterface is a u8 width, offset 8
const res = device.configReadData(2, .ProgrammingInterface);
expectEqual(res, 0xEF);
}
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .Subclass)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// Subclass is a u8 width, offset 16
const res = device.configReadData(2, .Subclass);
expectEqual(res, 0xCD);
}
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .ClassCode)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// ClassCode is a u8 width, offset 24
const res = device.configReadData(2, .ClassCode);
expectEqual(res, 0xAB);
}
}
test "configReadData u16" {
arch.initTest();
defer arch.freeTest();
// The bus, device and function values can be any value as we are testing the shifting and masking
// Have chosen bus = 0, device = 1 and function = 2.
// We only change the register as they will have different but widths.
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .VenderId)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// VenderId is a u16 width, offset 0
const res = device.configReadData(2, .VenderId);
expectEqual(res, 0xEF12);
}
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .DeviceId)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// DeviceId is a u16 width, offset 16
const res = device.configReadData(2, .DeviceId);
expectEqual(res, 0xABCD);
}
}
test "configReadData u32" {
arch.initTest();
defer arch.freeTest();
// The bus, device and function values can be any value as we are testing the shifting and masking
// Have chosen bus = 0, device = 1 and function = 2.
// We only change the register as they will have different but widths.
{
const device = PciDevice{
.bus = 0,
.device = 1,
};
arch.addTestParams("out", .{ CONFIG_ADDRESS, @bitCast(u32, device.getAddress(2, .BaseAddr0)) & 0xFFFFFFFC });
arch.addTestParams("in", .{ CONFIG_DATA, @as(u32, 0xABCDEF12) });
// BaseAddr0 is a u32 width, offset 0
const res = device.configReadData(2, .BaseAddr0);
expectEqual(res, 0xABCDEF12);
}
}
};
pub const PciDeviceInfo = struct {
pci_device: PciDevice,
function: u3,
vender_id: u16,
device_id: u16,
subclass: u8,
class_code: u8,
/// The error set.
pub const Error = error{
/// There is no functions available for the given function number for a given PCI device.
NoFunction,
};
pub fn create(pci_device: PciDevice, function: u3) Error!PciDeviceInfo {
const vender_id = pci_device.configReadData(function, .VenderId);
// No function available, try the next
if (vender_id == 0xFFFF) {
return Error.NoFunction;
}
return PciDeviceInfo{
.pci_device = pci_device,
.function = function,
.vender_id = vender_id,
.device_id = pci_device.configReadData(function, .DeviceId),
.subclass = pci_device.configReadData(function, .Subclass),
.class_code = pci_device.configReadData(function, .ClassCode),
};
}
pub fn print(device: arch.Device) void {
logger.info("BUS: 0x{X}, DEV: 0x{X}, FUN: 0x{X}, VID: 0x{X}, DID: 0x{X}, SC: 0x{X}, CC: 0x{X}\n", .{
device.pci_device.bus,
device.pci_device.device,
device.function,
device.vender_id,
device.device_id,
device.subclass,
device.class_code,
});
}
};
///
/// Get a list of all the PCI device. The returned list will needed to be freed by the caller.
///
/// Arguments:
/// IN allocator: *Allocator - An allocator used for creating the list.
///
/// Return: []PciDeviceInfo
/// The list of PCI devices information.
///
/// Error: Allocator.Error
/// error.OutOfMemory - If there isn't enough memory to create the info list.
///
pub fn getDevices(allocator: *Allocator) Allocator.Error![]PciDeviceInfo {
// Create an array list for the devices.
var pci_device_infos = ArrayList(PciDeviceInfo).init(allocator);
defer pci_device_infos.deinit();
// Iterate through all the possible devices
var _bus: u32 = 0;
while (_bus < 8) : (_bus += 1) {
const bus = @intCast(u8, _bus);
var _device: u32 = 0;
while (_device < 32) : (_device += 1) {
const device = @intCast(u5, _device);
// Devices have at least 1 function
const pci_device = PciDevice{
.bus = bus,
.device = device,
};
var num_functions: u32 = if (pci_device.configReadData(0, .HeaderType) & 0x80 != 0) 8 else 1;
var _function: u32 = 0;
while (_function < num_functions) : (_function += 1) {
const function = @intCast(u3, _function);
const device_info = PciDeviceInfo.create(pci_device, function) catch |e| switch (e) {
error.NoFunction => continue,
};
try pci_device_infos.append(device_info);
}
}
}
return pci_device_infos.toOwnedSlice();
}

View file

@ -252,7 +252,7 @@ var spurious_irq_counter: u32 = 0;
/// IN cmd: u8 - The command to send. /// IN cmd: u8 - The command to send.
/// ///
inline fn sendCommandMaster(cmd: u8) void { inline fn sendCommandMaster(cmd: u8) void {
arch.outb(MASTER_COMMAND_REG, cmd); arch.out(MASTER_COMMAND_REG, cmd);
} }
/// ///
@ -262,7 +262,7 @@ inline fn sendCommandMaster(cmd: u8) void {
/// IN cmd: u8 - The command to send. /// IN cmd: u8 - The command to send.
/// ///
inline fn sendCommandSlave(cmd: u8) void { inline fn sendCommandSlave(cmd: u8) void {
arch.outb(SLAVE_COMMAND_REG, cmd); arch.out(SLAVE_COMMAND_REG, cmd);
} }
/// ///
@ -272,7 +272,7 @@ inline fn sendCommandSlave(cmd: u8) void {
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
inline fn sendDataMaster(data: u8) void { inline fn sendDataMaster(data: u8) void {
arch.outb(MASTER_DATA_REG, data); arch.out(MASTER_DATA_REG, data);
} }
/// ///
@ -282,7 +282,7 @@ inline fn sendDataMaster(data: u8) void {
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
inline fn sendDataSlave(data: u8) void { inline fn sendDataSlave(data: u8) void {
arch.outb(SLAVE_DATA_REG, data); arch.out(SLAVE_DATA_REG, data);
} }
/// ///
@ -292,7 +292,7 @@ inline fn sendDataSlave(data: u8) void {
/// The data that is stored in the master data register. /// The data that is stored in the master data register.
/// ///
inline fn readDataMaster() u8 { inline fn readDataMaster() u8 {
return arch.inb(MASTER_DATA_REG); return arch.in(u8, MASTER_DATA_REG);
} }
/// ///
@ -302,7 +302,7 @@ inline fn readDataMaster() u8 {
/// The data that is stored in the salve data register. /// The data that is stored in the salve data register.
/// ///
inline fn readDataSlave() u8 { inline fn readDataSlave() u8 {
return arch.inb(SLAVE_DATA_REG); return arch.in(u8, SLAVE_DATA_REG);
} }
/// ///
@ -313,7 +313,7 @@ inline fn readDataSlave() u8 {
/// ///
inline fn readMasterIrr() u8 { inline fn readMasterIrr() u8 {
sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR); sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR);
return arch.inb(MASTER_STATUS_REG); return arch.in(u8, MASTER_STATUS_REG);
} }
/// ///
@ -324,7 +324,7 @@ inline fn readMasterIrr() u8 {
/// ///
inline fn readSlaveIrr() u8 { inline fn readSlaveIrr() u8 {
sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR); sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR);
return arch.inb(SLAVE_STATUS_REG); return arch.in(u8, SLAVE_STATUS_REG);
} }
/// ///
@ -335,7 +335,7 @@ inline fn readSlaveIrr() u8 {
/// ///
inline fn readMasterIsr() u8 { inline fn readMasterIsr() u8 {
sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR); sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR);
return arch.inb(MASTER_STATUS_REG); return arch.in(u8, MASTER_STATUS_REG);
} }
/// ///
@ -346,7 +346,7 @@ inline fn readMasterIsr() u8 {
/// ///
inline fn readSlaveIsr() u8 { inline fn readSlaveIsr() u8 {
sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR); sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR);
return arch.inb(SLAVE_STATUS_REG); return arch.in(u8, SLAVE_STATUS_REG);
} }
/// ///
@ -410,8 +410,8 @@ pub fn spuriousIrq(irq_num: u8) bool {
pub fn setMask(irq_num: u8) void { pub fn setMask(irq_num: u8) void {
const port: u16 = if (irq_num < 8) MASTER_DATA_REG else SLAVE_DATA_REG; const port: u16 = if (irq_num < 8) MASTER_DATA_REG else SLAVE_DATA_REG;
const shift = @intCast(u3, irq_num % 8); const shift = @intCast(u3, irq_num % 8);
const value: u8 = arch.inb(port) | (@as(u8, 1) << shift); const value: u8 = arch.in(u8, port) | (@as(u8, 1) << shift);
arch.outb(port, value); arch.out(port, value);
} }
/// ///
@ -423,8 +423,8 @@ pub fn setMask(irq_num: u8) void {
pub fn clearMask(irq_num: u8) void { pub fn clearMask(irq_num: u8) void {
const port: u16 = if (irq_num < 8) MASTER_DATA_REG else SLAVE_DATA_REG; const port: u16 = if (irq_num < 8) MASTER_DATA_REG else SLAVE_DATA_REG;
const shift = @intCast(u3, irq_num % 8); const shift = @intCast(u3, irq_num % 8);
const value: u8 = arch.inb(port) & ~(@as(u8, 1) << shift); const value: u8 = arch.in(u8, port) & ~(@as(u8, 1) << shift);
arch.outb(port, value); arch.out(port, value);
} }
/// ///
@ -481,7 +481,7 @@ test "sendCommandMaster" {
const cmd: u8 = 10; const cmd: u8 = 10;
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, cmd }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, cmd });
sendCommandMaster(cmd); sendCommandMaster(cmd);
} }
@ -493,7 +493,7 @@ test "sendCommandSlave" {
const cmd: u8 = 10; const cmd: u8 = 10;
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, cmd }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, cmd });
sendCommandSlave(cmd); sendCommandSlave(cmd);
} }
@ -505,7 +505,7 @@ test "sendDataMaster" {
const data: u8 = 10; const data: u8 = 10;
arch.addTestParams("outb", .{ MASTER_DATA_REG, data }); arch.addTestParams("out", .{ MASTER_DATA_REG, data });
sendDataMaster(data); sendDataMaster(data);
} }
@ -517,7 +517,7 @@ test "sendDataSlave" {
const data: u8 = 10; const data: u8 = 10;
arch.addTestParams("outb", .{ SLAVE_DATA_REG, data }); arch.addTestParams("out", .{ SLAVE_DATA_REG, data });
sendDataSlave(data); sendDataSlave(data);
} }
@ -527,7 +527,7 @@ test "readDataMaster" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readDataMaster()); expectEqual(@as(u8, 10), readDataMaster());
} }
@ -537,7 +537,7 @@ test "readDataSlave" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("inb", .{ SLAVE_DATA_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_DATA_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readDataSlave()); expectEqual(@as(u8, 10), readDataSlave());
} }
@ -547,8 +547,8 @@ test "readMasterIrr" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) });
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readMasterIrr()); expectEqual(@as(u8, 10), readMasterIrr());
} }
@ -558,8 +558,8 @@ test "readSlaveIrr" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) });
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readSlaveIrr()); expectEqual(@as(u8, 10), readSlaveIrr());
} }
@ -569,8 +569,8 @@ test "readMasterIsr" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readMasterIsr()); expectEqual(@as(u8, 10), readMasterIsr());
} }
@ -580,8 +580,8 @@ test "readSlaveIsr" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readSlaveIsr()); expectEqual(@as(u8, 10), readSlaveIsr());
} }
@ -593,7 +593,7 @@ test "sendEndOfInterrupt master only" {
var i: u8 = 0; var i: u8 = 0;
while (i < 8) : (i += 1) { while (i < 8) : (i += 1) {
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
sendEndOfInterrupt(i); sendEndOfInterrupt(i);
} }
@ -606,8 +606,8 @@ test "sendEndOfInterrupt master and slave" {
var i: u8 = 8; var i: u8 = 8;
while (i < 16) : (i += 1) { while (i < 16) : (i += 1) {
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, OCW2_END_OF_INTERRUPT }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, OCW2_END_OF_INTERRUPT });
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
sendEndOfInterrupt(i); sendEndOfInterrupt(i);
} }
@ -636,9 +636,9 @@ test "spuriousIrq spurious master IRQ number not spurious" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
// Return 0x80 from readMasterIsr() which will mean this was a real IRQ // Return 0x80 from readMasterIsr() which will mean this was a real IRQ
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 0x80) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x80) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); expectEqual(@as(u32, 0), spurious_irq_counter);
@ -658,9 +658,9 @@ test "spuriousIrq spurious master IRQ number spurious" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
// Return 0x0 from readMasterIsr() which will mean this was a spurious IRQ // Return 0x0 from readMasterIsr() which will mean this was a spurious IRQ
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 0x0) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x0) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); expectEqual(@as(u32, 0), spurious_irq_counter);
@ -680,9 +680,9 @@ test "spuriousIrq spurious slave IRQ number not spurious" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
// Return 0x80 from readSlaveIsr() which will mean this was a real IRQ // Return 0x80 from readSlaveIsr() which will mean this was a real IRQ
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 0x80) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 0x80) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); expectEqual(@as(u32, 0), spurious_irq_counter);
@ -702,11 +702,11 @@ test "spuriousIrq spurious slave IRQ number spurious" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
// Return 0x0 from readSlaveIsr() which will mean this was a spurious IRQ // Return 0x0 from readSlaveIsr() which will mean this was a spurious IRQ
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 0x0) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 0x0) });
// A EOI will be sent for a spurious IRQ 15 // A EOI will be sent for a spurious IRQ 15
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); expectEqual(@as(u32, 0), spurious_irq_counter);
@ -727,9 +727,9 @@ test "setMask master IRQ masked" {
defer arch.freeTest(); defer arch.freeTest();
// Going to assume all bits are masked out // Going to assume all bits are masked out
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFF) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
// Expect the 2nd bit to be set // Expect the 2nd bit to be set
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFF) }); arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
setMask(1); setMask(1);
} }
@ -740,9 +740,9 @@ test "setMask master IRQ unmasked" {
defer arch.freeTest(); defer arch.freeTest();
// IRQ already unmasked // IRQ already unmasked
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFD) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
// Expect the 2nd bit to be set // Expect the 2nd bit to be set
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFF) }); arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
setMask(1); setMask(1);
} }
@ -753,9 +753,9 @@ test "clearMask master IRQ masked" {
defer arch.freeTest(); defer arch.freeTest();
// Going to assume all bits are masked out // Going to assume all bits are masked out
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFF) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
// Expect the 2nd bit to be clear // Expect the 2nd bit to be clear
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFD) }); arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
clearMask(1); clearMask(1);
} }
@ -766,9 +766,9 @@ test "clearMask master IRQ unmasked" {
defer arch.freeTest(); defer arch.freeTest();
// IRQ already unmasked // IRQ already unmasked
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFD) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
// Expect the 2nd bit to still be clear // Expect the 2nd bit to still be clear
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFD) }); arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
clearMask(1); clearMask(1);
} }
@ -781,7 +781,7 @@ test "init" {
arch.addRepeatFunction("ioWait", arch.mock_ioWait); arch.addRepeatFunction("ioWait", arch.mock_ioWait);
// Just a long list of OUT instructions setting up the PIC // Just a long list of OUT instructions setting up the PIC
arch.addTestParams("outb", .{ arch.addTestParams("out", .{
MASTER_COMMAND_REG, MASTER_COMMAND_REG,
ICW1_INITIALISATION | ICW1_EXPECT_ICW4, ICW1_INITIALISATION | ICW1_EXPECT_ICW4,
SLAVE_COMMAND_REG, SLAVE_COMMAND_REG,
@ -806,7 +806,7 @@ test "init" {
@as(u8, 0xFB), @as(u8, 0xFB),
}); });
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFF) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
init(); init();
} }

View file

@ -199,7 +199,7 @@ var time_under_1_ns: u32 = undefined;
/// IN cmd: u8 - The command to send to the PIT. /// IN cmd: u8 - The command to send to the PIT.
/// ///
inline fn sendCommand(cmd: u8) void { inline fn sendCommand(cmd: u8) void {
arch.outb(COMMAND_REGISTER, cmd); arch.out(COMMAND_REGISTER, cmd);
} }
/// ///
@ -213,7 +213,7 @@ inline fn sendCommand(cmd: u8) void {
/// ///
inline fn readBackCommand(counter: CounterSelect) u8 { inline fn readBackCommand(counter: CounterSelect) u8 {
sendCommand(0xC2); sendCommand(0xC2);
return 0x3F & arch.inb(counter.getRegister()); return 0x3F & arch.in(u8, counter.getRegister());
} }
/// ///
@ -224,7 +224,7 @@ inline fn readBackCommand(counter: CounterSelect) u8 {
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
inline fn sendDataToCounter(counter: CounterSelect, data: u8) void { inline fn sendDataToCounter(counter: CounterSelect, data: u8) void {
arch.outb(counter.getRegister(), data); arch.out(counter.getRegister(), data);
} }
/// ///
@ -396,7 +396,7 @@ test "sendCommand" {
const cmd: u8 = 10; const cmd: u8 = 10;
arch.addTestParams("outb", .{ COMMAND_REGISTER, cmd }); arch.addTestParams("out", .{ COMMAND_REGISTER, cmd });
sendCommand(cmd); sendCommand(cmd);
} }
@ -407,8 +407,8 @@ test "readBackCommand" {
const cmd: u8 = 0xC2; const cmd: u8 = 0xC2;
arch.addTestParams("outb", .{ COMMAND_REGISTER, cmd }); arch.addTestParams("out", .{ COMMAND_REGISTER, cmd });
arch.addTestParams("inb", .{ COUNTER_0_REGISTER, @as(u8, 0x20) }); arch.addTestParams("in", .{ COUNTER_0_REGISTER, @as(u8, 0x20) });
const actual = readBackCommand(CounterSelect.Counter0); const actual = readBackCommand(CounterSelect.Counter0);
@ -421,7 +421,7 @@ test "sendDataToCounter" {
const data: u8 = 10; const data: u8 = 10;
arch.addTestParams("outb", .{ COUNTER_0_REGISTER, data }); arch.addTestParams("out", .{ COUNTER_0_REGISTER, data });
sendDataToCounter(CounterSelect.Counter0, data); sendDataToCounter(CounterSelect.Counter0, data);
} }
@ -445,7 +445,7 @@ test "setupCounter lowest frequency" {
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW(); const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
while (freq <= 18) : (freq += 1) { while (freq <= 18) : (freq += 1) {
// arch.addTestParams("outb", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8)); // arch.addTestParams("out", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode)); expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
// expectEqual(u32(0), ticks); // expectEqual(u32(0), ticks);
@ -482,7 +482,7 @@ test "setupCounter highest frequency" {
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY; const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW(); const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
// arch.addTestParams("outb", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8)); // arch.addTestParams("out", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode)); expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
@ -515,7 +515,7 @@ test "setupCounter normal frequency" {
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY; const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW(); const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
arch.addTestParams("outb", .{ COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8) }); arch.addTestParams("out", .{ COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8) });
setupCounter(counter, freq, mode) catch unreachable; setupCounter(counter, freq, mode) catch unreachable;

View file

@ -93,7 +93,7 @@ fn baudDivisor(baud: u32) SerialError!u16 {
/// If the transmission buffer is empty. /// If the transmission buffer is empty.
/// ///
fn transmitIsEmpty(port: Port) bool { fn transmitIsEmpty(port: Port) bool {
return arch.inb(@enumToInt(port) + 5) & 0x20 > 0; return arch.in(u8, @enumToInt(port) + 5) & 0x20 > 0;
} }
/// ///
@ -107,7 +107,7 @@ pub fn write(char: u8, port: Port) void {
while (!transmitIsEmpty(port)) { while (!transmitIsEmpty(port)) {
arch.halt(); arch.halt();
} }
arch.outb(@enumToInt(port), char); arch.out(@enumToInt(port), char);
} }
/// ///
@ -125,19 +125,19 @@ pub fn init(baud: u32, port: Port) SerialError!void {
const divisor: u16 = try baudDivisor(baud); const divisor: u16 = try baudDivisor(baud);
const port_int = @enumToInt(port); const port_int = @enumToInt(port);
// Send a byte to start setting the baudrate // Send a byte to start setting the baudrate
arch.outb(port_int + LCR, lcrValue(0, false, false, 1) catch |e| { arch.out(port_int + LCR, lcrValue(0, false, false, 1) catch |e| {
panic(@errorReturnTrace(), "Failed to initialise serial output setup: {}", .{e}); panic(@errorReturnTrace(), "Failed to initialise serial output setup: {}", .{e});
}); });
// Send the divisor's lsb // Send the divisor's lsb
arch.outb(port_int, @truncate(u8, divisor)); arch.out(port_int, @truncate(u8, divisor));
// Send the divisor's msb // Send the divisor's msb
arch.outb(port_int + 1, @truncate(u8, divisor >> 8)); arch.out(port_int + 1, @truncate(u8, divisor >> 8));
// Send the properties to use // Send the properties to use
arch.outb(port_int + LCR, lcrValue(CHAR_LEN, SINGLE_STOP_BIT, PARITY_BIT, 0) catch |e| { arch.out(port_int + LCR, lcrValue(CHAR_LEN, SINGLE_STOP_BIT, PARITY_BIT, 0) catch |e| {
panic(@errorReturnTrace(), "Failed to setup serial properties: {}", .{e}); panic(@errorReturnTrace(), "Failed to setup serial properties: {}", .{e});
}); });
// Stop initialisation // Stop initialisation
arch.outb(port_int + 1, 0); arch.out(port_int + 1, @as(u8, 0));
} }
test "lcrValue computes the correct value" { test "lcrValue computes the correct value" {

View file

@ -122,7 +122,7 @@ var cursor_scanline_end: u8 = undefined;
/// to. /// to.
/// ///
inline fn sendPort(index: u8) void { inline fn sendPort(index: u8) void {
arch.outb(PORT_ADDRESS, index); arch.out(PORT_ADDRESS, index);
} }
/// ///
@ -132,7 +132,7 @@ inline fn sendPort(index: u8) void {
/// IN data: u8 - The data to send to the selected register. /// IN data: u8 - The data to send to the selected register.
/// ///
inline fn sendData(data: u8) void { inline fn sendData(data: u8) void {
arch.outb(PORT_DATA, data); arch.out(PORT_DATA, data);
} }
/// ///
@ -142,7 +142,7 @@ inline fn sendData(data: u8) void {
/// The data in the selected register. /// The data in the selected register.
/// ///
inline fn getData() u8 { inline fn getData() u8 {
return arch.inb(PORT_DATA); return arch.in(u8, PORT_DATA);
} }
/// ///
/// Set the VGA register port to write to and sending data to that VGA register port. /// Set the VGA register port to write to and sending data to that VGA register port.
@ -345,7 +345,7 @@ test "updateCursor width out of bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -362,7 +362,7 @@ test "updateCursor height out of bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -379,7 +379,7 @@ test "updateCursor width and height out of bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -396,7 +396,7 @@ test "updateCursor width-1 and height out of bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -413,7 +413,7 @@ test "updateCursor width and height-1 out of bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -430,7 +430,7 @@ test "updateCursor in bounds" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for changing the hardware cursor: // Mocking out the arch.outb calls for changing the hardware cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW, PORT_DATA, expected_lower, PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH, PORT_DATA, expected_upper });
updateCursor(x, y); updateCursor(x, y);
} }
@ -441,10 +441,10 @@ test "getCursor 1: 10" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 10) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 10) });
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0) });
const actual = getCursor(); const actual = getCursor();
expectEqual(expect, actual); expectEqual(expect, actual);
@ -457,10 +457,10 @@ test "getCursor 2: 0xBEEF" {
arch.initTest(); arch.initTest();
defer arch.freeTest(); defer arch.freeTest();
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0xEF) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xEF) });
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0xBE) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xBE) });
const actual = getCursor(); const actual = getCursor();
expectEqual(expect, actual); expectEqual(expect, actual);
@ -471,7 +471,7 @@ test "enableCursor" {
defer arch.freeTest(); defer arch.freeTest();
// Need to init the cursor start and end positions, so call the init() to set this up // Need to init the cursor start and end positions, so call the init() to set this up
arch.addTestParams("outb", .{ arch.addTestParams("out", .{
PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE, PORT_DATA, CURSOR_SCANLINE_END, PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END, PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE, PORT_DATA, CURSOR_SCANLINE_END, PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END,
// Mocking out the arch.outb calls for enabling the cursor: // Mocking out the arch.outb calls for enabling the cursor:
// These are the default cursor positions from init() // These are the default cursor positions from init()
@ -487,7 +487,7 @@ test "disableCursor" {
defer arch.freeTest(); defer arch.freeTest();
// Mocking out the arch.outb calls for disabling the cursor: // Mocking out the arch.outb calls for disabling the cursor:
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_DISABLE }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_DISABLE });
disableCursor(); disableCursor();
} }
@ -498,7 +498,7 @@ test "setCursorShape UNDERLINE" {
// Mocking out the arch.outb calls for setting the cursor shape to underline: // Mocking out the arch.outb calls for setting the cursor shape to underline:
// This will also check that the scan line variables were set properly as these are using in // This will also check that the scan line variables were set properly as these are using in
// the arch.outb call // the arch.outb call
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END });
setCursorShape(CursorShape.UNDERLINE); setCursorShape(CursorShape.UNDERLINE);
} }
@ -510,7 +510,7 @@ test "setCursorShape BLOCK" {
// Mocking out the arch.outb calls for setting the cursor shape to block: // Mocking out the arch.outb calls for setting the cursor shape to block:
// This will also check that the scan line variables were set properly as these are using in // This will also check that the scan line variables were set properly as these are using in
// the arch.outb call // the arch.outb call
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_START, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_START, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END });
setCursorShape(CursorShape.BLOCK); setCursorShape(CursorShape.BLOCK);
} }
@ -522,7 +522,7 @@ test "init" {
// Mocking out the arch.outb calls for setting the cursor max scan line and the shape to block: // Mocking out the arch.outb calls for setting the cursor max scan line and the shape to block:
// This will also check that the scan line variables were set properly as these are using in // This will also check that the scan line variables were set properly as these are using in
// the arch.outb call for setting the cursor shape. // the arch.outb call for setting the cursor shape.
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE, PORT_DATA, CURSOR_SCANLINE_END, PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END }); arch.addTestParams("out", .{ PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE, PORT_DATA, CURSOR_SCANLINE_END, PORT_ADDRESS, REG_CURSOR_START, PORT_DATA, CURSOR_SCANLINE_MIDDLE, PORT_ADDRESS, REG_CURSOR_END, PORT_DATA, CURSOR_SCANLINE_END });
init(); init();
} }

View file

@ -9,7 +9,7 @@ const mock_path = build_options.mock_path;
const vmm = if (is_test) @import(mock_path ++ "vmm_mock.zig") else @import("vmm.zig"); const vmm = if (is_test) @import(mock_path ++ "vmm_mock.zig") else @import("vmm.zig");
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
const FreeListAllocator = struct { pub const FreeListAllocator = struct {
const Error = error{TooSmall}; const Error = error{TooSmall};
const Header = struct { const Header = struct {
size: usize, size: usize,

View file

@ -19,6 +19,7 @@ const scheduler = @import("scheduler.zig");
const vfs = @import("filesystem/vfs.zig"); const vfs = @import("filesystem/vfs.zig");
const initrd = @import("filesystem/initrd.zig"); const initrd = @import("filesystem/initrd.zig");
const keyboard = @import("keyboard.zig"); const keyboard = @import("keyboard.zig");
const Allocator = std.mem.Allocator;
comptime { comptime {
if (!is_test) { if (!is_test) {
@ -57,6 +58,8 @@ pub fn log(
log_root.log(level, "(" ++ @tagName(scope) ++ "): " ++ format, args); log_root.log(level, "(" ++ @tagName(scope) ++ "): " ++ format, args);
} }
var kernel_heap: heap.FreeListAllocator = undefined;
export fn kmain(boot_payload: arch.BootPayload) void { export fn kmain(boot_payload: arch.BootPayload) void {
const serial_stream = serial.init(boot_payload); const serial_stream = serial.init(boot_payload);
@ -86,7 +89,7 @@ export fn kmain(boot_payload: arch.BootPayload) void {
if (!std.math.isPowerOfTwo(heap_size)) { if (!std.math.isPowerOfTwo(heap_size)) {
heap_size = std.math.floorPowerOfTwo(usize, heap_size); heap_size = std.math.floorPowerOfTwo(usize, heap_size);
} }
var kernel_heap = heap.init(arch.VmmPayload, kernel_vmm, vmm.Attributes{ .kernel = true, .writable = true, .cachable = true }, heap_size) catch |e| { kernel_heap = heap.init(arch.VmmPayload, kernel_vmm, vmm.Attributes{ .kernel = true, .writable = true, .cachable = true }, heap_size) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel heap: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel heap: {}\n", .{e});
}; };
@ -169,6 +172,14 @@ fn initStage2() noreturn {
tty.print("Hello Pluto from kernel :)\n", .{}); tty.print("Hello Pluto from kernel :)\n", .{});
const devices = arch.getDevices(&kernel_heap.allocator) catch |e| {
panic_root.panic(@errorReturnTrace(), "Unable to get device list: {}\n", .{e});
};
for (devices) |device| {
device.print();
}
switch (build_options.test_mode) { switch (build_options.test_mode) {
.Initialisation => { .Initialisation => {
logger.info("SUCCESS\n", .{}); logger.info("SUCCESS\n", .{});

View file

@ -63,9 +63,9 @@ const types = .{
.{ "fn (u8) void", "FN_IU8_OVOID", "", "", "" }, .{ "fn (u8) void", "FN_IU8_OVOID", "", "", "" },
.{ "fn (u8) bool", "FN_IU8_OBOOL", "", "", "" }, .{ "fn (u8) bool", "FN_IU8_OBOOL", "", "", "" },
.{ "fn (u8, fn () callconv(.Naked) void) IdtError!void", "FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID", "", "", "" },
.{ "fn (u16) void", "FN_IU16_OVOID", "", "", "" }, .{ "fn (u16) void", "FN_IU16_OVOID", "", "", "" },
.{ "fn (u16) u8", "FN_IU16_OU8", "", "", "" }, .{ "fn (u16) u8", "FN_IU16_OU8", "", "", "" },
.{ "fn (u16) u32", "FN_IU16_OU32", "", "", "" },
.{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" }, .{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" },
.{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" }, .{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" },
.{ "fn (IdtEntry) bool", "FN_IIDTENTRY_OBOOL", "idt_mock", "", "IdtEntry" }, .{ "fn (IdtEntry) bool", "FN_IIDTENTRY_OBOOL", "idt_mock", "", "IdtEntry" },
@ -74,8 +74,10 @@ const types = .{
.{ "fn (u4, u4) u8", "FN_IU4_IU4_OU8", "", "", "" }, .{ "fn (u4, u4) u8", "FN_IU4_IU4_OU8", "", "", "" },
.{ "fn (u8, u8) u16", "FN_IU8_IU8_OU16", "", "", "" }, .{ "fn (u8, u8) u16", "FN_IU8_IU8_OU16", "", "", "" },
.{ "fn (u8, fn () callconv(.Naked) void) IdtError!void", "FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID", "", "", "" },
.{ "fn (u16, u8) void", "FN_IU16_IU8_OVOID", "", "", "" }, .{ "fn (u16, u8) void", "FN_IU16_IU8_OVOID", "", "", "" },
.{ "fn (u16, u16) void", "FN_IU16_IU16_OVOID", "", "", "" }, .{ "fn (u16, u16) void", "FN_IU16_IU16_OVOID", "", "", "" },
.{ "fn (u16, u32) void", "FN_IU16_IU32_OVOID", "", "", "" },
.{ "fn (StatusRegister, bool) u8", "FN_ISTATUSREGISTER_IBOOL_OU8", "", "", "" }, .{ "fn (StatusRegister, bool) u8", "FN_ISTATUSREGISTER_IBOOL_OU8", "", "", "" },
.{ "fn (*Task, usize) void", "FN_IPTRTASK_IUSIZE_OVOID", "", "", "" }, .{ "fn (*Task, usize) void", "FN_IPTRTASK_IUSIZE_OVOID", "", "", "" },
.{ "fn (*Task, *Allocator) void", "FN_IPTRTASK_IPTRALLOCATOR_OVOID", "", "", "" }, .{ "fn (*Task, *Allocator) void", "FN_IPTRTASK_IPTRALLOCATOR_OVOID", "", "", "" },

View file

@ -2,6 +2,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const mem = @import("mem_mock.zig"); const mem = @import("mem_mock.zig");
const MemProfile = mem.MemProfile; const MemProfile = mem.MemProfile;
const pci = @import("pci_mock.zig");
const gdt = @import("gdt_mock.zig"); const gdt = @import("gdt_mock.zig");
const idt = @import("idt_mock.zig"); const idt = @import("idt_mock.zig");
const vmm = @import("vmm_mock.zig"); const vmm = @import("vmm_mock.zig");
@ -12,6 +13,8 @@ const Keyboard = @import("../../../src/kernel/keyboard.zig").Keyboard;
pub const task = @import("task_mock.zig"); pub const task = @import("task_mock.zig");
pub const Device = pci.PciDeviceInfo;
const mock_framework = @import("mock_framework.zig"); const mock_framework = @import("mock_framework.zig");
pub const initTest = mock_framework.initTest; pub const initTest = mock_framework.initTest;
pub const freeTest = mock_framework.freeTest; pub const freeTest = mock_framework.freeTest;
@ -57,12 +60,12 @@ var KERNEL_VADDR_START: u32 = 0xC0100000;
var KERNEL_VADDR_END: u32 = 0xC1100000; var KERNEL_VADDR_END: u32 = 0xC1100000;
var KERNEL_ADDR_OFFSET: u32 = 0xC0000000; var KERNEL_ADDR_OFFSET: u32 = 0xC0000000;
pub fn outb(port: u16, data: u8) void { pub fn out(port: u16, data: anytype) void {
return mock_framework.performAction("outb", void, .{ port, data }); return mock_framework.performAction("out", void, .{ port, data });
} }
pub fn inb(port: u16) u8 { pub fn in(comptime Type: type, port: u16) Type {
return mock_framework.performAction("inb", u8, .{port}); return mock_framework.performAction("in", Type, .{port});
} }
pub fn ioWait() void { pub fn ioWait() void {
@ -147,6 +150,10 @@ pub fn initKeyboard(allocator: *Allocator) Allocator.Error!?*Keyboard {
return null; return null;
} }
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
return &[_]Device{};
}
pub fn init(mem_profile: *const MemProfile) void { pub fn init(mem_profile: *const MemProfile) void {
// I'll get back to this as this doesn't effect the current testing. // I'll get back to this as this doesn't effect the current testing.
// When I come on to the mem.zig testing, I'll fix :) // When I come on to the mem.zig testing, I'll fix :)

View file

@ -46,9 +46,9 @@ const DataElementType = enum {
FN_OIDTPTR, FN_OIDTPTR,
FN_IU8_OVOID, FN_IU8_OVOID,
FN_IU8_OBOOL, FN_IU8_OBOOL,
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
FN_IU16_OVOID, FN_IU16_OVOID,
FN_IU16_OU8, FN_IU16_OU8,
FN_IU16_OU32,
FN_IUSIZE_OBOOL, FN_IUSIZE_OBOOL,
FN_IRTCREGISTER_OU8, FN_IRTCREGISTER_OU8,
FN_IIDTENTRY_OBOOL, FN_IIDTENTRY_OBOOL,
@ -56,8 +56,10 @@ const DataElementType = enum {
FN_IPTRCONSTIDTPTR_OVOID, FN_IPTRCONSTIDTPTR_OVOID,
FN_IU4_IU4_OU8, FN_IU4_IU4_OU8,
FN_IU8_IU8_OU16, FN_IU8_IU8_OU16,
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
FN_IU16_IU8_OVOID, FN_IU16_IU8_OVOID,
FN_IU16_IU16_OVOID, FN_IU16_IU16_OVOID,
FN_IU16_IU32_OVOID,
FN_ISTATUSREGISTER_IBOOL_OU8, FN_ISTATUSREGISTER_IBOOL_OU8,
FN_IPTRTASK_IUSIZE_OVOID, FN_IPTRTASK_IUSIZE_OVOID,
FN_IPTRTASK_IPTRALLOCATOR_OVOID, FN_IPTRTASK_IPTRALLOCATOR_OVOID,
@ -98,9 +100,9 @@ const DataElement = union(DataElementType) {
FN_OIDTPTR: fn () IdtPtr, FN_OIDTPTR: fn () IdtPtr,
FN_IU8_OVOID: fn (u8) void, FN_IU8_OVOID: fn (u8) void,
FN_IU8_OBOOL: fn (u8) bool, FN_IU8_OBOOL: fn (u8) bool,
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID: fn (u8, fn () callconv(.Naked) void) IdtError!void,
FN_IU16_OVOID: fn (u16) void, FN_IU16_OVOID: fn (u16) void,
FN_IU16_OU8: fn (u16) u8, FN_IU16_OU8: fn (u16) u8,
FN_IU16_OU32: fn (u16) u32,
FN_IUSIZE_OBOOL: fn (usize) bool, FN_IUSIZE_OBOOL: fn (usize) bool,
FN_IRTCREGISTER_OU8: fn (RtcRegister) u8, FN_IRTCREGISTER_OU8: fn (RtcRegister) u8,
FN_IIDTENTRY_OBOOL: fn (IdtEntry) bool, FN_IIDTENTRY_OBOOL: fn (IdtEntry) bool,
@ -108,8 +110,10 @@ const DataElement = union(DataElementType) {
FN_IPTRCONSTIDTPTR_OVOID: fn (*const IdtPtr) void, FN_IPTRCONSTIDTPTR_OVOID: fn (*const IdtPtr) void,
FN_IU4_IU4_OU8: fn (u4, u4) u8, FN_IU4_IU4_OU8: fn (u4, u4) u8,
FN_IU8_IU8_OU16: fn (u8, u8) u16, FN_IU8_IU8_OU16: fn (u8, u8) u16,
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID: fn (u8, fn () callconv(.Naked) void) IdtError!void,
FN_IU16_IU8_OVOID: fn (u16, u8) void, FN_IU16_IU8_OVOID: fn (u16, u8) void,
FN_IU16_IU16_OVOID: fn (u16, u16) void, FN_IU16_IU16_OVOID: fn (u16, u16) void,
FN_IU16_IU32_OVOID: fn (u16, u32) void,
FN_ISTATUSREGISTER_IBOOL_OU8: fn (StatusRegister, bool) u8, FN_ISTATUSREGISTER_IBOOL_OU8: fn (StatusRegister, bool) u8,
FN_IPTRTASK_IUSIZE_OVOID: fn (*Task, usize) void, FN_IPTRTASK_IUSIZE_OVOID: fn (*Task, usize) void,
FN_IPTRTASK_IPTRALLOCATOR_OVOID: fn (*Task, *Allocator) void, FN_IPTRTASK_IPTRALLOCATOR_OVOID: fn (*Task, *Allocator) void,
@ -214,9 +218,9 @@ fn Mock() type {
fn () IdtPtr => DataElement{ .FN_OIDTPTR = arg }, fn () IdtPtr => DataElement{ .FN_OIDTPTR = arg },
fn (u8) void => DataElement{ .FN_IU8_OVOID = arg }, fn (u8) void => DataElement{ .FN_IU8_OVOID = arg },
fn (u8) bool => DataElement{ .FN_IU8_OBOOL = arg }, fn (u8) bool => DataElement{ .FN_IU8_OBOOL = arg },
fn (u8, fn () callconv(.Naked) void) IdtError!void => DataElement{ .FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID = arg },
fn (u16) void => DataElement{ .FN_IU16_OVOID = arg }, fn (u16) void => DataElement{ .FN_IU16_OVOID = arg },
fn (u16) u8 => DataElement{ .FN_IU16_OU8 = arg }, fn (u16) u8 => DataElement{ .FN_IU16_OU8 = arg },
fn (u16) u32 => DataElement{ .FN_IU16_OU32 = arg },
fn (usize) bool => DataElement{ .FN_IUSIZE_OBOOL = arg }, fn (usize) bool => DataElement{ .FN_IUSIZE_OBOOL = arg },
fn (RtcRegister) u8 => DataElement{ .FN_IRTCREGISTER_OU8 = arg }, fn (RtcRegister) u8 => DataElement{ .FN_IRTCREGISTER_OU8 = arg },
fn (IdtEntry) bool => DataElement{ .FN_IIDTENTRY_OBOOL = arg }, fn (IdtEntry) bool => DataElement{ .FN_IIDTENTRY_OBOOL = arg },
@ -224,8 +228,10 @@ fn Mock() type {
fn (*const IdtPtr) void => DataElement{ .FN_IPTRCONSTIDTPTR_OVOID = arg }, fn (*const IdtPtr) void => DataElement{ .FN_IPTRCONSTIDTPTR_OVOID = arg },
fn (u4, u4) u8 => DataElement{ .FN_IU4_IU4_OU8 = arg }, fn (u4, u4) u8 => DataElement{ .FN_IU4_IU4_OU8 = arg },
fn (u8, u8) u16 => DataElement{ .FN_IU8_IU8_OU16 = arg }, fn (u8, u8) u16 => DataElement{ .FN_IU8_IU8_OU16 = arg },
fn (u8, fn () callconv(.Naked) void) IdtError!void => DataElement{ .FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID = arg },
fn (u16, u8) void => DataElement{ .FN_IU16_IU8_OVOID = arg }, fn (u16, u8) void => DataElement{ .FN_IU16_IU8_OVOID = arg },
fn (u16, u16) void => DataElement{ .FN_IU16_IU16_OVOID = arg }, fn (u16, u16) void => DataElement{ .FN_IU16_IU16_OVOID = arg },
fn (u16, u32) void => DataElement{ .FN_IU16_IU32_OVOID = arg },
fn (StatusRegister, bool) u8 => DataElement{ .FN_ISTATUSREGISTER_IBOOL_OU8 = arg }, fn (StatusRegister, bool) u8 => DataElement{ .FN_ISTATUSREGISTER_IBOOL_OU8 = arg },
fn (*Task, usize) void => DataElement{ .FN_IPTRTASK_IUSIZE_OVOID = arg }, fn (*Task, usize) void => DataElement{ .FN_IPTRTASK_IUSIZE_OVOID = arg },
fn (*Task, *Allocator) void => DataElement{ .FN_IPTRTASK_IPTRALLOCATOR_OVOID = arg }, fn (*Task, *Allocator) void => DataElement{ .FN_IPTRTASK_IPTRALLOCATOR_OVOID = arg },
@ -270,9 +276,9 @@ fn Mock() type {
fn () IdtPtr => DataElement.FN_OIDTPTR, fn () IdtPtr => DataElement.FN_OIDTPTR,
fn (u8) void => DataElement.FN_IU8_OVOID, fn (u8) void => DataElement.FN_IU8_OVOID,
fn (u8) bool => DataElement.FN_IU8_OBOOL, fn (u8) bool => DataElement.FN_IU8_OBOOL,
fn (u8, fn () callconv(.Naked) void) IdtError!void => DataElement.FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
fn (u16) void => DataElement.FN_IU16_OVOID, fn (u16) void => DataElement.FN_IU16_OVOID,
fn (u16) u8 => DataElement.FN_IU16_OU8, fn (u16) u8 => DataElement.FN_IU16_OU8,
fn (u16) u32 => DataElement.FN_IU16_OU32,
fn (usize) bool => DataElement.FN_IUSIZE_OBOOL, fn (usize) bool => DataElement.FN_IUSIZE_OBOOL,
fn (RtcRegister) u8 => DataElement.FN_IRTCREGISTER_OU8, fn (RtcRegister) u8 => DataElement.FN_IRTCREGISTER_OU8,
fn (IdtEntry) bool => DataElement.FN_IIDTENTRY_OBOOL, fn (IdtEntry) bool => DataElement.FN_IIDTENTRY_OBOOL,
@ -280,8 +286,10 @@ fn Mock() type {
fn (*const IdtPtr) void => DataElement.FN_IPTRCONSTIDTPTR_OVOID, fn (*const IdtPtr) void => DataElement.FN_IPTRCONSTIDTPTR_OVOID,
fn (u4, u4) u8 => DataElement.FN_IU4_IU4_OU8, fn (u4, u4) u8 => DataElement.FN_IU4_IU4_OU8,
fn (u8, u8) u16 => DataElement.FN_IU8_IU8_OU16, fn (u8, u8) u16 => DataElement.FN_IU8_IU8_OU16,
fn (u8, fn () callconv(.Naked) void) IdtError!void => DataElement.FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
fn (u16, u8) void => DataElement.FN_IU16_IU8_OVOID, fn (u16, u8) void => DataElement.FN_IU16_IU8_OVOID,
fn (u16, u16) void => DataElement.FN_IU16_IU16_OVOID, fn (u16, u16) void => DataElement.FN_IU16_IU16_OVOID,
fn (u16, u32) void => DataElement.FN_IU16_IU32_OVOID,
fn (StatusRegister, bool) u8 => DataElement.FN_ISTATUSREGISTER_IBOOL_OU8, fn (StatusRegister, bool) u8 => DataElement.FN_ISTATUSREGISTER_IBOOL_OU8,
fn (*Task, usize) void => DataElement.FN_IPTRTASK_IUSIZE_OVOID, fn (*Task, usize) void => DataElement.FN_IPTRTASK_IUSIZE_OVOID,
fn (*Task, *Allocator) void => DataElement.FN_IPTRTASK_IPTRALLOCATOR_OVOID, fn (*Task, *Allocator) void => DataElement.FN_IPTRTASK_IPTRALLOCATOR_OVOID,
@ -328,9 +336,9 @@ fn Mock() type {
fn () IdtPtr => element.FN_OIDTPTR, fn () IdtPtr => element.FN_OIDTPTR,
fn (u8) void => element.FN_IU8_OVOID, fn (u8) void => element.FN_IU8_OVOID,
fn (u8) bool => element.FN_IU8_OBOOL, fn (u8) bool => element.FN_IU8_OBOOL,
fn (u8, fn () callconv(.Naked) void) IdtError!void => element.FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
fn (u16) void => element.FN_IU16_OVOID, fn (u16) void => element.FN_IU16_OVOID,
fn (u16) u8 => element.FN_IU16_OU8, fn (u16) u8 => element.FN_IU16_OU8,
fn (u16) u32 => element.FN_IU16_OU32,
fn (usize) bool => element.FN_IUSIZE_OBOOL, fn (usize) bool => element.FN_IUSIZE_OBOOL,
fn (RtcRegister) u8 => element.FN_IRTCREGISTER_OU8, fn (RtcRegister) u8 => element.FN_IRTCREGISTER_OU8,
fn (IdtEntry) bool => element.FN_IIDTENTRY_OBOOL, fn (IdtEntry) bool => element.FN_IIDTENTRY_OBOOL,
@ -338,8 +346,10 @@ fn Mock() type {
fn (*const IdtPtr) void => element.FN_IPTRCONSTIDTPTR_OVOID, fn (*const IdtPtr) void => element.FN_IPTRCONSTIDTPTR_OVOID,
fn (u4, u4) u8 => element.FN_IU4_IU4_OU8, fn (u4, u4) u8 => element.FN_IU4_IU4_OU8,
fn (u8, u8) u16 => element.FN_IU8_IU8_OU16, fn (u8, u8) u16 => element.FN_IU8_IU8_OU16,
fn (u8, fn () callconv(.Naked) void) IdtError!void => element.FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
fn (u16, u8) void => element.FN_IU16_IU8_OVOID, fn (u16, u8) void => element.FN_IU16_IU8_OVOID,
fn (u16, u16) void => element.FN_IU16_IU16_OVOID, fn (u16, u16) void => element.FN_IU16_IU16_OVOID,
fn (u16, u32) void => element.FN_IU16_IU32_OVOID,
fn (StatusRegister, bool) u8 => element.FN_ISTATUSREGISTER_IBOOL_OU8, fn (StatusRegister, bool) u8 => element.FN_ISTATUSREGISTER_IBOOL_OU8,
fn (*Task, usize) void => element.FN_IPTRTASK_IUSIZE_OVOID, fn (*Task, usize) void => element.FN_IPTRTASK_IUSIZE_OVOID,
fn (*Task, *Allocator) void => element.FN_IPTRTASK_IPTRALLOCATOR_OVOID, fn (*Task, *Allocator) void => element.FN_IPTRTASK_IPTRALLOCATOR_OVOID,

View file

@ -0,0 +1,108 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const arch = @import("arch_mock.zig");
const mock_framework = @import("mock_framework.zig");
pub const initTest = mock_framework.initTest;
pub const freeTest = mock_framework.freeTest;
pub const addTestParams = mock_framework.addTestParams;
pub const addConsumeFunction = mock_framework.addConsumeFunction;
pub const addRepeatFunction = mock_framework.addRepeatFunction;
const PciRegisters = enum(u8) {
VenderId = 0x00,
DeviceId = 0x02,
Command = 0x04,
Status = 0x06,
RevisionId = 0x08,
ProgrammingInterface = 0x09,
Subclass = 0x0A,
ClassCode = 0x0B,
CacheLineSize = 0x0C,
LatencyTimer = 0x0D,
HeaderType = 0x0E,
BIST = 0x0F,
BaseAddr0 = 0x10,
BaseAddr1 = 0x14,
BaseAddr2 = 0x18,
BaseAddr3 = 0x1C,
BaseAddr4 = 0x20,
BaseAddr5 = 0x24,
CardbusCISPtr = 0x28,
SubsystemVenderId = 0x2C,
SubsystemId = 0x2E,
ExpansionROMBaseAddr = 0x30,
CapabilitiesPtr = 0x34,
InterruptLine = 0x3C,
InterruptPin = 0x3D,
MinGrant = 0x3E,
MaxLatency = 0x3F,
pub fn getWidth(comptime pci_reg: PciRegisters) type {
return switch (pci_reg) {
.RevisionId, .ProgrammingInterface, .Subclass, .ClassCode, .CacheLineSize, .LatencyTimer, .HeaderType, .BIST, .InterruptLine, .InterruptPin, .MinGrant, .MaxLatency, .CapabilitiesPtr => u8,
.VenderId, .DeviceId, .Command, .Status, .SubsystemVenderId, .SubsystemId => u16,
.BaseAddr0, .BaseAddr1, .BaseAddr2, .BaseAddr3, .BaseAddr4, .BaseAddr5, .CardbusCISPtr, .ExpansionROMBaseAddr => u32,
};
}
};
const PciAddress = packed struct {
register_offset: u8,
function: u3,
device: u5,
bus: u8,
reserved: u7 = 0,
enable: u1 = 1,
};
const PciDevice = struct {
bus: u8,
device: u5,
const Self = @This();
pub fn getAddress(self: Self, function: u3, comptime pci_reg: PciRegisters) PciAddress {
return PciAddress{
.bus = self.bus,
.device = self.device,
.function = function,
.register_offset = @enumToInt(pci_reg),
};
}
pub fn configReadData(self: Self, function: u3, comptime pci_reg: PciRegisters) pci_reg.getWidth() {
return mock_framework.performAction("PciDevice.configReadData", pci_reg.getWidth(), .{ self, function, pci_reg });
}
};
pub const PciDeviceInfo = struct {
pci_device: PciDevice,
function: u3,
vender_id: u16,
device_id: u16,
subclass: u8,
class_code: u8,
pub const Error = error{NoFunction};
pub fn create(pci_device: PciDevice, function: u3) Error!PciDeviceInfo {
return mock_framework.performAction("PciDeviceInfo.create", Error!PciDeviceInfo, .{ pci_device, function });
}
pub fn print(device: arch.Device) void {
std.debug.print("BUS: 0x{X}, DEV: 0x{X}, FUN: 0x{X}, VID: 0x{X}, DID: 0x{X}, SC: 0x{X}, CC: 0x{X}\n", .{
device.pci_device.bus,
device.pci_device.device,
device.function,
device.vender_id,
device.device_id,
device.subclass,
device.class_code,
});
}
};
pub fn getDevices(allocator: *Allocator) Allocator.Error![]PciDeviceInfo {
return mock_framework.performAction("getDevices", Allocator.Error![]PciDeviceInfo, .{allocator});
}