[kernel] Update syscall MSRs for all CPUs

Since SYSCALL/SYSRET rely on MSRs to control their function, split out
syscall_enable() into syscall_initialize() and syscall_enable(), the
latter being called on all CPUs. This affects not just syscalls but also
the kernel_to_user_trampoline.

Additionally, do away with the max syscalls, and just make a single page
of syscall pointers and name pointers. Max syscalls was fragile and
needed to be kept in sync in multiple places.
This commit is contained in:
Justin C. Miller
2021-02-10 01:15:32 -08:00
parent 70d6094f46
commit 872f178d94
5 changed files with 64 additions and 47 deletions

View File

@@ -10,11 +10,11 @@
extern "C" {
void syscall_invalid(uint64_t call);
void syscall_handler_prelude();
}
uintptr_t syscall_registry[static_cast<unsigned>(syscall::MAX)];
const char * syscall_names[static_cast<unsigned>(syscall::MAX)];
uintptr_t syscall_registry[256] __attribute__((section(".syscall_registry")));
const char * syscall_names[256] __attribute__((section(".syscall_registry")));
static constexpr size_t num_syscalls = sizeof(syscall_registry) / sizeof(syscall_registry[0]);
void
syscall_invalid(uint64_t call)
@@ -23,13 +23,10 @@ syscall_invalid(uint64_t call)
cons->set_color(9);
cons->printf("\nReceived unknown syscall: %02x\n", call);
const unsigned num_calls =
static_cast<unsigned>(syscall::MAX);
cons->printf(" Known syscalls:\n");
cons->printf(" invalid %016lx\n", syscall_invalid);
for (unsigned i = 0; i < num_calls; ++i) {
for (unsigned i = 0; i < num_syscalls; ++i) {
const char *name = syscall_names[i];
uintptr_t handler = syscall_registry[i];
if (name)
@@ -41,33 +38,14 @@ syscall_invalid(uint64_t call)
}
void
syscall_enable()
syscall_initialize()
{
// IA32_STAR - high 32 bits contain k+u CS
// Kernel CS: GDT[1] ring 0 bits[47:32]
// User CS: GDT[3] ring 3 bits[63:48]
uint64_t star =
(((1ull << 3) | 0) << 32) |
(((3ull << 3) | 3) << 48);
wrmsr(msr::ia32_star, star);
// IA32_LSTAR - RIP for syscall
wrmsr(msr::ia32_lstar,
reinterpret_cast<uintptr_t>(&syscall_handler_prelude));
// IA32_FMASK - FLAGS mask inside syscall
wrmsr(msr::ia32_fmask, 0x200);
static constexpr unsigned num_calls =
static_cast<unsigned>(syscall::MAX);
kutil::memset(&syscall_registry, 0, sizeof(syscall_registry));
kutil::memset(&syscall_names, 0, sizeof(syscall_names));
#define SYSCALL(id, name, result, ...) \
syscall_registry[id] = reinterpret_cast<uintptr_t>(syscalls::name); \
syscall_names[id] = #name; \
static_assert( id <= num_calls, "Syscall " #name " has id > syscall::MAX" ); \
log::debug(logs::syscall, "Enabling syscall 0x%02x as " #name , id);
#include "j6/tables/syscalls.inc"
#undef SYSCALL