[kernel] Start all other processors in the system

This very large commit is mainly focused on getting the APs started and
to a state where they're waiting to have work scheduled. (Actually
scheduling on them is for another commit.)

To do this, a bunch of major changes were needed:

- Moving a lot of the CPU initialization (including for the BSP) to
  init_cpu(). This includes setting up IST stacks, writing MSRs, and
  creating the cpu_data structure. For the APs, this also creates and
  installs the GDT and TSS, and installs the global IDT.

- Creating the AP startup code, which tries to be as position
  independent as possible. It's copied from its location to 0x8000 for
  AP startup, and some of it is fixed at that address. The AP startup
  code jumps from real mode to long mode with paging in one swell foop.

- Adding limited IPI capability to the lapic class. This will need to
  improve.

- Renaming cpu/cpu.* to cpu/cpu_id.* because it was just annoying in GDB
  and really isn't anything but cpu_id anymore.

- Moved all the GDT, TSS, and IDT code into their own files and made
  them classes instead of a mess of free functions.

- Got rid of bsp_cpu_data everywhere. Now always call the new
  current_cpu() to get the current CPU's cpu_data.

- Device manager keeps a list of APIC ids now. This should go somewhere
  else eventually, device_manager needs to be refactored away.

- Moved some more things (notably the g_kernel_stacks vma) to the
  pre-constructor setup in memory_bootstrap. That whole file is in bad
  need of a refactor.
This commit is contained in:
Justin C. Miller
2021-02-07 23:26:47 -08:00
parent a65ecb157d
commit c88170f6e0
31 changed files with 952 additions and 446 deletions

View File

@@ -1,11 +1,19 @@
#include <stdint.h>
#include "kutil/assert.h"
#include "kutil/memory.h"
#include "apic.h"
#include "cpu.h"
#include "cpu/cpu.h"
#include "cpu/cpu_id.h"
#include "device_manager.h"
#include "gdt.h"
#include "idt.h"
#include "kernel_memory.h"
#include "log.h"
#include "msr.h"
#include "objects/vm_area.h"
#include "tss.h"
cpu_data bsp_cpu_data;
cpu_data g_bsp_cpu_data;
void
cpu_validate()
@@ -29,3 +37,70 @@ cpu_validate()
#undef CPU_FEATURE_OPT
#undef CPU_FEATURE_REQ
}
void
init_cpu(bool bsp)
{
extern TSS &g_bsp_tss;
extern GDT &g_bsp_gdt;
extern vm_area_guarded &g_kernel_stacks;
uint8_t id = 0;
TSS *tss = nullptr;
GDT *gdt = nullptr;
cpu_data *cpu = nullptr;
if (bsp) {
gdt = &g_bsp_gdt;
tss = &g_bsp_tss;
cpu = &g_bsp_cpu_data;
} else {
g_idt.install();
tss = new TSS;
gdt = new GDT {tss};
cpu = new cpu_data;
gdt->install();
lapic &apic = device_manager::get().get_lapic();
id = apic.get_id();
}
kutil::memset(cpu, 0, sizeof(cpu_data));
cpu->self = cpu;
cpu->id = id;
cpu->gdt = gdt;
cpu->tss = tss;
// Install the GS base pointint to the cpu_data
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
using memory::frame_size;
using memory::kernel_stack_pages;
constexpr size_t stack_size = kernel_stack_pages * frame_size;
uint8_t ist_entries = g_idt.used_ist_entries();
// Set up the IST stacks
for (unsigned ist = 1; ist < 8; ++ist) {
if (!(ist_entries & (1 << ist)))
continue;
// Two zero entries at the top for the null frame
uintptr_t stack_bottom = g_kernel_stacks.get_section();
uintptr_t stack_top = stack_bottom + stack_size - 2 * sizeof(uintptr_t);
// Pre-realize these stacks, they're no good if they page fault
*reinterpret_cast<uint64_t*>(stack_top) = 0;
tss->ist_stack(ist) = stack_top;
}
// Set up the page attributes table
uint64_t pat = rdmsr(msr::ia32_pat);
pat = (pat & 0x00ffffffffffffffull) | (0x01ull << 56); // set PAT 7 to WC
wrmsr(msr::ia32_pat, pat);
}