Support for SMP on x86_64.
No major changes to the kernel: just compiled in arch_smp.cpp and fixed the IDT load in arch_cpu_init_percpu to use the correct limit for x86_64 (uses sizeof(interrupt_descriptor)). In the boot loader, changed smp_boot_other_cpus to construct a temporary GDT and get the page directory address from CR3, as what's in kernel_args will be 64-bit stuff and will not work to switch the CPUs into 32-bit mode in the trampoline code. Refactored 64-bit kernel entry code to not use the stack after disabling paging, as the secondary CPUs are given a 32-bit virtual stack address by the SMP trampoline code which will no longer work.
This commit is contained in:
@@ -50,6 +50,10 @@ typedef struct segment_descriptor {
|
|||||||
uint32 base_31_24 : 8; // 24 - 31
|
uint32 base_31_24 : 8; // 24 - 31
|
||||||
} segment_descriptor;
|
} segment_descriptor;
|
||||||
|
|
||||||
|
typedef struct interrupt_descriptor {
|
||||||
|
uint32 a, b;
|
||||||
|
} interrupt_descriptor;
|
||||||
|
|
||||||
struct tss {
|
struct tss {
|
||||||
uint16 prev_task;
|
uint16 prev_task;
|
||||||
uint16 unused0;
|
uint16 unused0;
|
||||||
|
|||||||
@@ -83,11 +83,6 @@ struct interrupt_frame {
|
|||||||
uint32 eflags;
|
uint32 eflags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct interrupt_descriptor {
|
|
||||||
uint32 a;
|
|
||||||
uint32 b;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static interrupt_descriptor sDebugIDT[DEBUG_IDT_SLOT_COUNT];
|
static interrupt_descriptor sDebugIDT[DEBUG_IDT_SLOT_COUNT];
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "smp.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -31,6 +32,13 @@ static const uint64 kLargePageMappingFlags = 0x183;
|
|||||||
static const uint64 kPageMappingFlags = 0x103;
|
static const uint64 kPageMappingFlags = 0x103;
|
||||||
// Global, R/W, Present
|
// Global, R/W, Present
|
||||||
|
|
||||||
|
extern "C" void long_enter_kernel(int currentCPU, uint64 stackTop);
|
||||||
|
|
||||||
|
extern uint32 gLongPhysicalGDT;
|
||||||
|
extern uint64 gLongVirtualGDT;
|
||||||
|
extern uint32 gLongPhysicalPML4;
|
||||||
|
extern uint64 gLongKernelEntry;
|
||||||
|
|
||||||
|
|
||||||
/*! Convert a 32-bit address to a 64-bit address. */
|
/*! Convert a 32-bit address to a 64-bit address. */
|
||||||
static inline uint64
|
static inline uint64
|
||||||
@@ -71,6 +79,10 @@ long_gdt_init()
|
|||||||
DPL_USER);
|
DPL_USER);
|
||||||
set_segment_descriptor(&gdt[USER_DATA_SEG / 8], DT_DATA_WRITEABLE,
|
set_segment_descriptor(&gdt[USER_DATA_SEG / 8], DT_DATA_WRITEABLE,
|
||||||
DPL_USER);
|
DPL_USER);
|
||||||
|
|
||||||
|
// Used by long_enter_kernel().
|
||||||
|
gLongPhysicalGDT = gKernelArgs.arch_args.phys_gdt;
|
||||||
|
gLongVirtualGDT = gKernelArgs.arch_args.vir_gdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -222,6 +234,8 @@ long_mmu_init()
|
|||||||
gKernelArgs.virtual_allocated_range[i].start,
|
gKernelArgs.virtual_allocated_range[i].start,
|
||||||
gKernelArgs.virtual_allocated_range[i].size);
|
gKernelArgs.virtual_allocated_range[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gLongPhysicalPML4 = gKernelArgs.arch_args.phys_pgdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -275,12 +289,6 @@ convert_kernel_args()
|
|||||||
gKernelArgs.kernel_args_range[i].size);
|
gKernelArgs.kernel_args_range[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set correct kernel stack addresses.
|
|
||||||
for (uint32 i = 0; i < gKernelArgs.num_cpus; i++) {
|
|
||||||
gKernelArgs.cpu_kstack[i].start = fix_address(
|
|
||||||
gKernelArgs.cpu_kstack[i].start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix driver settings files.
|
// Fix driver settings files.
|
||||||
driver_settings_file* file = gKernelArgs.driver_settings;
|
driver_settings_file* file = gKernelArgs.driver_settings;
|
||||||
fix_address(gKernelArgs.driver_settings);
|
fix_address(gKernelArgs.driver_settings);
|
||||||
@@ -293,6 +301,27 @@ convert_kernel_args()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
long_smp_start_kernel(void)
|
||||||
|
{
|
||||||
|
uint32 cpu = smp_get_current_cpu();
|
||||||
|
|
||||||
|
// Important. Make sure supervisor threads can fault on read only pages...
|
||||||
|
asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
|
||||||
|
asm("cld");
|
||||||
|
asm("fninit");
|
||||||
|
|
||||||
|
// Fix our kernel stack address.
|
||||||
|
gKernelArgs.cpu_kstack[cpu].start
|
||||||
|
= fix_address(gKernelArgs.cpu_kstack[cpu].start);
|
||||||
|
|
||||||
|
long_enter_kernel(cpu, gKernelArgs.cpu_kstack[cpu].start
|
||||||
|
+ gKernelArgs.cpu_kstack[cpu].size);
|
||||||
|
|
||||||
|
panic("Shouldn't get here");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
long_start_kernel()
|
long_start_kernel()
|
||||||
{
|
{
|
||||||
@@ -305,8 +334,7 @@ long_start_kernel()
|
|||||||
preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
|
preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
|
||||||
gKernelArgs.kernel_image.Pointer());
|
gKernelArgs.kernel_image.Pointer());
|
||||||
|
|
||||||
// TODO: x86_64 SMP, disable for now.
|
smp_init_other_cpus();
|
||||||
gKernelArgs.num_cpus = 1;
|
|
||||||
|
|
||||||
long_gdt_init();
|
long_gdt_init();
|
||||||
long_idt_init();
|
long_idt_init();
|
||||||
@@ -315,23 +343,22 @@ long_start_kernel()
|
|||||||
|
|
||||||
debug_cleanup();
|
debug_cleanup();
|
||||||
|
|
||||||
// Calculate the arguments for long_enter_kernel().
|
// Save the kernel entry point address.
|
||||||
uint64 entry = image->elf_header.e_entry;
|
gLongKernelEntry = image->elf_header.e_entry;
|
||||||
uint64 stackTop = gKernelArgs.cpu_kstack[0].start
|
dprintf("kernel entry at %#llx\n", gLongKernelEntry);
|
||||||
+ gKernelArgs.cpu_kstack[0].size;
|
|
||||||
uint64 kernelArgs = (addr_t)&gKernelArgs;
|
|
||||||
|
|
||||||
dprintf("kernel entry at %#llx, stack %#llx, args %#llx\n", entry,
|
// Fix our kernel stack address.
|
||||||
stackTop, kernelArgs);
|
gKernelArgs.cpu_kstack[0].start
|
||||||
|
= fix_address(gKernelArgs.cpu_kstack[0].start);
|
||||||
|
|
||||||
// We're about to enter the kernel -- disable console output.
|
// We're about to enter the kernel -- disable console output.
|
||||||
stdout = NULL;
|
stdout = NULL;
|
||||||
|
|
||||||
|
smp_boot_other_cpus(long_smp_start_kernel);
|
||||||
|
|
||||||
// Enter the kernel!
|
// Enter the kernel!
|
||||||
long_enter_kernel(gKernelArgs.arch_args.phys_pgdir,
|
long_enter_kernel(0, gKernelArgs.cpu_kstack[0].start
|
||||||
gKernelArgs.arch_args.phys_gdt, gKernelArgs.arch_args.vir_gdt,
|
+ gKernelArgs.cpu_kstack[0].size);
|
||||||
entry, stackTop, kernelArgs, 0);
|
|
||||||
|
|
||||||
panic("Shouldn't get here");
|
panic("Shouldn't get here");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,6 @@
|
|||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
extern "C" void long_enter_kernel(uint32 physPML4, uint32 physGDT,
|
|
||||||
uint64 virtGDT, uint64 entry, uint64 stackTop, uint64 kernelArgs,
|
|
||||||
int currentCPU);
|
|
||||||
|
|
||||||
extern void long_start_kernel();
|
extern void long_start_kernel();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,17 @@
|
|||||||
.code32
|
.code32
|
||||||
|
|
||||||
|
|
||||||
/*! void long_enter_kernel(uint32 physPML4, uint32 physGDT, uint64 virtGDT,
|
/*! void long_enter_kernel(int currentCPU, uint64 stackTop); */
|
||||||
uint64 entry, uint64 stackTop, uint64 kernelArgs, int currentCPU);
|
|
||||||
*/
|
|
||||||
FUNCTION(long_enter_kernel):
|
FUNCTION(long_enter_kernel):
|
||||||
|
// Preserve the arguments. We may no longer be able to use the stack once
|
||||||
|
// paging is disabled.
|
||||||
|
movl 4(%esp), %ebx
|
||||||
|
movl 8(%esp), %edi
|
||||||
|
movl 12(%esp), %esi
|
||||||
|
|
||||||
// We're about to disable paging, so we need to load the the physical
|
// We're about to disable paging, so we need to load the the physical
|
||||||
// address of our GDT.
|
// address of our GDT.
|
||||||
movl 8(%esp), %eax
|
lgdtl long_phys_gdtr
|
||||||
movl %eax, (long_gdtr + 2)
|
|
||||||
lgdtl (long_gdtr)
|
|
||||||
|
|
||||||
// Currently running with 32-bit paging tables at an identity mapped
|
// 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,
|
// address. To switch to 64-bit paging we must first disable 32-bit paging,
|
||||||
@@ -40,11 +42,11 @@ FUNCTION(long_enter_kernel):
|
|||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
|
|
||||||
// Point CR3 to the kernel's PML4.
|
// Point CR3 to the kernel's PML4.
|
||||||
movl 4(%esp), %eax
|
movl gLongPhysicalPML4, %eax
|
||||||
movl %eax, %cr3
|
movl %eax, %cr3
|
||||||
|
|
||||||
// Enable long mode by setting EFER.LME.
|
// Enable long mode by setting EFER.LME.
|
||||||
movl $0xC0000080, %ecx
|
movl $0xc0000080, %ecx
|
||||||
rdmsr
|
rdmsr
|
||||||
orl $(1 << 8), %eax
|
orl $(1 << 8), %eax
|
||||||
wrmsr
|
wrmsr
|
||||||
@@ -68,32 +70,41 @@ FUNCTION(long_enter_kernel):
|
|||||||
mov %ax, %fs
|
mov %ax, %fs
|
||||||
mov %ax, %gs
|
mov %ax, %gs
|
||||||
|
|
||||||
// Clear the high 32 bits of RSP.
|
|
||||||
movl %esp, %esp
|
|
||||||
|
|
||||||
// Load the virtual address of the GDT.
|
// Load the virtual address of the GDT.
|
||||||
movq 12(%rsp), %rax
|
lgdtq long_virt_gdtr(%rip)
|
||||||
movq %rax, long_gdtr + 2(%rip)
|
|
||||||
lgdtq long_gdtr(%rip)
|
|
||||||
|
|
||||||
// Get the entry point address, arguments and new stack pointer.
|
// Set the stack pointer.
|
||||||
movq 20(%rsp), %rax
|
movl %edi, %esp
|
||||||
movq 36(%rsp), %rdi
|
shl $32, %rsi
|
||||||
movl 44(%rsp), %esi
|
orq %rsi, %rsp
|
||||||
movq 28(%rsp), %rsp
|
|
||||||
|
|
||||||
// Clear the stack frame/RFLAGS.
|
// Clear the stack frame/RFLAGS.
|
||||||
xorq %rbp, %rbp
|
xorq %rbp, %rbp
|
||||||
push $0
|
push $0
|
||||||
popf
|
popf
|
||||||
|
|
||||||
// Call the kernel entry point.
|
// Get arguments and call the kernel entry point.
|
||||||
|
leaq gKernelArgs(%rip), %rdi
|
||||||
|
movl %ebx, %esi
|
||||||
|
movq gLongKernelEntry(%rip), %rax
|
||||||
call *%rax
|
call *%rax
|
||||||
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
|
|
||||||
long_gdtr:
|
long_phys_gdtr:
|
||||||
.word GDT_LIMIT - 1
|
.word GDT_LIMIT - 1
|
||||||
|
SYMBOL(gLongPhysicalGDT):
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
long_virt_gdtr:
|
||||||
|
.word GDT_LIMIT - 1
|
||||||
|
SYMBOL(gLongVirtualGDT):
|
||||||
|
.quad 0
|
||||||
|
|
||||||
|
SYMBOL(gLongPhysicalPML4):
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
SYMBOL(gLongKernelEntry):
|
||||||
.quad 0
|
.quad 0
|
||||||
|
|||||||
@@ -20,8 +20,10 @@
|
|||||||
#include <boot/menu.h>
|
#include <boot/menu.h>
|
||||||
#include <arch/x86/apic.h>
|
#include <arch/x86/apic.h>
|
||||||
#include <arch/x86/arch_acpi.h>
|
#include <arch/x86/arch_acpi.h>
|
||||||
|
#include <arch/x86/arch_cpu.h>
|
||||||
#include <arch/x86/arch_smp.h>
|
#include <arch/x86/arch_smp.h>
|
||||||
#include <arch/x86/arch_system_info.h>
|
#include <arch/x86/arch_system_info.h>
|
||||||
|
#include <arch/x86/descriptors.h>
|
||||||
|
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "acpi.h"
|
#include "acpi.h"
|
||||||
@@ -37,10 +39,6 @@
|
|||||||
# define TRACE(x) ;
|
# define TRACE(x) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct gdt_idt_descr {
|
|
||||||
uint16 a;
|
|
||||||
uint32 *b;
|
|
||||||
} _PACKED;
|
|
||||||
|
|
||||||
static struct scan_spots_struct smp_scan_spots[] = {
|
static struct scan_spots_struct smp_scan_spots[] = {
|
||||||
{ 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 },
|
{ 0x9fc00, 0xa0000, 0xa0000 - 0x9fc00 },
|
||||||
@@ -54,9 +52,6 @@ extern "C" void smp_trampoline(void);
|
|||||||
extern "C" void smp_trampoline_end(void);
|
extern "C" void smp_trampoline_end(void);
|
||||||
|
|
||||||
|
|
||||||
static int smp_get_current_cpu(void);
|
|
||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
apic_read(uint32 offset)
|
apic_read(uint32 offset)
|
||||||
{
|
{
|
||||||
@@ -71,22 +66,6 @@ apic_write(uint32 offset, uint32 data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
smp_get_current_cpu(void)
|
|
||||||
{
|
|
||||||
if (gKernelArgs.arch_args.apic == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint8 apicID = apic_read(APIC_ID) >> 24;
|
|
||||||
for (uint32 i = 0; i < gKernelArgs.num_cpus; i++) {
|
|
||||||
if (gKernelArgs.arch_args.cpu_apic_id[i] == apicID)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static mp_floating_struct *
|
static mp_floating_struct *
|
||||||
smp_mp_probe(uint32 base, uint32 limit)
|
smp_mp_probe(uint32 base, uint32 limit)
|
||||||
{
|
{
|
||||||
@@ -341,56 +320,6 @@ smp_do_acpi_config(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Target function of the trampoline code.
|
|
||||||
The trampoline code should have the pgdir and a gdt set up for us,
|
|
||||||
along with us being on the final stack for this processor. We need
|
|
||||||
to set up the local APIC and load the global idt and gdt. When we're
|
|
||||||
done, we'll jump into the kernel with the cpu number as an argument.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
smp_cpu_ready(void)
|
|
||||||
{
|
|
||||||
uint32 curr_cpu = smp_get_current_cpu();
|
|
||||||
struct gdt_idt_descr idt_descr;
|
|
||||||
struct gdt_idt_descr gdt_descr;
|
|
||||||
|
|
||||||
//TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu));
|
|
||||||
|
|
||||||
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
|
|
||||||
gKernelArgs.kernel_image.Pointer());
|
|
||||||
|
|
||||||
// Important. Make sure supervisor threads can fault on read only pages...
|
|
||||||
asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
|
|
||||||
asm("cld");
|
|
||||||
asm("fninit");
|
|
||||||
|
|
||||||
// Set up the final idt
|
|
||||||
idt_descr.a = IDT_LIMIT - 1;
|
|
||||||
idt_descr.b = (uint32 *)(addr_t)gKernelArgs.arch_args.vir_idt;
|
|
||||||
|
|
||||||
asm("lidt %0;"
|
|
||||||
: : "m" (idt_descr));
|
|
||||||
|
|
||||||
// Set up the final gdt
|
|
||||||
gdt_descr.a = GDT_LIMIT - 1;
|
|
||||||
gdt_descr.b = (uint32 *)gKernelArgs.arch_args.vir_gdt;
|
|
||||||
|
|
||||||
asm("lgdt %0;"
|
|
||||||
: : "m" (gdt_descr));
|
|
||||||
|
|
||||||
asm("pushl %0; " // push the cpu number
|
|
||||||
"pushl %1; " // kernel args
|
|
||||||
"pushl $0x0;" // dummy retval for call to main
|
|
||||||
"pushl %2; " // this is the start address
|
|
||||||
"ret; " // jump.
|
|
||||||
: : "g" (curr_cpu), "g" (&gKernelArgs),
|
|
||||||
"g" (image->elf_header.e_entry));
|
|
||||||
|
|
||||||
// no where to return to
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calculate_apic_timer_conversion_factor(void)
|
calculate_apic_timer_conversion_factor(void)
|
||||||
{
|
{
|
||||||
@@ -429,6 +358,22 @@ calculate_apic_timer_conversion_factor(void)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
smp_get_current_cpu(void)
|
||||||
|
{
|
||||||
|
if (gKernelArgs.arch_args.apic == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8 apicID = apic_read(APIC_ID) >> 24;
|
||||||
|
for (uint32 i = 0; i < gKernelArgs.num_cpus; i++) {
|
||||||
|
if (gKernelArgs.arch_args.cpu_apic_id[i] == apicID)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
smp_init_other_cpus(void)
|
smp_init_other_cpus(void)
|
||||||
{
|
{
|
||||||
@@ -476,7 +421,7 @@ smp_init_other_cpus(void)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
smp_boot_other_cpus(void)
|
smp_boot_other_cpus(void (*entryFunc)())
|
||||||
{
|
{
|
||||||
if (gKernelArgs.num_cpus < 2)
|
if (gKernelArgs.num_cpus < 2)
|
||||||
return;
|
return;
|
||||||
@@ -516,7 +461,7 @@ smp_boot_other_cpus(void)
|
|||||||
tempStack = (finalStack
|
tempStack = (finalStack
|
||||||
+ (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE)
|
+ (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE)
|
||||||
/ sizeof(uint32)) - 1;
|
/ sizeof(uint32)) - 1;
|
||||||
*tempStack = (uint32)&smp_cpu_ready;
|
*tempStack = (uint32)entryFunc;
|
||||||
|
|
||||||
// set the trampoline stack up
|
// set the trampoline stack up
|
||||||
tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4);
|
tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4);
|
||||||
@@ -525,15 +470,20 @@ smp_boot_other_cpus(void)
|
|||||||
+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE - sizeof(uint32);
|
+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE - sizeof(uint32);
|
||||||
tempStack--;
|
tempStack--;
|
||||||
// page dir
|
// page dir
|
||||||
*tempStack = gKernelArgs.arch_args.phys_pgdir;
|
*tempStack = x86_read_cr3() & 0xfffff000;
|
||||||
|
|
||||||
// put a gdt descriptor at the bottom of the stack
|
// put a gdt descriptor at the bottom of the stack
|
||||||
*((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT
|
*((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT
|
||||||
*((uint32 *)(trampolineStack + 2)) = trampolineStack + 8;
|
*((uint32 *)(trampolineStack + 2)) = trampolineStack + 8;
|
||||||
|
|
||||||
// put the gdt at the bottom
|
// construct a temporary gdt at the bottom
|
||||||
memcpy(&((uint32 *)trampolineStack)[2],
|
segment_descriptor* tempGDT
|
||||||
(void *)gKernelArgs.arch_args.vir_gdt, 6 * 4);
|
= (segment_descriptor*)&((uint32 *)trampolineStack)[2];
|
||||||
|
clear_segment_descriptor(&tempGDT[0]);
|
||||||
|
set_segment_descriptor(&tempGDT[1], 0, 0xffffffff, DT_CODE_READABLE,
|
||||||
|
DPL_KERNEL);
|
||||||
|
set_segment_descriptor(&tempGDT[2], 0, 0xffffffff, DT_DATA_WRITEABLE,
|
||||||
|
DPL_KERNEL);
|
||||||
|
|
||||||
/* clear apic errors */
|
/* clear apic errors */
|
||||||
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
|
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ extern "C" {
|
|||||||
|
|
||||||
extern void smp_init(void);
|
extern void smp_init(void);
|
||||||
extern void smp_init_other_cpus(void);
|
extern void smp_init_other_cpus(void);
|
||||||
extern void smp_boot_other_cpus(void);
|
extern void smp_boot_other_cpus(void (*entryFunc)());
|
||||||
|
|
||||||
|
extern int smp_get_current_cpu(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,55 @@ platform_boot_options(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Target function of the SMP trampoline code.
|
||||||
|
The trampoline code should have the pgdir and a gdt set up for us,
|
||||||
|
along with us being on the final stack for this processor. We need
|
||||||
|
to set up the local APIC and load the global idt and gdt. When we're
|
||||||
|
done, we'll jump into the kernel with the cpu number as an argument.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
smp_start_kernel(void)
|
||||||
|
{
|
||||||
|
uint32 curr_cpu = smp_get_current_cpu();
|
||||||
|
struct gdt_idt_descr idt_descr;
|
||||||
|
struct gdt_idt_descr gdt_descr;
|
||||||
|
|
||||||
|
//TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu));
|
||||||
|
|
||||||
|
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
|
||||||
|
gKernelArgs.kernel_image.Pointer());
|
||||||
|
|
||||||
|
// Important. Make sure supervisor threads can fault on read only pages...
|
||||||
|
asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
|
||||||
|
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 the final gdt
|
||||||
|
gdt_descr.limit = GDT_LIMIT - 1;
|
||||||
|
gdt_descr.base = (uint32 *)gKernelArgs.arch_args.vir_gdt;
|
||||||
|
|
||||||
|
asm("lgdt %0;"
|
||||||
|
: : "m" (gdt_descr));
|
||||||
|
|
||||||
|
asm("pushl %0; " // push the cpu number
|
||||||
|
"pushl %1; " // kernel args
|
||||||
|
"pushl $0x0;" // dummy retval for call to main
|
||||||
|
"pushl %2; " // this is the start address
|
||||||
|
"ret; " // jump.
|
||||||
|
: : "g" (curr_cpu), "g" (&gKernelArgs),
|
||||||
|
"g" (image->elf_header.e_entry));
|
||||||
|
|
||||||
|
panic("kernel returned!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
platform_start_kernel(void)
|
platform_start_kernel(void)
|
||||||
{
|
{
|
||||||
@@ -99,7 +148,7 @@ platform_start_kernel(void)
|
|||||||
// We're about to enter the kernel -- disable console output.
|
// We're about to enter the kernel -- disable console output.
|
||||||
stdout = NULL;
|
stdout = NULL;
|
||||||
|
|
||||||
smp_boot_other_cpus();
|
smp_boot_other_cpus(smp_start_kernel);
|
||||||
|
|
||||||
dprintf("kernel entry at %lx\n", image->elf_header.e_entry);
|
dprintf("kernel entry at %lx\n", image->elf_header.e_entry);
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,7 @@ static const int kInterruptNameCount = 20;
|
|||||||
|
|
||||||
#define MAX_ARGS 16
|
#define MAX_ARGS 16
|
||||||
|
|
||||||
typedef struct {
|
static interrupt_descriptor* sIDTs[B_MAX_CPU_COUNT];
|
||||||
uint32 a, b;
|
|
||||||
} desc_table;
|
|
||||||
static desc_table* sIDTs[B_MAX_CPU_COUNT];
|
|
||||||
|
|
||||||
// table with functions handling respective interrupts
|
// table with functions handling respective interrupts
|
||||||
typedef void interrupt_handler_function(struct iframe* frame);
|
typedef void interrupt_handler_function(struct iframe* frame);
|
||||||
@@ -80,7 +77,7 @@ extern void hardware_interrupt(struct iframe* frame);
|
|||||||
/*! Initializes a descriptor in an IDT.
|
/*! Initializes a descriptor in an IDT.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
|
set_gate(interrupt_descriptor *gate_addr, addr_t addr, int type, int dpl)
|
||||||
{
|
{
|
||||||
unsigned int gate1; // first byte of gate desc
|
unsigned int gate1; // first byte of gate desc
|
||||||
unsigned int gate2; // second byte of gate desc
|
unsigned int gate2; // second byte of gate desc
|
||||||
@@ -353,7 +350,7 @@ arch_int_init(struct kernel_args *args)
|
|||||||
interrupt_handler_function** table;
|
interrupt_handler_function** table;
|
||||||
|
|
||||||
// set the global sIDT variable
|
// set the global sIDT variable
|
||||||
sIDTs[0] = (desc_table *)(addr_t)args->arch_args.vir_idt;
|
sIDTs[0] = (interrupt_descriptor *)(addr_t)args->arch_args.vir_idt;
|
||||||
|
|
||||||
// setup the standard programmable interrupt controller
|
// setup the standard programmable interrupt controller
|
||||||
pic_init();
|
pic_init();
|
||||||
@@ -668,7 +665,7 @@ arch_int_init_post_vm(struct kernel_args *args)
|
|||||||
int32 cpuCount = smp_get_num_cpus();
|
int32 cpuCount = smp_get_num_cpus();
|
||||||
if (cpuCount > 0) {
|
if (cpuCount > 0) {
|
||||||
size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
|
size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
|
||||||
desc_table* idt;
|
interrupt_descriptor* idt;
|
||||||
virtual_address_restrictions virtualRestrictions = {};
|
virtual_address_restrictions virtualRestrictions = {};
|
||||||
virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
|
virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
|
||||||
physical_address_restrictions physicalRestrictions = {};
|
physical_address_restrictions physicalRestrictions = {};
|
||||||
|
|||||||
@@ -270,34 +270,6 @@ arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
arch_smp_init(kernel_args *args)
|
|
||||||
{
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
|
|
||||||
{
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_smp_send_broadcast_ici(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_smp_send_ici(int32 target_cpu)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// The software breakpoint instruction (int3).
|
// The software breakpoint instruction (int3).
|
||||||
const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
|
const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ if $(TARGET_ARCH) = x86_64 {
|
|||||||
|
|
||||||
arch_commpage.cpp
|
arch_commpage.cpp
|
||||||
arch_debug.cpp
|
arch_debug.cpp
|
||||||
arch_smp.cpp
|
|
||||||
arch_user_debugger.cpp
|
arch_user_debugger.cpp
|
||||||
apm.cpp
|
apm.cpp
|
||||||
bios.cpp
|
bios.cpp
|
||||||
@@ -83,6 +82,7 @@ local archGenericSources =
|
|||||||
arch_int.cpp
|
arch_int.cpp
|
||||||
arch_platform.cpp
|
arch_platform.cpp
|
||||||
arch_real_time_clock.cpp
|
arch_real_time_clock.cpp
|
||||||
|
arch_smp.cpp
|
||||||
arch_system_info.cpp
|
arch_system_info.cpp
|
||||||
arch_thread.cpp
|
arch_thread.cpp
|
||||||
arch_timer.cpp
|
arch_timer.cpp
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ x86_init_fpu(void)
|
|||||||
static void
|
static void
|
||||||
load_tss(int cpu)
|
load_tss(int cpu)
|
||||||
{
|
{
|
||||||
short seg = ((TSS_BASE_SEGMENT + cpu) << 3) | DPL_KERNEL;
|
short seg = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
|
||||||
asm("ltr %%ax" : : "a" (seg));
|
asm("ltr %%ax" : : "a" (seg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +789,8 @@ arch_cpu_init_percpu(kernel_args* args, int cpu)
|
|||||||
uint16 limit;
|
uint16 limit;
|
||||||
void* address;
|
void* address;
|
||||||
} _PACKED descriptor = {
|
} _PACKED descriptor = {
|
||||||
256 * 8 - 1, // 256 descriptors, 8 bytes each (-1 for "limit")
|
256 * sizeof(interrupt_descriptor) - 1,
|
||||||
|
// 256 descriptors (-1 for "limit")
|
||||||
x86_get_idt(cpu)
|
x86_get_idt(cpu)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static int32
|
|||||||
x86_spurious_interrupt(void *data)
|
x86_spurious_interrupt(void *data)
|
||||||
{
|
{
|
||||||
// spurious interrupt
|
// spurious interrupt
|
||||||
TRACE(("spurious interrupt on cpu %ld\n", smp_get_current_cpu()));
|
TRACE(("spurious interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
|
||||||
|
|
||||||
// spurious interrupts must not be acknowledged as it does not expect
|
// spurious interrupts must not be acknowledged as it does not expect
|
||||||
// a end of interrupt - if we still do it we would loose the next best
|
// a end of interrupt - if we still do it we would loose the next best
|
||||||
@@ -65,7 +65,7 @@ static int32
|
|||||||
x86_smp_error_interrupt(void *data)
|
x86_smp_error_interrupt(void *data)
|
||||||
{
|
{
|
||||||
// smp error interrupt
|
// smp error interrupt
|
||||||
TRACE(("smp error interrupt on cpu %ld\n", smp_get_current_cpu()));
|
TRACE(("smp error interrupt on cpu %" B_PRId32 "\n", smp_get_current_cpu()));
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,8 @@ status_t
|
|||||||
arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
|
arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
|
||||||
{
|
{
|
||||||
// set up the local apic on the current cpu
|
// set up the local apic on the current cpu
|
||||||
TRACE(("arch_smp_init_percpu: setting up the apic on cpu %ld\n", cpu));
|
TRACE(("arch_smp_init_percpu: setting up the apic on cpu %" B_PRId32 "\n",
|
||||||
|
cpu));
|
||||||
apic_per_cpu_init(args, cpu);
|
apic_per_cpu_init(args, cpu);
|
||||||
|
|
||||||
// setup FPU and SSE if supported
|
// setup FPU and SSE if supported
|
||||||
@@ -154,7 +155,7 @@ arch_smp_send_ici(int32 target_cpu)
|
|||||||
asm volatile ("pause;");
|
asm volatile ("pause;");
|
||||||
|
|
||||||
if (timeout == 0)
|
if (timeout == 0)
|
||||||
panic("arch_smp_send_ici: timeout, target_cpu %ld", target_cpu);
|
panic("arch_smp_send_ici: timeout, target_cpu %" B_PRId32, target_cpu);
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user