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 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
|
||||||
///
|
///
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
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.
|
/// 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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" {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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", .{});
|
||||||
|
|
|
@ -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", "", "", "" },
|
||||||
|
|
|
@ -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 :)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
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