mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 15:02:25 +00:00
parent
f0f473392d
commit
cf3ff17c50
@ -6,4 +6,6 @@ SRC_S += bootstrap/spec/x86_64/crt0_translation_table.s
|
|||||||
|
|
||||||
SRC_CC += hw/spec/64bit/memory_map.cc
|
SRC_CC += hw/spec/64bit/memory_map.cc
|
||||||
|
|
||||||
|
NR_OF_CPUS = 32
|
||||||
|
|
||||||
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
||||||
|
@ -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_64/platform_support.cc
|
||||||
SRC_CC += spec/x86/platform_services.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_component.cc
|
||||||
SRC_CC += spec/x86/io_port_session_support.cc
|
SRC_CC += spec/x86/io_port_session_support.cc
|
||||||
SRC_CC += spec/x86_64/bios_data_area.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/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/platform_support_common.cc
|
||||||
|
SRC_CC += spec/x86_64/smp/cpu.cc
|
||||||
|
|
||||||
SRC_CC += spec/64bit/memory_map.cc
|
SRC_CC += spec/64bit/memory_map.cc
|
||||||
|
|
||||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||||
|
|
||||||
|
NR_OF_CPUS = 32
|
||||||
|
|
||||||
# include less specific configuration
|
# include less specific configuration
|
||||||
include $(BASE_DIR)/../base-hw/lib/mk/core-hw.inc
|
include $(BASE_DIR)/../base-hw/lib/mk/core-hw.inc
|
||||||
|
include $(BASE_DIR)/../base-hw/lib/mk/spec/smp/core-hw.inc
|
||||||
|
@ -1 +1 @@
|
|||||||
a4ce6a1f3bc1209e4c9f8ecf163d7af354c188af
|
e51f0c9bfe99c284b3cf3bcf5fb81f7e9052f8a6
|
||||||
|
10
repos/base-hw/ports/muen.patch
Normal file
10
repos/base-hw/ports/muen.patch
Normal 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>
|
@ -6,6 +6,8 @@ URL(muen) := https://git.codelabs.ch/git/muen.git
|
|||||||
REV(muen) := 807cb0381e12329d84cb7e6b2f778b1e1559a2e8
|
REV(muen) := 807cb0381e12329d84cb7e6b2f778b1e1559a2e8
|
||||||
DIR(muen) := src/kernel/muen
|
DIR(muen) := src/kernel/muen
|
||||||
|
|
||||||
|
PATCHES := ports/muen.patch
|
||||||
|
|
||||||
$(call check_tool,git)
|
$(call check_tool,git)
|
||||||
$(call check_tool,iasl)
|
$(call check_tool,iasl)
|
||||||
$(call check_tool,tidy)
|
$(call check_tool,tidy)
|
||||||
|
@ -4,16 +4,19 @@
|
|||||||
* \author Martin Stein
|
* \author Martin Stein
|
||||||
* \author Reto Buerki
|
* \author Reto Buerki
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2015-02-06
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.set STACK_SIZE, 4096
|
||||||
|
|
||||||
.section ".text.crt0"
|
.section ".text.crt0"
|
||||||
|
|
||||||
/* magic multi-boot 1 header */
|
/* magic multi-boot 1 header */
|
||||||
@ -34,9 +37,55 @@
|
|||||||
.long 0x8
|
.long 0x8
|
||||||
__mbi2_end:
|
__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
|
.code32
|
||||||
.global _start
|
.global _start
|
||||||
@ -55,40 +104,30 @@
|
|||||||
xor %eax, %eax
|
xor %eax, %eax
|
||||||
rep stosl
|
rep stosl
|
||||||
|
|
||||||
/* Enable PAE (prerequisite for IA-32e mode) */
|
|
||||||
movl %cr4, %eax
|
|
||||||
btsl $5, %eax
|
|
||||||
movl %eax, %cr4
|
|
||||||
|
|
||||||
/* Load initial pagetables */
|
/* Load initial pagetables */
|
||||||
leal _kernel_pml4, %eax
|
leal _kernel_pml4, %eax
|
||||||
mov %eax, %cr3
|
mov %eax, %cr3
|
||||||
|
|
||||||
/* Enable IA-32e mode and execute-disable */
|
/* setup paging */
|
||||||
movl $0xc0000080, %ecx
|
SETUP_PAGING
|
||||||
rdmsr
|
|
||||||
btsl $8, %eax
|
|
||||||
btsl $11, %eax
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
/* Enable paging, write protection and caching */
|
/* setup GDT */
|
||||||
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)
|
|
||||||
lgdt __gdt_ptr
|
lgdt __gdt_ptr
|
||||||
|
|
||||||
/* Indirect long jump to 64-bit code */
|
/* Indirect long jump to 64-bit code */
|
||||||
ljmp $8, $_start64
|
ljmp $8, $_start64_bsp
|
||||||
|
|
||||||
|
|
||||||
.code64
|
.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:
|
_start64:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -99,26 +138,38 @@
|
|||||||
mov %eax, %fs
|
mov %eax, %fs
|
||||||
mov %eax, %gs
|
mov %eax, %gs
|
||||||
|
|
||||||
/*
|
/* increment CPU counter atomically */
|
||||||
* Install initial temporary environment that is replaced later by the
|
movq __cpus_booted@GOTPCREL(%rip),%rax
|
||||||
* environment that init_main_thread creates.
|
movq $1, %rcx
|
||||||
*/
|
lock xaddq %rcx, (%rax)
|
||||||
leaq _stack_high@GOTPCREL(%rip),%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 (%rax), %rsp
|
||||||
|
addq %rcx, %rsp
|
||||||
movq __initial_ax@GOTPCREL(%rip),%rax
|
|
||||||
movq %rsi, (%rax)
|
|
||||||
|
|
||||||
movq __initial_bx@GOTPCREL(%rip),%rax
|
|
||||||
movq %rbx, (%rax)
|
|
||||||
|
|
||||||
/* kernel-initialization */
|
/* kernel-initialization */
|
||||||
call init
|
call init
|
||||||
|
|
||||||
/* catch erroneous return of the kernel initialization */
|
/* 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) **
|
** Global Descriptor Table (GDT) **
|
||||||
** See Intel SDM Vol. 3A, section 3.5.1 **
|
** See Intel SDM Vol. 3A, section 3.5.1 **
|
||||||
@ -128,7 +179,7 @@
|
|||||||
.space 2
|
.space 2
|
||||||
__gdt_ptr:
|
__gdt_ptr:
|
||||||
.word 55 /* limit */
|
.word 55 /* limit */
|
||||||
.long 0 /* base address */
|
.long __gdt_start /* base address */
|
||||||
|
|
||||||
.set TSS_LIMIT, 0x68
|
.set TSS_LIMIT, 0x68
|
||||||
.set TSS_TYPE, 0x8900
|
.set TSS_TYPE, 0x8900
|
||||||
@ -171,12 +222,19 @@
|
|||||||
.bss
|
.bss
|
||||||
|
|
||||||
/* stack of the temporary initial environment */
|
/* stack of the temporary initial environment */
|
||||||
.p2align 8
|
.p2align 12
|
||||||
.space 32 * 1024
|
.globl __bootstrap_stack
|
||||||
_stack_high:
|
__bootstrap_stack:
|
||||||
|
.rept NR_OF_CPUS
|
||||||
|
.space STACK_SIZE
|
||||||
|
.endr
|
||||||
|
|
||||||
.globl __initial_ax
|
.globl __initial_ax
|
||||||
__initial_ax:
|
__initial_ax:
|
||||||
.space 8
|
.space 8
|
||||||
.globl __initial_bx
|
.globl __initial_bx
|
||||||
__initial_bx:
|
__initial_bx:
|
||||||
.space 8
|
.space 8
|
||||||
|
.globl __cpus_booted
|
||||||
|
__cpus_booted:
|
||||||
|
.quad 0
|
||||||
|
@ -34,14 +34,15 @@
|
|||||||
/* PDP */
|
/* PDP */
|
||||||
.p2align MIN_PAGE_SIZE_LOG2
|
.p2align MIN_PAGE_SIZE_LOG2
|
||||||
_kernel_pdp:
|
_kernel_pdp:
|
||||||
.quad _kernel_pd + 0xf
|
.quad _kernel_pd_0 + 0xf
|
||||||
.fill 2, 8, 0x0
|
.fill 1, 8, 0x0
|
||||||
.quad _kernel_pd_503 + 0xf
|
.quad _kernel_pd_2 + 0xf
|
||||||
|
.quad _kernel_pd_3 + 0xf
|
||||||
.fill 508, 8, 0x0
|
.fill 508, 8, 0x0
|
||||||
|
|
||||||
/* PD */
|
/* PD [0G-1G) */
|
||||||
.p2align MIN_PAGE_SIZE_LOG2
|
.p2align MIN_PAGE_SIZE_LOG2
|
||||||
_kernel_pd:
|
_kernel_pd_0:
|
||||||
.quad _kernel_pt_bda + 0xf
|
.quad _kernel_pt_bda + 0xf
|
||||||
.set entry, 0x20018f
|
.set entry, 0x20018f
|
||||||
.rept 511
|
.rept 511
|
||||||
@ -49,9 +50,23 @@
|
|||||||
.set entry, entry + 0x200000
|
.set entry, entry + 0x200000
|
||||||
.endr
|
.endr
|
||||||
|
|
||||||
|
/* PD [2G-3G) */
|
||||||
.p2align MIN_PAGE_SIZE_LOG2
|
.p2align MIN_PAGE_SIZE_LOG2
|
||||||
_kernel_pd_503:
|
_kernel_pd_2:
|
||||||
.fill 502, 8, 0x0
|
.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 0xfec0019f
|
||||||
.quad 0xfee0019f
|
.quad 0xfee0019f
|
||||||
.fill 8, 8, 0x0
|
.fill 8, 8, 0x0
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
* \brief Platform implementations specific for x86_64
|
* \brief Platform implementations specific for x86_64
|
||||||
* \author Reto Buerki
|
* \author Reto Buerki
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2015-05-04
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* 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 */
|
/* contains physical pointer to multiboot */
|
||||||
extern "C" Genode::addr_t __initial_bx;
|
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()
|
Bootstrap::Platform::Board::Board()
|
||||||
: core_mmio(Memory_region { 0, 0x1000 },
|
: core_mmio(Memory_region { 0, 0x1000 },
|
||||||
Memory_region { Hw::Cpu_memory_map::lapic_phys_base(), 0x1000 },
|
Memory_region { Hw::Cpu_memory_map::lapic_phys_base(), 0x1000 },
|
||||||
@ -97,22 +131,37 @@ Bootstrap::Platform::Board::Board()
|
|||||||
|
|
||||||
lambda(base, size);
|
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 {
|
} else {
|
||||||
error("invalid multiboot magic value: ", Hex(__initial_ax));
|
error("invalid multiboot magic value: ", Hex(__initial_ax));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acpi_rsdp.valid())
|
/* remember max supported CPUs and use ACPI to get the actual number */
|
||||||
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 */
|
|
||||||
unsigned const max_cpus = cpus;
|
unsigned const max_cpus = cpus;
|
||||||
cpus = 0;
|
cpus = 0;
|
||||||
|
|
||||||
|
/* 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 (table_addr) {
|
||||||
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_addr);
|
Hw::Acpi_generic * table = reinterpret_cast<Hw::Acpi_generic *>(table_addr);
|
||||||
if (!memcmp(table->signature, "RSDT", 4)) {
|
if (!memcmp(table->signature, "RSDT", 4)) {
|
||||||
Hw::for_each_rsdt_entry(*table, [&](uint32_t paddr_table) {
|
Hw::for_each_rsdt_entry(*table, [&](uint32_t paddr_table) {
|
||||||
@ -144,20 +193,116 @@ Bootstrap::Platform::Board::Board()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else
|
}
|
||||||
Genode::error("unknown table signature");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cpus || cpus > max_cpus) {
|
if (!cpus || cpus > max_cpus) {
|
||||||
Genode::warning("CPU count is unsupported ", cpus, "/", max_cpus);
|
Genode::warning("CPU count is unsupported ", cpus, "/", max_cpus,
|
||||||
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()
|
unsigned Bootstrap::Platform::enable_mmu()
|
||||||
{
|
{
|
||||||
Cpu::Cr3::write(Cpu::Cr3::Pdb::masked((addr_t)core_pd->table_base));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
void Genode::Cpu::switch_to(Context & context, Mmu_context &mmu_context)
|
||||||
{
|
{
|
||||||
_fpu.switch_to(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);
|
Cr3::write(mmu_context.cr3);
|
||||||
|
|
||||||
tss.ist[0] = (addr_t)&context + sizeof(Genode::Cpu_state);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,10 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
|||||||
/**
|
/**
|
||||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
* 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 {
|
enum Eflags {
|
||||||
EFLAGS_IF_SET = 1 << 9,
|
EFLAGS_IF_SET = 1 << 9,
|
||||||
@ -100,7 +103,7 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
|||||||
};
|
};
|
||||||
|
|
||||||
Context(bool privileged);
|
Context(bool privileged);
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
struct Mmu_context
|
struct Mmu_context
|
||||||
@ -121,7 +124,7 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
|||||||
/**
|
/**
|
||||||
* Return kernel name of the executing 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
|
* Return kernel name of the primary CPU
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
* \brief Startup code for Genode 64Bit applications
|
* \brief Startup code for Genode 64Bit applications
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Martin Stein
|
* \author Martin Stein
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2011-05-11
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@ -21,11 +22,20 @@
|
|||||||
.global _start
|
.global _start
|
||||||
_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 */
|
/* switch to kernel stack */
|
||||||
mov kernel_stack@GOTPCREL(%rip), %rax
|
movq kernel_stack@GOTPCREL(%rip), %rbx
|
||||||
mov kernel_stack_size@GOTPCREL(%rip), %rbx
|
addq %rbx, %rax
|
||||||
add (%rbx), %rax
|
subq $8, %rax
|
||||||
mov %rax, %rsp
|
movq %rax, %rsp
|
||||||
|
|
||||||
/* jump to C entry code */
|
/* jump to C entry code */
|
||||||
jmp kernel_init
|
jmp kernel_init
|
||||||
|
@ -111,12 +111,22 @@
|
|||||||
pushq %r9
|
pushq %r9
|
||||||
pushq %r8
|
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 */
|
/* Restore kernel stack and continue kernel execution */
|
||||||
_load_address kernel_stack rax
|
movq %rsp, %rax
|
||||||
_load_address kernel_stack_size rbx
|
addq $KERNEL_STACK_OFFSET, %rax
|
||||||
|
movq (%rax), %rsp
|
||||||
|
|
||||||
_load_address kernel rcx
|
_load_address kernel rcx
|
||||||
add (%rbx), %rax
|
|
||||||
mov %rax, %rsp
|
|
||||||
jmp *%rcx
|
jmp *%rcx
|
||||||
|
|
||||||
|
|
||||||
@ -159,5 +169,7 @@
|
|||||||
|
|
||||||
.global idle_thread_main
|
.global idle_thread_main
|
||||||
idle_thread_main:
|
idle_thread_main:
|
||||||
pause
|
sti
|
||||||
|
hlt
|
||||||
|
cli
|
||||||
jmp idle_thread_main
|
jmp idle_thread_main
|
||||||
|
@ -30,6 +30,7 @@ void Kernel::Cpu::init(Pic &pic)
|
|||||||
|
|
||||||
/* enable timer interrupt */
|
/* enable timer interrupt */
|
||||||
unsigned const cpu = Cpu::executing_id();
|
unsigned const cpu = Cpu::executing_id();
|
||||||
|
pic.store_apic_id(cpu);
|
||||||
pic.unmask(_timer.interrupt_id(), cpu);
|
pic.unmask(_timer.interrupt_id(), cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ class Genode::Pic
|
|||||||
void mask(unsigned const) { }
|
void mask(unsigned const) { }
|
||||||
bool is_ip_interrupt(unsigned, unsigned) { return false; }
|
bool is_ip_interrupt(unsigned, unsigned) { return false; }
|
||||||
void trigger_ip_interrupt(unsigned) { }
|
void trigger_ip_interrupt(unsigned) { }
|
||||||
|
void store_apic_id(unsigned const) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
* \brief Programmable interrupt controller for core
|
* \brief Programmable interrupt controller for core
|
||||||
* \author Adrian-Ken Rueegsegger
|
* \author Adrian-Ken Rueegsegger
|
||||||
* \author Reto Buerki
|
* \author Reto Buerki
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2015-02-17
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@ -23,6 +24,8 @@
|
|||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
uint8_t Pic::lapic_ids[NR_OF_CPUS];
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PIC_CMD_MASTER = 0x20,
|
PIC_CMD_MASTER = 0x20,
|
||||||
PIC_CMD_SLAVE = 0xa0,
|
PIC_CMD_SLAVE = 0xa0,
|
||||||
@ -99,6 +102,25 @@ inline unsigned Pic::get_lowest_bit(void)
|
|||||||
return 0;
|
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];
|
Ioapic::Irq_mode Ioapic::_irq_mode[IRQ_COUNT];
|
||||||
|
|
||||||
void Ioapic::setup_irq_mode(unsigned irq_number, unsigned trigger,
|
void Ioapic::setup_irq_mode(unsigned irq_number, unsigned trigger,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Programmable interrupt controller for core
|
* \brief Programmable interrupt controller for core
|
||||||
* \author Reto Buerki
|
* \author Reto Buerki
|
||||||
|
* \author Alexander Boettcher
|
||||||
* \date 2015-02-17
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@ -142,6 +143,7 @@ class Genode::Pic : public Mmio
|
|||||||
* Registers
|
* Registers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct Id : Register<0x020, 32> { };
|
||||||
struct EOI : Register<0x0b0, 32, true> { };
|
struct EOI : Register<0x0b0, 32, true> { };
|
||||||
struct Svr : Register<0x0f0, 32>
|
struct Svr : Register<0x0f0, 32>
|
||||||
{
|
{
|
||||||
@ -155,6 +157,18 @@ class Genode::Pic : public Mmio
|
|||||||
*/
|
*/
|
||||||
struct Isr : Register_array<0x100, 32, 8 * 4, 32> { };
|
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
|
* Determine lowest pending interrupt in ISR register
|
||||||
*
|
*
|
||||||
@ -163,6 +177,11 @@ class Genode::Pic : public Mmio
|
|||||||
*/
|
*/
|
||||||
inline unsigned get_lowest_bit(void);
|
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:
|
public:
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -190,12 +209,12 @@ class Genode::Pic : public Mmio
|
|||||||
|
|
||||||
void mask(unsigned const i);
|
void mask(unsigned const i);
|
||||||
|
|
||||||
/*
|
void store_apic_id(unsigned const cpu_id) {
|
||||||
* Dummies
|
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 send_ipi(unsigned const);
|
||||||
void trigger_ip_interrupt(unsigned) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Kernel { using Genode::Pic; }
|
namespace Kernel { using Genode::Pic; }
|
||||||
|
25
repos/base-hw/src/core/spec/x86_64/smp/cpu.cc
Normal file
25
repos/base-hw/src/core/spec/x86_64/smp/cpu.cc
Normal 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>(); }
|
@ -11,6 +11,7 @@ if {
|
|||||||
![expr [have_spec zynq] && ![have_spec zynq_qemu] ] &&
|
![expr [have_spec zynq] && ![have_spec zynq_qemu] ] &&
|
||||||
![expr [have_spec x86_32] && [have_spec foc] ] &&
|
![expr [have_spec x86_32] && [have_spec foc] ] &&
|
||||||
![expr [have_spec x86_64] && [have_spec foc] ] &&
|
![expr [have_spec x86_64] && [have_spec foc] ] &&
|
||||||
|
![expr [have_spec x86_64] && [have_spec hw] ] &&
|
||||||
![have_spec nova] &&
|
![have_spec nova] &&
|
||||||
![have_spec sel4]
|
![have_spec sel4]
|
||||||
} {
|
} {
|
||||||
|
@ -40,7 +40,6 @@ if {[have_include "power_on/qemu"]} {
|
|||||||
if {[have_spec okl4]} { set want_cpus 1 }
|
if {[have_spec okl4]} { set want_cpus 1 }
|
||||||
if {[have_spec pistachio]} { set want_cpus 1 }
|
if {[have_spec pistachio]} { set want_cpus 1 }
|
||||||
if {[have_spec fiasco]} { 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 }
|
if {[have_spec zynq]} { set want_cpus 1 }
|
||||||
|
|
||||||
append qemu_args " -nographic -smp $want_cpus,cores=$want_cpus "
|
append qemu_args " -nographic -smp $want_cpus,cores=$want_cpus "
|
||||||
|
Loading…
Reference in New Issue
Block a user