paging done
This commit is contained in:
parent
97aa541b34
commit
07089c2ea1
17 changed files with 247 additions and 253 deletions
|
|
@ -29,3 +29,8 @@ slowly porting from rust.
|
|||
## interrupts
|
||||
|
||||
`interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`)
|
||||
|
||||
## layout
|
||||
|
||||
`0->4Mib` kernel reserved
|
||||
`1Mib` interrupt stack
|
||||
|
|
|
|||
3
qemu.sh
3
qemu.sh
|
|
@ -12,10 +12,11 @@ start() {
|
|||
-m 1337M \
|
||||
-curses \
|
||||
-append "Hello" \
|
||||
-drive file=disk.img,if=virtio\
|
||||
-kernel ${KERNEL}
|
||||
# -no-reboot \
|
||||
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
||||
# build/kernel.iso
|
||||
"$@"
|
||||
|
||||
# this allows this switch to monitor with ^a-c, but doesn't
|
||||
# play nice with irqs apparently...
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ __start:
|
|||
|
||||
push %ebx // Pass multiboot info structure.
|
||||
push %eax // Pass multiboot magic code.
|
||||
|
||||
call kmain // Call the kernel.
|
||||
|
||||
// Halt the CPU.
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ pub fn initialize() void {
|
|||
loadGDT(&gdtr);
|
||||
|
||||
// Initialize TSS.
|
||||
const tss_entry = makeEntry(@ptrToInt(&tss), @sizeOf(TSS) - 1, TSS_ACCESS, PROTECTED);
|
||||
gdt[TSS_DESC / @sizeOf(GDTEntry)] = tss_entry;
|
||||
x86.ltr(TSS_DESC);
|
||||
// const tss_entry = makeEntry(@ptrToInt(&tss), @sizeOf(TSS) - 1, TSS_ACCESS, PROTECTED);
|
||||
// gdt[TSS_DESC / @sizeOf(GDTEntry)] = tss_entry;
|
||||
// x86.ltr(TSS_DESC);
|
||||
|
||||
// tty.stepOK();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Kernel stack for interrupt handling.
|
||||
KERNEL_STACK = 0x800000
|
||||
KERNEL_STACK = 0x10000
|
||||
// GDT selectors.
|
||||
KERNEL_DS = 0x10
|
||||
|
||||
|
|
|
|||
6
src/arch/x86/layout.zig
Normal file
6
src/arch/x86/layout.zig
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//https://wiki.osdev.org/Memory_Map_(x86)
|
||||
|
||||
pub const KSTACK = 0x80000; // todo: move to .bss
|
||||
pub const KERNEL = 0x100000;
|
||||
pub const IDENTITY = 0x400000; // 0->4MiB
|
||||
pub const HEAP = 0x800000;
|
||||
|
|
@ -8,7 +8,7 @@ SECTIONS {
|
|||
. = 0xb8000;
|
||||
. += 80 * 25 * 2;
|
||||
|
||||
/* lower half kernel */
|
||||
/* lower half kernel <1MiB */
|
||||
. = 0x10000;
|
||||
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
|
|
@ -37,32 +37,12 @@ SECTIONS {
|
|||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
/* NOT A GOOD IDEA TO GROUP debug_* SYMBOLS ! */
|
||||
/* .debug : */
|
||||
/* { */
|
||||
/* /1* KEEP(*(.debug_*)) *1/ */
|
||||
/* *(.debug_*) */
|
||||
/* . = ALIGN(4K); */
|
||||
/* } */
|
||||
|
||||
.gdt :
|
||||
{
|
||||
*(.gdt)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.got.plt :
|
||||
{
|
||||
*(.got.plt)
|
||||
. = ALIGN(4K);
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
|
|
|
|||
|
|
@ -12,26 +12,11 @@ const x86 = @import("lib/index.zig");
|
|||
/// x86 specific intialization
|
||||
/// first entry point (see linker.ld)
|
||||
pub fn x86_main(info: *const MultibootInfo) void {
|
||||
// set up the physical frame allocator
|
||||
memory.initialize(info);
|
||||
|
||||
println("{}", memory.allocator.allocate(1));
|
||||
// println("{}", memory.allocator.allocate(1));
|
||||
// println("{}", memory.allocator.allocate(1));
|
||||
// println("{}", memory.allocator.allocate(1));
|
||||
|
||||
// setup memory segmentation
|
||||
gdt.initialize();
|
||||
|
||||
// setup interrupts
|
||||
idt.initialize();
|
||||
memory.initialize(info);
|
||||
paging.initialize();
|
||||
|
||||
// enable interrupts
|
||||
x86.sti();
|
||||
|
||||
// set up the virtual page mapper
|
||||
paging.initialize();
|
||||
|
||||
// test breakpoint
|
||||
// x86.int3();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +1,88 @@
|
|||
usingnamespace @import("kernel").multiboot;
|
||||
usingnamespace @import("../../vga.zig");
|
||||
usingnamespace @import("kernel").vga;
|
||||
const assert = @import("std").debug.assert;
|
||||
const std = @import("std");
|
||||
|
||||
pub var allocator: bumpAllocator = undefined;
|
||||
var stack: [*]usize = undefined; // Stack of free physical page.
|
||||
var stack_index: usize = 0; // Index into the stack.
|
||||
|
||||
// Boundaries of the frame stack.
|
||||
pub var stack_size: usize = undefined;
|
||||
pub var stack_end: usize = undefined;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
// 4095 -> 4096
|
||||
// 4096 -> 4096
|
||||
// 4097 -> 8192
|
||||
pub fn pageAlign(address: u32) u32 {
|
||||
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
|
||||
////
|
||||
// Return the amount of variable elements (in bytes).
|
||||
//
|
||||
pub fn available() usize {
|
||||
return stack_index * PAGE_SIZE;
|
||||
}
|
||||
|
||||
////
|
||||
// Request a free physical page and return its address.
|
||||
//
|
||||
pub fn allocate() ?usize {
|
||||
if (available() == 0) {
|
||||
println("out of memory");
|
||||
return null;
|
||||
}
|
||||
|
||||
stack_index -= 1;
|
||||
return stack[stack_index];
|
||||
}
|
||||
|
||||
////
|
||||
// Free a previously allocated physical page.
|
||||
//
|
||||
// Arguments:
|
||||
// address: Address of the page to be freed.
|
||||
//
|
||||
pub fn free(address: usize) void {
|
||||
stack[stack_index] = address;
|
||||
stack_index += 1;
|
||||
}
|
||||
|
||||
////
|
||||
// Scan the memory map to index all available memory.
|
||||
//
|
||||
// Arguments:
|
||||
// info: Information structure from bootloader.
|
||||
//
|
||||
pub fn initialize(info: *const MultibootInfo) void {
|
||||
// Ensure the bootloader has given us the memory map.
|
||||
assert((info.flags & MULTIBOOT_INFO_MEMORY) != 0);
|
||||
assert((info.flags & MULTIBOOT_INFO_MEM_MAP) != 0);
|
||||
|
||||
format_multibootinfo(info);
|
||||
allocator = bumpAllocator.new(info);
|
||||
}
|
||||
|
||||
fn format_multibootentry(entry: *MultibootMMapEntry) void {
|
||||
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||
print(" AVAILABLE: ");
|
||||
} else {
|
||||
print("NOT AVAILABLE: ");
|
||||
}
|
||||
print("{x} ", entry.addr);
|
||||
if (entry.len / (1024 * 1024) > 0) {
|
||||
println("({} MB)", entry.len / (1024 * 1024));
|
||||
} else {
|
||||
println("({} kB)", entry.len / (1024));
|
||||
}
|
||||
}
|
||||
|
||||
fn format_multibootinfo(info: *const MultibootInfo) void {
|
||||
var cmdline_ptr = @intToPtr([*c]const u8, info.cmdline);
|
||||
var cmdline = @ptrCast([*c]const u8, cmdline_ptr);
|
||||
// var cmdline = std.cstr.toSliceConst(info.cmdline);
|
||||
println("flags: {b}", info.flags);
|
||||
println("lower: {x}", info.mem_lower);
|
||||
println("upper: {x}", info.mem_upper);
|
||||
println("mmap_l: {}", info.mmap_length);
|
||||
println("mmap_a: {x}", info.mmap_addr);
|
||||
println("cmdline: {x}", cmdline_ptr);
|
||||
println("cmdline: {}", cmdline);
|
||||
// Place the stack of free pages after the last Multiboot module.
|
||||
stack = @intToPtr([*]usize, 0x200000);
|
||||
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
|
||||
// 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_end = pageAlign(@ptrToInt(stack) + stack_size);
|
||||
|
||||
var map: usize = info.mmap_addr;
|
||||
while (map < info.mmap_addr + info.mmap_length) {
|
||||
var entry = @intToPtr(*MultibootMMapEntry, map);
|
||||
format_multibootentry(entry);
|
||||
|
||||
// Calculate the start and end of this memory area.
|
||||
var start = @truncate(usize, entry.addr);
|
||||
var end = @truncate(usize, start + entry.len);
|
||||
// Anything that comes before the end of the stack of free pages is reserved.
|
||||
start = if (start >= stack_end) start else stack_end;
|
||||
|
||||
// Flag all the pages in this memory area as free.
|
||||
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
|
||||
free(start);
|
||||
|
||||
// Go to the next entry in the memory map.
|
||||
map += entry.size + @sizeOf(@typeOf(entry.size));
|
||||
}
|
||||
}
|
||||
|
||||
// returns each available physical frame one by one in order
|
||||
pub const bumpAllocator = struct {
|
||||
next_free_frame: PhysFrame,
|
||||
current_area: ?*MultibootMMapEntry,
|
||||
info: *const MultibootInfo,
|
||||
|
||||
pub fn new(info: *const MultibootInfo) bumpAllocator {
|
||||
const first_area = @intToPtr(*MultibootMMapEntry, info.mmap_addr);
|
||||
var allocato = bumpAllocator{
|
||||
.current_area = first_area,
|
||||
.next_free_frame = PhysFrame.from_addr(@intCast(u32, first_area.addr)),
|
||||
.info = info,
|
||||
};
|
||||
return allocato;
|
||||
println("available memory: {d} MiB ", available() / 1024 / 1024);
|
||||
}
|
||||
|
||||
pub fn allocate(self: var, count: u32) ?PhysFrame {
|
||||
if (count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (self.current_area == null) {
|
||||
return null;
|
||||
}
|
||||
if (self.current_area.?.type != MULTIBOOT_MEMORY_AVAILABLE) {
|
||||
self.choose_next_area();
|
||||
return self.allocate(count);
|
||||
}
|
||||
// <4MB identity mapped kernel, lazy trick
|
||||
if (PhysFrame.start_addr(self.next_free_frame) < 0x400000) {
|
||||
self.next_free_frame.number += 1;
|
||||
return self.allocate(count);
|
||||
}
|
||||
|
||||
const start_frame = self.next_free_frame;
|
||||
const end_frame = self.next_free_frame.add(count - 1);
|
||||
const current_area_last_frame = PhysFrame.from_addr(@intCast(u32, self.current_area.?.addr + self.current_area.?.len));
|
||||
if (end_frame.number > current_area_last_frame.number) {
|
||||
self.choose_next_area();
|
||||
return self.allocate(count);
|
||||
}
|
||||
self.next_free_frame.number += count;
|
||||
return start_frame;
|
||||
}
|
||||
|
||||
pub fn choose_next_area(self: var) void {
|
||||
println("choosing next area");
|
||||
const current = self.current_area.?;
|
||||
var next_area = @ptrToInt(current) + current.size + @sizeOf(@typeOf(current));
|
||||
if (next_area >= self.info.mmap_addr + self.info.mmap_length) {
|
||||
self.current_area = null;
|
||||
} else {
|
||||
self.current_area = @intToPtr(*MultibootMMapEntry, next_area);
|
||||
format_multibootentry(self.current_area.?);
|
||||
self.next_free_frame = PhysFrame.from_addr(@intCast(u32, self.current_area.?.addr));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const PAGE_SIZE = 4096;
|
||||
|
||||
pub const PhysFrame = struct {
|
||||
number: u32,
|
||||
|
||||
pub fn from_addr(addr: u32) PhysFrame {
|
||||
return PhysFrame{ .number = @divTrunc(addr, PAGE_SIZE) };
|
||||
}
|
||||
|
||||
pub fn add(self: PhysFrame, count: u32) PhysFrame {
|
||||
return PhysFrame{ .number = self.number + count };
|
||||
}
|
||||
|
||||
pub fn start_addr(self: PhysFrame) u32 {
|
||||
return (self.number * PAGE_SIZE);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,13 +11,15 @@ setupPaging:
|
|||
mov +4(%esp), %eax // Fetch the phys_pd parameter.
|
||||
mov %eax, %cr3 // Point CR3 to the page directory.
|
||||
|
||||
// Enable Page Size Extension and Page Global.
|
||||
// Enable Page Size Extension
|
||||
mov %cr4, %eax
|
||||
or $0b00010000, %eax
|
||||
or $0x10, %eax
|
||||
mov %eax, %cr4
|
||||
|
||||
// Enable Paging.
|
||||
mov %cr0, %eax
|
||||
mov $1, %eax
|
||||
or $(1 << 0), %eax
|
||||
or $(1 << 31), %eax
|
||||
mov %eax, %cr0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,89 +1,102 @@
|
|||
const x86 = @import("lib/index.zig");
|
||||
const allocator = @import("memory.zig").allocator;
|
||||
const memory = @import("memory.zig");
|
||||
const interrupt = @import("interrupt.zig");
|
||||
const assert = @import("std").debug.assert;
|
||||
const println = @import("../../vga.zig").println;
|
||||
|
||||
extern fn setupPaging(phys_pd: usize) void;
|
||||
|
||||
pub var mapper: Mapper = undefined;
|
||||
const PageEntry = usize;
|
||||
pub const PAGE_SIZE = 4096;
|
||||
pub const PT = @intToPtr([*]PageEntry, 0xFFC00000);
|
||||
pub const PD = @intToPtr([*]PageEntry, 0xFFFFF000);
|
||||
const PRESENT = 0x1;
|
||||
const WRITE = 0x2;
|
||||
const USER = 0x4;
|
||||
const WRITE_THRU = 0x8;
|
||||
const NOCACHE = 0x10;
|
||||
const ACCESSED = 0x20;
|
||||
const HUGE = 0x80;
|
||||
|
||||
pub var pageDirectory: [1024]PageEntry align(4096) linksection(".bss") = [_]PageEntry{0} ** 1024;
|
||||
|
||||
fn pageFault() void {
|
||||
println("pagefault");
|
||||
while (true) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
fn pageBase(addr: usize) usize {
|
||||
return addr & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
fn pde(addr: usize) *PageEntry {
|
||||
return &PD[addr >> 22];
|
||||
}
|
||||
fn pte(addr: usize) *PageEntry {
|
||||
return &PT[addr >> 12];
|
||||
}
|
||||
|
||||
// virtual to physical
|
||||
pub fn translate(virt: usize) ?usize {
|
||||
if (pde(virt).* == 0) return null;
|
||||
return pageBase(pte(virt).*);
|
||||
}
|
||||
|
||||
pub fn unmap(virt: usize) void {
|
||||
var pte = pte(virt);
|
||||
if (pte.* == 0) {
|
||||
println("can't unmap 0x{x}, map is empty.", addr);
|
||||
return;
|
||||
}
|
||||
pte.* = 0;
|
||||
memory.free(translate(virt));
|
||||
}
|
||||
|
||||
pub fn mmap(virt: usize, phys: ?usize) void {
|
||||
var pde: *PageEntry = &PD[virt >> 22];
|
||||
if (pde.* == 0) {
|
||||
pde.* = memory.allocate() | WRITE | PRESENT;
|
||||
}
|
||||
var pte: *PageEntry = &PT[virt >> 12];
|
||||
pte.* = if (phys) |p| p else allocate() | PRESENT;
|
||||
}
|
||||
|
||||
pub fn addrspace() void {
|
||||
var i: usize = 1;
|
||||
i = 0;
|
||||
while (i < 1024) : (i += 1) {
|
||||
if (PD[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
println("p2[{}] -> 0x{x}", i, PD[i]);
|
||||
if (PD[i] & HUGE != 0) {
|
||||
continue;
|
||||
}
|
||||
var j: usize = 0;
|
||||
while (j < 1024) : (j += 1) {
|
||||
var entry: PageEntry = PT[i * 1024 + j];
|
||||
if (entry != 0) {
|
||||
println("p2[{}]p1[{}] -> 0x{x}", i, j, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize() void {
|
||||
const empty_page = PageDirectoryEntry{};
|
||||
// var p2 = allocator.allocate(1);
|
||||
var p2 = [_]PageDirectoryEntry{empty_page} ** 1024;
|
||||
// var p2 = [_]u32{0} ** 1024;
|
||||
|
||||
var p2 = pageDirectory[0..];
|
||||
// identity map 0 -> 4MB
|
||||
p2[0].pageTable = 0x0;
|
||||
p2[0].present = true;
|
||||
p2[0].read_write = true;
|
||||
p2[0].huge = true;
|
||||
// p2[0] = @bitReverse(u32, 0b10000011);
|
||||
|
||||
println("p2[0] {b}", p2[0]);
|
||||
println("p2[0] {b}", @bitCast(u32, p2[0]));
|
||||
// x86.hang();
|
||||
// paging.s
|
||||
// setupPaging(@ptrToInt(&p2));
|
||||
p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
|
||||
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
|
||||
|
||||
// mapper = Mapper{
|
||||
// .p2 = p2,
|
||||
// };
|
||||
const addr = mapper.translate(0xfffff000);
|
||||
}
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const Mapper = struct {
|
||||
p2: PageDirectory,
|
||||
|
||||
// virt to phys
|
||||
pub fn translate(self: Mapper, virt: u32) ?u32 {
|
||||
const map = @bitCast(VirtAddr, virt);
|
||||
println("{}", builtin.endian);
|
||||
println("virt {x} -> {}-{}-{x}", virt, map.page_directory, map.page_table, map.offset);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VirtAddr = packed struct {
|
||||
page_directory: u10,
|
||||
page_table: u10,
|
||||
offset: u12,
|
||||
};
|
||||
|
||||
pub const PageDirectoryEntry = packed struct {
|
||||
pageTable: u20 = 0,
|
||||
available: u3 = 0,
|
||||
ignored: bool = false,
|
||||
huge: bool = false,
|
||||
zero: bool = false,
|
||||
accessed: bool = false,
|
||||
cache_disabled: bool = false,
|
||||
write_thru: bool = false,
|
||||
supervisor: bool = false,
|
||||
read_write: bool = false,
|
||||
present: bool = false,
|
||||
};
|
||||
|
||||
pub const PageTableEntry = packed struct {
|
||||
addr: u20 = 0,
|
||||
available: u3 = 0,
|
||||
global: bool = false,
|
||||
zero: bool = false,
|
||||
dirty: bool = false,
|
||||
accessed: bool = false,
|
||||
cache_disabled: bool = false,
|
||||
write_thru: bool = false,
|
||||
supervisor: bool = false,
|
||||
read_write: bool = false,
|
||||
present: bool = false,
|
||||
};
|
||||
|
||||
pub const PageTable = [1024]PageTableEntry;
|
||||
pub const PageDirectory = [1024]PageDirectoryEntry;
|
||||
|
||||
comptime {
|
||||
assert(@sizeOf(PageDirectoryEntry) == 4); //32 bits
|
||||
assert(@sizeOf(PageTableEntry) == 4); //32 bits
|
||||
assert(memory.stack_end < 0x400000);
|
||||
// const first: *u32 = @ptrCast(*u32, p2);
|
||||
// println("p2[0] {b}", first.*);
|
||||
|
||||
interrupt.register(14, pageFault);
|
||||
setupPaging(@ptrToInt(&pageDirectory[0]));
|
||||
|
||||
addrspace();
|
||||
// const addr = mapper.translate(0xfffff000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ pub fn keypress(char: u8) void {
|
|||
}
|
||||
|
||||
pub fn initialize() void {
|
||||
// vga.clear();
|
||||
interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||
vga.writeString("> ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ const assert = @import("std").debug.assert;
|
|||
|
||||
// arch independant initialization
|
||||
export fn kmain(magic: u32, info: *const MultibootInfo) noreturn {
|
||||
clear();
|
||||
assert(magic == MULTIBOOT_BOOTLOADER_MAGIC);
|
||||
|
||||
println("--- x86 initialization ---");
|
||||
|
||||
x86.x86_main(info);
|
||||
|
||||
// pagefault_test(0xfeffc000);
|
||||
|
|
|
|||
8
src/memory.zig
Normal file
8
src/memory.zig
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const paging = @import("arch/x86/paging.zig");
|
||||
|
||||
pub fn alloc(size: usize) usize {
|
||||
|
||||
}
|
||||
|
||||
pub fn free() {
|
||||
}
|
||||
|
|
@ -81,8 +81,12 @@ pub const MultibootInfo = packed struct {
|
|||
// Return the ending address of the last module.
|
||||
//
|
||||
pub fn lastModuleEnd(self: *const MultibootInfo) usize {
|
||||
if (self.mods_count > 0) {
|
||||
const mods = @intToPtr([*]MultibootModule, self.mods_addr);
|
||||
return mods[self.mods_count - 1].mod_end;
|
||||
} else {
|
||||
return self.mods_addr;
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
|
|
|||
61
src/pci.zig
61
src/pci.zig
|
|
@ -17,31 +17,28 @@ pub const PciDevice = struct {
|
|||
bus: u8,
|
||||
slot: u5,
|
||||
function: u3,
|
||||
device: u16,
|
||||
vendor: u16,
|
||||
class: u8,
|
||||
subclass: u8,
|
||||
header_type: u8,
|
||||
device: u16 = undefined,
|
||||
vendor: u16 = undefined,
|
||||
class: u8 = undefined,
|
||||
subclass: u8 = undefined,
|
||||
header_type: u8 = undefined,
|
||||
driver: ?Driver = null,
|
||||
|
||||
pub fn init(bus: u8, slot: u5, function: u3) ?PciDevice {
|
||||
var pcidevice = PciDevice{
|
||||
var dev = PciDevice{
|
||||
.bus = bus,
|
||||
.slot = slot,
|
||||
.function = function,
|
||||
.device = undefined,
|
||||
.class = undefined,
|
||||
.subclass = undefined,
|
||||
.header_type = undefined,
|
||||
.vendor = undefined,
|
||||
};
|
||||
pcidevice.vendor = pci_config_read_word(pcidevice, 0);
|
||||
if (pcidevice.vendor == 0xffff)
|
||||
dev.vendor = dev.pci_config_read_word(0);
|
||||
if (dev.vendor == 0xffff)
|
||||
return null;
|
||||
pcidevice.device = pci_config_read_word(pcidevice, 2);
|
||||
pcidevice.subclass = pci_config_read_byte(pcidevice, 10);
|
||||
pcidevice.class = pci_config_read_byte(pcidevice, 11);
|
||||
pcidevice.header_type = pci_config_read_byte(pcidevice, 14);
|
||||
return (pcidevice);
|
||||
dev.device = dev.pci_config_read_word(2);
|
||||
dev.subclass = dev.pci_config_read_byte(10);
|
||||
dev.class = dev.pci_config_read_byte(11);
|
||||
dev.header_type = dev.pci_config_read_byte(14);
|
||||
dev.driver = dev.get_driver();
|
||||
return (dev);
|
||||
}
|
||||
|
||||
pub fn address(self: PciDevice, offset: u8) u32 {
|
||||
|
|
@ -57,7 +54,11 @@ pub const PciDevice = struct {
|
|||
}
|
||||
|
||||
pub fn format(self: PciDevice) void {
|
||||
println("{}:{}.{} {x},{x}: {x} {x}", self.bus, self.slot, self.function, self.class, self.subclass, self.vendor, self.device);
|
||||
print("{}:{}.{}", self.bus, self.slot, self.function);
|
||||
print(" {x},{x}: {x} {x}", self.class, self.subclass, self.vendor, self.device);
|
||||
if (self.driver) |d|
|
||||
print(" {}", d.name);
|
||||
println("");
|
||||
}
|
||||
|
||||
pub fn access(self: PciDevice, offset: u8) void {
|
||||
|
|
@ -78,13 +79,33 @@ pub const PciDevice = struct {
|
|||
self.access(offset);
|
||||
return (arch.inl(PCI_CONFIG_DATA));
|
||||
}
|
||||
|
||||
pub fn get_driver(self: PciDevice) ?Driver {
|
||||
var i: usize = 0;
|
||||
while (i < Drivers.len) : (i += 1) {
|
||||
var driver = Drivers[i];
|
||||
if (self.class == driver.class and self.subclass == driver.subclass and (driver.vendor == null or self.vendor == driver.vendor.?)) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const Driver = struct {
|
||||
name: [*]u8,
|
||||
class: u8,
|
||||
subclass: u8,
|
||||
vendor: ?u16 = null,
|
||||
};
|
||||
|
||||
const name = "virtio-blk";
|
||||
pub var Drivers: [1]Driver = [_]Driver{Driver{ .name = &name, .class = 0x1, .subclass = 0x0, .vendor = 0x1af4 }};
|
||||
|
||||
pub fn lspci() void {
|
||||
var slot: u5 = 0;
|
||||
while (true) {
|
||||
if (PciDevice.init(0, slot, 0)) |device| {
|
||||
device.format();
|
||||
var function: u3 = 0;
|
||||
while (true) {
|
||||
if (PciDevice.init(0, slot, function)) |vf|
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ pub fn print(comptime format: []const u8, args: ...) void {
|
|||
pub fn println(comptime format: []const u8, args: ...) void {
|
||||
var a = std.fmt.format({}, Errors, printCallback, format ++ "\n", args);
|
||||
}
|
||||
pub fn clear() void {
|
||||
vga.clear();
|
||||
}
|
||||
|
||||
fn printCallback(context: void, string: []const u8) Errors!void {
|
||||
vga.writeString(string);
|
||||
|
|
|
|||
Loading…
Reference in a new issue