hw/x86: enable SMP support

Fixes #2929
This commit is contained in:
Alexander Boettcher 2018-08-01 15:46:06 +02:00 committed by Christian Helmuth
parent f0f473392d
commit cf3ff17c50
19 changed files with 462 additions and 115 deletions

View File

@ -6,4 +6,6 @@ SRC_S += bootstrap/spec/x86_64/crt0_translation_table.s
SRC_CC += hw/spec/64bit/memory_map.cc
NR_OF_CPUS = 32
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc

View File

@ -20,7 +20,6 @@ SRC_CC += spec/x86_64/kernel/thread_exception.cc
SRC_CC += spec/x86_64/platform_support.cc
SRC_CC += spec/x86/platform_services.cc
SRC_CC += kernel/kernel.cc
SRC_CC += spec/x86/io_port_session_component.cc
SRC_CC += spec/x86/io_port_session_support.cc
SRC_CC += spec/x86_64/bios_data_area.cc
@ -30,10 +29,14 @@ SRC_CC += spec/x86_64/kernel/cpu.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/kernel/thread.cc
SRC_CC += spec/x86_64/platform_support_common.cc
SRC_CC += spec/x86_64/smp/cpu.cc
SRC_CC += spec/64bit/memory_map.cc
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
NR_OF_CPUS = 32
# include less specific configuration
include $(BASE_DIR)/../base-hw/lib/mk/core-hw.inc
include $(BASE_DIR)/../base-hw/lib/mk/spec/smp/core-hw.inc

View File

@ -1 +1 @@
a4ce6a1f3bc1209e4c9f8ecf163d7af354c188af
e51f0c9bfe99c284b3cf3bcf5fb81f7e9052f8a6

View File

@ -0,0 +1,10 @@
+++ src/kernel/muen/policy/xml/vcpu_subject_base_hw.xml
@@ -9,7 +9,7 @@
</vmx>
<registers>
<gpr>
- <rip>16#0020_0028#</rip>
+ <rip>16#0020_0078#</rip>
<rsp>16#0000#</rsp>
</gpr>
</registers>

View File

@ -6,6 +6,8 @@ URL(muen) := https://git.codelabs.ch/git/muen.git
REV(muen) := 807cb0381e12329d84cb7e6b2f778b1e1559a2e8
DIR(muen) := src/kernel/muen
PATCHES := ports/muen.patch
$(call check_tool,git)
$(call check_tool,iasl)
$(call check_tool,tidy)

View File

@ -4,16 +4,19 @@
* \author Martin Stein
* \author Reto Buerki
* \author Stefan Kalkowski
* \author Alexander Boettcher
* \date 2015-02-06
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
.set STACK_SIZE, 4096
.section ".text.crt0"
/* magic multi-boot 1 header */
@ -34,9 +37,55 @@
.long 0x8
__mbi2_end:
/**********************************
** Startup code for primary CPU **
**********************************/
.macro SETUP_PAGING
/* Enable PAE (prerequisite for IA-32e mode) */
movl $0x20, %eax
movl %eax, %cr4
/* Enable IA-32e mode and execute-disable */
movl $0xc0000080, %ecx
rdmsr
btsl $8, %eax
btsl $11, %eax
wrmsr
/* Enable paging, write protection and caching */
xorl %eax, %eax
btsl $0, %eax /* protected mode */
btsl $16, %eax /* write protect */
btsl $31, %eax /* paging */
movl %eax, %cr0
.endm
/*******************************************************************
** Startup code for non-primary CPU (AP - application processor) **
*******************************************************************/
.code16
.global _ap
_ap:
/* Load initial pagetables */
mov $_kernel_pml4, %eax
mov %eax, %cr3
/* setup paging */
SETUP_PAGING
/* setup GDT */
lgdtl %cs:__gdt - _ap
ljmpl $8, $_start64
__gdt:
.word 55
.long __gdt_start
/**************************************************************
** Startup code for primary CPU (bootstrap processor - BSP) **
**************************************************************/
.code32
.global _start
@ -55,40 +104,30 @@
xor %eax, %eax
rep stosl
/* Enable PAE (prerequisite for IA-32e mode) */
movl %cr4, %eax
btsl $5, %eax
movl %eax, %cr4
/* Load initial pagetables */
leal _kernel_pml4, %eax
mov %eax, %cr3
/* Enable IA-32e mode and execute-disable */
movl $0xc0000080, %ecx
rdmsr
btsl $8, %eax
btsl $11, %eax
wrmsr
/* setup paging */
SETUP_PAGING
/* Enable paging, write protection and caching */
movl %cr0, %eax
btsl $16, %eax
btrl $29, %eax
btrl $30, %eax
btsl $31, %eax
movl %eax, %cr0
/* Set up GDT */
movl $__gdt_ptr+2, %eax
movl $__gdt_start, (%eax)
/* setup GDT */
lgdt __gdt_ptr
/* Indirect long jump to 64-bit code */
ljmp $8, $_start64
ljmp $8, $_start64_bsp
.code64
_start64_bsp:
/* save rax & rbx, used to lookup multiboot structures */
movq __initial_ax@GOTPCREL(%rip),%rax
movq %rsi, (%rax)
movq __initial_bx@GOTPCREL(%rip),%rax
movq %rbx, (%rax)
_start64:
/*
@ -99,26 +138,38 @@
mov %eax, %fs
mov %eax, %gs
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leaq _stack_high@GOTPCREL(%rip),%rax
/* increment CPU counter atomically */
movq __cpus_booted@GOTPCREL(%rip),%rax
movq $1, %rcx
lock xaddq %rcx, (%rax)
/* if more CPUs started than supported, then stop them */
cmp $NR_OF_CPUS, %rcx
jge 1f
/* calculate stack depending on CPU counter */
movq $STACK_SIZE, %rax
inc %rcx
mulq %rcx
movq %rax, %rcx
subq $8, %rcx
leaq __bootstrap_stack@GOTPCREL(%rip),%rax
movq (%rax), %rsp
movq __initial_ax@GOTPCREL(%rip),%rax
movq %rsi, (%rax)
movq __initial_bx@GOTPCREL(%rip),%rax
movq %rbx, (%rax)
addq %rcx, %rsp
/* kernel-initialization */
call init
/* catch erroneous return of the kernel initialization */
1: jmp 1b
1:
hlt
jmp 1b
.global bootstrap_stack_size
bootstrap_stack_size:
.quad STACK_SIZE
/******************************************
** Global Descriptor Table (GDT) **
** See Intel SDM Vol. 3A, section 3.5.1 **
@ -128,7 +179,7 @@
.space 2
__gdt_ptr:
.word 55 /* limit */
.long 0 /* base address */
.long __gdt_start /* base address */
.set TSS_LIMIT, 0x68
.set TSS_TYPE, 0x8900
@ -171,12 +222,19 @@
.bss
/* stack of the temporary initial environment */
.p2align 8
.space 32 * 1024
_stack_high:
.p2align 12
.globl __bootstrap_stack
__bootstrap_stack:
.rept NR_OF_CPUS
.space STACK_SIZE
.endr
.globl __initial_ax
__initial_ax:
.space 8
.globl __initial_bx
__initial_bx:
.space 8
.globl __cpus_booted
__cpus_booted:
.quad 0

View File

@ -34,14 +34,15 @@
/* PDP */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pdp:
.quad _kernel_pd + 0xf
.fill 2, 8, 0x0
.quad _kernel_pd_503 + 0xf
.quad _kernel_pd_0 + 0xf
.fill 1, 8, 0x0
.quad _kernel_pd_2 + 0xf
.quad _kernel_pd_3 + 0xf
.fill 508, 8, 0x0
/* PD */
/* PD [0G-1G) */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd:
_kernel_pd_0:
.quad _kernel_pt_bda + 0xf
.set entry, 0x20018f
.rept 511
@ -49,9 +50,23 @@
.set entry, entry + 0x200000
.endr
/* PD [2G-3G) */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd_503:
.fill 502, 8, 0x0
_kernel_pd_2:
.set entry, 0x8000018f
.rept 512
.quad entry
.set entry, entry + 0x200000
.endr
/* PD [3G-4G) */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd_3:
.set entry, 0xc000018f
.rept 502
.quad entry
.set entry, entry + 0x200000
.endr
.quad 0xfec0019f
.quad 0xfee0019f
.fill 8, 8, 0x0

View File

@ -2,11 +2,12 @@
* \brief Platform implementations specific for x86_64
* \author Reto Buerki
* \author Stefan Kalkowski
* \author Alexander Boettcher
* \date 2015-05-04
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
* Copyright (C) 2015-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -27,6 +28,39 @@ extern "C" Genode::addr_t __initial_ax;
/* contains physical pointer to multiboot */
extern "C" Genode::addr_t __initial_bx;
/* pointer to stack base */
extern "C" Genode::addr_t __bootstrap_stack;
/* number of booted CPUs */
extern "C" Genode::addr_t __cpus_booted;
/* stack size per CPU */
extern "C" Genode::addr_t const bootstrap_stack_size;
/* hardcoded physical page or AP CPUs boot code */
enum { AP_BOOT_CODE_PAGE = 0x1000 };
extern "C" void * _start;
extern "C" void * _ap;
static Hw::Acpi_rsdp search_rsdp(addr_t area, addr_t area_size)
{
if (area && area_size && area < area + area_size) {
for (addr_t addr = 0; addr + sizeof(Hw::Acpi_rsdp) <= area_size;
addr += sizeof(Hw::Acpi_rsdp::signature))
{
Hw::Acpi_rsdp * rsdp = reinterpret_cast<Hw::Acpi_rsdp *>(area + addr);
if (rsdp->valid())
return *rsdp;
}
}
Hw::Acpi_rsdp invalid;
return invalid;
}
Bootstrap::Platform::Board::Board()
: core_mmio(Memory_region { 0, 0x1000 },
Memory_region { Hw::Cpu_memory_map::lapic_phys_base(), 0x1000 },
@ -97,67 +131,178 @@ Bootstrap::Platform::Board::Board()
lambda(base, size);
}
/* search ACPI RSDP pointer at known places */
/* BIOS range to scan for */
enum { BIOS_BASE = 0xe0000, BIOS_SIZE = 0x20000 };
acpi_rsdp = search_rsdp(BIOS_BASE, BIOS_SIZE);
if (!acpi_rsdp.valid()) {
/* page 0 is remapped to 2M - 4k - see crt_translation table */
addr_t const bios_addr = 2 * 1024 * 1024 - 4096;
/* search EBDA (BIOS addr + 0x40e) */
addr_t ebda_phys = (*reinterpret_cast<uint16_t *>(bios_addr + 0x40e)) << 4;
if (ebda_phys < 0x1000)
ebda_phys = bios_addr;
acpi_rsdp = search_rsdp(ebda_phys, 0x1000 /* EBDA size */);
}
} else {
error("invalid multiboot magic value: ", Hex(__initial_ax));
}
if (!acpi_rsdp.valid())
return;
uint64_t const table_addr = acpi_rsdp.xsdt ? acpi_rsdp.xsdt : acpi_rsdp.rsdt;
if (!table_addr)
return;
/* find out the number of available CPUs */
/* remember max supported CPUs and use ACPI to get the actual number */
unsigned const max_cpus = cpus;
cpus = 0;
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_addr);
if (!memcmp(table->signature, "RSDT", 4)) {
Hw::for_each_rsdt_entry(*table, [&](uint32_t paddr_table) {
addr_t const table_virt_addr = paddr_table;
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_virt_addr);
/* scan ACPI tables to find out number of CPUs in this machine */
if (acpi_rsdp.valid()) {
uint64_t const table_addr = acpi_rsdp.xsdt ? acpi_rsdp.xsdt : acpi_rsdp.rsdt;
if (memcmp(table->signature, "APIC", 4))
return;
if (table_addr) {
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_addr);
if (!memcmp(table->signature, "RSDT", 4)) {
Hw::for_each_rsdt_entry(*table, [&](uint32_t paddr_table) {
addr_t const table_virt_addr = paddr_table;
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_virt_addr);
Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){
if (e->type == Hw::Apic_madt::LAPIC) {
Hw::Apic_madt::Lapic lapic(e);
cpus ++;
}
});
});
} else if (!memcmp(table->signature, "XSDT", 4)) {
Hw::for_each_xsdt_entry(*table, [&](uint64_t paddr_table) {
addr_t const table_virt_addr = paddr_table;
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_virt_addr);
if (memcmp(table->signature, "APIC", 4))
return;
if (memcmp(table->signature, "APIC", 4))
return;
Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){
if (e->type == Hw::Apic_madt::LAPIC) {
Hw::Apic_madt::Lapic lapic(e);
cpus ++;
}
});
});
} else if (!memcmp(table->signature, "XSDT", 4)) {
Hw::for_each_xsdt_entry(*table, [&](uint64_t paddr_table) {
addr_t const table_virt_addr = paddr_table;
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_virt_addr);
Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){
if (e->type == Hw::Apic_madt::LAPIC) {
Hw::Apic_madt::Lapic lapic(e);
cpus ++;
}
});
});
} else
Genode::error("unknown table signature");
if (memcmp(table->signature, "APIC", 4))
return;
Hw::for_each_apic_struct(*table,[&](Hw::Apic_madt const *e){
if (e->type == Hw::Apic_madt::LAPIC) {
Hw::Apic_madt::Lapic lapic(e);
cpus ++;
}
});
});
}
}
}
if (!cpus || cpus > max_cpus) {
Genode::warning("CPU count is unsupported ", cpus, "/", max_cpus);
cpus = max_cpus;
Genode::warning("CPU count is unsupported ", cpus, "/", max_cpus,
acpi_rsdp.valid() ? " - invalid or missing RSDT/XSDT"
: " - invalid RSDP");
cpus = !cpus ? 1 : max_cpus;
}
if (cpus > 1) {
/* copy 16 bit boot code for AP CPUs */
addr_t ap_code_size = (addr_t)&_start - (addr_t)&_ap;
memcpy((void *)AP_BOOT_CODE_PAGE, &_ap, ap_code_size);
}
}
struct Lapic : Mmio
{
struct Svr : Register<0x0f0, 32>
{
struct APIC_enable : Bitfield<8, 1> { };
};
struct Icr_low : Register<0x300, 32> {
struct Vector : Bitfield< 0, 8> { };
struct Delivery_mode : Bitfield< 8, 3> {
enum Mode { INIT = 5, SIPI = 6 };
};
struct Delivery_status : Bitfield<12, 1> { };
struct Level_assert : Bitfield<14, 1> { };
struct Dest_shorthand : Bitfield<18, 2> {
enum { ALL_OTHERS = 3 };
};
};
struct Icr_high : Register<0x310, 32> {
struct Destination : Bitfield<24, 8> { };
};
Lapic(addr_t const addr) : Mmio(addr) { }
};
static inline Genode::uint64_t rdtsc()
{
Genode::uint32_t lo, hi;
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (Genode::uint64_t)hi << 32 | lo;
}
static inline void ipi_to_all(Lapic &lapic, unsigned const boot_frame,
Lapic::Icr_low::Delivery_mode::Mode const mode)
{
/* wait until ready */
while (lapic.read<Lapic::Icr_low::Delivery_status>())
asm volatile ("pause":::"memory");
unsigned const apic_cpu_id = 0; /* unused for IPI to all */
Lapic::Icr_low::access_t icr_low = 0;
Lapic::Icr_low::Vector::set(icr_low, boot_frame);
Lapic::Icr_low::Delivery_mode::set(icr_low, mode);
Lapic::Icr_low::Level_assert::set(icr_low);
Lapic::Icr_low::Level_assert::set(icr_low);
Lapic::Icr_low::Dest_shorthand::set(icr_low, Lapic::Icr_low::Dest_shorthand::ALL_OTHERS);
/* program */
lapic.write<Lapic::Icr_high::Destination>(apic_cpu_id);
lapic.write<Lapic::Icr_low>(icr_low);
}
unsigned Bootstrap::Platform::enable_mmu()
{
Cpu::Cr3::write(Cpu::Cr3::Pdb::masked((addr_t)core_pd->table_base));
return 0;
addr_t const stack_base = reinterpret_cast<addr_t>(&__bootstrap_stack);
addr_t const this_stack = reinterpret_cast<addr_t>(&stack_base);
addr_t const cpu_id = (this_stack - stack_base) / bootstrap_stack_size;
/* we like to use local APIC */
Cpu::IA32_apic_base::access_t lapic_msr = Cpu::IA32_apic_base::read();
Cpu::IA32_apic_base::Lapic::set(lapic_msr);
Cpu::IA32_apic_base::write(lapic_msr);
/* skip the SMP when ACPI parsing did not reveal the number of CPUs */
if (board.cpus <= 1)
return cpu_id;
Lapic lapic(board.core_mmio.virt_addr(Hw::Cpu_memory_map::lapic_phys_base()));
/* enable local APIC if required */
if (!lapic.read<Lapic::Svr::APIC_enable>())
lapic.write<Lapic::Svr::APIC_enable>(true);
if (!Cpu::IA32_apic_base::Bsp::get(lapic_msr))
/* AP - done */
return cpu_id;
/* BSP - we're primary CPU - wake now all other CPUs */
/* see Intel Multiprocessor documentation - we need to do INIT-SIPI-SIPI */
ipi_to_all(lapic, 0 /* unused */, Lapic::Icr_low::Delivery_mode::INIT);
/* wait 10 ms - debates ongoing whether this is still required */
ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, Lapic::Icr_low::Delivery_mode::SIPI);
/* wait 200 us - debates ongoing whether this is still required */
/* debates ongoing whether the second SIPI is still required */
ipi_to_all(lapic, AP_BOOT_CODE_PAGE >> 12, Lapic::Icr_low::Delivery_mode::SIPI);
return cpu_id;
}

View File

@ -105,6 +105,10 @@ void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault)
}
extern void const * const kernel_stack;
extern Genode::size_t const kernel_stack_size;
void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
{
_fpu.switch_to(context);
@ -113,4 +117,19 @@ void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
Cr3::write(mmu_context.cr3);
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
context.kernel_stack = stack_base +
(Cpu::executing_id() + 1) * kernel_stack_size -
sizeof(addr_t);
}
unsigned Genode::Cpu::executing_id()
{
void * const stack_ptr = nullptr;
addr_t const stack_addr = reinterpret_cast<addr_t>(&stack_ptr);
addr_t const stack_base = reinterpret_cast<addr_t>(&kernel_stack);
unsigned const cpu_id = (stack_addr - stack_base) / kernel_stack_size;
return cpu_id;
}

View File

@ -92,7 +92,10 @@ class Genode::Cpu : public Hw::X86_64_cpu
/**
* Extend basic CPU state by members relevant for 'base-hw' only
*/
struct alignas(16) Context : Cpu_state, Fpu::Context
struct Kernel_stack { unsigned long kernel_stack { }; };
/* exception_vector.s depends on the position of the Kernel_stack */
struct alignas(16) Context : Cpu_state, Kernel_stack, Fpu::Context
{
enum Eflags {
EFLAGS_IF_SET = 1 << 9,
@ -100,7 +103,7 @@ class Genode::Cpu : public Hw::X86_64_cpu
};
Context(bool privileged);
};
} __attribute__((packed));
struct Mmu_context
@ -121,7 +124,7 @@ class Genode::Cpu : public Hw::X86_64_cpu
/**
* Return kernel name of the executing CPU
*/
static unsigned executing_id() { return 0; }
static unsigned executing_id();
/**
* Return kernel name of the primary CPU

View File

@ -2,11 +2,12 @@
* \brief Startup code for Genode 64Bit applications
* \author Sebastian Sumpf
* \author Martin Stein
* \author Alexander Boettcher
* \date 2011-05-11
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2011-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -21,11 +22,20 @@
.global _start
_start:
/* load kernel stack size */
movq kernel_stack_size@GOTPCREL(%rip), %rbx
movq (%rbx), %rax
/* calculate stack top (rdi contains cpu_id), stack top is stored in rax */
movq %rdi, %rbx
inc %rbx
mulq %rbx
/* switch to kernel stack */
mov kernel_stack@GOTPCREL(%rip), %rax
mov kernel_stack_size@GOTPCREL(%rip), %rbx
add (%rbx), %rax
mov %rax, %rsp
movq kernel_stack@GOTPCREL(%rip), %rbx
addq %rbx, %rax
subq $8, %rax
movq %rax, %rsp
/* jump to C entry code */
jmp kernel_init

View File

@ -111,12 +111,22 @@
pushq %r9
pushq %r8
/**
* Calculate offset into Kernel_stack member of Cpu::Context as defined
* in cpu.h - struct Context : Cpu_state, Kernel_stack, Fpu_context
*/
.set REGISTER_COUNT, 22
.set REGISTER_SIZE, 8
.set SIZEOF_CPU_STATE, REGISTER_COUNT * REGISTER_SIZE /* sizeof (Cpu_state) */
.set KERNEL_STACK_OFFSET, SIZEOF_CPU_STATE
/* rsp contains pointer to Cpu::Context */
/* Restore kernel stack and continue kernel execution */
_load_address kernel_stack rax
_load_address kernel_stack_size rbx
movq %rsp, %rax
addq $KERNEL_STACK_OFFSET, %rax
movq (%rax), %rsp
_load_address kernel rcx
add (%rbx), %rax
mov %rax, %rsp
jmp *%rcx
@ -159,5 +169,7 @@
.global idle_thread_main
idle_thread_main:
pause
sti
hlt
cli
jmp idle_thread_main

View File

@ -30,6 +30,7 @@ void Kernel::Cpu::init(Pic &pic)
/* enable timer interrupt */
unsigned const cpu = Cpu::executing_id();
pic.store_apic_id(cpu);
pic.unmask(_timer.interrupt_id(), cpu);
}

View File

@ -62,6 +62,7 @@ class Genode::Pic
void mask(unsigned const) { }
bool is_ip_interrupt(unsigned, unsigned) { return false; }
void trigger_ip_interrupt(unsigned) { }
void store_apic_id(unsigned const) { }
private:

View File

@ -2,11 +2,12 @@
* \brief Programmable interrupt controller for core
* \author Adrian-Ken Rueegsegger
* \author Reto Buerki
* \author Alexander Boettcher
* \date 2015-02-17
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
* Copyright (C) 2015-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -23,6 +24,8 @@
using namespace Genode;
uint8_t Pic::lapic_ids[NR_OF_CPUS];
enum {
PIC_CMD_MASTER = 0x20,
PIC_CMD_SLAVE = 0xa0,
@ -99,6 +102,25 @@ inline unsigned Pic::get_lowest_bit(void)
return 0;
}
void Pic::send_ipi(unsigned const cpu_id) {
while (read<Icr_low::Delivery_status>())
asm volatile("pause" : : : "memory");
Icr_high::access_t icr_high = 0;
Icr_low::access_t icr_low = 0;
Icr_high::Destination::set(icr_high, lapic_ids[cpu_id]);
Icr_low::Vector::set(icr_low, Pic::IPI);
Icr_low::Level_assert::set(icr_low);
/* program */
write<Icr_high>(icr_high);
write<Icr_low>(icr_low);
}
Ioapic::Irq_mode Ioapic::_irq_mode[IRQ_COUNT];
void Ioapic::setup_irq_mode(unsigned irq_number, unsigned trigger,

View File

@ -1,11 +1,12 @@
/*
* \brief Programmable interrupt controller for core
* \author Reto Buerki
* \author Alexander Boettcher
* \date 2015-02-17
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
* Copyright (C) 2015-2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -142,6 +143,7 @@ class Genode::Pic : public Mmio
* Registers
*/
struct Id : Register<0x020, 32> { };
struct EOI : Register<0x0b0, 32, true> { };
struct Svr : Register<0x0f0, 32>
{
@ -155,6 +157,18 @@ class Genode::Pic : public Mmio
*/
struct Isr : Register_array<0x100, 32, 8 * 4, 32> { };
/*
* Interrupt control register
*/
struct Icr_low : Register<0x300, 32, true> {
struct Vector : Bitfield< 0, 8> { };
struct Delivery_status : Bitfield<12, 1> { };
struct Level_assert : Bitfield<14, 1> { };
};
struct Icr_high : Register<0x310, 32, true> {
struct Destination : Bitfield<24, 8> { };
};
/**
* Determine lowest pending interrupt in ISR register
*
@ -163,6 +177,11 @@ class Genode::Pic : public Mmio
*/
inline unsigned get_lowest_bit(void);
/**
* Mapping of our logical boot CPUs to the local APIC IDs
*/
static uint8_t lapic_ids[NR_OF_CPUS];
public:
enum {
@ -190,12 +209,12 @@ class Genode::Pic : public Mmio
void mask(unsigned const i);
/*
* Dummies
*/
void store_apic_id(unsigned const cpu_id) {
Id::access_t const lapic_id = read<Id>();
lapic_ids[cpu_id] = (lapic_id >> 24) & 0xff;
}
bool is_ip_interrupt(unsigned, unsigned) { return false; }
void trigger_ip_interrupt(unsigned) { }
void send_ipi(unsigned const);
};
namespace Kernel { using Genode::Pic; }

View File

@ -0,0 +1,25 @@
/*
* \brief Cpu class implementation specific to SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* core includes */
#include <kernel/lock.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* spin-lock used to synchronize kernel access of different cpus */
Kernel::Lock & Kernel::data_lock() {
return *unmanaged_singleton<Kernel::Lock>(); }

View File

@ -11,6 +11,7 @@ if {
![expr [have_spec zynq] && ![have_spec zynq_qemu] ] &&
![expr [have_spec x86_32] && [have_spec foc] ] &&
![expr [have_spec x86_64] && [have_spec foc] ] &&
![expr [have_spec x86_64] && [have_spec hw] ] &&
![have_spec nova] &&
![have_spec sel4]
} {

View File

@ -40,7 +40,6 @@ if {[have_include "power_on/qemu"]} {
if {[have_spec okl4]} { set want_cpus 1 }
if {[have_spec pistachio]} { set want_cpus 1 }
if {[have_spec fiasco]} { set want_cpus 1 }
if {([have_spec x86_64] && [have_spec hw])} { set want_cpus 1 }
if {[have_spec zynq]} { set want_cpus 1 }
append qemu_args " -nographic -smp $want_cpus,cores=$want_cpus "