diff --git a/repos/base-hw/lib/mk/spec/x86_pc/bootstrap-hw.mk b/repos/base-hw/lib/mk/spec/x86_pc/bootstrap-hw.mk
index fb1c93dce8..d7885e91c8 100644
--- a/repos/base-hw/lib/mk/spec/x86_pc/bootstrap-hw.mk
+++ b/repos/base-hw/lib/mk/spec/x86_pc/bootstrap-hw.mk
@@ -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
diff --git a/repos/base-hw/lib/mk/spec/x86_pc/core-hw.mk b/repos/base-hw/lib/mk/spec/x86_pc/core-hw.mk
index 55035f9223..d45685b2c1 100644
--- a/repos/base-hw/lib/mk/spec/x86_pc/core-hw.mk
+++ b/repos/base-hw/lib/mk/spec/x86_pc/core-hw.mk
@@ -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
diff --git a/repos/base-hw/ports/muen.hash b/repos/base-hw/ports/muen.hash
index f35ba7bb70..39590c03ad 100644
--- a/repos/base-hw/ports/muen.hash
+++ b/repos/base-hw/ports/muen.hash
@@ -1 +1 @@
-a4ce6a1f3bc1209e4c9f8ecf163d7af354c188af
+e51f0c9bfe99c284b3cf3bcf5fb81f7e9052f8a6
diff --git a/repos/base-hw/ports/muen.patch b/repos/base-hw/ports/muen.patch
new file mode 100644
index 0000000000..519f6f3e68
--- /dev/null
+++ b/repos/base-hw/ports/muen.patch
@@ -0,0 +1,10 @@
++++ src/kernel/muen/policy/xml/vcpu_subject_base_hw.xml
+@@ -9,7 +9,7 @@
+
+
+
+- 16#0020_0028#
++ 16#0020_0078#
+ 16#0000#
+
+
diff --git a/repos/base-hw/ports/muen.port b/repos/base-hw/ports/muen.port
index 65957e5e14..f75d8b251d 100644
--- a/repos/base-hw/ports/muen.port
+++ b/repos/base-hw/ports/muen.port
@@ -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)
diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s b/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s
index ae7be6c214..0e75f38c9f 100644
--- a/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s
+++ b/repos/base-hw/src/bootstrap/spec/x86_64/crt0.s
@@ -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
diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s b/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s
index 5906cf32f8..6fbde692ce 100644
--- a/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s
+++ b/repos/base-hw/src/bootstrap/spec/x86_64/crt0_translation_table.s
@@ -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
diff --git a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc
index 4ddc8c2057..927b60b39b 100644
--- a/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc
+++ b/repos/base-hw/src/bootstrap/spec/x86_64/platform.cc
@@ -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(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(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(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(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(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(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(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(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())
+ 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(apic_cpu_id);
+ lapic.write(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(&__bootstrap_stack);
+ addr_t const this_stack = reinterpret_cast(&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.write(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;
}
diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc
index 9828f9c9e1..6416537eed 100644
--- a/repos/base-hw/src/core/spec/x86_64/cpu.cc
+++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc
@@ -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(&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(&stack_ptr);
+ addr_t const stack_base = reinterpret_cast(&kernel_stack);
+ unsigned const cpu_id = (stack_addr - stack_base) / kernel_stack_size;
+ return cpu_id;
}
diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.h b/repos/base-hw/src/core/spec/x86_64/cpu.h
index 99deec7b48..fb58e2ffb9 100644
--- a/repos/base-hw/src/core/spec/x86_64/cpu.h
+++ b/repos/base-hw/src/core/spec/x86_64/cpu.h
@@ -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
diff --git a/repos/base-hw/src/core/spec/x86_64/crt0.s b/repos/base-hw/src/core/spec/x86_64/crt0.s
index d85f7f8d53..e7842bb7dc 100644
--- a/repos/base-hw/src/core/spec/x86_64/crt0.s
+++ b/repos/base-hw/src/core/spec/x86_64/crt0.s
@@ -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
diff --git a/repos/base-hw/src/core/spec/x86_64/exception_vector.s b/repos/base-hw/src/core/spec/x86_64/exception_vector.s
index ca9425ee5d..9e4799df63 100644
--- a/repos/base-hw/src/core/spec/x86_64/exception_vector.s
+++ b/repos/base-hw/src/core/spec/x86_64/exception_vector.s
@@ -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
diff --git a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc
index d657e2a489..a8aa0aafbc 100644
--- a/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc
+++ b/repos/base-hw/src/core/spec/x86_64/kernel/cpu.cc
@@ -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);
}
diff --git a/repos/base-hw/src/core/spec/x86_64/muen/pic.h b/repos/base-hw/src/core/spec/x86_64/muen/pic.h
index b603987453..580775d2c5 100644
--- a/repos/base-hw/src/core/spec/x86_64/muen/pic.h
+++ b/repos/base-hw/src/core/spec/x86_64/muen/pic.h
@@ -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:
diff --git a/repos/base-hw/src/core/spec/x86_64/pic.cc b/repos/base-hw/src/core/spec/x86_64/pic.cc
index 9d73374091..8182e15732 100644
--- a/repos/base-hw/src/core/spec/x86_64/pic.cc
+++ b/repos/base-hw/src/core/spec/x86_64/pic.cc
@@ -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())
+ 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);
+ write(icr_low);
+
+}
+
Ioapic::Irq_mode Ioapic::_irq_mode[IRQ_COUNT];
void Ioapic::setup_irq_mode(unsigned irq_number, unsigned trigger,
diff --git a/repos/base-hw/src/core/spec/x86_64/pic.h b/repos/base-hw/src/core/spec/x86_64/pic.h
index cfd7ef7002..71ecdb1eab 100644
--- a/repos/base-hw/src/core/spec/x86_64/pic.h
+++ b/repos/base-hw/src/core/spec/x86_64/pic.h
@@ -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();
+ 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; }
diff --git a/repos/base-hw/src/core/spec/x86_64/smp/cpu.cc b/repos/base-hw/src/core/spec/x86_64/smp/cpu.cc
new file mode 100644
index 0000000000..b370b7acca
--- /dev/null
+++ b/repos/base-hw/src/core/spec/x86_64/smp/cpu.cc
@@ -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
+#include
+#include
+
+/* base-internal includes */
+#include
+
+
+/* spin-lock used to synchronize kernel access of different cpus */
+Kernel::Lock & Kernel::data_lock() {
+ return *unmanaged_singleton(); }
diff --git a/repos/base/run/affinity.run b/repos/base/run/affinity.run
index aafc857511..729f7bb4e6 100644
--- a/repos/base/run/affinity.run
+++ b/repos/base/run/affinity.run
@@ -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]
} {
diff --git a/repos/base/run/mp_server.run b/repos/base/run/mp_server.run
index ef7cf987bd..b80993b206 100644
--- a/repos/base/run/mp_server.run
+++ b/repos/base/run/mp_server.run
@@ -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 "