WIP x86 SMP
This commit is contained in:
@@ -3,6 +3,7 @@ Checks: >
|
|||||||
-*,
|
-*,
|
||||||
bugprone-*,
|
bugprone-*,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-reserved-identifier,
|
||||||
|
|
||||||
clang-diagnostic-*,
|
clang-diagnostic-*,
|
||||||
-clang-diagnostic-unused-command-line-argument,
|
-clang-diagnostic-unused-command-line-argument,
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ bool arch_mmu_supports_user_aspaces(void) { return false; }
|
|||||||
|
|
||||||
void x86_mmu_early_init(void) {
|
void x86_mmu_early_init(void) {
|
||||||
/* Set WP bit in CR0*/
|
/* Set WP bit in CR0*/
|
||||||
volatile uint32_t cr0 = x86_get_cr0();
|
uint32_t cr0 = x86_get_cr0();
|
||||||
cr0 |= X86_CR0_WP;
|
cr0 |= X86_CR0_WP;
|
||||||
x86_set_cr0(cr0);
|
x86_set_cr0(cr0);
|
||||||
|
|
||||||
|
|||||||
@@ -624,15 +624,13 @@ bool arch_mmu_supports_ns_mappings(void) { return false; }
|
|||||||
bool arch_mmu_supports_user_aspaces(void) { return false; }
|
bool arch_mmu_supports_user_aspaces(void) { return false; }
|
||||||
|
|
||||||
void x86_mmu_early_init(void) {
|
void x86_mmu_early_init(void) {
|
||||||
volatile uint64_t efer_msr, cr0, cr4;
|
|
||||||
|
|
||||||
/* Set WP bit in CR0*/
|
/* Set WP bit in CR0*/
|
||||||
cr0 = x86_get_cr0();
|
uint64_t cr0 = x86_get_cr0();
|
||||||
cr0 |= X86_CR0_WP;
|
cr0 |= X86_CR0_WP;
|
||||||
x86_set_cr0(cr0);
|
x86_set_cr0(cr0);
|
||||||
|
|
||||||
/* Setting the SMEP & SMAP bit in CR4 */
|
/* Setting the SMEP & SMAP bit in CR4 */
|
||||||
cr4 = x86_get_cr4();
|
uint64_t cr4 = x86_get_cr4();
|
||||||
if (x86_feature_test(X86_FEATURE_SMEP))
|
if (x86_feature_test(X86_FEATURE_SMEP))
|
||||||
cr4 |= X86_CR4_SMEP;
|
cr4 |= X86_CR4_SMEP;
|
||||||
if (x86_feature_test(X86_FEATURE_SMAP))
|
if (x86_feature_test(X86_FEATURE_SMAP))
|
||||||
@@ -640,7 +638,7 @@ void x86_mmu_early_init(void) {
|
|||||||
x86_set_cr4(cr4);
|
x86_set_cr4(cr4);
|
||||||
|
|
||||||
/* Set NXE bit in MSR_EFER*/
|
/* Set NXE bit in MSR_EFER*/
|
||||||
efer_msr = read_msr(X86_MSR_IA32_EFER);
|
uint64_t efer_msr = read_msr(X86_MSR_IA32_EFER);
|
||||||
efer_msr |= X86_EFER_NXE;
|
efer_msr |= X86_EFER_NXE;
|
||||||
write_msr(X86_MSR_IA32_EFER, efer_msr);
|
write_msr(X86_MSR_IA32_EFER, efer_msr);
|
||||||
|
|
||||||
|
|||||||
@@ -204,6 +204,11 @@ highaddr:
|
|||||||
/* set up the idt */
|
/* set up the idt */
|
||||||
call setup_idt
|
call setup_idt
|
||||||
|
|
||||||
|
/* set up the percpu data structure pointer for the boot cpu */
|
||||||
|
xor %edi, %edi
|
||||||
|
xor %esi, %esi
|
||||||
|
call x86_percpu_init_early
|
||||||
|
|
||||||
/* call the main module */
|
/* call the main module */
|
||||||
call lk_main
|
call lk_main
|
||||||
|
|
||||||
|
|||||||
@@ -19,35 +19,31 @@
|
|||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Describe how start.S sets up the MMU.
|
/* Describe how start.S sets up the MMU.
|
||||||
* These data structures are later used by vm routines to lookup pointers
|
* These data structures are later used by vm routines to lookup pointers
|
||||||
* to physical pages based on physical addresses.
|
* to physical pages based on physical addresses.
|
||||||
*/
|
*/
|
||||||
struct mmu_initial_mapping mmu_initial_mappings[] = {
|
struct mmu_initial_mapping mmu_initial_mappings[] = {
|
||||||
#if ARCH_X86_64
|
/* 64GB of the first 64GB of memory mapped 1:1 */
|
||||||
/* 64GB of memory mapped where the kernel lives */
|
|
||||||
{
|
{
|
||||||
.phys = MEMBASE,
|
.phys = MEMBASE,
|
||||||
.virt = KERNEL_ASPACE_BASE,
|
.virt = KERNEL_ASPACE_BASE,
|
||||||
.size = PHYSMAP_SIZE, /* x86-64 maps first 64GB by default, 1GB on x86-32 */
|
.size = PHYSMAP_SIZE, /* x86-64 maps first 64GB by default, 1GB on x86-32, 16MB in legacy mode */
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.name = "physmap"
|
.name = "physmap"
|
||||||
},
|
},
|
||||||
#endif
|
#if ARCH_X86_64
|
||||||
/* 1GB of memory mapped where the kernel lives */
|
/* Another linear map of the first GB of memory where the kernel image
|
||||||
|
* lives at the top of the address space. */
|
||||||
{
|
{
|
||||||
.phys = MEMBASE,
|
.phys = MEMBASE,
|
||||||
.virt = KERNEL_BASE,
|
.virt = KERNEL_BASE,
|
||||||
#if X86_LEGACY
|
.size = 1*GB,
|
||||||
.size = 16*MB, /* only map the first 16MB on legacy x86 due to page table usage */
|
|
||||||
#else
|
|
||||||
.size = 1*GB, /* x86 maps first 1GB by default */
|
|
||||||
#endif
|
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.name = "kernel"
|
.name = "kernel"
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
/* null entry to terminate the list */
|
/* null entry to terminate the list */
|
||||||
{ 0 }
|
{ 0 }
|
||||||
@@ -70,6 +66,7 @@ void arch_early_init(void) {
|
|||||||
/* enable caches here for now */
|
/* enable caches here for now */
|
||||||
clear_in_cr0(X86_CR0_NW | X86_CR0_CD);
|
clear_in_cr0(X86_CR0_NW | X86_CR0_CD);
|
||||||
|
|
||||||
|
/* configure the system TSS */
|
||||||
#if ARCH_X86_32
|
#if ARCH_X86_32
|
||||||
system_tss.esp0 = 0;
|
system_tss.esp0 = 0;
|
||||||
system_tss.ss0 = DATA_SELECTOR;
|
system_tss.ss0 = DATA_SELECTOR;
|
||||||
@@ -78,9 +75,10 @@ void arch_early_init(void) {
|
|||||||
system_tss.eflags = 0x00003002;
|
system_tss.eflags = 0x00003002;
|
||||||
system_tss.bitmap = offsetof(tss_32_t, tss_bitmap);
|
system_tss.bitmap = offsetof(tss_32_t, tss_bitmap);
|
||||||
system_tss.trace = 1; // trap on hardware task switch
|
system_tss.trace = 1; // trap on hardware task switch
|
||||||
|
#elif ARCH_X86_64
|
||||||
|
/* nothing to be done here, a fully zeroed TSS is a good starting point */
|
||||||
#endif
|
#endif
|
||||||
|
x86_set_gdt_descriptor(TSS_SELECTOR, &system_tss, sizeof(system_tss), 1, 0, 0, SEG_TYPE_TSS, 0, 0);
|
||||||
set_global_desc(TSS_SELECTOR, &system_tss, sizeof(system_tss), 1, 0, 0, SEG_TYPE_TSS, 0, 0);
|
|
||||||
x86_ltr(TSS_SELECTOR);
|
x86_ltr(TSS_SELECTOR);
|
||||||
|
|
||||||
x86_feature_early_init();
|
x86_feature_early_init();
|
||||||
|
|||||||
@@ -5,62 +5,89 @@
|
|||||||
* license that can be found in the LICENSE file or at
|
* license that can be found in the LICENSE file or at
|
||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <lk/compiler.h>
|
|
||||||
#include <arch/x86/descriptor.h>
|
#include <arch/x86/descriptor.h>
|
||||||
|
|
||||||
/* not the best way to do this, but easy for now */
|
#include <assert.h>
|
||||||
typedef union {
|
#include <lk/compiler.h>
|
||||||
struct {
|
|
||||||
uint16_t limit_15_0;
|
|
||||||
uint16_t base_15_0;
|
|
||||||
uint8_t base_23_16;
|
|
||||||
|
|
||||||
uint8_t type : 4;
|
extern uint64_t _gdt[];
|
||||||
uint8_t s : 1;
|
|
||||||
uint8_t dpl : 2;
|
|
||||||
uint8_t p : 1;
|
|
||||||
|
|
||||||
uint8_t limit_19_16 : 4;
|
void x86_set_gdt_descriptor(seg_sel_t sel, void *base, uint32_t limit,
|
||||||
uint8_t avl : 1;
|
|
||||||
uint8_t reserved_0 : 1;
|
|
||||||
uint8_t d_b : 1;
|
|
||||||
uint8_t g : 1;
|
|
||||||
|
|
||||||
uint8_t base_31_24;
|
|
||||||
} __PACKED seg_desc_legacy;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t base_63_32;
|
|
||||||
uint32_t reserved_1;
|
|
||||||
} __PACKED seg_desc_64;
|
|
||||||
} __PACKED seg_desc_t;
|
|
||||||
|
|
||||||
extern seg_desc_t _gdt[];
|
|
||||||
|
|
||||||
void set_global_desc(seg_sel_t sel, void *base, uint32_t limit,
|
|
||||||
uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits) {
|
uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits) {
|
||||||
// convert selector into index
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
uint16_t limit_15_0;
|
||||||
|
uint16_t base_15_0;
|
||||||
|
uint8_t base_23_16;
|
||||||
|
|
||||||
|
uint8_t type : 4;
|
||||||
|
uint8_t s : 1;
|
||||||
|
uint8_t dpl : 2;
|
||||||
|
uint8_t p : 1;
|
||||||
|
|
||||||
|
uint8_t limit_19_16 : 4;
|
||||||
|
uint8_t avl : 1;
|
||||||
|
uint8_t reserved : 1;
|
||||||
|
uint8_t d_b : 1;
|
||||||
|
uint8_t g : 1;
|
||||||
|
|
||||||
|
uint8_t base_31_24;
|
||||||
|
} seg_desc_legacy;
|
||||||
|
|
||||||
|
#if ARCH_X86_64
|
||||||
|
// some descriptors have additional fields for x86-64
|
||||||
|
struct {
|
||||||
|
uint32_t base_63_32;
|
||||||
|
uint32_t reserved;
|
||||||
|
} seg_desc_64;
|
||||||
|
#endif
|
||||||
|
} seg_desc_t;
|
||||||
|
|
||||||
|
#if ARCH_X86_64
|
||||||
|
static_assert(sizeof(seg_desc_t) == 16, "seg_desc_t size mismatch");
|
||||||
|
#else
|
||||||
|
static_assert(sizeof(seg_desc_t) == 8, "seg_desc_t size mismatch");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
seg_desc_t desc = {0};
|
||||||
|
|
||||||
|
desc.seg_desc_legacy.limit_15_0 = limit & 0x0000ffff;
|
||||||
|
desc.seg_desc_legacy.limit_19_16 = (limit & 0x000f0000) >> 16;
|
||||||
|
|
||||||
|
desc.seg_desc_legacy.base_15_0 = ((uintptr_t) base) & 0x0000ffff;
|
||||||
|
desc.seg_desc_legacy.base_23_16 = (((uintptr_t) base) & 0x00ff0000) >> 16;
|
||||||
|
desc.seg_desc_legacy.base_31_24 = ((uintptr_t) base) >> 24;
|
||||||
|
|
||||||
|
desc.seg_desc_legacy.type = type & 0x0f; // segment type
|
||||||
|
desc.seg_desc_legacy.s = sys != 0; // system / non-system
|
||||||
|
desc.seg_desc_legacy.dpl = ring & 0x03; // descriptor privilege level
|
||||||
|
desc.seg_desc_legacy.p = present != 0; // present
|
||||||
|
desc.seg_desc_legacy.avl = 0;
|
||||||
|
desc.seg_desc_legacy.reserved = 0;
|
||||||
|
desc.seg_desc_legacy.d_b = bits != 0; // 16 / 32 bit
|
||||||
|
desc.seg_desc_legacy.g = gran != 0; // granularity
|
||||||
|
|
||||||
|
// convert selector into index, which are always 8 byte indexed
|
||||||
uint16_t index = sel >> 3;
|
uint16_t index = sel >> 3;
|
||||||
|
seg_desc_t *entry = (seg_desc_t *)&_gdt[index];
|
||||||
_gdt[index].seg_desc_legacy.limit_15_0 = limit & 0x0000ffff;
|
entry->seg_desc_legacy = desc.seg_desc_legacy;
|
||||||
_gdt[index].seg_desc_legacy.limit_19_16 = (limit & 0x000f0000) >> 16;
|
|
||||||
|
|
||||||
_gdt[index].seg_desc_legacy.base_15_0 = ((uintptr_t) base) & 0x0000ffff;
|
|
||||||
_gdt[index].seg_desc_legacy.base_23_16 = (((uintptr_t) base) & 0x00ff0000) >> 16;
|
|
||||||
_gdt[index].seg_desc_legacy.base_31_24 = ((uintptr_t) base) >> 24;
|
|
||||||
|
|
||||||
_gdt[index].seg_desc_legacy.type = type & 0x0f; // segment type
|
|
||||||
_gdt[index].seg_desc_legacy.p = present != 0; // present
|
|
||||||
_gdt[index].seg_desc_legacy.dpl = ring & 0x03; // descriptor privilege level
|
|
||||||
_gdt[index].seg_desc_legacy.g = gran != 0; // granularity
|
|
||||||
_gdt[index].seg_desc_legacy.s = sys != 0; // system / non-system
|
|
||||||
_gdt[index].seg_desc_legacy.d_b = bits != 0; // 16 / 32 bit
|
|
||||||
|
|
||||||
#ifdef ARCH_X86_64
|
#ifdef ARCH_X86_64
|
||||||
if (TSS_SELECTOR == sel) {
|
if (sys == 0) {
|
||||||
_gdt[index + 1].seg_desc_64.base_63_32 = (uint32_t)((uintptr_t) base >> 32);
|
// some of the system descriptors have two more words
|
||||||
_gdt[index + 1].seg_desc_64.reserved_1 = 0;
|
switch (type) {
|
||||||
|
case SEG_TYPE_TSS:
|
||||||
|
case SEG_TYPE_TSS_BUSY:
|
||||||
|
case SEG_TYPE_LDT:
|
||||||
|
case SEG_TYPE_CALL_GATE:
|
||||||
|
// copy the lower 32 bits of the descriptor (base and limit)
|
||||||
|
desc.seg_desc_64.base_63_32 = (uint32_t)((uintptr_t) base >> 32);
|
||||||
|
desc.seg_desc_64.reserved = 0;
|
||||||
|
|
||||||
|
// copy the upper 64 bits of the descriptor
|
||||||
|
entry->seg_desc_64 = desc.seg_desc_64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,10 @@ _tss_gde:
|
|||||||
.byte 0x89 /* P(1) DPL(00) S(0) TYPE(9) */
|
.byte 0x89 /* P(1) DPL(00) S(0) TYPE(9) */
|
||||||
.byte 0x80 /* G(1) D/B(0) L(0) AVL(0) limit 19:16 */
|
.byte 0x80 /* G(1) D/B(0) L(0) AVL(0) limit 19:16 */
|
||||||
.byte 0 /* base 31:24 */
|
.byte 0 /* base 31:24 */
|
||||||
|
#if ARCH_X86_64
|
||||||
|
/* 64-bit TSSs are 16 bytes long */
|
||||||
.quad 0x0000000000000000
|
.quad 0x0000000000000000
|
||||||
|
#endif
|
||||||
.set i, i+1
|
.set i, i+1
|
||||||
.endr
|
.endr
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,13 @@
|
|||||||
|
|
||||||
/* based on how start.S sets up the physmap */
|
/* based on how start.S sets up the physmap */
|
||||||
#if ARCH_X86_64
|
#if ARCH_X86_64
|
||||||
#define PHYSMAP_SIZE (64ULL*GB)
|
#define PHYSMAP_SIZE (64ULL*1024*1024*1024)
|
||||||
|
#elif X86_LEGACY
|
||||||
|
/* Only map the first 16MB on legacy x86 due to page table usage
|
||||||
|
* due to lack of 4MB pages. */
|
||||||
|
#define PHYSMAP_SIZE (16ULL*1024*1024)
|
||||||
#elif ARCH_X86_32
|
#elif ARCH_X86_32
|
||||||
#define PHYSMAP_SIZE (1ULL*GB)
|
/* Map 1GB by default for x86-32 */
|
||||||
|
#define PHYSMAP_SIZE (1ULL*1024*1024*1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -25,17 +25,33 @@
|
|||||||
#define USER_CODE_64_SELECTOR 0x38
|
#define USER_CODE_64_SELECTOR 0x38
|
||||||
#define USER_DATA_64_SELECTOR 0x40
|
#define USER_DATA_64_SELECTOR 0x40
|
||||||
|
|
||||||
|
/* base selector for a list of TSSes, one per cpu (SMP_MAX_CPUS) */
|
||||||
#define TSS_SELECTOR 0x48
|
#define TSS_SELECTOR 0x48
|
||||||
|
|
||||||
/*
|
/* code/data segment types (S = 1) */
|
||||||
* Descriptor Types
|
/* bit 0 is accessed */
|
||||||
*/
|
#define SEG_TYPE_DATA_RO 0x0
|
||||||
#define SEG_TYPE_TSS 0x9
|
#define SEG_TYPE_DATA_RW 0x2
|
||||||
#define SEG_TYPE_TSS_BUSY 0xb
|
#define SEG_TYPE_DATA_RO_EXPAND_DOWN 0x4
|
||||||
#define SEG_TYPE_TASK_GATE 0x5
|
#define SEG_TYPE_DATA_RW_EXPAND_DOWN 0x6
|
||||||
#define SEG_TYPE_INT_GATE 0xe // 32 bit
|
#define SEG_TYPE_CODE_XO 0x8
|
||||||
#define SEG_TYPE_DATA_RW 0x2
|
#define SEG_TYPE_CODE_RO 0xa
|
||||||
#define SEG_TYPE_CODE_RW 0xa
|
#define SEG_TYPE_CODE_XO_CONFORMING 0xc
|
||||||
|
#define SEG_TYPE_CODE_RO_CONFORMING 0xe
|
||||||
|
|
||||||
|
/* system segment types (S = 0) */
|
||||||
|
#define SEG_TYPE_TSS_16 0x1
|
||||||
|
#define SEG_TYPE_LDT 0x2
|
||||||
|
#define SEG_TYPE_TSS_16_BUSY 0x3
|
||||||
|
#define SEG_TYPE_CALL_GATE_16 0x4
|
||||||
|
#define SEG_TYPE_TASK_GATE 0x5
|
||||||
|
#define SEG_TYPE_INT_GATE_16 0x6
|
||||||
|
#define SEG_TYPE_TRAP_GATE_16 0x7
|
||||||
|
#define SEG_TYPE_TSS 0x9
|
||||||
|
#define SEG_TYPE_TSS_BUSY 0xb
|
||||||
|
#define SEG_TYPE_CALL_GATE 0xc
|
||||||
|
#define SEG_TYPE_INT_GATE 0xe
|
||||||
|
#define SEG_TYPE_TRAP_GATE 0xf
|
||||||
|
|
||||||
#ifndef ASSEMBLY
|
#ifndef ASSEMBLY
|
||||||
|
|
||||||
@@ -43,7 +59,7 @@
|
|||||||
|
|
||||||
typedef uint16_t seg_sel_t;
|
typedef uint16_t seg_sel_t;
|
||||||
|
|
||||||
void set_global_desc(seg_sel_t sel, void *base, uint32_t limit,
|
void x86_set_gdt_descriptor(seg_sel_t sel, void *base, uint32_t limit,
|
||||||
uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits);
|
uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <arch/x86.h>
|
#include <arch/x86.h>
|
||||||
#include <inttypes.h>
|
|
||||||
#include <lk/compiler.h>
|
#include <lk/compiler.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|||||||
28
arch/x86/include/arch/x86/mp.h
Normal file
28
arch/x86/include/arch/x86/mp.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Travis Geiselbrecht
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a MIT-style
|
||||||
|
* license that can be found in the LICENSE file or at
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
// per cpu pointer pointed to by a segment register on x86
|
||||||
|
typedef struct x86_percpu {
|
||||||
|
// pointer back to ourselves so we can get a raw pointer via segment:0
|
||||||
|
struct x86_percpu *self;
|
||||||
|
|
||||||
|
uint cpu_num;
|
||||||
|
uint apic_id;
|
||||||
|
|
||||||
|
struct thread *current_thread;
|
||||||
|
|
||||||
|
// XXX add more stuff:
|
||||||
|
// per cpu TSS
|
||||||
|
// per cpu doublefault/nmi stacks
|
||||||
|
} x86_percpu_t;
|
||||||
|
|
||||||
|
// called extremely early on the boot cpu and each secondary cpu
|
||||||
|
void x86_percpu_init_early(uint cpu_num, uint apic_id);
|
||||||
42
arch/x86/mp.c
Normal file
42
arch/x86/mp.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Travis Geiselbrecht
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a MIT-style
|
||||||
|
* license that can be found in the LICENSE file or at
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
#include <arch/x86/mp.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <arch/x86.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
// the boot cpu's percpu struct
|
||||||
|
static x86_percpu_t x86_boot_percpu;
|
||||||
|
// pointer to an array of percpu structs for each of the secondary cpus
|
||||||
|
static x86_percpu_t **x86_ap_percpus;
|
||||||
|
|
||||||
|
static x86_percpu_t *percpu_for_cpu(uint cpu_num) {
|
||||||
|
DEBUG_ASSERT(cpu_num < SMP_MAX_CPUS);
|
||||||
|
if (cpu_num == 0) {
|
||||||
|
return &x86_boot_percpu;
|
||||||
|
}
|
||||||
|
DEBUG_ASSERT(x86_ap_percpus);
|
||||||
|
return x86_ap_percpus[cpu_num - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_percpu_init_early(uint cpu_num, uint apic_id) {
|
||||||
|
x86_percpu_t *percpu = percpu_for_cpu(cpu_num);
|
||||||
|
|
||||||
|
percpu->self = percpu;
|
||||||
|
percpu->cpu_num = cpu_num;
|
||||||
|
percpu->apic_id = apic_id;
|
||||||
|
|
||||||
|
// XXX load into gs:/fs/etc
|
||||||
|
#if ARCH_X86_64
|
||||||
|
write_msr(X86_MSR_IA32_KERNEL_GS_BASE, 0);
|
||||||
|
write_msr(X86_MSR_IA32_GS_BASE, (uint64_t)percpu);
|
||||||
|
#else
|
||||||
|
//#error implement
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@ MODULE_SRCS += \
|
|||||||
$(LOCAL_DIR)/faults.c \
|
$(LOCAL_DIR)/faults.c \
|
||||||
$(LOCAL_DIR)/feature.c \
|
$(LOCAL_DIR)/feature.c \
|
||||||
$(LOCAL_DIR)/gdt.S \
|
$(LOCAL_DIR)/gdt.S \
|
||||||
|
$(LOCAL_DIR)/mp.c \
|
||||||
$(LOCAL_DIR)/thread.c \
|
$(LOCAL_DIR)/thread.c \
|
||||||
|
|
||||||
# legacy x86's dont have fpu support
|
# legacy x86's dont have fpu support
|
||||||
|
|||||||
Reference in New Issue
Block a user