Fixed tesing

Add mocking of functions


Added new function type


Fixed up the mock testing


Working mock_framework :), fixed up all tests for VGA and TTY


Adding tests


VGA testing done


Fin vga and tty mock testing


Fixed build


Removed white spaces


WIP


Added tests for all build modes + reduced import string length for testing


Added comments refactoring


Re-added constants


Added some comments


Updated to master of zig


Added unit tests to pipeline


PR comments


Fixed typos
This commit is contained in:
ED 2019-09-08 20:48:23 +01:00
parent 89c47d064b
commit d5d4082a66
24 changed files with 1812 additions and 829 deletions

View file

@ -1,6 +1,6 @@
const builtin = @import("builtin");
pub const internals = switch (builtin.arch) {
pub const internals = if (builtin.is_test) @import("mocking").arch else switch (builtin.arch) {
builtin.Arch.i386 => @import("arch/x86/arch.zig"),
else => unreachable,
};

View file

@ -1,5 +1,6 @@
// Zig version: 0.4.0
const std = @import("std");
const builtin = @import("builtin");
const gdt = @import("gdt.zig");
const idt = @import("idt.zig");
@ -7,6 +8,8 @@ const irq = @import("irq.zig");
const isr = @import("isr.zig");
const log = @import("../../log.zig");
const pit = @import("pit.zig");
const paging = @import("paging.zig");
const MemProfile = @import("../../mem.zig").MemProfile;
const syscalls = @import("syscalls.zig");
pub const InterruptContext = struct {
@ -39,9 +42,6 @@ pub const InterruptContext = struct {
user_esp: u32,
ss: u32,
};
const paging = @import("paging.zig");
const std = @import("std");
const MemProfile = @import("../../mem.zig").MemProfile;
///
/// Initialise the architecture

View file

@ -1,4 +1,4 @@
const constants = @import("constants.zig");
const constants = @import("constants");
const ALIGN = 1 << 0;
const MEMINFO = 1 << 1;

View file

@ -7,7 +7,8 @@ const MemProfile = @import("../../mem.zig").MemProfile;
const testing = @import("std").testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
const constants = @import("constants.zig");
extern var KERNEL_ADDR_OFFSET: *u32;
const ENTRIES_PER_DIRECTORY = 1024;
@ -34,7 +35,7 @@ const ENTRY_AVAILABLE = 0xE00;
const ENTRY_PAGE_ADDR = 0xFFC00000;
const Directory = packed struct {
entries: [ENTRIES_PER_DIRECTORY]DirectoryEntry
entries: [ENTRIES_PER_DIRECTORY]DirectoryEntry,
};
const PagingError = error {
@ -42,7 +43,7 @@ const PagingError = error {
InvalidVirtAddresses,
PhysicalVirtualMismatch,
UnalignedPhysAddresses,
UnalignedVirtAddresses
UnalignedVirtAddresses,
};
///
@ -140,7 +141,7 @@ pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void
@memset(@ptrCast([*]u8, kernel_directory), 0, @sizeOf(Directory));
mapDir(kernel_directory, p_start, p_end, v_start, v_end, allocator) catch unreachable;
const dir_physaddr = @ptrToInt(kernel_directory) - constants.KERNEL_ADDR_OFFSET;
const dir_physaddr = @ptrToInt(kernel_directory) - @ptrToInt(&KERNEL_ADDR_OFFSET);
asm volatile ("mov %[addr], %%cr3" :: [addr] "{eax}" (dir_physaddr));
isr.registerIsr(14, pageFault) catch unreachable;
}

View file

@ -2,13 +2,13 @@
const std = @import("std");
const builtin = @import("builtin");
const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals;
const arch = @import("arch.zig").internals;
const multiboot = @import("multiboot.zig");
const tty = @import("tty.zig");
const vga = @import("vga.zig");
const log = @import("log.zig");
const serial = @import("serial.zig");
const mem = @import("mem.zig");
const mem = if (builtin.is_test) @import("mocking").mem else @import("mem.zig");
const options = @import("build_options");
comptime {
@ -18,9 +18,13 @@ comptime {
}
}
// This is for unit testing as we need to export KERNEL_ADDR_OFFSET as it is no longer available
// from the linker script
export var KERNEL_ADDR_OFFSET: u32 = if (builtin.is_test) 0xC0000000 else undefined;
// Need to import this as we need the panic to be in the root source file, or zig will just use the
// builtin panic and just loop, which is what we don't want
const panic_root = @import("panic.zig");
const panic_root = if (builtin.is_test) @import("mocking").panic else @import("panic.zig");
// Just call the panic function, as this need to be in the root source file
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {

View file

@ -5,7 +5,7 @@ pub const Level = enum {
INFO,
DEBUG,
WARNING,
ERROR
ERROR,
};
fn logCallback(context: void, str: []const u8) anyerror!void {
@ -23,9 +23,11 @@ pub fn logInfo(comptime format: []const u8, args: ...) void {
pub fn logDebug(comptime format: []const u8, args: ...) void {
log(Level.DEBUG, format, args);
}
pub fn logWarning(comptime format: []const u8, args: ...) void {
log(Level.WARNING, format, args);
}
pub fn logError(comptime format: []const u8, args: ...) void {
log(Level.ERROR, format, args);
}

View file

@ -6,7 +6,7 @@ pub const MemProfile = struct {
physaddr_end: [*]u8,
physaddr_start: [*]u8,
mem_kb: u32,
fixed_alloc_size: u32
fixed_alloc_size: u32,
};
// The virtual/physical start/end of the kernel code

View file

@ -2,7 +2,7 @@
const builtin = @import("builtin");
const tty = @import("tty.zig");
const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals;
const arch = @import("arch.zig").internals;
pub fn panicFmt(trace: ?*builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
@setCold(true);

File diff suppressed because it is too large Load diff

View file

@ -1,70 +1,64 @@
// Zig version: 0.4.0
const builtin = @import("builtin");
const arch = @import("arch.zig").internals;
const expectEqual = @import("std").testing.expectEqual;
const warn = @import("std").debug.warn;
/// The port address for the VGA register selection.
const PORT_ADDRESS: u16 = 0x03D4;
pub const PORT_ADDRESS: u16 = 0x03D4;
/// The port address for the VGA data.
const PORT_DATA: u16 = 0x03D5;
pub const PORT_DATA: u16 = 0x03D5;
// The indexes that is passed to the address port to select the register for the data to be
// read or written to.
const REG_HORIZONTAL_TOTAL: u8 = 0x00;
const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8 = 0x01;
const REG_START_HORIZONTAL_BLINKING: u8 = 0x02;
const REG_END_HORIZONTAL_BLINKING: u8 = 0x03;
const REG_START_HORIZONTAL_RETRACE_PULSE: u8 = 0x04;
const REG_END_HORIZONTAL_RETRACE_PULSE: u8 = 0x05;
const REG_VERTICAL_TOTAL: u8 = 0x06;
const REG_OVERFLOW: u8 = 0x07;
const REG_PRESET_ROW_SCAN: u8 = 0x08;
const REG_MAXIMUM_SCAN_LINE: u8 = 0x09;
/// The indexes that is passed to the address port to select the register for the data to be
/// read or written to.
pub const REG_HORIZONTAL_TOTAL: u8 = 0x00;
pub const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8 = 0x01;
pub const REG_START_HORIZONTAL_BLINKING: u8 = 0x02;
pub const REG_END_HORIZONTAL_BLINKING: u8 = 0x03;
pub const REG_START_HORIZONTAL_RETRACE_PULSE: u8 = 0x04;
pub const REG_END_HORIZONTAL_RETRACE_PULSE: u8 = 0x05;
pub const REG_VERTICAL_TOTAL: u8 = 0x06;
pub const REG_OVERFLOW: u8 = 0x07;
pub const REG_PRESET_ROW_SCAN: u8 = 0x08;
pub const REG_MAXIMUM_SCAN_LINE: u8 = 0x09;
/// The command for setting the start of the cursor scan line.
const REG_CURSOR_START: u8 = 0x0A;
/// The register select for setting the cursor scan lines.
pub const REG_CURSOR_START: u8 = 0x0A;
pub const REG_CURSOR_END: u8 = 0x0B;
pub const REG_START_ADDRESS_HIGH: u8 = 0x0C;
pub const REG_START_ADDRESS_LOW: u8 = 0x0D;
/// The command for setting the end of the cursor scan line.
const REG_CURSOR_END: u8 = 0x0B;
const REG_START_ADDRESS_HIGH: u8 = 0x0C;
const REG_START_ADDRESS_LOW: u8 = 0x0D;
/// The command for setting the cursor's linear location.
pub const REG_CURSOR_LOCATION_HIGH: u8 = 0x0E;
pub const REG_CURSOR_LOCATION_LOW: u8 = 0x0F;
/// The command for setting the upper byte of the cursor's linear location.
const REG_CURSOR_LOCATION_HIGH: u8 = 0x0E;
/// Other VGA registers.
pub const REG_VERTICAL_RETRACE_START: u8 = 0x10;
pub const REG_VERTICAL_RETRACE_END: u8 = 0x11;
pub const REG_VERTICAL_DISPLAY_ENABLE_END: u8 = 0x12;
pub const REG_OFFSET: u8 = 0x13;
pub const REG_UNDERLINE_LOCATION: u8 = 0x14;
pub const REG_START_VERTICAL_BLINKING: u8 = 0x15;
pub const REG_END_VERTICAL_BLINKING: u8 = 0x16;
pub const REG_CRT_MODE_CONTROL: u8 = 0x17;
pub const REG_LINE_COMPARE: u8 = 0x18;
/// The command for setting the lower byte of the cursor's linear location.
const REG_CURSOR_LOCATION_LOW: u8 = 0x0F;
const REG_VERTICAL_RETRACE_START: u8 = 0x10;
const REG_VERTICAL_RETRACE_END: u8 = 0x11;
const REG_VERTICAL_DISPLAY_ENABLE_END: u8 = 0x12;
const REG_OFFSET: u8 = 0x13;
const REG_UNDERLINE_LOCATION: u8 = 0x14;
const REG_START_VERTICAL_BLINKING: u8 = 0x15;
const REG_END_VERTICAL_BLINKING: u8 = 0x16;
const REG_CRT_MODE_CONTROL: u8 = 0x17;
const REG_LINE_COMPARE: u8 = 0x18;
/// The start of the cursor scan line, the very beginning.
pub const CURSOR_SCANLINE_START: u8 = 0x0;
/// The scan line for use in the underline cursor shape.
pub const CURSOR_SCANLINE_MIDDLE: u8 = 0xE;
///The start of the cursor scan line, the very beginning.
const CURSOR_SCANLINE_START: u8 = 0x0;
///The scan line for use in the underline cursor shape.
const CURSOR_SCANLINE_MIDDLE: u8 = 0xE;
///The end of the cursor scan line, the very end.
const CURSOR_SCANLINE_END: u8 = 0xF;
/// The end of the cursor scan line, the very end.
pub const CURSOR_SCANLINE_END: u8 = 0xF;
/// If set, disables the cursor.
const CURSOR_DISABLE: u8 = 0x20;
pub const CURSOR_DISABLE: u8 = 0x20;
/// The number of characters wide the screen is.
pub const WIDTH: u16 = 80;
/// The number of characters heigh the screen is.
pub const HEIGHT: u16 = 25;
// The set of colours that VGA supports and can display for the foreground and background.
/// The set of colours that VGA supports and can display for the foreground and background.
pub const COLOUR_BLACK: u4 = 0x00;
pub const COLOUR_BLUE: u4 = 0x01;
pub const COLOUR_GREEN: u4 = 0x02;
@ -83,7 +77,7 @@ pub const COLOUR_LIGHT_BROWN: u4 = 0x0E;
pub const COLOUR_WHITE: u4 = 0x0F;
/// The set of shapes that can be displayed.
pub const CursorShape = enum(u1) {
pub const CursorShape = enum {
/// The cursor has the underline shape.
UNDERLINE,
@ -97,6 +91,28 @@ var cursor_scanline_start: u8 = undefined;
/// The cursor scan line end so to know whether is in block or underline mode.
var cursor_scanline_end: u8 = undefined;
/// A inline function for setting the VGA register port to read from or write to.
inline fn sendPort(port: u8) void {
arch.outb(PORT_ADDRESS, port);
}
/// A inline function for sending data to the set VGA register port.
inline fn sendData(data: u8) void {
arch.outb(PORT_DATA, data);
}
/// A inline function for setting the VGA register port to read from or write toa and sending data
/// to the set VGA register port.
inline fn sendPortData(port: u8, data: u8) void {
sendPort(port);
sendData(data);
}
/// A inline function for getting data from a set VGA register port.
inline fn getData() u8 {
return arch.inb(PORT_DATA);
}
///
/// Takes two 4 bit values that represent the foreground and background colour of the text and
/// returns a 8 bit value that gives both to be displayed.
@ -105,7 +121,7 @@ var cursor_scanline_end: u8 = undefined;
/// IN fg: u4 - The foreground colour.
/// IN bg: u4 - The background colour.
///
/// Return:
/// Return: u8
/// Both combined into 1 byte for the colour to be displayed.
///
pub fn entryColour(fg: u4, bg: u4) u8 {
@ -117,30 +133,25 @@ pub fn entryColour(fg: u4, bg: u4) u8 {
/// background colour.
///
/// Arguments:
/// IN uc: u8 - The character.
/// IN char: u8 - The character ro display.
/// IN colour: u8 - The foreground and background colour.
///
/// Return:
/// The VGA entry.
/// Return: u16
/// A VGA entry.
///
pub fn entry(uc: u8, colour: u8) u16 {
return u16(uc) | u16(colour) << 8;
pub fn entry(char: u8, colour: u8) u16 {
return u16(char) | u16(colour) << 8;
}
///
/// Update the hardware on screen cursor.
///
/// Arguments:
/// IN x: u16 - The horizontal position of the cursor.
/// IN y: u16 - The vertical position of the cursor.
///
/// Return:
/// The VGA entry.
/// IN x: u16 - The horizontal position of the cursor (column).
/// IN y: u16 - The vertical position of the cursor (row).
///
pub fn updateCursor(x: u16, y: u16) void {
var pos: u16 = undefined;
var pos_upper: u16 = undefined;
var pos_lower: u16 = undefined;
// Make sure new cursor position is within the screen
if (x < WIDTH and y < HEIGHT) {
@ -150,31 +161,28 @@ pub fn updateCursor(x: u16, y: u16) void {
pos = (HEIGHT - 1) * WIDTH + (WIDTH - 1);
}
pos_upper = (pos >> 8) & 0x00FF;
pos_lower = pos & 0x00FF;
const pos_upper = (pos >> 8) & 0x00FF;
const pos_lower = pos & 0x00FF;
// Set the cursor position
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
arch.outb(PORT_DATA, @truncate(u8, pos_lower));
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
arch.outb(PORT_DATA, @truncate(u8, pos_upper));
sendPortData(REG_CURSOR_LOCATION_LOW, @truncate(u8, pos_lower));
sendPortData(REG_CURSOR_LOCATION_HIGH, @truncate(u8, pos_upper));
}
///
/// Get the hardware cursor position.
/// Get the linear position of the hardware cursor.
///
/// Return:
/// Return: u16
/// The linear cursor position.
///
pub fn getCursor() u16 {
var cursor: u16 = 0;
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
cursor |= u16(arch.inb(PORT_DATA));
sendPort(REG_CURSOR_LOCATION_LOW);
cursor |= u16(getData());
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
cursor |= u16(arch.inb(PORT_DATA)) << 8;
sendPort(REG_CURSOR_LOCATION_HIGH);
cursor |= u16(getData()) << 8;
return cursor;
}
@ -183,50 +191,37 @@ pub fn getCursor() u16 {
/// Enables the blinking cursor to that is is visible.
///
pub fn enableCursor() void {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, cursor_scanline_start);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, cursor_scanline_end);
sendPortData(REG_CURSOR_START, cursor_scanline_start);
sendPortData(REG_CURSOR_END, cursor_scanline_end);
}
///
/// Disables the blinking cursor to that is is visible.
///
pub fn disableCursor() void {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_DISABLE);
sendPortData(REG_CURSOR_START, CURSOR_DISABLE);
}
///
/// Set the shape of the cursor. This can be and underline or block shape.
///
/// Arguments:
/// IN shape: CURSOR_SHAPE - The enum CURSOR_SHAPE that selects which shape to use.
/// IN shape: CursorShape - The enum CursorShape that selects which shape to use.
///
pub fn setCursorShape(shape: CursorShape) void {
switch (shape) {
CursorShape.UNDERLINE => {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
cursor_scanline_start = CURSOR_SCANLINE_MIDDLE;
cursor_scanline_end = CURSOR_SCANLINE_END;
},
CursorShape.BLOCK => {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_SCANLINE_START);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
cursor_scanline_start = CURSOR_SCANLINE_START;
cursor_scanline_end = CURSOR_SCANLINE_END;
},
}
sendPortData(REG_CURSOR_START, cursor_scanline_start);
sendPortData(REG_CURSOR_END, cursor_scanline_end);
}
///
@ -234,176 +229,8 @@ pub fn setCursorShape(shape: CursorShape) void {
///
pub fn init() void {
// Set the maximum scan line to 0x0F
arch.outb(PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
sendPortData(REG_MAXIMUM_SCAN_LINE, CURSOR_SCANLINE_END);
// Set by default the underline cursor
setCursorShape(CursorShape.UNDERLINE);
}
test "entryColour" {
var fg: u4 = COLOUR_BLACK;
var bg: u4 = COLOUR_BLACK;
var res: u8 = entryColour(fg, bg);
expectEqual(u8(0x00), res);
fg = COLOUR_LIGHT_GREEN;
bg = COLOUR_BLACK;
res = entryColour(fg, bg);
expectEqual(u8(0x0A), res);
fg = COLOUR_BLACK;
bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg);
expectEqual(u8(0xA0), res);
fg = COLOUR_BROWN;
bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg);
expectEqual(u8(0xA6), res);
}
test "entry" {
var colour: u8 = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN);
expectEqual(u8(0xA6), colour);
// Character '0' is 0x30
var video_entry: u16 = entry('0', colour);
expectEqual(u16(0xA630), video_entry);
video_entry = entry(0x55, colour);
expectEqual(u16(0xA655), video_entry);
}
fn testOutOfBounds(x: u16, y: u16) bool {
if (x < HEIGHT and y < WIDTH) {
return true;
}
return false;
}
fn testUpperVal(x: u16, y: u16) u16 {
const pos: u16 = x * WIDTH + y;
const pos_upper: u16 = (pos >> 8) & 0x00FF;
return pos_upper;
}
fn testLowerVal(x: u16, y: u16) u16 {
const pos: u16 = x * WIDTH + y;
const pos_lower: u16 = pos & 0x00FF;
return pos_lower;
}
test "updateCursor out of bounds" {
var x: u16 = 0;
var y: u16 = 0;
var res: bool = testOutOfBounds(x, y);
expectEqual(true, res);
x = HEIGHT - 1;
res = testOutOfBounds(x, y);
expectEqual(true, res);
y = WIDTH - 1;
res = testOutOfBounds(x, y);
expectEqual(true, res);
x = HEIGHT;
y = WIDTH;
res = testOutOfBounds(x, y);
expectEqual(false, res);
x = HEIGHT - 1;
y = WIDTH;
res = testOutOfBounds(x, y);
expectEqual(false, res);
x = HEIGHT;
y = WIDTH - 1;
res = testOutOfBounds(x, y);
expectEqual(false, res);
}
test "updateCursor lower values" {
var x: u16 = 0x0000;
var y: u16 = 0x0000;
var res: u16 = testLowerVal(x, y);
var expected: u16 = 0x0000;
expectEqual(expected, res);
x = 0x0000;
y = 0x000A;
res = testLowerVal(x, y);
expected = 0x000A;
expectEqual(expected, res);
x = 0x000A;
y = 0x0000;
res = testLowerVal(x, y);
expected = 0x0020;
expectEqual(expected, res);
x = 0x000A;
y = 0x000A;
res = testLowerVal(x, y);
expected = 0x002A;
expectEqual(expected, res);
}
test "updateCursor upper values" {
var x: u16 = 0x0000;
var y: u16 = 0x0000;
var res: u16 = testUpperVal(x, y);
var expected: u16 = 0x0000;
expectEqual(expected, res);
x = 0x0000;
y = 0x000A;
res = testUpperVal(x, y);
expected = 0x0000;
expectEqual(expected, res);
x = 0x000A;
y = 0x0000;
res = testUpperVal(x, y);
expected = 0x0003;
expectEqual(expected, res);
x = 0x000A;
y = 0x000A;
res = testUpperVal(x, y);
expected = 0x0003;
expectEqual(expected, res);
}
test "getCursor all" {
warn(" Waiting for mocking ");
var res = getCursor();
}
test "enableCursor all" {
warn(" Waiting for mocking ");
enableCursor();
}
test "disableCursor all" {
warn(" Waiting for mocking ");
disableCursor();
}
test "setCursorShape all" {
setCursorShape(CursorShape.UNDERLINE);
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
setCursorShape(CursorShape.BLOCK);
expectEqual(CURSOR_SCANLINE_START, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
}
test "init all" {
warn(" Waiting for mocking ");
init();
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
}