aboutsummaryrefslogtreecommitdiff
path: root/mirai/crimson/render.zig
blob: 5877aa5945d93f7fce829d521455b31c0fd73ecf (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Crimson screen rendering

const colors = @import("../common/constants/colors.zig");
const crimson_limits = @import("../common/limits/crimson.zig");
const font = @import("../graphics/fonts/psf.zig");
const format = @import("format.zig");
const multiboot = @import("../boot/multiboot/multiboot.zig");
const types = @import("types.zig");
const video_const = @import("../common/constants/video.zig");

pub fn screen(fb: multiboot.FramebufferInfo, message: []const u8, context: ?*const types.Context) void {
    fill_crimson(fb);

    const char_height = font.get_height();
    var y: u32 = 60;

    const heading = "Hey! You finally met Crimson!";
    centered_text(heading, y, fb, colors.WHITE);
    y += char_height + 20;

    const desc1 = "Mirai Kernel has encountered an error and the system";
    const desc2 = "will need to be restarted. Please reboot your machine.";
    centered_text(desc1, y, fb, colors.WHITE);
    y += char_height + 4;
    centered_text(desc2, y, fb, colors.WHITE);
    y += char_height + 30;

    centered_text("Error:", y, fb, colors.WHITE);
    y += char_height + 4;
    centered_text(message, y, fb, colors.WHITE);
    y += char_height + 30;

    if (context) |ctx| {
        registers(ctx, y, fb);
        y += (char_height + 4) * 10;

        centered_text("Stack Trace:", y, fb, colors.WHITE);
        y += char_height + 4;
        stack_trace(ctx.rbp, ctx.rip, y, fb);
    }
}

fn fill_crimson(fb: multiboot.FramebufferInfo) void {
    if (fb.bpp == video_const.BPP_32) {
        const pixels = @as([*]volatile u32, @ptrFromInt(fb.addr));
        const total = fb.height * (fb.pitch / 4);

        for (0..total) |i| {
            pixels[i] = colors.CRIMSON;
        }
    } else if (fb.bpp == video_const.BPP_24) {
        const pixels = @as([*]volatile u8, @ptrFromInt(fb.addr));

        const r: u8 = @truncate((colors.CRIMSON >> 16) & 0xFF);
        const g: u8 = @truncate((colors.CRIMSON >> 8) & 0xFF);
        const b: u8 = @truncate(colors.CRIMSON & 0xFF);

        for (0..fb.height) |y| {
            for (0..fb.width) |x| {
                const offset = y * fb.pitch + x * 3;
                pixels[offset] = b;
                pixels[offset + 1] = g;
                pixels[offset + 2] = r;
            }
        }
    }
}

pub fn centered_text(text: []const u8, y: u32, fb: multiboot.FramebufferInfo, color: u32) void {
    const char_width: u32 = font.get_width();
    const text_width: u32 = @intCast(text.len * char_width);

    if (text_width > fb.width) {
        font.render_text(text, 20, y, fb, color);
    } else {
        const x: u32 = (fb.width - text_width) / 2;
        font.render_text(text, x, y, fb, color);
    }
}

fn registers(ctx: *const types.Context, start_y: u32, fb: multiboot.FramebufferInfo) void {
    const char_height = font.get_height();
    var y = start_y;
    var buffer: [crimson_limits.REGISTER_BUFFER_SIZE]u8 = undefined;

    register_pair("RAX", ctx.rax, "RBX", ctx.rbx, y, &buffer, fb);
    y += char_height + 4;

    register_pair("RCX", ctx.rcx, "RDX", ctx.rdx, y, &buffer, fb);
    y += char_height + 4;

    register_pair("RSI", ctx.rsi, "RDI", ctx.rdi, y, &buffer, fb);
    y += char_height + 4;

    register_pair("RBP", ctx.rbp, "RSP", ctx.rsp, y, &buffer, fb);
    y += char_height + 4;

    register_pair("R8 ", ctx.r8, "R9 ", ctx.r9, y, &buffer, fb);
    y += char_height + 4;

    register_pair("R10", ctx.r10, "R11", ctx.r11, y, &buffer, fb);
    y += char_height + 4;

    register_pair("R12", ctx.r12, "R13", ctx.r13, y, &buffer, fb);
    y += char_height + 4;

    register_pair("R14", ctx.r14, "R15", ctx.r15, y, &buffer, fb);
    y += char_height + 4;

    register_pair("RIP", ctx.rip, "CR2", ctx.cr2, y, &buffer, fb);
    y += char_height + 4;

    register_pair("CR3", ctx.cr3, "ERR", ctx.error_code, y, &buffer, fb);
}

fn register_pair(label1: []const u8, val1: u64, label2: []const u8, val2: u64, y: u32, buffer: []u8, fb: multiboot.FramebufferInfo) void {
    const left_x: u32 = 100;
    const right_x: u32 = 500;

    const text1 = format.register(label1, val1, buffer[0..49]);
    font.render_text(text1, left_x, y, fb, colors.WHITE);

    const text2 = format.register(label2, val2, buffer[50..99]);
    font.render_text(text2, right_x, y, fb, colors.WHITE);
}

fn stack_trace(rbp: u64, rip: u64, start_y: u32, fb: multiboot.FramebufferInfo) void {
    const char_height = font.get_height();
    var y = start_y;
    var buffer: [crimson_limits.STACK_FRAME_BUFFER_SIZE]u8 = undefined;

    const text0 = format.stack_frame(0, rip, &buffer);
    centered_text(text0, y, fb, colors.WHITE);
    y += char_height + 2;

    var frame_rbp = rbp;
    var frame_num: usize = 1;

    while (frame_num < crimson_limits.MAX_STACK_FRAMES) : (frame_num += 1) {
        if (frame_rbp < 0xFFFF800000000000 or frame_rbp == 0) break;

        const ret_addr = @as(*const u64, @ptrFromInt(frame_rbp + 8)).*;

        if (ret_addr < 0xFFFF800000000000) break;

        const text = format.stack_frame(frame_num, ret_addr, &buffer);
        centered_text(text, y, fb, colors.WHITE);
        y += char_height + 2;

        const next_rbp = @as(*const u64, @ptrFromInt(frame_rbp)).*;

        if (next_rbp == 0 or next_rbp == frame_rbp) break;
        frame_rbp = next_rbp;
    }
}