-
Notifications
You must be signed in to change notification settings - Fork 0
/
linux_emu.zig
140 lines (122 loc) · 4.38 KB
/
linux_emu.zig
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
137
138
139
140
const std = @import("std");
const c = @cImport({
@cInclude("stdint.h");
@cInclude("mini-rv32ima.h");
});
var state: c.MiniRV32IMAState = undefined;
var totalcycles: u32 = undefined;
var stdout: std.fs.File.Writer = undefined;
export fn mmio_store(addr: u32, val: u32) void {
switch (addr) {
0x10000000 => {
// std.debug.print("{} @ {} UART: {c}\n", .{totalcycles, state.pc, @as(u8, @truncate(val))});
stdout.writeByte(@truncate(val)) catch @panic("write failed");
if (val == '\n') {
std.log.debug("write @ cycle {}", .{ totalcycles });
}
},
0x11004004 => {
state.timermatchh = val;
},
0x11004000 => {
state.timermatchl = val;
},
0x11100000 => {
std.debug.print("SYSCON: {}\n", .{val});
},
else => {
// std.log.warn("invalid mmio write @ 0x{x:0>8} = {}", .{addr, val});
},
}
}
export fn mmio_load(addr: u32) u32 {
return switch (addr) {
0x10000005 => 0x60,
0x1100bffc => state.timerh,
0x1100bff8 => state.timerl,
else => 0,
};
}
fn save(mem: []const u8) !void {
std.log.debug("saving machine state @ {}", .{totalcycles});
{
var file = try std.fs.cwd().createFile("state/machine.state", .{});
defer file.close();
var bw = std.io.bufferedWriter(file.writer());
var writer = bw.writer();
inline for (std.meta.fields(c.MiniRV32IMAState)) |field| {
const fname = field.name;
if (comptime (!std.mem.eql(u8, fname, "regs") and !std.mem.eql(u8, fname, "extraflags"))) {
try writer.print("{s} {}\n", .{fname, @field(state, fname)});
}
}
try writer.print("privilege {}\n", .{state.extraflags & 3});
try writer.print("wfi {}\n", .{ (state.extraflags & 4) >> 2});
try writer.print("reserved {}\n", .{state.extraflags >> 3});
try writer.print("totalcycles {}\n", .{totalcycles});
for (0..32) |i| {
try writer.print("x{} {}\n", .{i, state.regs[i]});
}
try bw.flush();
}
{
var file = try std.fs.cwd().createFile("state/memory.dump", .{});
defer file.close();
var writer = file.writer();
try writer.writeAll(mem);
}
}
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
stdout = std.io.getStdOut().writer();
const mem = try std.heap.page_allocator.alloc(u8, (1 << 24) * 4);
defer std.heap.page_allocator.free(mem);
@memset(mem, 0);
var args = std.process.args();
_ = args.next();
const image_path = args.next() orelse return error.MissingArg;
const dtb_path = args.next() orelse return error.MissingArg;
const cwd = std.fs.cwd();
const image = try cwd.readFileAlloc(allocator, image_path, std.math.maxInt(usize));
const dtb = try cwd.readFileAlloc(allocator, dtb_path, std.math.maxInt(usize));
// Place linux at the beginning of the address space
@memcpy(mem[0..image.len], image);
// Place the dtb at 0x3000000 physical (0x83000000 virtual)
const dtb_offset = 0x3000000;
@memcpy(mem[dtb_offset..][0..dtb.len], dtb);
state = std.mem.zeroes(c.MiniRV32IMAState);
state.pc = c.MINIRV32_RAM_IMAGE_OFFSET;
state.extraflags |= 3; // privilege level
state.regs[10] = 0x00;
state.regs[11] = dtb_offset + c.MINIRV32_RAM_IMAGE_OFFSET;
totalcycles = 0;
while (true) {
// if (totalcycles % 0x1000 == 0) {
// std.debug.print("executing {} cycle {}\n", .{ @as(i32, @bitCast(state.pc)), totalcycles });
// }
// if (totalcycles > 500_000) {
// std.process.exit(0);
// }
switch (c.MiniRV32IMAStep(&state, mem.ptr, 0, 1, 1)) {
0 => {
if (state.mcause == 3) {
std.log.debug("ebreak", .{});
}
},
else => |e| {
if (state.extraflags & 0x4 != 0) {
// WFI, ignore
} else {
std.log.err("mini-rv32ima error: {}", .{e});
std.process.exit(1);
}
}
}
totalcycles +%= 1;
// if (totalcycles == 294749) {
// try save(mem);
// }
}
}