cleaning up before kmalloc
This commit is contained in:
parent
902aa136c6
commit
5880d5296e
16 changed files with 119 additions and 84 deletions
33
README.md
33
README.md
|
|
@ -1,36 +1,33 @@
|
||||||
## hobby kernel in zig
|
# hobby kernel in zig
|
||||||
|
|
||||||
slowly porting from rust.
|
|
||||||
|
|
||||||
### features
|
### features
|
||||||
|
|
||||||
- vga frame buffer
|
- 80x25 frame buffer
|
||||||
- ps2 keyboard driver
|
- ps2 keyboard driver
|
||||||
- interrupts
|
|
||||||
- terminal console
|
- terminal console
|
||||||
- lspci
|
- lspci
|
||||||
|
- x86
|
||||||
|
- MMU
|
||||||
|
- interrupts
|
||||||
|
|
||||||
### dependencies
|
### dependencies
|
||||||
|
|
||||||
`zig` compiler
|
- [ziglang](https://github.com/ziglang/zig) 0.5.0
|
||||||
|
|
||||||
### compile
|
# How to
|
||||||
|
|
||||||
`zig build` compiles and links the multiboot kernel, without a bootloader.
|
## compile
|
||||||
|
|
||||||
### test
|
`zig build` compiles and links the multiboot kernel (without a bootloader)
|
||||||
|
|
||||||
`./qemu.sh start`
|
## test
|
||||||
`./qemu.sh monitor`
|
|
||||||
`./qemu.sh gdb`
|
- `./qemu.sh start`
|
||||||
|
- `./qemu.sh monitor`
|
||||||
|
- `./qemu.sh gdb`
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
|
|
||||||
## interrupts
|
## interrupt call chain
|
||||||
|
|
||||||
`interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`)
|
`interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`)
|
||||||
|
|
||||||
## layout
|
|
||||||
|
|
||||||
`0->4Mib` kernel reserved
|
|
||||||
`1Mib` interrupt stack
|
|
||||||
|
|
|
||||||
2
qemu.sh
2
qemu.sh
|
|
@ -18,7 +18,7 @@ start() {
|
||||||
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
||||||
# build/kernel.iso
|
# build/kernel.iso
|
||||||
|
|
||||||
# this allows this switch to monitor with ^a-c, but doesn't
|
# this allows to monitor with ^a-c, but doesn't
|
||||||
# play nice with irqs apparently...
|
# play nice with irqs apparently...
|
||||||
# -serial mon:stdio \
|
# -serial mon:stdio \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ pub fn initialize() void {
|
||||||
isr.install_irqs();
|
isr.install_irqs();
|
||||||
isr.install_syscalls();
|
isr.install_syscalls();
|
||||||
interrupt.registerIRQ(0, interrupt.pit_handler);
|
interrupt.registerIRQ(0, interrupt.pit_handler);
|
||||||
|
interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||||
|
|
||||||
// load IDT
|
// load IDT
|
||||||
lidt(@ptrToInt(&idtr));
|
lidt(@ptrToInt(&idtr));
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
|
// std
|
||||||
|
pub const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
|
// from core kernel
|
||||||
pub usingnamespace @import("../../vga.zig");
|
pub usingnamespace @import("../../vga.zig");
|
||||||
pub const multiboot = @import("../../multiboot.zig");
|
pub const multiboot = @import("../../multiboot.zig");
|
||||||
pub const time = @import("../../time.zig");
|
pub const time = @import("../../time.zig");
|
||||||
|
pub const ps2 = @import("../../ps2.zig");
|
||||||
|
|
||||||
|
// x86 namespace
|
||||||
pub usingnamespace @import("lib/io.zig");
|
pub usingnamespace @import("lib/io.zig");
|
||||||
pub usingnamespace @import("lib/instructions.zig");
|
pub usingnamespace @import("lib/instructions.zig");
|
||||||
pub usingnamespace @import("main.zig");
|
pub usingnamespace @import("main.zig");
|
||||||
|
pub const layout = @import("layout.zig");
|
||||||
pub const memory = @import("memory.zig");
|
pub const memory = @import("memory.zig");
|
||||||
pub const paging = @import("paging.zig");
|
pub const paging = @import("paging.zig");
|
||||||
pub const idt = @import("idt.zig");
|
pub const idt = @import("idt.zig");
|
||||||
pub const isr = @import("isr.zig");
|
pub const isr = @import("isr.zig");
|
||||||
pub const gdt = @import("gdt.zig");
|
pub const gdt = @import("gdt.zig");
|
||||||
pub const interrupt = @import("interrupt.zig");
|
pub const interrupt = @import("interrupt.zig");
|
||||||
|
|
||||||
pub const assert = @import("std").debug.assert;
|
|
||||||
|
|
|
||||||
|
|
@ -175,11 +175,8 @@ pub fn maskIRQ(irq: u8, mask: bool) void {
|
||||||
|
|
||||||
// Mask or unmask the interrupt.
|
// Mask or unmask the interrupt.
|
||||||
const shift = @intCast(u3, irq % 8);
|
const shift = @intCast(u3, irq % 8);
|
||||||
if (mask) {
|
if (mask) outb(port, old | (u8(1) << shift));
|
||||||
outb(port, old | (u8(1) << shift));
|
if (!mask) outb(port, old & ~(u8(1) << shift));
|
||||||
} else {
|
|
||||||
outb(port, old & ~(u8(1) << shift));
|
|
||||||
}
|
|
||||||
const new = inb(port); // Retrieve the current mask.
|
const new = inb(port); // Retrieve the current mask.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
//https://wiki.osdev.org/Memory_Map_(x86)
|
//https://wiki.osdev.org/Memory_Map_(x86)
|
||||||
|
|
||||||
pub const KSTACK = 0x80000; // todo: move to .bss
|
const kiB = 1024;
|
||||||
pub const KERNEL = 0x100000;
|
const MiB = 1024 * kiB; // 0x100000
|
||||||
pub const IDENTITY = 0x400000; // 0->4MiB
|
const GiB = 1024 * MiB;
|
||||||
pub const HEAP = 0x800000;
|
|
||||||
|
// zig fmt: off
|
||||||
|
pub const KSTACK = 0x80000; // todo: move to .bss
|
||||||
|
pub const KERNEL = 1 * MiB;
|
||||||
|
pub const IDENTITY = 4 * MiB; // 0->4MiB
|
||||||
|
|
||||||
|
pub const HEAP = 8 * MiB;
|
||||||
|
pub const USER_STACKS = 0x1000000;
|
||||||
|
pub const USER_STACKS_END = 0x10000000;
|
||||||
|
// zig fmt: on
|
||||||
|
|
|
||||||
|
|
@ -8,27 +8,31 @@ pub var stack_size: usize = undefined;
|
||||||
pub var stack_end: usize = undefined;
|
pub var stack_end: usize = undefined;
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
// 4095 -> 4096
|
pub inline fn pageAlign(address: u32) u32 {
|
||||||
// 4096 -> 4096
|
// 4095 -> 4096
|
||||||
// 4097 -> 8192
|
// 4096 -> 4096
|
||||||
pub fn pageAlign(address: u32) u32 {
|
// 4097 -> 8192
|
||||||
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
|
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
// Return the amount of variable elements (in bytes).
|
// Return the amount of variable elements (in bytes).
|
||||||
//
|
//
|
||||||
pub fn available() usize {
|
pub inline fn available() usize {
|
||||||
return stack_index * PAGE_SIZE;
|
return stack_index * PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn available_MiB() usize {
|
||||||
|
return available() / (1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
// Request a free physical page and return its address.
|
// Request a free physical page and return its address.
|
||||||
//
|
//
|
||||||
pub fn allocate() ?usize {
|
pub fn allocate() !usize {
|
||||||
if (available() == 0) {
|
if (available() == 0) {
|
||||||
println("out of memory");
|
println("out of memory");
|
||||||
return null;
|
return error.OutOfMemory;
|
||||||
}
|
}
|
||||||
stack_index -= 1;
|
stack_index -= 1;
|
||||||
return stack[stack_index];
|
return stack[stack_index];
|
||||||
|
|
@ -56,9 +60,14 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
||||||
assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0);
|
assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0);
|
||||||
assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
|
assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
|
||||||
|
|
||||||
|
// TODO: WHAT WHY WHAAAAT, must check back here later
|
||||||
|
// Place stack at 0x200000 so that in the future I trigger a
|
||||||
|
// random bug and I won't ever know where it came from, great.
|
||||||
|
stack = @intToPtr([*]usize, 0x200000); // 2 MiB
|
||||||
|
|
||||||
// Place the stack of free pages after the last Multiboot module.
|
// Place the stack of free pages after the last Multiboot module.
|
||||||
stack = @intToPtr([*]usize, 0x200000);
|
|
||||||
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
|
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
|
||||||
|
|
||||||
// Calculate the approximate size of the stack based on the amount of total upper memory.
|
// Calculate the approximate size of the stack based on the amount of total upper memory.
|
||||||
stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize);
|
stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize);
|
||||||
stack_end = pageAlign(@ptrToInt(stack) + stack_size);
|
stack_end = pageAlign(@ptrToInt(stack) + stack_size);
|
||||||
|
|
@ -83,3 +92,7 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
||||||
|
|
||||||
println("available memory: {d} MiB ", available() / 1024 / 1024);
|
println("available memory: {d} MiB ", available() / 1024 / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn introspect() void {
|
||||||
|
println("physframes left: {d} ({d} MiB)", stack_index, available_MiB());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ fn pageFault() void {
|
||||||
while (true) asm volatile ("hlt");
|
while (true) asm volatile ("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pageBase(addr: usize) usize {
|
inline fn pageBase(addr: usize) usize {
|
||||||
return addr & (~PAGE_SIZE +% 1);
|
return addr & (~PAGE_SIZE +% 1);
|
||||||
}
|
}
|
||||||
fn pde(addr: usize) *PageEntry {
|
inline fn pde(addr: usize) *PageEntry {
|
||||||
return &PD[addr >> 22];
|
return &PD[addr >> 22];
|
||||||
}
|
}
|
||||||
fn pte(addr: usize) *PageEntry {
|
inline fn pte(addr: usize) *PageEntry {
|
||||||
return &PT[addr >> 12];
|
return &PT[addr >> 12];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,14 +46,28 @@ pub fn unmap(virt: usize) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mmap(virt: usize, phys: ?usize) void {
|
pub fn mmap(virt: usize, phys: ?usize) !void {
|
||||||
var pde: *PageEntry = pde(virt);
|
var pde: *PageEntry = pde(virt);
|
||||||
if (pde.* == 0) pde.* = memory.allocate() | WRITE | PRESENT;
|
if (pde.* == 0) pde.* = try memory.allocate() | WRITE | PRESENT;
|
||||||
var pte: *PageEntry = pte(virt);
|
var pte: *PageEntry = pte(virt);
|
||||||
pte.* = if (phys) |p| p else allocate() | PRESENT;
|
pte.* = if (phys) |p| p else allocate() | PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addrspace() void {
|
pub fn initialize() void {
|
||||||
|
var p2 = pageDirectory[0..];
|
||||||
|
|
||||||
|
// identity map 0 -> 4MB
|
||||||
|
p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
|
||||||
|
// recursive mapping
|
||||||
|
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
|
||||||
|
|
||||||
|
assert(memory.stack_end < layout.IDENTITY);
|
||||||
|
|
||||||
|
interrupt.register(14, pageFault);
|
||||||
|
setupPaging(@ptrToInt(&pageDirectory[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn introspect() void {
|
||||||
var i: usize = 1;
|
var i: usize = 1;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < 1024) : (i += 1) {
|
while (i < 1024) : (i += 1) {
|
||||||
|
|
@ -67,17 +81,3 @@ pub fn addrspace() void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize() void {
|
|
||||||
var p2 = pageDirectory[0..];
|
|
||||||
|
|
||||||
// identity map 0 -> 4MB
|
|
||||||
p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
|
|
||||||
// recursive mapping
|
|
||||||
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
|
|
||||||
|
|
||||||
assert(memory.stack_end < 0x400000);
|
|
||||||
|
|
||||||
interrupt.register(14, pageFault);
|
|
||||||
setupPaging(@ptrToInt(&pageDirectory[0]));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ var command: [10]u8 = undefined;
|
||||||
var command_len: usize = 0;
|
var command_len: usize = 0;
|
||||||
|
|
||||||
fn execute(com: []u8) void {
|
fn execute(com: []u8) void {
|
||||||
if (@import("std").mem.eql(u8, com, "lspci")) pci.lspci();
|
const eql = std.mem.eql;
|
||||||
if (@import("std").mem.eql(u8, com, "paging")) x86.paging.addrspace();
|
if (eql(u8, com, "x86paging")) return x86.paging.introspect();
|
||||||
if (@import("std").mem.eql(u8, com, "uptime")) time.uptime();
|
if (eql(u8, com, "x86memory")) return x86.memory.introspect();
|
||||||
if (@import("std").mem.eql(u8, com, "topbar")) topbar();
|
if (eql(u8, com, "lspci")) return pci.lspci();
|
||||||
|
if (eql(u8, com, "uptime")) return time.uptime();
|
||||||
|
if (eql(u8, com, "topbar")) return topbar();
|
||||||
|
println("{}: command not found", com);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keypress(char: u8) void {
|
pub fn keypress(char: u8) void {
|
||||||
|
|
@ -15,7 +18,7 @@ pub fn keypress(char: u8) void {
|
||||||
switch (char) {
|
switch (char) {
|
||||||
'\n' => {
|
'\n' => {
|
||||||
print("\n");
|
print("\n");
|
||||||
execute(command[0..command_len]);
|
if (command_len > 0) execute(command[0..command_len]);
|
||||||
print("> ");
|
print("> ");
|
||||||
command_len = 0;
|
command_len = 0;
|
||||||
},
|
},
|
||||||
|
|
@ -38,6 +41,6 @@ pub fn keypress(char: u8) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize() void {
|
pub fn initialize() void {
|
||||||
x86.interrupt.registerIRQ(1, ps2.keyboard_handler);
|
ps2.keyboard_callback = keypress;
|
||||||
print("> ");
|
print("> ");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
pub const assert = @import("std").debug.assert;
|
// std
|
||||||
pub const std = @import("std");
|
pub const std = @import("std");
|
||||||
|
pub const assert = std.debug.assert;
|
||||||
|
|
||||||
|
// main namespace
|
||||||
pub usingnamespace @import("vga.zig");
|
pub usingnamespace @import("vga.zig");
|
||||||
|
pub const x86 = @import("arch/x86/index.zig");
|
||||||
pub const multiboot = @import("multiboot.zig");
|
pub const multiboot = @import("multiboot.zig");
|
||||||
|
pub const mem = @import("memory.zig");
|
||||||
|
pub const task = @import("task.zig");
|
||||||
pub const console = @import("console.zig");
|
pub const console = @import("console.zig");
|
||||||
pub const pci = @import("pci/pci.zig");
|
pub const pci = @import("pci/pci.zig");
|
||||||
pub const ps2 = @import("ps2.zig");
|
pub const ps2 = @import("ps2.zig");
|
||||||
pub const x86 = @import("arch/x86/index.zig");
|
|
||||||
pub const time = @import("time.zig");
|
pub const time = @import("time.zig");
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
||||||
pci.scan();
|
pci.scan();
|
||||||
console.initialize();
|
console.initialize();
|
||||||
|
|
||||||
|
// const t = task.Task.new(@ptrToInt(topbar));
|
||||||
|
|
||||||
while (true) asm volatile ("hlt");
|
while (true) asm volatile ("hlt");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
const paging = @import("arch/x86/paging.zig");
|
pub usingnamespace @import("index.zig");
|
||||||
|
|
||||||
pub fn alloc(size: usize) usize {
|
pub fn allocate(comptime T: type) !*type {}
|
||||||
|
|
||||||
}
|
pub fn free(address: usize) void {}
|
||||||
|
|
||||||
pub fn free() {
|
pub fn initialize() void {}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,12 @@ pub const PciDevice = struct {
|
||||||
var drv = Drivers[i];
|
var drv = Drivers[i];
|
||||||
if (self.class() != drv.class or self.subclass() != drv.subclass)
|
if (self.class() != drv.class or self.subclass() != drv.subclass)
|
||||||
continue;
|
continue;
|
||||||
if (drv.vendor) |v| if (self.vendor != v)
|
if (drv.vendor) |v|
|
||||||
continue;
|
if (self.vendor != v)
|
||||||
if (drv.subsystem) |ss| if (self.subsystem() != ss)
|
continue;
|
||||||
continue;
|
if (drv.subsystem) |ss|
|
||||||
|
if (self.subsystem() != ss)
|
||||||
|
continue;
|
||||||
return drv;
|
return drv;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -139,7 +141,7 @@ pub fn scan() void {
|
||||||
|
|
||||||
pub fn lspci() void {
|
pub fn lspci() void {
|
||||||
var slot: u5 = 0;
|
var slot: u5 = 0;
|
||||||
println("b:s.f c,s v d drv");
|
println("b:s.f c, s v d drv");
|
||||||
while (slot < 31) : (slot += 1) {
|
while (slot < 31) : (slot += 1) {
|
||||||
if (PciDevice.init(0, slot, 0)) |dev| {
|
if (PciDevice.init(0, slot, 0)) |dev| {
|
||||||
var function: u3 = 0;
|
var function: u3 = 0;
|
||||||
|
|
|
||||||
|
|
@ -78,9 +78,13 @@ fn key_isrelease(scancode: u8) bool {
|
||||||
return scancode & (1 << 7) != 0;
|
return scancode & (1 << 7) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub var keyboard_callback: fn (u8) void = undefined;
|
||||||
|
|
||||||
pub fn keyboard_handler() void {
|
pub fn keyboard_handler() void {
|
||||||
const scancode = ps2_scancode();
|
const scancode = ps2_scancode();
|
||||||
|
if (scancode > KEYMAP_US.len) return;
|
||||||
if (key_isrelease(scancode)) return; // don't process releases
|
if (key_isrelease(scancode)) return; // don't process releases
|
||||||
const shift = false; // don't know about modifiers yet
|
const shift = false; // don't know about modifiers yet
|
||||||
console.keypress(KEYMAP_US[scancode][if (shift) 1 else 0]);
|
const character = KEYMAP_US[scancode][if (shift) 1 else 0];
|
||||||
|
if (keyboard_callback != undefined) keyboard_callback(character);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@ pub fn increment(value: u32) void {
|
||||||
|
|
||||||
pub fn uptime() void {
|
pub fn uptime() void {
|
||||||
const offset_ms = offset_us / 1000;
|
const offset_ms = offset_us / 1000;
|
||||||
println("uptime: {}.{:.3}", offset_s, offset_ms);
|
println("{}.{:.3}", offset_s, offset_ms);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
const time = @import("time.zig");
|
const time = @import("time.zig");
|
||||||
const x86 = @import("arch/x86/index.zig");
|
const x86 = @import("arch/x86/index.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
// Screen size.
|
// Screen size.
|
||||||
pub const VGA_WIDTH = 80;
|
pub const VGA_WIDTH = 80;
|
||||||
pub const VGA_HEIGHT = 25;
|
pub const VGA_HEIGHT = 25;
|
||||||
|
|
@ -70,8 +69,7 @@ pub fn topbar() void {
|
||||||
vga.cursor = 0;
|
vga.cursor = 0;
|
||||||
vga.background = Color.Red;
|
vga.background = Color.Red;
|
||||||
|
|
||||||
const offset_ms = time.offset_us / 1000;
|
time.uptime();
|
||||||
println("{}.{}", time.offset_s, offset_ms / 10);
|
|
||||||
|
|
||||||
vga.cursor = cursor;
|
vga.cursor = cursor;
|
||||||
vga.background = bg;
|
vga.background = bg;
|
||||||
|
|
@ -154,10 +152,12 @@ const VGA = struct {
|
||||||
//
|
//
|
||||||
fn scrollDown(self: *VGA) void {
|
fn scrollDown(self: *VGA) void {
|
||||||
const first = VGA_WIDTH; // Index of first line.
|
const first = VGA_WIDTH; // Index of first line.
|
||||||
|
const second = 2 * VGA_WIDTH; // Index of first line.
|
||||||
const last = VGA_SIZE - VGA_WIDTH; // Index of last line.
|
const last = VGA_SIZE - VGA_WIDTH; // Index of last line.
|
||||||
|
|
||||||
// Copy all the screen (apart from the first line) up one line.
|
// Copy all the screen (apart from the first line) up one line.
|
||||||
std.mem.copy(VGAEntry, self.vram[0..last], self.vram[first..VGA_SIZE]);
|
// std.mem.copy(VGAEntry, self.vram[0..last], self.vram[first .. VGA_SIZE]); // whole screen
|
||||||
|
std.mem.copy(VGAEntry, self.vram[first..last], self.vram[second..VGA_SIZE]); // skip topbar
|
||||||
// Clean the last line.
|
// Clean the last line.
|
||||||
std.mem.set(VGAEntry, self.vram[last..VGA_SIZE], self.entry(' '));
|
std.mem.set(VGAEntry, self.vram[last..VGA_SIZE], self.entry(' '));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue