x86[_64]: Separate bootloader and kernel GDT and IDT logic
From now on bootloader sets up its own minimal valid GDT and IDT. Then the kernel replaces them with its own tables.
This commit is contained in:
parent
e646703a6e
commit
527da4ca8a
@ -78,11 +78,6 @@ struct interrupt_descriptor {
|
||||
uint32 reserved : 32;
|
||||
} _PACKED;
|
||||
|
||||
struct gdt_idt_descr {
|
||||
uint16 limit;
|
||||
addr_t base;
|
||||
} _PACKED;
|
||||
|
||||
struct tss {
|
||||
uint32 _reserved1;
|
||||
uint64 sp0;
|
||||
|
@ -17,9 +17,6 @@
|
||||
|
||||
#define _PACKED __attribute__((packed))
|
||||
|
||||
#define IDT_LIMIT 0x800
|
||||
#define GDT_LIMIT 0x800
|
||||
|
||||
// kernel args
|
||||
typedef struct {
|
||||
// architecture specific
|
||||
@ -30,10 +27,6 @@ typedef struct {
|
||||
uint32 num_pgtables;
|
||||
uint32 pgtables[MAX_BOOT_PTABLES];
|
||||
uint64 virtual_end;
|
||||
uint32 phys_idt;
|
||||
uint64 vir_idt;
|
||||
uint32 phys_gdt;
|
||||
uint64 vir_gdt;
|
||||
uint64 page_hole;
|
||||
// smp stuff
|
||||
uint32 apic_time_cv_factor; // apic ticks per second
|
||||
|
@ -49,8 +49,6 @@ enum gate_types {
|
||||
|
||||
void x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu);
|
||||
void x86_descriptors_init(kernel_args* args);
|
||||
void x86_descriptors_init_percpu(kernel_args* args, int cpu);
|
||||
status_t x86_descriptors_init_post_vm(kernel_args* args);
|
||||
|
||||
|
||||
#endif // !_ASSEMBLER
|
||||
|
@ -229,17 +229,3 @@ set_debug_idt()
|
||||
set_idt(sDebugIDTDescriptor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
interrupts_init_kernel_idt(void* idt, size_t idtSize)
|
||||
{
|
||||
// clear it but copy the descriptors we've set up for the exceptions
|
||||
memset(idt, 0, idtSize);
|
||||
memcpy(idt, sDebugIDT, sizeof(sDebugIDT));
|
||||
|
||||
// load the idt
|
||||
gdt_idt_descr idtDescriptor;
|
||||
idtDescriptor.limit = idtSize - 1;
|
||||
idtDescriptor.base = idt;
|
||||
set_idt(idtDescriptor);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ __BEGIN_DECLS
|
||||
void interrupts_init();
|
||||
void set_debug_idt();
|
||||
void restore_bios_idt();
|
||||
void interrupts_init_kernel_idt(void* idt, size_t idtSize);
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include <kernel.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "smp.h"
|
||||
#include "mmu.h"
|
||||
#include "smp.h"
|
||||
|
||||
|
||||
static const uint64 kTableMappingFlags = 0x7;
|
||||
@ -34,8 +34,7 @@ static const uint64 kPageMappingFlags = 0x103;
|
||||
|
||||
extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop);
|
||||
|
||||
extern uint32 gLongPhysicalGDT;
|
||||
extern uint64 gLongVirtualGDT;
|
||||
extern uint64 gLongGDT;
|
||||
extern uint32 gLongPhysicalPML4;
|
||||
extern uint64 gLongKernelEntry;
|
||||
|
||||
@ -63,47 +62,21 @@ fix_address(FixedWidthPointer<Type>& p)
|
||||
static void
|
||||
long_gdt_init()
|
||||
{
|
||||
// Allocate memory for the GDT.
|
||||
segment_descriptor* gdt = (segment_descriptor*)
|
||||
mmu_allocate_page(&gKernelArgs.arch_args.phys_gdt);
|
||||
gKernelArgs.arch_args.vir_gdt = fix_address((addr_t)gdt);
|
||||
|
||||
dprintf("GDT at phys 0x%lx, virt 0x%llx\n", gKernelArgs.arch_args.phys_gdt,
|
||||
gKernelArgs.arch_args.vir_gdt);
|
||||
|
||||
clear_segment_descriptor(&gdt[0]);
|
||||
clear_segment_descriptor(&gBootGDT[0]);
|
||||
|
||||
// Set up code/data segments (TSS segments set up later in the kernel).
|
||||
set_segment_descriptor(&gdt[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
set_segment_descriptor(&gBootGDT[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
DPL_KERNEL);
|
||||
set_segment_descriptor(&gdt[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
set_segment_descriptor(&gBootGDT[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
DPL_KERNEL);
|
||||
set_segment_descriptor(&gdt[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
set_segment_descriptor(&gBootGDT[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
DPL_USER);
|
||||
set_segment_descriptor(&gdt[USER_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
set_segment_descriptor(&gBootGDT[USER_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
DPL_USER);
|
||||
|
||||
// Used by long_enter_kernel().
|
||||
gLongPhysicalGDT = gKernelArgs.arch_args.phys_gdt;
|
||||
gLongVirtualGDT = gKernelArgs.arch_args.vir_gdt;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
long_idt_init()
|
||||
{
|
||||
interrupt_descriptor* idt = (interrupt_descriptor*)
|
||||
mmu_allocate_page(&gKernelArgs.arch_args.phys_idt);
|
||||
gKernelArgs.arch_args.vir_idt = fix_address((addr_t)idt);
|
||||
|
||||
dprintf("IDT at phys %#lx, virt %#llx\n", gKernelArgs.arch_args.phys_idt,
|
||||
gKernelArgs.arch_args.vir_idt);
|
||||
|
||||
// The 32-bit kernel gets an IDT with the loader's exception handlers until
|
||||
// it can set up its own. Can't do that here because they won't work after
|
||||
// switching to long mode. Therefore, just clear the IDT and leave the
|
||||
// kernel to set it up.
|
||||
memset(idt, 0, B_PAGE_SIZE);
|
||||
gLongGDT = fix_address((addr_t)gBootGDT);
|
||||
dprintf("GDT at 0x%llx\n", gLongGDT);
|
||||
}
|
||||
|
||||
|
||||
@ -340,7 +313,6 @@ long_start_kernel()
|
||||
smp_init_other_cpus();
|
||||
|
||||
long_gdt_init();
|
||||
long_idt_init();
|
||||
long_mmu_init();
|
||||
debug_cleanup();
|
||||
convert_kernel_args();
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#define __x86_64__
|
||||
#include <arch/x86/descriptors.h>
|
||||
|
||||
#include "mmu.h"
|
||||
#undef __x86_64__
|
||||
|
||||
|
||||
@ -25,10 +27,6 @@ FUNCTION(long_enter_kernel):
|
||||
movl 8(%esp), %edi
|
||||
movl 12(%esp), %esi
|
||||
|
||||
// We're about to disable paging, so we need to load the the physical
|
||||
// address of our GDT.
|
||||
lgdtl long_phys_gdtr
|
||||
|
||||
// Currently running with 32-bit paging tables at an identity mapped
|
||||
// address. To switch to 64-bit paging we must first disable 32-bit paging,
|
||||
// otherwise loading the new CR3 will fault.
|
||||
@ -57,6 +55,9 @@ FUNCTION(long_enter_kernel):
|
||||
orl $(1 << 31), %ecx
|
||||
movl %ecx, %cr0
|
||||
|
||||
// Load 64-bit enabled GDT
|
||||
lgdtl long_gdtr
|
||||
|
||||
// Jump into the 64-bit code segment.
|
||||
ljmp $KERNEL_CODE_SELECTOR, $.Llmode
|
||||
.align 8
|
||||
@ -71,9 +72,6 @@ FUNCTION(long_enter_kernel):
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
// Load the virtual address of the GDT.
|
||||
lgdtq long_virt_gdtr(%rip)
|
||||
|
||||
// Set the stack pointer.
|
||||
movl %edi, %esp
|
||||
shl $32, %rsi
|
||||
@ -94,16 +92,11 @@ FUNCTION(long_enter_kernel):
|
||||
.data
|
||||
|
||||
|
||||
long_phys_gdtr:
|
||||
.word GDT_LIMIT - 1
|
||||
SYMBOL(gLongPhysicalGDT):
|
||||
long_gdtr:
|
||||
.word BOOT_GDT_SEGMENT_COUNT * 8 - 1
|
||||
SYMBOL(gLongGDT):
|
||||
.long 0
|
||||
|
||||
long_virt_gdtr:
|
||||
.word GDT_LIMIT - 1
|
||||
SYMBOL(gLongVirtualGDT):
|
||||
.quad 0
|
||||
|
||||
SYMBOL(gLongPhysicalPML4):
|
||||
.long 0
|
||||
|
||||
|
@ -69,6 +69,8 @@ struct extended_memory {
|
||||
};
|
||||
|
||||
|
||||
segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT];
|
||||
|
||||
static const uint32 kDefaultPageTableFlags = 0x07; // present, user, R/W
|
||||
static const size_t kMaxKernelSize = 0x1000000; // 16 MB for the kernel
|
||||
|
||||
@ -535,76 +537,36 @@ extern "C" void
|
||||
mmu_init_for_kernel(void)
|
||||
{
|
||||
TRACE("mmu_init_for_kernel\n");
|
||||
// set up a new idt
|
||||
{
|
||||
uint32 *idt;
|
||||
|
||||
// find a new idt
|
||||
idt = (uint32 *)get_next_physical_page();
|
||||
gKernelArgs.arch_args.phys_idt = (uint32)idt;
|
||||
|
||||
TRACE("idt at %p\n", idt);
|
||||
|
||||
// map the idt into virtual space
|
||||
gKernelArgs.arch_args.vir_idt = (uint32)get_next_virtual_page();
|
||||
map_page(gKernelArgs.arch_args.vir_idt, (uint32)idt, kDefaultPageFlags);
|
||||
|
||||
// initialize it
|
||||
interrupts_init_kernel_idt((void*)(addr_t)gKernelArgs.arch_args.vir_idt,
|
||||
IDT_LIMIT);
|
||||
|
||||
TRACE("idt at virtual address 0x%llx\n", gKernelArgs.arch_args.vir_idt);
|
||||
}
|
||||
|
||||
// set up a new gdt
|
||||
{
|
||||
struct gdt_idt_descr gdtDescriptor;
|
||||
segment_descriptor *gdt;
|
||||
|
||||
// find a new gdt
|
||||
gdt = (segment_descriptor *)get_next_physical_page();
|
||||
gKernelArgs.arch_args.phys_gdt = (uint32)gdt;
|
||||
// put standard segment descriptors in GDT
|
||||
clear_segment_descriptor(&gBootGDT[0]);
|
||||
|
||||
TRACE("gdt at %p\n", gdt);
|
||||
// seg 0x08 - kernel 4GB code
|
||||
set_segment_descriptor(&gBootGDT[KERNEL_CODE_SEGMENT], 0, 0xffffffff,
|
||||
DT_CODE_READABLE, DPL_KERNEL);
|
||||
|
||||
// map the gdt into virtual space
|
||||
gKernelArgs.arch_args.vir_gdt = (uint32)get_next_virtual_page();
|
||||
map_page(gKernelArgs.arch_args.vir_gdt, (uint32)gdt, kDefaultPageFlags);
|
||||
// seg 0x10 - kernel 4GB data
|
||||
set_segment_descriptor(&gBootGDT[KERNEL_DATA_SEGMENT], 0, 0xffffffff,
|
||||
DT_DATA_WRITEABLE, DPL_KERNEL);
|
||||
|
||||
// put standard segment descriptors in it
|
||||
segment_descriptor* virtualGDT
|
||||
= (segment_descriptor*)(addr_t)gKernelArgs.arch_args.vir_gdt;
|
||||
clear_segment_descriptor(&virtualGDT[0]);
|
||||
// seg 0x1b - ring 3 user 4GB code
|
||||
set_segment_descriptor(&gBootGDT[USER_CODE_SEGMENT], 0, 0xffffffff,
|
||||
DT_CODE_READABLE, DPL_USER);
|
||||
|
||||
// seg 0x08 - kernel 4GB code
|
||||
set_segment_descriptor(&virtualGDT[KERNEL_CODE_SEGMENT], 0, 0xffffffff,
|
||||
DT_CODE_READABLE, DPL_KERNEL);
|
||||
// seg 0x23 - ring 3 user 4GB data
|
||||
set_segment_descriptor(&gBootGDT[USER_DATA_SEGMENT], 0, 0xffffffff,
|
||||
DT_DATA_WRITEABLE, DPL_USER);
|
||||
|
||||
// seg 0x10 - kernel 4GB data
|
||||
set_segment_descriptor(&virtualGDT[KERNEL_DATA_SEGMENT], 0, 0xffffffff,
|
||||
DT_DATA_WRITEABLE, DPL_KERNEL);
|
||||
// load the GDT
|
||||
struct gdt_idt_descr gdtDescriptor;
|
||||
gdtDescriptor.limit = sizeof(gBootGDT);
|
||||
gdtDescriptor.base = gBootGDT;
|
||||
|
||||
// seg 0x1b - ring 3 user 4GB code
|
||||
set_segment_descriptor(&virtualGDT[USER_CODE_SEGMENT], 0, 0xffffffff,
|
||||
DT_CODE_READABLE, DPL_USER);
|
||||
asm("lgdt %0" : : "m" (gdtDescriptor));
|
||||
|
||||
// seg 0x23 - ring 3 user 4GB data
|
||||
set_segment_descriptor(&virtualGDT[USER_DATA_SEGMENT], 0, 0xffffffff,
|
||||
DT_DATA_WRITEABLE, DPL_USER);
|
||||
|
||||
// virtualGDT[5] and above will be filled later by the kernel
|
||||
// to contain the TSS descriptors, and for TLS (one for every CPU)
|
||||
|
||||
// load the GDT
|
||||
gdtDescriptor.limit = GDT_LIMIT - 1;
|
||||
gdtDescriptor.base = (void*)(addr_t)gKernelArgs.arch_args.vir_gdt;
|
||||
|
||||
asm("lgdt %0;"
|
||||
: : "m" (gdtDescriptor));
|
||||
|
||||
TRACE("gdt at virtual address %p\n",
|
||||
(void*)gKernelArgs.arch_args.vir_gdt);
|
||||
}
|
||||
TRACE("gdt at virtual address %p\n", gBootGDT);
|
||||
|
||||
// Save the memory we've virtually allocated (for the kernel and other
|
||||
// stuff)
|
||||
|
@ -6,9 +6,21 @@
|
||||
#define MMU_H
|
||||
|
||||
|
||||
#include <arch/x86/descriptors.h>
|
||||
|
||||
|
||||
#define BOOT_GDT_SEGMENT_COUNT (USER_DATA_SEGMENT + 1)
|
||||
|
||||
|
||||
#ifndef _ASSEMBLER
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
extern segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT];
|
||||
|
||||
|
||||
// For use with mmu_map_physical_memory()
|
||||
static const uint32 kDefaultPageFlags = 0x3; // present, R/W
|
||||
|
||||
@ -33,4 +45,6 @@ extern bool mmu_get_virtual_mapping(addr_t virtualAddress,
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !_ASSEMBLER
|
||||
|
||||
#endif /* MMU_H */
|
||||
|
@ -97,16 +97,12 @@ smp_start_kernel(void)
|
||||
asm("cld");
|
||||
asm("fninit");
|
||||
|
||||
// Set up the final idt
|
||||
idt_descr.limit = IDT_LIMIT - 1;
|
||||
idt_descr.base = (uint32 *)(addr_t)gKernelArgs.arch_args.vir_idt;
|
||||
|
||||
asm("lidt %0;"
|
||||
: : "m" (idt_descr));
|
||||
// Set up idt
|
||||
set_debug_idt();
|
||||
|
||||
// Set up the final gdt
|
||||
gdt_descr.limit = GDT_LIMIT - 1;
|
||||
gdt_descr.base = (uint32 *)gKernelArgs.arch_args.vir_gdt;
|
||||
gdt_descr.limit = sizeof(gBootGDT) - 1;
|
||||
gdt_descr.base = gBootGDT;
|
||||
|
||||
asm("lgdt %0;"
|
||||
: : "m" (gdt_descr));
|
||||
|
@ -99,11 +99,41 @@ set_task_gate(int32 cpu, int32 n, int32 segment)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static inline void
|
||||
load_tss()
|
||||
{
|
||||
short seg = (TSS_SEGMENT << 3) | DPL_KERNEL;
|
||||
asm("ltr %%ax" : : "a" (seg));
|
||||
uint16 segment = (TSS_SEGMENT << 3) | DPL_KERNEL;
|
||||
asm("ltr %w0" : : "r" (segment));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
load_gdt(int cpu)
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED gdtDescriptor = {
|
||||
GDT_SEGMENT_COUNT * sizeof(segment_descriptor) - 1,
|
||||
gGDTs[cpu]
|
||||
};
|
||||
|
||||
asm volatile("lgdt %0" : : "m" (gdtDescriptor));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
load_idt(int cpu)
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED idtDescriptor = {
|
||||
IDT_GATES_COUNT * sizeof(interrupt_descriptor) - 1,
|
||||
&sIDTs[cpu]
|
||||
};
|
||||
|
||||
asm volatile("lidt %0" : : "m" (idtDescriptor));
|
||||
}
|
||||
|
||||
|
||||
@ -181,8 +211,8 @@ init_double_fault(int cpuNum)
|
||||
struct tss* tss = &gCPU[cpuNum].arch.double_fault_tss;
|
||||
|
||||
memset(tss, 0, sizeof(struct tss));
|
||||
size_t stackSize;
|
||||
tss->sp0 = (addr_t)x86_get_double_fault_stack(cpuNum, &stackSize);
|
||||
size_t stackSize = 0;
|
||||
//tss->sp0 = (addr_t)x86_get_double_fault_stack(cpuNum, &stackSize);
|
||||
tss->sp0 += stackSize;
|
||||
tss->ss0 = KERNEL_DATA_SELECTOR;
|
||||
tss->cr3 = x86_read_cr3();
|
||||
@ -206,21 +236,6 @@ init_double_fault(int cpuNum)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
load_gdt(int cpu)
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED gdt_descriptor = {
|
||||
GDT_SEGMENT_COUNT * sizeof(segment_descriptor) - 1,
|
||||
gGDTs[cpu]
|
||||
};
|
||||
|
||||
asm volatile("lgdt %0" : : "m" (gdt_descriptor));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_gdt_percpu(kernel_args* args, int cpu)
|
||||
{
|
||||
@ -264,22 +279,7 @@ init_gdt_percpu(kernel_args* args, int cpu)
|
||||
load_tss();
|
||||
|
||||
// set kernel TLS segment
|
||||
asm volatile("movw %0, %%gs" : : "r" (KERNEL_TLS_SEGMENT << 3));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
load_idt(int cpu)
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED idt_descriptor = {
|
||||
IDT_GATES_COUNT * sizeof(interrupt_descriptor) - 1,
|
||||
&sIDTs[cpu]
|
||||
};
|
||||
|
||||
asm volatile("lidt %0" : : "m" (idt_descriptor));
|
||||
asm volatile("movw %w0, %%gs" : : "r" (KERNEL_TLS_SEGMENT << 3));
|
||||
}
|
||||
|
||||
|
||||
@ -593,16 +593,3 @@ x86_descriptors_init(kernel_args* args)
|
||||
table[19] = x86_unexpected_exception; // SIMD Floating-Point Exception (#XF)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_descriptors_init_percpu(kernel_args* /* args */, int /* cpu */)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
x86_descriptors_init_post_vm(kernel_args* /* args */)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -15,23 +15,56 @@
|
||||
#include <arch/user_debugger.h>
|
||||
|
||||
|
||||
#define IDT_GATES_COUNT 256
|
||||
|
||||
|
||||
typedef void interrupt_handler_function(iframe* frame);
|
||||
|
||||
|
||||
static segment_descriptor* sGDT;
|
||||
static interrupt_descriptor* sIDT;
|
||||
static segment_descriptor sGDT[GDT_SEGMENT_COUNT];
|
||||
static interrupt_descriptor sIDT[IDT_GATES_COUNT];
|
||||
|
||||
static const uint32 kInterruptHandlerTableSize = 256;
|
||||
static const uint32 kInterruptHandlerTableSize = IDT_GATES_COUNT;
|
||||
interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
|
||||
|
||||
extern uint8 isr_array[kInterruptHandlerTableSize][16];
|
||||
|
||||
|
||||
static void
|
||||
static inline void
|
||||
load_tss(int cpu)
|
||||
{
|
||||
uint16 seg = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
|
||||
asm volatile("ltr %%ax" :: "a" (seg));
|
||||
uint16 segment = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
|
||||
asm volatile("ltr %w0" : : "a" (segment));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
load_gdt()
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED gdtDescriptor = {
|
||||
GDT_SEGMENT_COUNT * sizeof(segment_descriptor) - 1,
|
||||
sGDT
|
||||
};
|
||||
|
||||
asm volatile("lgdt %0" : : "m" (gdtDescriptor));
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
load_idt()
|
||||
{
|
||||
struct {
|
||||
uint16 limit;
|
||||
void* address;
|
||||
} _PACKED idtDescriptor = {
|
||||
IDT_GATES_COUNT * sizeof(interrupt_descriptor) - 1,
|
||||
sIDT
|
||||
};
|
||||
|
||||
asm volatile("lidt %0" : : "m" (idtDescriptor));
|
||||
}
|
||||
|
||||
|
||||
@ -61,18 +94,43 @@ x86_64_general_protection_fault(iframe* frame)
|
||||
|
||||
|
||||
void
|
||||
x86_descriptors_preboot_init_percpu(kernel_args* /* args */, int /* cpu */)
|
||||
x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu)
|
||||
{
|
||||
if (cpu == 0) {
|
||||
STATIC_ASSERT(GDT_SEGMENT_COUNT <= 8192);
|
||||
|
||||
set_segment_descriptor(&sGDT[KERNEL_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
DPL_KERNEL);
|
||||
set_segment_descriptor(&sGDT[KERNEL_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
DPL_KERNEL);
|
||||
set_segment_descriptor(&sGDT[USER_CODE_SEGMENT], DT_CODE_EXECUTE_ONLY,
|
||||
DPL_USER);
|
||||
set_segment_descriptor(&sGDT[USER_DATA_SEGMENT], DT_DATA_WRITEABLE,
|
||||
DPL_USER);
|
||||
}
|
||||
|
||||
memset(&gCPU[cpu].arch.tss, 0, sizeof(struct tss));
|
||||
gCPU[cpu].arch.tss.io_map_base = sizeof(struct tss);
|
||||
|
||||
// Set up the descriptor for this TSS.
|
||||
set_tss_descriptor(&sGDT[TSS_SEGMENT(cpu)], (addr_t)&gCPU[cpu].arch.tss,
|
||||
sizeof(struct tss));
|
||||
|
||||
// Set up the double fault IST entry (see x86_descriptors_init()).
|
||||
struct tss* tss = &gCPU[cpu].arch.tss;
|
||||
size_t stackSize;
|
||||
tss->ist1 = (addr_t)x86_get_double_fault_stack(cpu, &stackSize);
|
||||
tss->ist1 += stackSize;
|
||||
|
||||
load_idt();
|
||||
load_gdt();
|
||||
load_tss(cpu);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_descriptors_init(kernel_args* args)
|
||||
{
|
||||
// The boot loader sets up a GDT and allocates an empty IDT for us.
|
||||
sGDT = (segment_descriptor*)args->arch_args.vir_gdt;
|
||||
sIDT = (interrupt_descriptor*)args->arch_args.vir_idt;
|
||||
|
||||
// Fill out the IDT, pointing each entry to the corresponding entry in the
|
||||
// ISR array created in arch_interrupts.S (see there to see how this works).
|
||||
for(uint32 i = 0; i < kInterruptHandlerTableSize; i++) {
|
||||
@ -120,59 +178,3 @@ x86_descriptors_init(kernel_args* args)
|
||||
table[19] = x86_unexpected_exception; // SIMD Floating-Point Exception (#XF)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_descriptors_init_percpu(kernel_args* args, int cpu)
|
||||
{
|
||||
// Load the IDT.
|
||||
gdt_idt_descr idtr = {
|
||||
256 * sizeof(interrupt_descriptor) - 1,
|
||||
(addr_t)sIDT
|
||||
};
|
||||
asm volatile("lidt %0" :: "m" (idtr));
|
||||
|
||||
// Load the TSS for non-boot CPUs (boot CPU gets done below).
|
||||
if (cpu != 0) {
|
||||
load_tss(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
x86_descriptors_init_post_vm(kernel_args* args)
|
||||
{
|
||||
area_id area;
|
||||
|
||||
// Create an area for the GDT.
|
||||
area = create_area("gdt", (void**)&sGDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
|
||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||
if (area < B_OK)
|
||||
return area;
|
||||
|
||||
// Same for the IDT.
|
||||
area = create_area("idt", (void**)&sIDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
|
||||
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||
if (area < B_OK)
|
||||
return area;
|
||||
|
||||
for (uint32 i = 0; i < args->num_cpus; i++) {
|
||||
// Set up the task state segment.
|
||||
memset(&gCPU[i].arch.tss, 0, sizeof(struct tss));
|
||||
gCPU[i].arch.tss.io_map_base = sizeof(struct tss);
|
||||
|
||||
// Set up the descriptor for this TSS.
|
||||
set_tss_descriptor(&sGDT[TSS_SEGMENT(i)], (addr_t)&gCPU[i].arch.tss,
|
||||
sizeof(struct tss));
|
||||
|
||||
// Set up the double fault IST entry (see x86_descriptors_init()).
|
||||
struct tss* tss = &gCPU[i].arch.tss;
|
||||
size_t stackSize;
|
||||
tss->ist1 = (addr_t)x86_get_double_fault_stack(i, &stackSize);
|
||||
tss->ist1 += stackSize;
|
||||
}
|
||||
|
||||
// Load the TSS for the boot CPU.
|
||||
load_tss(0);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1053,8 +1053,6 @@ detect_amdc1e_noarat()
|
||||
status_t
|
||||
arch_cpu_init_percpu(kernel_args* args, int cpu)
|
||||
{
|
||||
x86_descriptors_init_percpu(args, cpu);
|
||||
|
||||
detect_cpu(cpu);
|
||||
|
||||
if (!gCpuIdleFunc) {
|
||||
@ -1115,9 +1113,6 @@ arch_cpu_init_post_vm(kernel_args* args)
|
||||
&virtualRestrictions, &physicalRestrictions,
|
||||
(void**)&sDoubleFaultStacks);
|
||||
|
||||
// More descriptor table setup.
|
||||
x86_descriptors_init_post_vm(args);
|
||||
|
||||
X86PagingStructures* kernelPagingStructures
|
||||
= static_cast<X86VMTranslationMap*>(
|
||||
VMAddressSpace::Kernel()->TranslationMap())->PagingStructures();
|
||||
|
Loading…
Reference in New Issue
Block a user