1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
const std = @import("std");
const debug_console = @import("sbi/debug_console.zig");
const fdt = @import("fdt.zig");
const instructions = @import("instructions.zig");
const interrupts = @import("interrupts.zig");
const mem = @import("mem.zig");
const paging = @import("paging.zig");
const pci = @import("pci.zig");
const plic = @import("plic.zig");
const process = @import("process.zig");
const time = @import("sbi/time.zig");
const Error = error{
HartIdOutOfRange,
SuspiciousFdtAddr,
};
export fn start() callconv(.Naked) noreturn {
// Stack grows down, use (exclusive) end instead of start.
asm volatile (
\\ la sp, _stack_end
\\ call %[function]
:
: [function] "s" (&kmain),
);
}
fn kmain(hart_id: usize, fdt_blob: *fdt.RawHeader) noreturn {
const w = debug_console.writer() catch while (true) {};
w.print("Kernel init\r\n", .{}) catch while (true) {};
run(hart_id, fdt_blob, w) catch |err| {
w.print("Fatal error: {any}\r\n", .{err}) catch while (true) {};
while (true) {}
};
}
fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noreturn {
try w.print("\r\n", .{});
try w.print("Hart : {d}\r\n", .{hart_id});
try w.print("FDT address : 0x{x:0>8}\r\n", .{@intFromPtr(fdt_blob)});
if (hart_id > ~@as(u16, 0)) return Error.HartIdOutOfRange;
if (@intFromPtr(fdt_blob) < 0xf000000) return Error.SuspiciousFdtAddr;
const dt_header = try fdt.Header.parse(fdt_blob);
paging.init();
const kmem: *paging.Table = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
try w.print("\r\n", .{});
try w.print("===================== Kernel Page Table =====================\r\n", .{});
try w.print("MMIO: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ paging.mmio_start, paging.mmio_end });
try w.print("\r\n", .{});
try w.print(".text: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (r-x)\r\n", .{ @intFromPtr(paging.text_start), @intFromPtr(paging.text_end) });
try w.print(".rodata: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (r--)\r\n", .{ @intFromPtr(paging.rodata_start), @intFromPtr(paging.rodata_end) });
try w.print(".data: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.data_start), @intFromPtr(paging.data_end) });
try w.print(".bss: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.bss_start), @intFromPtr(paging.bss_end) });
try w.print("Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.stack_start), @intFromPtr(paging.stack_end) });
try w.print("Trap Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.stvec_stack_start), @intFromPtr(paging.stvec_stack_end) });
try w.print("\r\n", .{});
try w.print("Heap: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.heap_start), @intFromPtr(paging.heap_end) });
try w.print("\r\n", .{});
try w.print("FDT: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (r--)\r\n", .{ @intFromPtr(fdt_blob), @intFromPtr(fdt_blob) + dt_header.total_size });
try w.print("=============================================================\r\n", .{});
try w.print("\r\n", .{});
try kmem.mapKernel();
try kmem.identityMapRange(@intFromPtr(fdt_blob), @intFromPtr(fdt_blob) + dt_header.total_size, paging.EntryFlags.readOnly);
instructions.setSatp(kmem.satp(0));
try w.print("Paging : Sv39\r\n", .{});
interrupts.init();
interrupts.setEnabled(interrupts.Enable.all);
try w.print("Interrupts : All\r\n", .{});
try w.print("\r\n", .{});
var chunk_allocator = try mem.ChunkAllocator(.{ .auto_merge_free = true }).init(64);
const allocator = chunk_allocator.allocator();
try w.print("Parse FDT\r\n", .{});
fdt.default = try dt_header.parseTree(allocator);
try w.print("\r\n", .{});
try time.interruptInSeconds(null, 1);
try w.print("Timer : 1 Hz\r\n", .{});
try plic.init(&fdt.default, allocator);
try w.print("PLIC : Disabled\r\n", .{});
try w.print("\r\n", .{});
try w.print("Locate PCI MMIO\r\n", .{});
const pci_controller = try pci.controllerFromFdt(&fdt.default);
try w.print("\r\n", .{});
for (0..256) |bus| {
for (0..32) |device| {
const cfg_space = pci_controller.cfgSpace(@intCast(bus), @intCast(device), 0);
const vendor_id = cfg_space.getVendorId();
const device_id = cfg_space.getDeviceId();
const class = cfg_space.getClass();
const subclass = cfg_space.getSubclass();
if (vendor_id != 0xffff) {
try w.print("PCI {:0>3}.{:0>3}: Vendor = 0x{x:0>4}, Device = 0x{x:0>4}, Class = 0x{x:0>4}, Subclass = 0x{x:0>4}\r\n", .{ bus, device, vendor_id, device_id, class, subclass });
}
}
}
try w.print("\r\n", .{});
try w.print("Deref 0x1\r\n", .{});
@as(*volatile u8, @ptrFromInt(0x1)).* = 0;
try w.print("Segfault successful\r\n", .{});
try w.print("Enter process demo\r\n", .{});
try process.demo(allocator);
while (true) {
asm volatile ("wfi");
}
}
|