Merge pull request #249 from ZystemOS/feature/pci
Initial PCI interface
This commit is contained in:
commit
39b857df5c
14 changed files with 677 additions and 147 deletions
|
@ -9,6 +9,7 @@ const irq = @import("irq.zig");
|
|||
const isr = @import("isr.zig");
|
||||
const paging = @import("paging.zig");
|
||||
const pic = @import("pic.zig");
|
||||
const pci = @import("pci.zig");
|
||||
const pit = @import("pit.zig");
|
||||
const rtc = @import("rtc.zig");
|
||||
const serial = @import("serial.zig");
|
||||
|
@ -25,6 +26,9 @@ const TTY = @import("../../tty.zig").TTY;
|
|||
const Keyboard = @import("../../keyboard.zig").Keyboard;
|
||||
const MemProfile = mem.MemProfile;
|
||||
|
||||
/// The type of a device.
|
||||
pub const Device = pci.PciDeviceInfo;
|
||||
|
||||
/// The virtual end of the kernel code.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
/// Arguments:
|
||||
/// 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.
|
||||
///
|
||||
pub fn inb(port: u16) u8 {
|
||||
return asm volatile ("inb %[port], %[result]"
|
||||
: [result] "={al}" (-> u8)
|
||||
pub fn in(comptime Type: type, port: u16) Type {
|
||||
return switch (Type) {
|
||||
u8 => asm volatile ("inb %[port], %[result]"
|
||||
: [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.
|
||||
///
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
|
||||
return pci.getDevices(allocator);
|
||||
}
|
||||
|
||||
///
|
||||
/// Initialise the architecture
|
||||
///
|
||||
|
|
|
@ -139,9 +139,9 @@ pub const RtcRegister = enum {
|
|||
///
|
||||
inline fn selectRegister(reg: u8, comptime disable_nmi: bool) void {
|
||||
if (disable_nmi) {
|
||||
arch.outb(ADDRESS, reg | NMI_BIT);
|
||||
arch.out(ADDRESS, reg | NMI_BIT);
|
||||
} 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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
inline fn readRegister() u8 {
|
||||
return arch.inb(DATA);
|
||||
return arch.in(u8, DATA);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -240,7 +240,7 @@ test "selectRegister" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_A });
|
||||
arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_A });
|
||||
|
||||
const reg = STATUS_REGISTER_A;
|
||||
|
||||
|
@ -251,7 +251,7 @@ test "selectRegister no NMI" {
|
|||
arch.initTest();
|
||||
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;
|
||||
|
||||
|
@ -262,7 +262,7 @@ test "writeRegister" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ DATA, @as(u8, 0xAA) });
|
||||
arch.addTestParams("out", .{ DATA, @as(u8, 0xAA) });
|
||||
|
||||
const data = @as(u8, 0xAA);
|
||||
|
||||
|
@ -273,7 +273,7 @@ test "readRegister" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x55) });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x55) });
|
||||
|
||||
const expected = @as(u8, 0x55);
|
||||
const actual = readRegister();
|
||||
|
@ -285,8 +285,8 @@ test "selectAndReadRegister NMI" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C });
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) });
|
||||
arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
|
||||
arch.addConsumeFunction("ioWait", arch.mock_ioWait);
|
||||
|
||||
const reg = STATUS_REGISTER_C;
|
||||
|
@ -301,8 +301,8 @@ test "selectAndReadRegister no NMI" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT });
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) });
|
||||
arch.addTestParams("out", .{ ADDRESS, STATUS_REGISTER_C | NMI_BIT });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
|
||||
arch.addConsumeFunction("ioWait", arch.mock_ioWait);
|
||||
|
||||
const reg = STATUS_REGISTER_C;
|
||||
|
@ -317,7 +317,7 @@ test "selectAndWriteRegister NMI" {
|
|||
arch.initTest();
|
||||
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);
|
||||
|
||||
const reg = STATUS_REGISTER_C;
|
||||
|
@ -330,7 +330,7 @@ test "selectAndWriteRegister no NMI" {
|
|||
arch.initTest();
|
||||
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);
|
||||
|
||||
const reg = STATUS_REGISTER_C;
|
||||
|
@ -358,8 +358,8 @@ test "readRtcRegister" {
|
|||
.CENTURY => REGISTER_CENTURY,
|
||||
};
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, r });
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x44) });
|
||||
arch.addTestParams("out", .{ ADDRESS, r });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x44) });
|
||||
|
||||
const expected = @as(u8, 0x44);
|
||||
const actual = readRtcRegister(reg);
|
||||
|
@ -383,8 +383,8 @@ test "readStatusRegister NMI" {
|
|||
.C => STATUS_REGISTER_C,
|
||||
};
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, r });
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x78) });
|
||||
arch.addTestParams("out", .{ ADDRESS, r });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x78) });
|
||||
|
||||
const expected = @as(u8, 0x78);
|
||||
const actual = readStatusRegister(reg, false);
|
||||
|
@ -408,8 +408,8 @@ test "readStatusRegister no NMI" {
|
|||
.C => STATUS_REGISTER_C,
|
||||
};
|
||||
|
||||
arch.addTestParams("outb", .{ ADDRESS, r | NMI_BIT });
|
||||
arch.addTestParams("inb", .{ DATA, @as(u8, 0x78) });
|
||||
arch.addTestParams("out", .{ ADDRESS, r | NMI_BIT });
|
||||
arch.addTestParams("in", .{ DATA, @as(u8, 0x78) });
|
||||
|
||||
const expected = @as(u8, 0x78);
|
||||
const actual = readStatusRegister(reg, true);
|
||||
|
@ -433,7 +433,7 @@ test "writeStatusRegister NMI" {
|
|||
.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);
|
||||
writeStatusRegister(reg, data, false);
|
||||
|
@ -455,7 +455,7 @@ test "writeStatusRegister no NMI" {
|
|||
.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);
|
||||
writeStatusRegister(reg, data, true);
|
||||
|
|
|
@ -32,7 +32,7 @@ var on_print_screen = false;
|
|||
/// The byte waiting in the keyboard buffer
|
||||
///
|
||||
fn readKeyboardBuffer() u8 {
|
||||
return arch.inb(0x60);
|
||||
return arch.in(u8, 0x60);
|
||||
}
|
||||
|
||||
///
|
||||
|
|
359
src/kernel/arch/x86/pci.zig
Normal file
359
src/kernel/arch/x86/pci.zig
Normal 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();
|
||||
}
|
|
@ -252,7 +252,7 @@ var spurious_irq_counter: u32 = 0;
|
|||
/// IN cmd: u8 - The command to send.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
const port: u16 = if (irq_num < 8) MASTER_DATA_REG else SLAVE_DATA_REG;
|
||||
const shift = @intCast(u3, irq_num % 8);
|
||||
const value: u8 = arch.inb(port) | (@as(u8, 1) << shift);
|
||||
arch.outb(port, value);
|
||||
const value: u8 = arch.in(u8, port) | (@as(u8, 1) << shift);
|
||||
arch.out(port, value);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -423,8 +423,8 @@ pub fn setMask(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 shift = @intCast(u3, irq_num % 8);
|
||||
const value: u8 = arch.inb(port) & ~(@as(u8, 1) << shift);
|
||||
arch.outb(port, value);
|
||||
const value: u8 = arch.in(u8, port) & ~(@as(u8, 1) << shift);
|
||||
arch.out(port, value);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -481,7 +481,7 @@ test "sendCommandMaster" {
|
|||
|
||||
const cmd: u8 = 10;
|
||||
|
||||
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, cmd });
|
||||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, cmd });
|
||||
|
||||
sendCommandMaster(cmd);
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ test "sendCommandSlave" {
|
|||
|
||||
const cmd: u8 = 10;
|
||||
|
||||
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, cmd });
|
||||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, cmd });
|
||||
|
||||
sendCommandSlave(cmd);
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ test "sendDataMaster" {
|
|||
|
||||
const data: u8 = 10;
|
||||
|
||||
arch.addTestParams("outb", .{ MASTER_DATA_REG, data });
|
||||
arch.addTestParams("out", .{ MASTER_DATA_REG, data });
|
||||
|
||||
sendDataMaster(data);
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ test "sendDataSlave" {
|
|||
|
||||
const data: u8 = 10;
|
||||
|
||||
arch.addTestParams("outb", .{ SLAVE_DATA_REG, data });
|
||||
arch.addTestParams("out", .{ SLAVE_DATA_REG, data });
|
||||
|
||||
sendDataSlave(data);
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ test "readDataMaster" {
|
|||
arch.initTest();
|
||||
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());
|
||||
}
|
||||
|
@ -537,7 +537,7 @@ test "readDataSlave" {
|
|||
arch.initTest();
|
||||
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());
|
||||
}
|
||||
|
@ -547,8 +547,8 @@ test "readMasterIrr" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readMasterIrr());
|
||||
}
|
||||
|
@ -558,8 +558,8 @@ test "readSlaveIrr" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readSlaveIrr());
|
||||
}
|
||||
|
@ -569,8 +569,8 @@ test "readMasterIsr" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readMasterIsr());
|
||||
}
|
||||
|
@ -580,8 +580,8 @@ test "readSlaveIsr" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readSlaveIsr());
|
||||
}
|
||||
|
@ -593,7 +593,7 @@ test "sendEndOfInterrupt master only" {
|
|||
|
||||
var i: u8 = 0;
|
||||
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);
|
||||
}
|
||||
|
@ -606,8 +606,8 @@ test "sendEndOfInterrupt master and slave" {
|
|||
|
||||
var i: u8 = 8;
|
||||
while (i < 16) : (i += 1) {
|
||||
arch.addTestParams("outb", .{ SLAVE_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
|
||||
sendEndOfInterrupt(i);
|
||||
}
|
||||
|
@ -636,9 +636,9 @@ test "spuriousIrq spurious master IRQ number not spurious" {
|
|||
arch.initTest();
|
||||
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
|
||||
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 0x80) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x80) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
@ -658,9 +658,9 @@ test "spuriousIrq spurious master IRQ number spurious" {
|
|||
arch.initTest();
|
||||
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
|
||||
arch.addTestParams("inb", .{ MASTER_STATUS_REG, @as(u8, 0x0) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x0) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
@ -680,9 +680,9 @@ test "spuriousIrq spurious slave IRQ number not spurious" {
|
|||
arch.initTest();
|
||||
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
|
||||
arch.addTestParams("inb", .{ SLAVE_STATUS_REG, @as(u8, 0x80) });
|
||||
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 0x80) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
@ -702,11 +702,11 @@ test "spuriousIrq spurious slave IRQ number spurious" {
|
|||
arch.initTest();
|
||||
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
|
||||
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
|
||||
arch.addTestParams("outb", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
@ -727,9 +727,9 @@ test "setMask master IRQ masked" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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
|
||||
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
|
||||
setMask(1);
|
||||
}
|
||||
|
@ -740,9 +740,9 @@ test "setMask master IRQ unmasked" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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
|
||||
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
|
||||
setMask(1);
|
||||
}
|
||||
|
@ -753,9 +753,9 @@ test "clearMask master IRQ masked" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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
|
||||
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
|
||||
arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
|
||||
|
||||
clearMask(1);
|
||||
}
|
||||
|
@ -766,9 +766,9 @@ test "clearMask master IRQ unmasked" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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
|
||||
arch.addTestParams("outb", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
|
||||
arch.addTestParams("out", .{ MASTER_DATA_REG, @as(u8, 0xFD) });
|
||||
|
||||
clearMask(1);
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ test "init" {
|
|||
arch.addRepeatFunction("ioWait", arch.mock_ioWait);
|
||||
|
||||
// Just a long list of OUT instructions setting up the PIC
|
||||
arch.addTestParams("outb", .{
|
||||
arch.addTestParams("out", .{
|
||||
MASTER_COMMAND_REG,
|
||||
ICW1_INITIALISATION | ICW1_EXPECT_ICW4,
|
||||
SLAVE_COMMAND_REG,
|
||||
|
@ -806,7 +806,7 @@ test "init" {
|
|||
@as(u8, 0xFB),
|
||||
});
|
||||
|
||||
arch.addTestParams("inb", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 0xFF) });
|
||||
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ var time_under_1_ns: u32 = undefined;
|
|||
/// IN cmd: u8 - The command to send to the PIT.
|
||||
///
|
||||
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 {
|
||||
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.
|
||||
///
|
||||
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;
|
||||
|
||||
arch.addTestParams("outb", .{ COMMAND_REGISTER, cmd });
|
||||
arch.addTestParams("out", .{ COMMAND_REGISTER, cmd });
|
||||
|
||||
sendCommand(cmd);
|
||||
}
|
||||
|
@ -407,8 +407,8 @@ test "readBackCommand" {
|
|||
|
||||
const cmd: u8 = 0xC2;
|
||||
|
||||
arch.addTestParams("outb", .{ COMMAND_REGISTER, cmd });
|
||||
arch.addTestParams("inb", .{ COUNTER_0_REGISTER, @as(u8, 0x20) });
|
||||
arch.addTestParams("out", .{ COMMAND_REGISTER, cmd });
|
||||
arch.addTestParams("in", .{ COUNTER_0_REGISTER, @as(u8, 0x20) });
|
||||
|
||||
const actual = readBackCommand(CounterSelect.Counter0);
|
||||
|
||||
|
@ -421,7 +421,7 @@ test "sendDataToCounter" {
|
|||
|
||||
const data: u8 = 10;
|
||||
|
||||
arch.addTestParams("outb", .{ COUNTER_0_REGISTER, data });
|
||||
arch.addTestParams("out", .{ COUNTER_0_REGISTER, data });
|
||||
|
||||
sendDataToCounter(CounterSelect.Counter0, data);
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ test "setupCounter lowest frequency" {
|
|||
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
|
||||
|
||||
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));
|
||||
|
||||
// expectEqual(u32(0), ticks);
|
||||
|
@ -482,7 +482,7 @@ test "setupCounter highest frequency" {
|
|||
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
|
||||
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));
|
||||
|
||||
|
@ -515,7 +515,7 @@ test "setupCounter normal frequency" {
|
|||
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
|
||||
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;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ fn baudDivisor(baud: u32) SerialError!u16 {
|
|||
/// If the transmission buffer is empty.
|
||||
///
|
||||
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)) {
|
||||
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 port_int = @enumToInt(port);
|
||||
// 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});
|
||||
});
|
||||
// Send the divisor's lsb
|
||||
arch.outb(port_int, @truncate(u8, divisor));
|
||||
arch.out(port_int, @truncate(u8, divisor));
|
||||
// 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
|
||||
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});
|
||||
});
|
||||
// Stop initialisation
|
||||
arch.outb(port_int + 1, 0);
|
||||
arch.out(port_int + 1, @as(u8, 0));
|
||||
}
|
||||
|
||||
test "lcrValue computes the correct value" {
|
||||
|
|
|
@ -122,7 +122,7 @@ var cursor_scanline_end: u8 = undefined;
|
|||
/// to.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
///
|
||||
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.
|
||||
|
@ -345,7 +345,7 @@ test "updateCursor width out of bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ test "updateCursor height out of bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ test "updateCursor width and height out of bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ test "updateCursor width-1 and height out of bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -413,7 +413,7 @@ test "updateCursor width and height-1 out of bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -430,7 +430,7 @@ test "updateCursor in bounds" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -441,10 +441,10 @@ test "getCursor 1: 10" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
|
||||
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 10) });
|
||||
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
|
||||
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0) });
|
||||
arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
|
||||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 10) });
|
||||
arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
|
||||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0) });
|
||||
|
||||
const actual = getCursor();
|
||||
expectEqual(expect, actual);
|
||||
|
@ -457,10 +457,10 @@ test "getCursor 2: 0xBEEF" {
|
|||
arch.initTest();
|
||||
defer arch.freeTest();
|
||||
|
||||
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
|
||||
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0xEF) });
|
||||
arch.addTestParams("outb", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
|
||||
arch.addTestParams("inb", .{ PORT_DATA, @as(u8, 0xBE) });
|
||||
arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_LOW });
|
||||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xEF) });
|
||||
arch.addTestParams("out", .{ PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH });
|
||||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xBE) });
|
||||
|
||||
const actual = getCursor();
|
||||
expectEqual(expect, actual);
|
||||
|
@ -471,7 +471,7 @@ test "enableCursor" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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,
|
||||
// Mocking out the arch.outb calls for enabling the cursor:
|
||||
// These are the default cursor positions from init()
|
||||
|
@ -487,7 +487,7 @@ test "disableCursor" {
|
|||
defer arch.freeTest();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -498,7 +498,7 @@ test "setCursorShape 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
|
||||
// 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);
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ test "setCursorShape 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
|
||||
// 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);
|
||||
}
|
||||
|
@ -522,7 +522,7 @@ test "init" {
|
|||
// 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
|
||||
// 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();
|
||||
}
|
||||
|
|
|
@ -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 panic = @import("panic.zig").panic;
|
||||
|
||||
const FreeListAllocator = struct {
|
||||
pub const FreeListAllocator = struct {
|
||||
const Error = error{TooSmall};
|
||||
const Header = struct {
|
||||
size: usize,
|
||||
|
|
|
@ -19,6 +19,7 @@ const scheduler = @import("scheduler.zig");
|
|||
const vfs = @import("filesystem/vfs.zig");
|
||||
const initrd = @import("filesystem/initrd.zig");
|
||||
const keyboard = @import("keyboard.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
comptime {
|
||||
if (!is_test) {
|
||||
|
@ -57,6 +58,8 @@ pub fn log(
|
|||
log_root.log(level, "(" ++ @tagName(scope) ++ "): " ++ format, args);
|
||||
}
|
||||
|
||||
var kernel_heap: heap.FreeListAllocator = undefined;
|
||||
|
||||
export fn kmain(boot_payload: arch.BootPayload) void {
|
||||
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)) {
|
||||
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});
|
||||
};
|
||||
|
||||
|
@ -169,6 +172,14 @@ fn initStage2() noreturn {
|
|||
|
||||
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) {
|
||||
.Initialisation => {
|
||||
logger.info("SUCCESS\n", .{});
|
||||
|
|
|
@ -63,9 +63,9 @@ const types = .{
|
|||
|
||||
.{ "fn (u8) void", "FN_IU8_OVOID", "", "", "" },
|
||||
.{ "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) u8", "FN_IU16_OU8", "", "", "" },
|
||||
.{ "fn (u16) u32", "FN_IU16_OU32", "", "", "" },
|
||||
.{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" },
|
||||
.{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" },
|
||||
.{ "fn (IdtEntry) bool", "FN_IIDTENTRY_OBOOL", "idt_mock", "", "IdtEntry" },
|
||||
|
@ -74,8 +74,10 @@ const types = .{
|
|||
|
||||
.{ "fn (u4, u4) u8", "FN_IU4_IU4_OU8", "", "", "" },
|
||||
.{ "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, u16) void", "FN_IU16_IU16_OVOID", "", "", "" },
|
||||
.{ "fn (u16, u32) void", "FN_IU16_IU32_OVOID", "", "", "" },
|
||||
.{ "fn (StatusRegister, bool) u8", "FN_ISTATUSREGISTER_IBOOL_OU8", "", "", "" },
|
||||
.{ "fn (*Task, usize) void", "FN_IPTRTASK_IUSIZE_OVOID", "", "", "" },
|
||||
.{ "fn (*Task, *Allocator) void", "FN_IPTRTASK_IPTRALLOCATOR_OVOID", "", "", "" },
|
||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
const Allocator = std.mem.Allocator;
|
||||
const mem = @import("mem_mock.zig");
|
||||
const MemProfile = mem.MemProfile;
|
||||
const pci = @import("pci_mock.zig");
|
||||
const gdt = @import("gdt_mock.zig");
|
||||
const idt = @import("idt_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 Device = pci.PciDeviceInfo;
|
||||
|
||||
const mock_framework = @import("mock_framework.zig");
|
||||
pub const initTest = mock_framework.initTest;
|
||||
pub const freeTest = mock_framework.freeTest;
|
||||
|
@ -57,12 +60,12 @@ var KERNEL_VADDR_START: u32 = 0xC0100000;
|
|||
var KERNEL_VADDR_END: u32 = 0xC1100000;
|
||||
var KERNEL_ADDR_OFFSET: u32 = 0xC0000000;
|
||||
|
||||
pub fn outb(port: u16, data: u8) void {
|
||||
return mock_framework.performAction("outb", void, .{ port, data });
|
||||
pub fn out(port: u16, data: anytype) void {
|
||||
return mock_framework.performAction("out", void, .{ port, data });
|
||||
}
|
||||
|
||||
pub fn inb(port: u16) u8 {
|
||||
return mock_framework.performAction("inb", u8, .{port});
|
||||
pub fn in(comptime Type: type, port: u16) Type {
|
||||
return mock_framework.performAction("in", Type, .{port});
|
||||
}
|
||||
|
||||
pub fn ioWait() void {
|
||||
|
@ -147,6 +150,10 @@ pub fn initKeyboard(allocator: *Allocator) Allocator.Error!?*Keyboard {
|
|||
return null;
|
||||
}
|
||||
|
||||
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
|
||||
return &[_]Device{};
|
||||
}
|
||||
|
||||
pub fn init(mem_profile: *const MemProfile) void {
|
||||
// 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 :)
|
||||
|
|
|
@ -46,9 +46,9 @@ const DataElementType = enum {
|
|||
FN_OIDTPTR,
|
||||
FN_IU8_OVOID,
|
||||
FN_IU8_OBOOL,
|
||||
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
|
||||
FN_IU16_OVOID,
|
||||
FN_IU16_OU8,
|
||||
FN_IU16_OU32,
|
||||
FN_IUSIZE_OBOOL,
|
||||
FN_IRTCREGISTER_OU8,
|
||||
FN_IIDTENTRY_OBOOL,
|
||||
|
@ -56,8 +56,10 @@ const DataElementType = enum {
|
|||
FN_IPTRCONSTIDTPTR_OVOID,
|
||||
FN_IU4_IU4_OU8,
|
||||
FN_IU8_IU8_OU16,
|
||||
FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID,
|
||||
FN_IU16_IU8_OVOID,
|
||||
FN_IU16_IU16_OVOID,
|
||||
FN_IU16_IU32_OVOID,
|
||||
FN_ISTATUSREGISTER_IBOOL_OU8,
|
||||
FN_IPTRTASK_IUSIZE_OVOID,
|
||||
FN_IPTRTASK_IPTRALLOCATOR_OVOID,
|
||||
|
@ -98,9 +100,9 @@ const DataElement = union(DataElementType) {
|
|||
FN_OIDTPTR: fn () IdtPtr,
|
||||
FN_IU8_OVOID: fn (u8) void,
|
||||
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_OU8: fn (u16) u8,
|
||||
FN_IU16_OU32: fn (u16) u32,
|
||||
FN_IUSIZE_OBOOL: fn (usize) bool,
|
||||
FN_IRTCREGISTER_OU8: fn (RtcRegister) u8,
|
||||
FN_IIDTENTRY_OBOOL: fn (IdtEntry) bool,
|
||||
|
@ -108,8 +110,10 @@ const DataElement = union(DataElementType) {
|
|||
FN_IPTRCONSTIDTPTR_OVOID: fn (*const IdtPtr) void,
|
||||
FN_IU4_IU4_OU8: fn (u4, u4) u8,
|
||||
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_IU16_OVOID: fn (u16, u16) void,
|
||||
FN_IU16_IU32_OVOID: fn (u16, u32) void,
|
||||
FN_ISTATUSREGISTER_IBOOL_OU8: fn (StatusRegister, bool) u8,
|
||||
FN_IPTRTASK_IUSIZE_OVOID: fn (*Task, usize) void,
|
||||
FN_IPTRTASK_IPTRALLOCATOR_OVOID: fn (*Task, *Allocator) void,
|
||||
|
@ -214,9 +218,9 @@ fn Mock() type {
|
|||
fn () IdtPtr => DataElement{ .FN_OIDTPTR = arg },
|
||||
fn (u8) void => DataElement{ .FN_IU8_OVOID = 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) u8 => DataElement{ .FN_IU16_OU8 = arg },
|
||||
fn (u16) u32 => DataElement{ .FN_IU16_OU32 = arg },
|
||||
fn (usize) bool => DataElement{ .FN_IUSIZE_OBOOL = arg },
|
||||
fn (RtcRegister) u8 => DataElement{ .FN_IRTCREGISTER_OU8 = 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 (u4, u4) u8 => DataElement{ .FN_IU4_IU4_OU8 = 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, 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 (*Task, usize) void => DataElement{ .FN_IPTRTASK_IUSIZE_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 (u8) void => DataElement.FN_IU8_OVOID,
|
||||
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) u8 => DataElement.FN_IU16_OU8,
|
||||
fn (u16) u32 => DataElement.FN_IU16_OU32,
|
||||
fn (usize) bool => DataElement.FN_IUSIZE_OBOOL,
|
||||
fn (RtcRegister) u8 => DataElement.FN_IRTCREGISTER_OU8,
|
||||
fn (IdtEntry) bool => DataElement.FN_IIDTENTRY_OBOOL,
|
||||
|
@ -280,8 +286,10 @@ fn Mock() type {
|
|||
fn (*const IdtPtr) void => DataElement.FN_IPTRCONSTIDTPTR_OVOID,
|
||||
fn (u4, u4) u8 => DataElement.FN_IU4_IU4_OU8,
|
||||
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, 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 (*Task, usize) void => DataElement.FN_IPTRTASK_IUSIZE_OVOID,
|
||||
fn (*Task, *Allocator) void => DataElement.FN_IPTRTASK_IPTRALLOCATOR_OVOID,
|
||||
|
@ -328,9 +336,9 @@ fn Mock() type {
|
|||
fn () IdtPtr => element.FN_OIDTPTR,
|
||||
fn (u8) void => element.FN_IU8_OVOID,
|
||||
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) u8 => element.FN_IU16_OU8,
|
||||
fn (u16) u32 => element.FN_IU16_OU32,
|
||||
fn (usize) bool => element.FN_IUSIZE_OBOOL,
|
||||
fn (RtcRegister) u8 => element.FN_IRTCREGISTER_OU8,
|
||||
fn (IdtEntry) bool => element.FN_IIDTENTRY_OBOOL,
|
||||
|
@ -338,8 +346,10 @@ fn Mock() type {
|
|||
fn (*const IdtPtr) void => element.FN_IPTRCONSTIDTPTR_OVOID,
|
||||
fn (u4, u4) u8 => element.FN_IU4_IU4_OU8,
|
||||
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, 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 (*Task, usize) void => element.FN_IPTRTASK_IUSIZE_OVOID,
|
||||
fn (*Task, *Allocator) void => element.FN_IPTRTASK_IPTRALLOCATOR_OVOID,
|
||||
|
|
108
test/mock/kernel/pci_mock.zig
Normal file
108
test/mock/kernel/pci_mock.zig
Normal 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});
|
||||
}
|
Loading…
Reference in a new issue