From cf3ff17c5077afe7563ee137a9d99c294423be41 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 1 Aug 2018 15:46:06 +0200 Subject: [PATCH] hw/x86: enable SMP support Fixes #2929 --- .../lib/mk/spec/x86_pc/bootstrap-hw.mk | 2 + repos/base-hw/lib/mk/spec/x86_pc/core-hw.mk | 5 +- repos/base-hw/ports/muen.hash | 2 +- repos/base-hw/ports/muen.patch | 10 + repos/base-hw/ports/muen.port | 2 + .../base-hw/src/bootstrap/spec/x86_64/crt0.s | 144 +++++++---- .../spec/x86_64/crt0_translation_table.s | 29 ++- .../src/bootstrap/spec/x86_64/platform.cc | 229 ++++++++++++++---- repos/base-hw/src/core/spec/x86_64/cpu.cc | 19 ++ repos/base-hw/src/core/spec/x86_64/cpu.h | 9 +- repos/base-hw/src/core/spec/x86_64/crt0.s | 20 +- .../src/core/spec/x86_64/exception_vector.s | 22 +- .../src/core/spec/x86_64/kernel/cpu.cc | 1 + repos/base-hw/src/core/spec/x86_64/muen/pic.h | 1 + repos/base-hw/src/core/spec/x86_64/pic.cc | 24 +- repos/base-hw/src/core/spec/x86_64/pic.h | 31 ++- repos/base-hw/src/core/spec/x86_64/smp/cpu.cc | 25 ++ repos/base/run/affinity.run | 1 + repos/base/run/mp_server.run | 1 - 19 files changed, 462 insertions(+), 115 deletions(-) create mode 100644 repos/base-hw/ports/muen.patch create mode 100644 repos/base-hw/src/core/spec/x86_64/smp/cpu.cc 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 "