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
|
#include "arch/cpu/interrupts.hpp"
#include "kapi/cpu.hpp"
#include "arch/cpu/segment_selector.hpp"
#include <kstd/print>
#include <cstdint>
namespace arch::cpu
{
namespace
{
constexpr auto isr_code_PF = 14;
auto handle_page_fault(interrupt_frame * frame) -> void
{
auto fault_address = std::uintptr_t{};
asm volatile("mov %%cr2, %0" : "=r"(fault_address));
auto const present = (frame->interrupt.error_code & 0x1) != 0;
auto const write = (frame->interrupt.error_code & 0x2) != 0;
auto const user = (frame->interrupt.error_code & 0x4) != 0;
kstd::println(kstd::print_sink::stderr, "[x86_64:MMU] PAGE FAULT!");
kstd::println(kstd::print_sink::stderr, "\tFault address: 0x{:x}", fault_address);
kstd::println(kstd::print_sink::stderr, "\tPresent: {}", present);
kstd::println(kstd::print_sink::stderr, "\tWrite: {}", write);
kstd::println(kstd::print_sink::stderr, "\tUser: {}", user);
kstd::println(kstd::print_sink::stderr, "\tRIP: {:#018x}", frame->cpu_saved.rip);
kstd::println(kstd::print_sink::stderr, "\tHalting the system now!");
kapi::cpu::halt();
}
} // namespace
extern "C"
{
extern std::uintptr_t const isr_stub_table[256];
auto interrupt_dispatch(interrupt_frame * frame) -> void
{
switch (frame->interrupt.number)
{
case isr_code_PF:
handle_page_fault(frame);
break;
default:
kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {} received with code {}",
frame->interrupt.number, frame->interrupt.error_code);
kapi::cpu::halt();
}
}
}
interrupt_descriptor_table::interrupt_descriptor_table() noexcept
{
for (auto i = 0uz; i < 256; ++i)
{
m_descriptors[i] = gate_descriptor{
.offset_low = static_cast<std::uint16_t>(isr_stub_table[i] & 0xffff), // NOLINT(readability-magic-numbers)
.m_code_segment = segment_selector{0, false, 1},
.interrupt_stack_table_selector = 0,
.gate_type = gate_type::interrupt_gate,
.descriptor_privilege_level = 0,
.present = true,
.offset_middle =
static_cast<std::uint16_t>((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers)
.offset_high =
static_cast<std::uint32_t>((isr_stub_table[i] >> 32) & 0xffff'ffff), // NOLINT(readability-magic-numbers)
};
}
}
auto interrupt_descriptor_table::load() const -> void
{
interrupt_descriptor_table_register{.limit = sizeof(m_descriptors) - 1, .base = m_descriptors.data()}.load();
}
auto interrupt_descriptor_table_register::load() const -> void
{
asm volatile("lidt %0" : : "m"(*this));
}
auto interrupt_descriptor_table_register::read() -> interrupt_descriptor_table_register
{
interrupt_descriptor_table_register idtr{};
asm volatile("sidt %0" : : "m"(idtr));
return idtr;
}
auto enable_interrupts() -> void
{
asm volatile("sti");
}
auto disable_interrupts() -> void
{
asm volatile("cli");
}
} // namespace arch::cpu
|