* renamed smp_boot.c to smp.cpp
* there is now a "Disable Hyper-Threading" safemode in the boot loader * the SMP & HT menu items are now added in smp.cpp - and are only added if the system supports one of them. * more cleanup to smp_apic.h * removed cpuid() from the boot loader's support.S - instead, it will now use the one from the kernel. * added a very weak HT detection: if the MP config only listed one CPU, and this CPU supports HT, we enable the other logic processor manually - as this currently doesn't work, it's disabled, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14536 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -8,70 +8,83 @@
|
|||||||
#ifndef _KERNEL_ARCH_x86_SMP_APIC_H
|
#ifndef _KERNEL_ARCH_x86_SMP_APIC_H
|
||||||
#define _KERNEL_ARCH_x86_SMP_APIC_H
|
#define _KERNEL_ARCH_x86_SMP_APIC_H
|
||||||
|
|
||||||
#define MP_FLT_SIGNATURE '_PM_'
|
#define MP_FLOATING_SIGNATURE '_PM_'
|
||||||
#define MP_CTH_SIGNATURE 'PCMP'
|
#define MP_CONFIG_TABLE_SIGNATURE 'PCMP'
|
||||||
|
|
||||||
#define APIC_ENABLE 0x100
|
#define APIC_ENABLE 0x100
|
||||||
#define APIC_FOCUS (~(1 << 9))
|
#define APIC_FOCUS (~(1 << 9))
|
||||||
#define APIC_SIV (0xff)
|
#define APIC_SIV (0xff)
|
||||||
|
|
||||||
// offsets to APIC register
|
// offsets to APIC register
|
||||||
#define APIC_ID 0x020
|
#define APIC_ID 0x020
|
||||||
#define APIC_VERSION 0x030
|
#define APIC_VERSION 0x030
|
||||||
#define APIC_TPRI 0x080
|
#define APIC_TASK_PRIORITY 0x080
|
||||||
#define APIC_EOI 0x0b0
|
#define APIC_ARBITRATION_PRIORITY 0x090
|
||||||
#define APIC_LDR 0x0d0
|
#define APIC_PROCESSOR_PRIORITY 0x0a0
|
||||||
#define APIC_SIVR 0x0f0
|
#define APIC_EOI 0x0b0
|
||||||
#define APIC_ESR 0x280
|
#define APIC_LOGICAL_DEST 0x0d0
|
||||||
#define APIC_ICR1 0x300
|
#define APIC_DEST_FORMAT 0x0e0
|
||||||
#define APIC_ICR2 0x310
|
#define APIC_SPURIOUS_INTR_VECTOR 0x0f0
|
||||||
#define APIC_LVTT 0x320
|
#define APIC_ERROR_STATUS 0x280
|
||||||
#define APIC_LINT0 0x350
|
#define APIC_INTR_COMMAND_1 0x300 // bits 0-31
|
||||||
#define APIC_LINT1 0x360
|
#define APIC_INTR_COMMAND_2 0x310 // bits 32-63
|
||||||
#define APIC_LVT3 0x370
|
#define APIC_LVT_TIMER 0x320
|
||||||
#define APIC_ICRT 0x380
|
#define APIC_LVT_THERMAL_SENSOR 0x330
|
||||||
#define APIC_CCRT 0x390
|
#define APIC_LVT_PERFMON_COUNTERS 0x340
|
||||||
#define APIC_TDCR 0x3e0
|
#define APIC_LVT_LINT0 0x350
|
||||||
|
#define APIC_LVT_LINT1 0x360
|
||||||
|
#define APIC_LVT_ERROR 0x370
|
||||||
|
#define APIC_INITIAL_TIMER_COUNT 0x380
|
||||||
|
#define APIC_CURRENT_TIMER_COUNT 0x390
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG 0x3e0
|
||||||
|
|
||||||
/* ICR defines */
|
/* standard APIC interrupt defines */
|
||||||
#define APIC_ICR1_WRITE_MASK 0xfff3f000
|
#define APIC_DELIVERY_MODE_FIXED 0
|
||||||
#define APIC_ICR1_READ_MASK 0xfff32000
|
#define APIC_DELIVERY_MODE_LOWESTPRI (1 << 8) // ICR1 only
|
||||||
#define APIC_ICR2_MASK 0x00ffffff
|
#define APIC_DELIVERY_MODE_SMI (2 << 8)
|
||||||
|
#define APIC_DELIVERY_MODE_NMI (4 << 8)
|
||||||
|
#define APIC_DELIVERY_MODE_INIT (5 << 8)
|
||||||
|
#define APIC_DELIVERY_MODE_STARTUP (6 << 8) // ICR1 only
|
||||||
|
#define APIC_DELIVERY_MODE_ExtINT (7 << 8) // LINT0/1 only
|
||||||
|
|
||||||
#define APIC_ICR1_DELIVERY_MODE_FIXED 0
|
#define APIC_DELIVERY_STATUS (1 << 12)
|
||||||
#define APIC_ICR1_DELIVERY_MODE_LOWESTPRI (1 << 8)
|
#define APIC_TRIGGER_MODE_LEVEL (1 << 15)
|
||||||
#define APIC_ICR1_DELIVERY_MODE_INIT (5 << 8)
|
|
||||||
#define APIC_ICR1_DELIVERY_MODE_STARTUP (6 << 8)
|
|
||||||
|
|
||||||
#define APIC_ICR1_DEST_MODE_PHYSICAL 0
|
/* Interrupt Command defines */
|
||||||
#define APIC_ICR1_DEST_MODE_LOGICAL (1 << 11)
|
#define APIC_INTR_COMMAND_1_MASK 0xfff3f000
|
||||||
|
#define APIC_INTR_COMMAND_2_MASK 0x00ffffff
|
||||||
|
|
||||||
#define APIC_ICR1_ASSERT (1 << 13)
|
#define APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL 0
|
||||||
#define APIC_ICR1_TRIGGER_MODE_LEVEL (1 << 14)
|
#define APIC_INTR_COMMAND_1_DEST_MODE_LOGICAL (1 << 11)
|
||||||
#define APIC_ICR1_DELIVERY_STATUS (1 << 12)
|
|
||||||
|
|
||||||
#define APIC_ICR1_DEST_FIELD 0
|
#define APIC_INTR_COMMAND_1_ASSERT (1 << 14)
|
||||||
#define APIC_ICR1_DEST_SELF (1 << 18)
|
|
||||||
#define APIC_ICR1_DEST_ALL (2 << 18)
|
|
||||||
#define APIC_ICR1_DEST_ALL_BUT_SELF (3 << 18)
|
|
||||||
|
|
||||||
/* other defines */
|
#define APIC_INTR_COMMAND_1_DEST_FIELD 0
|
||||||
|
#define APIC_INTR_COMMAND_1_DEST_SELF (1 << 18)
|
||||||
|
#define APIC_INTR_COMMAND_1_DEST_ALL (2 << 18)
|
||||||
|
#define APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF (3 << 18)
|
||||||
|
|
||||||
#define APIC_TDCR_2 0x00
|
/* Local Vector Table defines */
|
||||||
#define APIC_TDCR_4 0x01
|
#define APIC_LVT_MASKED (1 << 16)
|
||||||
#define APIC_TDCR_8 0x02
|
|
||||||
#define APIC_TDCR_16 0x03
|
|
||||||
#define APIC_TDCR_32 0x08
|
|
||||||
#define APIC_TDCR_64 0x09
|
|
||||||
#define APIC_TDCR_128 0x0a
|
|
||||||
#define APIC_TDCR_1 0x0b
|
|
||||||
|
|
||||||
#define APIC_LVTT_MASK 0x000310ff
|
// timer defines
|
||||||
#define APIC_LVTT_VECTOR 0x000000ff
|
#define APIC_LVT_TIMER_MASK 0xfffcef00
|
||||||
#define APIC_LVTT_DS 0x00001000
|
|
||||||
#define APIC_LVTT_M 0x00010000
|
|
||||||
#define APIC_LVTT_TM 0x00020000
|
|
||||||
|
|
||||||
|
// LINT0/1 defines
|
||||||
|
#define APIC_LVT_LINT_MASK 0xfffe0800
|
||||||
|
#define APIC_LVT_LINT_INPUT_POLARITY (1 << 13)
|
||||||
|
|
||||||
|
// Timer Divide Config Divisors
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_1 0x0b
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_2 0x00
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_4 0x01
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_8 0x02
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_16 0x03
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_32 0x08
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_64 0x09
|
||||||
|
#define APIC_TIMER_DIVIDE_CONFIG_128 0x0a
|
||||||
|
|
||||||
|
/*
|
||||||
#define APIC_LVT_DM 0x00000700
|
#define APIC_LVT_DM 0x00000700
|
||||||
#define APIC_LVT_DM_ExtINT 0x00000700
|
#define APIC_LVT_DM_ExtINT 0x00000700
|
||||||
#define APIC_LVT_DM_NMI 0x00000400
|
#define APIC_LVT_DM_NMI 0x00000400
|
||||||
@@ -87,10 +100,6 @@
|
|||||||
#define APIC_SVR_SWEN 0x00000100
|
#define APIC_SVR_SWEN 0x00000100
|
||||||
#define APIC_SVR_FOCUS 0x00000200
|
#define APIC_SVR_FOCUS 0x00000200
|
||||||
|
|
||||||
#define APIC_DEST_STARTUP 0x00600
|
|
||||||
|
|
||||||
#define LOPRIO_LEVEL 0x00000010
|
|
||||||
|
|
||||||
#define IOAPIC_ID 0x0
|
#define IOAPIC_ID 0x0
|
||||||
#define IOAPIC_VERSION 0x1
|
#define IOAPIC_VERSION 0x1
|
||||||
#define IOAPIC_ARB 0x2
|
#define IOAPIC_ARB 0x2
|
||||||
@@ -101,12 +110,7 @@
|
|||||||
#define IPI_INV_PTE 0x42
|
#define IPI_INV_PTE 0x42
|
||||||
#define IPI_INV_RESCHED 0x43
|
#define IPI_INV_RESCHED 0x43
|
||||||
#define IPI_STOP 0x44
|
#define IPI_STOP 0x44
|
||||||
|
*/
|
||||||
#define MP_EXT_PE 0
|
|
||||||
#define MP_EXT_BUS 1
|
|
||||||
#define MP_EXT_IO_APIC 2
|
|
||||||
#define MP_EXT_IO_INT 3
|
|
||||||
#define MP_EXT_LOCAL_INT 4
|
|
||||||
|
|
||||||
struct mp_config_table {
|
struct mp_config_table {
|
||||||
uint32 signature; /* "PCMP" */
|
uint32 signature; /* "PCMP" */
|
||||||
@@ -134,6 +138,15 @@ struct mp_floating_struct {
|
|||||||
uint8 mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */
|
uint8 mp_feature_3, mp_feature_4, mp_feature_5; /* reserved */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* base config entry types */
|
||||||
|
enum {
|
||||||
|
MP_BASE_PROCESSOR = 0,
|
||||||
|
MP_BASE_BUS,
|
||||||
|
MP_BASE_IO_APIC,
|
||||||
|
MP_BASE_IO_INTR,
|
||||||
|
MP_BASE_LOCAL_INTR,
|
||||||
|
};
|
||||||
|
|
||||||
struct mp_base_processor {
|
struct mp_base_processor {
|
||||||
uint8 type;
|
uint8 type;
|
||||||
uint8 apic_id;
|
uint8 apic_id;
|
||||||
@@ -171,10 +184,10 @@ struct mp_base_interrupt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MP_INT_TYPE_INT = 0,
|
MP_INTR_TYPE_INT = 0,
|
||||||
MP_INT_TYPE_NMI,
|
MP_INTR_TYPE_NMI,
|
||||||
MP_INT_TYPE_SMI,
|
MP_INTR_TYPE_SMI,
|
||||||
MP_INT_TYPE_ExtINT,
|
MP_INTR_TYPE_ExtINT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_x86_SMP_APIC_H */
|
#endif /* _KERNEL_ARCH_x86_SMP_APIC_H */
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
#define B_SAFEMODE_DISABLE_USER_ADD_ONS "disableuseraddons"
|
#define B_SAFEMODE_DISABLE_USER_ADD_ONS "disableuseraddons"
|
||||||
#define B_SAFEMODE_DISABLE_IDE_DMA "disableidedma"
|
#define B_SAFEMODE_DISABLE_IDE_DMA "disableidedma"
|
||||||
#define B_SAFEMODE_DISABLE_SMP "disablesmp"
|
#define B_SAFEMODE_DISABLE_SMP "disable_smp"
|
||||||
|
#define B_SAFEMODE_DISABLE_HYPER_THREADING "disable_hyperthreading"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ KernelLd boot_loader :
|
|||||||
<$(SOURCE_GRIST)!libroot!posix!string>strrchr.o
|
<$(SOURCE_GRIST)!libroot!posix!string>strrchr.o
|
||||||
<$(SOURCE_GRIST)!libroot!posix!stdlib>strtol.o
|
<$(SOURCE_GRIST)!libroot!posix!stdlib>strtol.o
|
||||||
<$(SOURCE_GRIST)!libroot>qsort.o
|
<$(SOURCE_GRIST)!libroot>qsort.o
|
||||||
|
<$(SOURCE_GRIST)!kernel!arch!$(OBOS_ARCH)>cpuid.o
|
||||||
: $(SUBDIR)/ldscripts/$(OBOS_ARCH)/boot_loader.ld
|
: $(SUBDIR)/ldscripts/$(OBOS_ARCH)/boot_loader.ld
|
||||||
: -Bstatic
|
: -Bstatic
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ KernelMergeObject boot_platform_bios_ia32.o :
|
|||||||
menu.cpp
|
menu.cpp
|
||||||
mmu.cpp
|
mmu.cpp
|
||||||
cpu.cpp
|
cpu.cpp
|
||||||
smp_boot.c
|
smp.cpp
|
||||||
smp_trampoline.S
|
smp_trampoline.S
|
||||||
support.S
|
support.S
|
||||||
video.cpp
|
video.cpp
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "keyboard.h"
|
|
||||||
#include "console.h"
|
|
||||||
#include "bios.h"
|
#include "bios.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
#include "smp.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
|
|
||||||
#include <boot/platform.h>
|
#include <boot/platform.h>
|
||||||
@@ -464,9 +465,8 @@ platform_add_menus(Menu *menu)
|
|||||||
item->SetTarget(video_mode_hook);
|
item->SetTarget(video_mode_hook);
|
||||||
break;
|
break;
|
||||||
case SAFE_MODE_MENU:
|
case SAFE_MODE_MENU:
|
||||||
menu->AddItem(item = new MenuItem("Disable SMP"));
|
smp_add_safemode_menus(menu);
|
||||||
item->SetData(B_SAFEMODE_DISABLE_SMP);
|
|
||||||
item->SetType(MENU_ITEM_MARKABLE);
|
|
||||||
menu->AddItem(item = new MenuItem("Don't call the BIOS"));
|
menu->AddItem(item = new MenuItem("Don't call the BIOS"));
|
||||||
item->SetType(MENU_ITEM_MARKABLE);
|
item->SetType(MENU_ITEM_MARKABLE);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+109
-42
@@ -12,10 +12,12 @@
|
|||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
#include <arch/x86/smp_apic.h>
|
|
||||||
#include <safemode.h>
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
#include <safemode.h>
|
||||||
|
#include <boot/stage2.h>
|
||||||
|
#include <boot/menu.h>
|
||||||
|
#include <arch/x86/smp_apic.h>
|
||||||
|
#include <arch/x86/arch_system_info.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -46,10 +48,10 @@ static struct smp_scan_spots_struct smp_scan_spots[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern void execute_n_instructions(int count);
|
extern "C" void execute_n_instructions(int count);
|
||||||
|
|
||||||
extern void smp_trampoline(void);
|
extern "C" void smp_trampoline(void);
|
||||||
extern void smp_trampoline_end(void);
|
extern "C" void smp_trampoline_end(void);
|
||||||
|
|
||||||
|
|
||||||
static struct mp_floating_struct *sFloatingStruct = NULL;
|
static struct mp_floating_struct *sFloatingStruct = NULL;
|
||||||
@@ -72,6 +74,21 @@ apic_write(uint32 offset, uint32 data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
supports_hyper_threading(void)
|
||||||
|
{
|
||||||
|
cpuid_info info;
|
||||||
|
if (get_current_cpuid(&info, 0) == B_OK
|
||||||
|
&& !strncmp(info.eax_0.vendor_id, "GenuineIntel", 12)
|
||||||
|
&& info.eax_0.max_eax > 0) {
|
||||||
|
if (get_current_cpuid(&info, 1) == B_OK)
|
||||||
|
return (info.eax_1.features & (1 << 28)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
smp_get_current_cpu(void)
|
smp_get_current_cpu(void)
|
||||||
{
|
{
|
||||||
@@ -90,7 +107,7 @@ smp_probe(uint32 base, uint32 limit)
|
|||||||
TRACE(("smp_probe: entry base 0x%lx, limit 0x%lx\n", base, limit));
|
TRACE(("smp_probe: entry base 0x%lx, limit 0x%lx\n", base, limit));
|
||||||
|
|
||||||
for (ptr = (uint32 *) base; (uint32)ptr < limit; ptr++) {
|
for (ptr = (uint32 *) base; (uint32)ptr < limit; ptr++) {
|
||||||
if (*ptr == MP_FLT_SIGNATURE) {
|
if (*ptr == MP_FLOATING_SIGNATURE) {
|
||||||
TRACE(("smp_probe: found floating pointer structure at %p\n", ptr));
|
TRACE(("smp_probe: found floating pointer structure at %p\n", ptr));
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@@ -134,7 +151,7 @@ smp_do_config(void)
|
|||||||
ptr = (char *)((uint32)config + sizeof(struct mp_config_table));
|
ptr = (char *)((uint32)config + sizeof(struct mp_config_table));
|
||||||
for (i = 0; i < config->num_base_entries; i++) {
|
for (i = 0; i < config->num_base_entries; i++) {
|
||||||
switch (*ptr) {
|
switch (*ptr) {
|
||||||
case MP_EXT_PE:
|
case MP_BASE_PROCESSOR:
|
||||||
{
|
{
|
||||||
struct mp_base_processor *processor = (struct mp_base_processor *)ptr;
|
struct mp_base_processor *processor = (struct mp_base_processor *)ptr;
|
||||||
|
|
||||||
@@ -151,7 +168,7 @@ smp_do_config(void)
|
|||||||
ptr += sizeof(struct mp_base_processor);
|
ptr += sizeof(struct mp_base_processor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MP_EXT_BUS:
|
case MP_BASE_BUS:
|
||||||
{
|
{
|
||||||
struct mp_base_bus *bus = (struct mp_base_bus *)ptr;
|
struct mp_base_bus *bus = (struct mp_base_bus *)ptr;
|
||||||
|
|
||||||
@@ -162,7 +179,7 @@ smp_do_config(void)
|
|||||||
ptr += sizeof(struct mp_base_bus);
|
ptr += sizeof(struct mp_base_bus);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MP_EXT_IO_APIC:
|
case MP_BASE_IO_APIC:
|
||||||
{
|
{
|
||||||
struct mp_base_ioapic *io = (struct mp_base_ioapic *) ptr;
|
struct mp_base_ioapic *io = (struct mp_base_ioapic *) ptr;
|
||||||
gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
|
gKernelArgs.arch_args.ioapic_phys = (uint32)io->addr;
|
||||||
@@ -173,13 +190,13 @@ smp_do_config(void)
|
|||||||
ptr += sizeof(struct mp_base_ioapic);
|
ptr += sizeof(struct mp_base_ioapic);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MP_EXT_IO_INT:
|
case MP_BASE_IO_INTR:
|
||||||
case MP_EXT_LOCAL_INT:
|
case MP_BASE_LOCAL_INTR:
|
||||||
{
|
{
|
||||||
struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)ptr;
|
struct mp_base_interrupt *interrupt = (struct mp_base_interrupt *)ptr;
|
||||||
|
|
||||||
dprintf("smp: %s int: type %d, source bus %d, irq %d, dest apic %d, int %d, polarity %d, trigger mode %d\n",
|
dprintf("smp: %s int: type %d, source bus %d, irq %d, dest apic %d, int %d, polarity %d, trigger mode %d\n",
|
||||||
interrupt->type == MP_EXT_IO_INT ? "I/O" : "local",
|
interrupt->type == MP_BASE_IO_INTR ? "I/O" : "local",
|
||||||
interrupt->interrupt_type, interrupt->source_bus_id,
|
interrupt->interrupt_type, interrupt->source_bus_id,
|
||||||
interrupt->source_bus_irq, interrupt->dest_apic_id,
|
interrupt->source_bus_irq, interrupt->dest_apic_id,
|
||||||
interrupt->dest_apic_int, interrupt->polarity,
|
interrupt->dest_apic_int, interrupt->polarity,
|
||||||
@@ -195,6 +212,26 @@ smp_do_config(void)
|
|||||||
(void *)gKernelArgs.arch_args.ioapic_phys,
|
(void *)gKernelArgs.arch_args.ioapic_phys,
|
||||||
gKernelArgs.num_cpus);
|
gKernelArgs.num_cpus);
|
||||||
|
|
||||||
|
// Try to detect single CPU hyper threading setup
|
||||||
|
// ToDo: this should be done using the ACPI APIC table
|
||||||
|
// ToDo: this only works with a single HT enabled CPU anyway
|
||||||
|
|
||||||
|
if (gKernelArgs.num_cpus == 1 && supports_hyper_threading()) {
|
||||||
|
cpuid_info info;
|
||||||
|
get_current_cpuid(&info, 1);
|
||||||
|
|
||||||
|
dprintf("CPU supports Hyper-Threading, %ld processors in package\n",
|
||||||
|
info.eax_1.logical_cpus);
|
||||||
|
|
||||||
|
// enable the second logical processor
|
||||||
|
/*
|
||||||
|
gKernelArgs.num_cpus = 2;
|
||||||
|
gKernelArgs.arch_args.cpu_apic_id[1] = gKernelArgs.arch_args.cpu_apic_id[0] + 1;
|
||||||
|
gKernelArgs.arch_args.cpu_os_id[gKernelArgs.arch_args.cpu_apic_id[1]] = 1;
|
||||||
|
gKernelArgs.arch_args.cpu_apic_version[1] = gKernelArgs.arch_args.cpu_apic_version[0];;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// this BIOS looks broken, because it didn't report any cpus (VMWare)
|
// this BIOS looks broken, because it didn't report any cpus (VMWare)
|
||||||
if (gKernelArgs.num_cpus == 0)
|
if (gKernelArgs.num_cpus == 0)
|
||||||
gKernelArgs.num_cpus = 1;
|
gKernelArgs.num_cpus = 1;
|
||||||
@@ -211,7 +248,6 @@ smp_find_mp_config(void)
|
|||||||
return gKernelArgs.num_cpus = 1;
|
return gKernelArgs.num_cpus = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// XXX for now, assume the memory is identity mapped by the 1st stage
|
|
||||||
for (i = 0; smp_scan_spots[i].length > 0; i++) {
|
for (i = 0; smp_scan_spots[i].length > 0; i++) {
|
||||||
sFloatingStruct = (struct mp_floating_struct *)smp_probe(smp_scan_spots[i].start,
|
sFloatingStruct = (struct mp_floating_struct *)smp_probe(smp_scan_spots[i].start,
|
||||||
smp_scan_spots[i].stop);
|
smp_scan_spots[i].stop);
|
||||||
@@ -308,19 +344,20 @@ calculate_apic_timer_conversion_factor(void)
|
|||||||
uint32 count;
|
uint32 count;
|
||||||
|
|
||||||
// setup the timer
|
// setup the timer
|
||||||
config = apic_read(APIC_LVTT);
|
config = apic_read(APIC_LVT_TIMER);
|
||||||
config = (config & ~APIC_LVTT_MASK) + APIC_LVTT_M; // timer masked, vector 0
|
config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; // timer masked, vector 0
|
||||||
apic_write(APIC_LVTT, config);
|
apic_write(APIC_LVT_TIMER, config);
|
||||||
|
|
||||||
config = (apic_read(APIC_TDCR) & ~0x0000000f) + 0xb; // divide clock by one
|
config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f);
|
||||||
apic_write(APIC_TDCR, config);
|
apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1);
|
||||||
|
// divide clock by one
|
||||||
|
|
||||||
t1 = system_time();
|
t1 = system_time();
|
||||||
apic_write(APIC_ICRT, 0xffffffff); // start the counter
|
apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter
|
||||||
|
|
||||||
execute_n_instructions(128*20000);
|
execute_n_instructions(128*20000);
|
||||||
|
|
||||||
count = apic_read(APIC_CCRT);
|
count = apic_read(APIC_CURRENT_TIMER_COUNT);
|
||||||
t2 = system_time();
|
t2 = system_time();
|
||||||
|
|
||||||
count = 0xffffffff - count;
|
count = 0xffffffff - count;
|
||||||
@@ -397,32 +434,36 @@ smp_boot_other_cpus(void)
|
|||||||
|
|
||||||
/* clear apic errors */
|
/* clear apic errors */
|
||||||
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
|
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
|
||||||
apic_write(APIC_ESR, 0);
|
apic_write(APIC_ERROR_STATUS, 0);
|
||||||
apic_read(APIC_ESR);
|
apic_read(APIC_ERROR_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dprintf("assert INIT\n");
|
||||||
/* send (aka assert) INIT IPI */
|
/* send (aka assert) INIT IPI */
|
||||||
config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK)
|
config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
|
||||||
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
||||||
apic_write(APIC_ICR2, config); /* set target pe */
|
apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */
|
||||||
config = (apic_read(APIC_ICR1) & 0xfff00000) | APIC_ICR1_TRIGGER_MODE_LEVEL
|
config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
|
||||||
| APIC_ICR1_ASSERT | APIC_ICR1_DELIVERY_MODE_INIT;
|
| APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT | APIC_DELIVERY_MODE_INIT;
|
||||||
apic_write(APIC_ICR1, config);
|
apic_write(APIC_INTR_COMMAND_1, config);
|
||||||
|
|
||||||
|
dprintf("wait for delivery\n");
|
||||||
// wait for pending to end
|
// wait for pending to end
|
||||||
while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0)
|
while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
dprintf("deassert INIT\n");
|
||||||
/* deassert INIT */
|
/* deassert INIT */
|
||||||
config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK)
|
config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
|
||||||
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
||||||
apic_write(APIC_ICR2, config);
|
apic_write(APIC_INTR_COMMAND_2, config);
|
||||||
config = (apic_read(APIC_ICR1) & 0xfff00000) | APIC_ICR1_TRIGGER_MODE_LEVEL
|
config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
|
||||||
| APIC_ICR1_DELIVERY_MODE_INIT;
|
| APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT;
|
||||||
apic_write(APIC_ICR1, config);
|
apic_write(APIC_INTR_COMMAND_1, config);
|
||||||
|
|
||||||
|
dprintf("wait for delivery\n");
|
||||||
// wait for pending to end
|
// wait for pending to end
|
||||||
while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0)
|
while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* wait 10ms */
|
/* wait 10ms */
|
||||||
@@ -430,24 +471,27 @@ smp_boot_other_cpus(void)
|
|||||||
|
|
||||||
/* is this a local apic or an 82489dx ? */
|
/* is this a local apic or an 82489dx ? */
|
||||||
numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0;
|
numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) ? 2 : 0;
|
||||||
|
dprintf("num startups = %ld\n", numStartups);
|
||||||
for (j = 0; j < numStartups; j++) {
|
for (j = 0; j < numStartups; j++) {
|
||||||
/* it's a local apic, so send STARTUP IPIs */
|
/* it's a local apic, so send STARTUP IPIs */
|
||||||
apic_write(APIC_ESR, 0);
|
dprintf("send STARTUP\n");
|
||||||
|
apic_write(APIC_ERROR_STATUS, 0);
|
||||||
|
|
||||||
/* set target pe */
|
/* set target pe */
|
||||||
config = (apic_read(APIC_ICR2) & APIC_ICR2_MASK)
|
config = (apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK)
|
||||||
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
|
||||||
apic_write(APIC_ICR2, config);
|
apic_write(APIC_INTR_COMMAND_2, config);
|
||||||
|
|
||||||
/* send the IPI */
|
/* send the IPI */
|
||||||
config = (apic_read(APIC_ICR1) & 0xfff0f800) | APIC_ICR1_DELIVERY_MODE_STARTUP
|
config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800)
|
||||||
| (trampolineCode >> 12);
|
| APIC_DELIVERY_MODE_STARTUP | (trampolineCode >> 12);
|
||||||
apic_write(APIC_ICR1, config);
|
apic_write(APIC_INTR_COMMAND_1, config);
|
||||||
|
|
||||||
/* wait */
|
/* wait */
|
||||||
spin(200);
|
spin(200);
|
||||||
|
|
||||||
while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0)
|
dprintf("wait for delivery\n");
|
||||||
|
while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -456,6 +500,29 @@ smp_boot_other_cpus(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
smp_add_safemode_menus(Menu *menu)
|
||||||
|
{
|
||||||
|
MenuItem *item;
|
||||||
|
|
||||||
|
if (gKernelArgs.num_cpus < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// ToDo: this should work with dual CPUs with HT as well!
|
||||||
|
if (gKernelArgs.num_cpus > 2 || !supports_hyper_threading()) {
|
||||||
|
menu->AddItem(item = new MenuItem("Disable SMP"));
|
||||||
|
item->SetData(B_SAFEMODE_DISABLE_SMP);
|
||||||
|
item->SetType(MENU_ITEM_MARKABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supports_hyper_threading()) {
|
||||||
|
menu->AddItem(item = new MenuItem("Disable Hyper-Threading"));
|
||||||
|
item->SetData(B_SAFEMODE_DISABLE_HYPER_THREADING);
|
||||||
|
item->SetType(MENU_ITEM_MARKABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
smp_init(void)
|
smp_init(void)
|
||||||
{
|
{
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
// this is only available in C++
|
||||||
|
# include <boot/menu.h>
|
||||||
|
extern void smp_add_safemode_menus(Menu *menu);
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -54,30 +54,6 @@ FUNCTION(system_time):
|
|||||||
popl %ebx
|
popl %ebx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
FUNCTION(cpuid):
|
|
||||||
pushl %ebx
|
|
||||||
pushl %edi
|
|
||||||
movl 12(%esp),%eax
|
|
||||||
movl 16(%esp),%edi
|
|
||||||
cpuid
|
|
||||||
movl %eax,0(%edi)
|
|
||||||
movl %ebx,4(%edi)
|
|
||||||
movl %ecx,8(%edi)
|
|
||||||
movl %edx,12(%edi)
|
|
||||||
popl %edi
|
|
||||||
popl %ebx
|
|
||||||
ret
|
|
||||||
|
|
||||||
FUNCTION(get_eflags):
|
|
||||||
pushfl
|
|
||||||
popl %eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
FUNCTION(set_eflags):
|
|
||||||
pushl 4(%esp)
|
|
||||||
popfl
|
|
||||||
ret
|
|
||||||
|
|
||||||
null_idt_descr:
|
null_idt_descr:
|
||||||
.word 0
|
.word 0
|
||||||
.word 0,0
|
.word 0,0
|
||||||
|
|||||||
@@ -103,12 +103,12 @@ setup_apic(kernel_args *args, int32 cpu)
|
|||||||
{
|
{
|
||||||
uint32 config;
|
uint32 config;
|
||||||
|
|
||||||
TRACE(("setting up the apic..."));
|
TRACE(("setting up the APIC for CPU %ld...\n", cpu));
|
||||||
|
|
||||||
/* set spurious interrupt vector to 0xff */
|
/* set spurious interrupt vector to 0xff */
|
||||||
config = apic_read(APIC_SIVR) & 0xffffff00;
|
config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00;
|
||||||
config |= APIC_ENABLE | 0xff;
|
config |= APIC_ENABLE | 0xff;
|
||||||
apic_write(APIC_SIVR, config);
|
apic_write(APIC_SPURIOUS_INTR_VECTOR, config);
|
||||||
|
|
||||||
// don't touch the LINT0/1 configuration in virtual wire mode
|
// don't touch the LINT0/1 configuration in virtual wire mode
|
||||||
// ToDo: implement support for other modes...
|
// ToDo: implement support for other modes...
|
||||||
@@ -124,32 +124,45 @@ setup_apic(kernel_args *args, int32 cpu)
|
|||||||
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
|
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
|
||||||
apic_write(APIC_LINT1, config);
|
apic_write(APIC_LINT1, config);
|
||||||
}
|
}
|
||||||
|
if (cpu > 0) {
|
||||||
|
dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0));
|
||||||
|
dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1));
|
||||||
|
|
||||||
|
/* disable LINT0/1 */
|
||||||
|
config = apic_read(APIC_LINT0);
|
||||||
|
apic_write(APIC_LINT0, config | APIC_LVT_MASKED);
|
||||||
|
|
||||||
|
config = apic_read(APIC_LINT1);
|
||||||
|
apic_write(APIC_LINT1, config | APIC_LVT_MASKED);
|
||||||
|
} else {
|
||||||
|
dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0));
|
||||||
|
dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* setup timer */
|
/* setup timer */
|
||||||
config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK;
|
config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
|
||||||
config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked
|
config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
|
||||||
apic_write(APIC_LVTT, config);
|
apic_write(APIC_LVT_TIMER, config);
|
||||||
|
|
||||||
apic_write(APIC_ICRT, 0); // zero out the clock
|
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
|
||||||
|
|
||||||
config = apic_read(APIC_TDCR) & ~0x0000000f;
|
config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
|
||||||
config |= APIC_TDCR_1; // clock division by 1
|
config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
|
||||||
apic_write(APIC_TDCR, config);
|
apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
|
||||||
|
|
||||||
/* setup error vector to 0xfe */
|
/* setup error vector to 0xfe */
|
||||||
config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe;
|
config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
|
||||||
apic_write(APIC_LVT3, config);
|
apic_write(APIC_LVT_ERROR, config);
|
||||||
|
|
||||||
/* accept all interrupts */
|
/* accept all interrupts */
|
||||||
config = apic_read(APIC_TPRI) & 0xffffff00;
|
config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00;
|
||||||
apic_write(APIC_TPRI, config);
|
apic_write(APIC_TASK_PRIORITY, config);
|
||||||
|
|
||||||
config = apic_read(APIC_SIVR);
|
config = apic_read(APIC_SPURIOUS_INTR_VECTOR);
|
||||||
apic_write(APIC_EOI, 0);
|
apic_write(APIC_EOI, 0);
|
||||||
|
|
||||||
TRACE((" done\n"));
|
return B_OK;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -203,9 +216,11 @@ arch_smp_send_broadcast_ici(void)
|
|||||||
uint32 config;
|
uint32 config;
|
||||||
cpu_status state = disable_interrupts();
|
cpu_status state = disable_interrupts();
|
||||||
|
|
||||||
config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK;
|
config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK;
|
||||||
apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELIVERY_MODE_FIXED
|
apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED
|
||||||
| APIC_ICR1_DEST_MODE_PHYSICAL | APIC_ICR1_DEST_ALL_BUT_SELF);
|
| APIC_INTR_COMMAND_1_ASSERT
|
||||||
|
| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
|
||||||
|
| APIC_INTR_COMMAND_1_DEST_ALL_BUT_SELF);
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
@@ -217,15 +232,17 @@ arch_smp_send_ici(int32 target_cpu)
|
|||||||
uint32 config;
|
uint32 config;
|
||||||
int state = disable_interrupts();
|
int state = disable_interrupts();
|
||||||
|
|
||||||
config = apic_read(APIC_ICR2) & APIC_ICR2_MASK;
|
config = apic_read(APIC_INTR_COMMAND_2) & APIC_INTR_COMMAND_2_MASK;
|
||||||
apic_write(APIC_ICR2, config | cpu_apic_id[target_cpu] << 24);
|
apic_write(APIC_INTR_COMMAND_2, config | cpu_apic_id[target_cpu] << 24);
|
||||||
|
|
||||||
config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK;
|
config = apic_read(APIC_INTR_COMMAND_1) & APIC_INTR_COMMAND_1_MASK;
|
||||||
apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELIVERY_MODE_FIXED
|
apic_write(APIC_INTR_COMMAND_1, config | 0xfd | APIC_DELIVERY_MODE_FIXED
|
||||||
| APIC_ICR1_DEST_MODE_PHYSICAL | APIC_ICR1_DEST_FIELD);
|
| APIC_INTR_COMMAND_1_ASSERT
|
||||||
|
| APIC_INTR_COMMAND_1_DEST_MODE_PHYSICAL
|
||||||
|
| APIC_INTR_COMMAND_1_DEST_FIELD);
|
||||||
|
|
||||||
// wait for message to be sent
|
// wait for message to be sent
|
||||||
while ((apic_read(APIC_ICR1) & APIC_ICR1_DELIVERY_STATUS) != 0)
|
while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) != 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
@@ -258,18 +275,18 @@ arch_smp_set_apic_timer(bigtime_t relativeTimeout)
|
|||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
|
|
||||||
config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer
|
config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||||
apic_write(APIC_LVTT, config);
|
apic_write(APIC_LVT_TIMER, config);
|
||||||
|
|
||||||
apic_write(APIC_ICRT, 0); // zero out the timer
|
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||||
|
|
||||||
config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer
|
config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer
|
||||||
apic_write(APIC_LVTT, config);
|
apic_write(APIC_LVT_TIMER, config);
|
||||||
|
|
||||||
TRACE(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
|
TRACE(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
|
||||||
config, relativeTimeout, apic_timer_tics_per_sec, ticks));
|
config, relativeTimeout, apic_timer_tics_per_sec, ticks));
|
||||||
|
|
||||||
apic_write(APIC_ICRT, ticks); // start it up
|
apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
@@ -288,13 +305,12 @@ arch_smp_clear_apic_timer(void)
|
|||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
|
|
||||||
config = apic_read(APIC_LVTT) | APIC_LVTT_M; // mask the timer
|
config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||||
apic_write(APIC_LVTT, config);
|
apic_write(APIC_LVT_TIMER, config);
|
||||||
|
|
||||||
apic_write(APIC_ICRT, 0); // zero out the timer
|
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ process_pending_ici(int32 currentCPU)
|
|||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
TRACE((" message = %d\n", msg->message));
|
TRACE((" cpu %d message = %d\n", curr_cpu, msg->message));
|
||||||
|
|
||||||
switch (msg->message) {
|
switch (msg->message) {
|
||||||
case SMP_MSG_INVL_PAGE_RANGE:
|
case SMP_MSG_INVL_PAGE_RANGE:
|
||||||
|
|||||||
Reference in New Issue
Block a user