arch/intel64: add cpu specific data and per-cpu interrupt stacks
Use GS base regsiter to store reference to CPU private data. Then we can easily refer to private CPU data using the GS segment. Required for SMP support. Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
parent
87dfcd1020
commit
c6170286ca
17 changed files with 645 additions and 95 deletions
|
@ -134,6 +134,7 @@ config ARCH_X86_64
|
|||
select ARCH_HAVE_FPU
|
||||
select ARCH_HAVE_DPFPU
|
||||
select ARCH_HAVE_TESTSET
|
||||
select ARCH_HAVE_INTERRUPTSTACK
|
||||
select ARCH_HAVE_CUSTOMOPT
|
||||
select LIBC_ARCH_ELF_64BIT if LIBC_ARCH_ELF
|
||||
---help---
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#define X86_GDT_DATA_SEL_NUM 2
|
||||
# define X86_GDT_DATA_SEL (X86_GDT_DATA_SEL_NUM * X86_GDT_ENTRY_SIZE)
|
||||
|
||||
/* The first TSS entry */
|
||||
|
||||
#define X86_GDT_ISTL_SEL_NUM 6
|
||||
#define X86_GDT_ISTH_SEL_NUM (X86_GDT_ISTL_SEL_NUM + 1)
|
||||
|
||||
|
@ -263,7 +265,12 @@
|
|||
#define X86_PIC_8086 1
|
||||
#define X86_PIC_EOI 0x20
|
||||
|
||||
#define BITS_PER_LONG 64
|
||||
#define BITS_PER_LONG 64
|
||||
|
||||
/* Interrupt Stack Table size */
|
||||
|
||||
#define X86_IST_SIZE 104
|
||||
#define X86_TSS_SIZE (104 + 8)
|
||||
|
||||
/* Reset Control Register (RST_CNT) */
|
||||
|
||||
|
@ -370,9 +377,13 @@ begin_packed_struct struct ist_s
|
|||
uint16_t IOPB_OFFSET; /* IOPB_offset */
|
||||
} end_packed_struct;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
/* TSS */
|
||||
|
||||
begin_packed_struct struct tss_s
|
||||
{
|
||||
struct ist_s ist; /* IST */
|
||||
void *cpu; /* CPU private data */
|
||||
} end_packed_struct;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
|
|
|
@ -58,18 +58,27 @@
|
|||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* This holds a references to the current interrupt level register storage
|
||||
* structure. It is non-NULL only during interrupt processing.
|
||||
/* CPU private data */
|
||||
|
||||
struct intel64_cpu_s
|
||||
{
|
||||
int id;
|
||||
uint8_t loapic_id;
|
||||
bool ready;
|
||||
|
||||
/* current_regs holds a references to the current interrupt level
|
||||
* register storage structure. If is non-NULL only during interrupt
|
||||
* processing. Access to current_regs must be through
|
||||
* up_current_regs() and up_set_current_regs() functions
|
||||
*/
|
||||
|
||||
extern volatile uint64_t *g_current_regs;
|
||||
#endif
|
||||
uint64_t *current_regs;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
|
@ -100,6 +109,22 @@ extern "C"
|
|||
* Inline functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline_function uint64_t *up_current_regs(void)
|
||||
{
|
||||
uint64_t *regs;
|
||||
asm volatile("movq %%gs:(%c1), %0"
|
||||
: "=rm" (regs)
|
||||
: "i" (offsetof(struct intel64_cpu_s, current_regs)));
|
||||
return regs;
|
||||
}
|
||||
|
||||
static inline_function void up_set_current_regs(uint64_t *regs)
|
||||
{
|
||||
asm volatile("movq %0, %%gs:(%c1)"
|
||||
:: "r" (regs), "i" (offsetof(struct intel64_cpu_s,
|
||||
current_regs)));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_interrupt_context
|
||||
*
|
||||
|
@ -109,7 +134,11 @@ extern "C"
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define up_interrupt_context() (g_current_regs != NULL)
|
||||
noinstrument_function
|
||||
static inline_function bool up_interrupt_context(void)
|
||||
{
|
||||
return up_current_regs() != NULL;
|
||||
}
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -39,6 +39,6 @@
|
|||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
uintptr_t up_get_intstackbase(int cpu)
|
||||
{
|
||||
return (uintptr_t)g_intstackalloc;
|
||||
return (uintptr_t)(g_intstackalloc + (cpu * IRQ_STACK_SIZE));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -111,7 +111,15 @@
|
|||
* referenced is passed to get the state from the TCB.
|
||||
*/
|
||||
|
||||
#define x86_64_restorestate(regs) (g_current_regs = regs)
|
||||
#define x86_64_restorestate(regs) (up_set_current_regs(regs))
|
||||
|
||||
/* ISR/IRQ stack size */
|
||||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK == 0
|
||||
# define IRQ_STACK_SIZE 0x2000
|
||||
#else
|
||||
# define IRQ_STACK_SIZE CONFIG_ARCH_INTERRUPTSTACK
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
|
@ -138,7 +146,7 @@ extern const uintptr_t g_idle_topstack;
|
|||
|
||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||
extern uint8_t g_intstackalloc[];
|
||||
extern uint8_t g_intstacktop[];
|
||||
extern uint8_t g_intstackalloc[];
|
||||
#endif
|
||||
|
||||
/* These symbols are setup by the linker script. */
|
||||
|
|
|
@ -63,7 +63,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
|
|||
|
||||
/* Are we in an interrupt handler? */
|
||||
|
||||
if (g_current_regs)
|
||||
if (up_current_regs())
|
||||
{
|
||||
/* Yes, then we have to do things differently.
|
||||
* Just copy the g_current_regs into the OLD rtcb.
|
||||
|
|
|
@ -45,7 +45,8 @@ set(SRCS
|
|||
intel64_lowsetup.c
|
||||
intel64_serial.c
|
||||
intel64_rng.c
|
||||
intel64_check_capability.c)
|
||||
intel64_check_capability.c
|
||||
intel64_cpu.c)
|
||||
|
||||
if(CONFIG_ARCH_HAVE_TESTSET)
|
||||
list(APPEND SRCS intel64_testset.S)
|
||||
|
|
|
@ -32,6 +32,7 @@ CMN_CSRCS += intel64_systemreset.c intel64_freq.c intel64_cache.c
|
|||
CHIP_ASRCS = intel64_saveusercontext.S intel64_fullcontextrestore.S intel64_vectors.S intel64_head.S
|
||||
CHIP_CSRCS = intel64_start.c intel64_handlers.c intel64_idle.c intel64_lowsetup.c
|
||||
CHIP_CSRCS += intel64_serial.c intel64_rng.c intel64_check_capability.c
|
||||
CHIP_CSRCS += intel64_cpu.c
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HAVE_TESTSET), y)
|
||||
CHIP_ASRCS += intel64_testset.S
|
||||
|
|
383
arch/x86_64/src/intel64/intel64_cpu.c
Normal file
383
arch/x86_64/src/intel64/intel64_cpu.c
Normal file
|
@ -0,0 +1,383 @@
|
|||
/****************************************************************************
|
||||
* arch/x86_64/src/intel64/intel64_cpu.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
#include <arch/io.h>
|
||||
#include <arch/acpi.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <intel64_cpu.h>
|
||||
|
||||
#include "x86_64_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Avoid undefined error when CONFIG_SPINLOCK=n */
|
||||
|
||||
#ifndef spin_lock
|
||||
# define spin_lock(s)
|
||||
#endif
|
||||
|
||||
#define IRQ_STACK_ALLOC (IRQ_STACK_SIZE * CONFIG_SMP_NCPUS)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
extern volatile uint32_t g_cpu_count;
|
||||
volatile static spinlock_t g_ap_boot;
|
||||
|
||||
/* CPU private data */
|
||||
|
||||
struct intel64_cpu_s g_cpu_priv[CONFIG_SMP_NCPUS];
|
||||
|
||||
/* Allocate stack for interrupts and isr */
|
||||
|
||||
uint8_t g_intstackalloc[IRQ_STACK_ALLOC] aligned_data(16);
|
||||
uint8_t g_isrstackalloc[IRQ_STACK_ALLOC] aligned_data(16);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_get
|
||||
*
|
||||
* Description:
|
||||
* Get TSS for a given CPU data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static struct tss_s *x86_64_cpu_tss_get(uint8_t cpu)
|
||||
{
|
||||
return (struct tss_s *)((uintptr_t)&g_ist64_low + X86_64_LOAD_OFFSET +
|
||||
(X86_TSS_SIZE * cpu));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_load
|
||||
*
|
||||
* Description:
|
||||
* Load TSS for the current CPU
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void x86_64_cpu_tss_load(int cpu)
|
||||
{
|
||||
uint16_t addr;
|
||||
|
||||
/* Get offset for TSS */
|
||||
|
||||
addr = X86_GDT_ISTL_SEL_NUM * 8 + 16 * cpu;
|
||||
|
||||
asm volatile ("mov %0, %%ax; ltr %%ax":: "m"(addr) : "memory", "rax");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize the TSS
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_tss_init(int cpu)
|
||||
{
|
||||
struct tss_s *tss = NULL;
|
||||
struct ist_s *ist64 = NULL;
|
||||
struct gdt_entry_s tss_l;
|
||||
uint64_t tss_h;
|
||||
|
||||
/* Get TSS - one per CPU */
|
||||
|
||||
tss = x86_64_cpu_tss_get(cpu);
|
||||
|
||||
/* Setup IST pointer */
|
||||
|
||||
ist64 = &tss->ist;
|
||||
|
||||
/* Reset local data */
|
||||
|
||||
memset(&tss_l, 0, sizeof(tss_l));
|
||||
memset(&tss_h, 0, sizeof(tss_h));
|
||||
|
||||
/* Segment limit = IST size - 1 */
|
||||
|
||||
tss_l.limit_low = ((X86_IST_SIZE - 1) & 0xffff);
|
||||
|
||||
/* Low address 1 */
|
||||
|
||||
tss_l.base_low = ((uintptr_t)ist64 & 0x00ffffff);
|
||||
|
||||
/* Low address 2 */
|
||||
|
||||
tss_l.base_high = (((uintptr_t)ist64 & 0xff000000) >> 24);
|
||||
tss_l.P = 1;
|
||||
|
||||
/* Set type as IST */
|
||||
|
||||
tss_l.AC = 1;
|
||||
tss_l.EX = 1;
|
||||
|
||||
/* High address */
|
||||
|
||||
tss_h = (((uintptr_t)ist64 >> 32) & 0xffffffff);
|
||||
|
||||
g_gdt64[X86_GDT_ISTL_SEL_NUM + 2 * cpu] = tss_l;
|
||||
|
||||
/* memcpy used to handle type punning compiler warning */
|
||||
|
||||
memcpy((void *)&g_gdt64[X86_GDT_ISTH_SEL_NUM + 2 * cpu],
|
||||
&tss_h, sizeof(g_gdt64[0]));
|
||||
|
||||
/* Stack for IRQ0-IRQ15 */
|
||||
|
||||
ist64->IST1 = (uintptr_t)(g_isrstackalloc + ((cpu + 1) * IRQ_STACK_SIZE));
|
||||
|
||||
/* Stack for the rest IRQ */
|
||||
|
||||
ist64->IST2 = (uintptr_t)(g_intstackalloc + ((cpu + 1) * IRQ_STACK_SIZE));
|
||||
|
||||
/* Now load TSS */
|
||||
|
||||
x86_64_cpu_tss_load(cpu);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_now_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU TSS data associated with the current CPU
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct tss_s *x86_64_cpu_tss_now_get(void)
|
||||
{
|
||||
uint64_t *ist = 0;
|
||||
uint16_t seg = 0;
|
||||
uint16_t ist_offset = 0;
|
||||
uintptr_t tss_addr = 0;
|
||||
|
||||
/* Get TSS associated with this CPU */
|
||||
|
||||
asm volatile ("str %%ax; mov %%ax, %0": "=rm"(seg) :: "memory", "rax");
|
||||
|
||||
/* This is BSP if TSS not configured yet */
|
||||
|
||||
if (seg == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Decode TSS */
|
||||
|
||||
ist_offset = ((seg - X86_GDT_ISTL_SEL_NUM * 8) / 8);
|
||||
ist = (uint64_t *)((uintptr_t)&g_gdt64_ist_low + X86_64_LOAD_OFFSET);
|
||||
|
||||
/* Low address */
|
||||
|
||||
tss_addr = (ist[ist_offset] >> 16) & 0x00ffffff;
|
||||
tss_addr |= ((ist[ist_offset] >> 56) & 0xff) << 24;
|
||||
|
||||
/* High address */
|
||||
|
||||
tss_addr |= ist[ist_offset + 1] << 32;
|
||||
|
||||
return (struct tss_s *)tss_addr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize CPU data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_init(void)
|
||||
{
|
||||
struct tss_s *tss = NULL;
|
||||
struct acpi_lapic_s *lapic = NULL;
|
||||
int i = 0;
|
||||
int ret = OK;
|
||||
|
||||
/* Map logical CPU to Local APIC IDs */
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
ret = acpi_lapic_get(i, &lapic);
|
||||
if (ret == OK)
|
||||
{
|
||||
g_cpu_priv[i].loapic_id = lapic->apic_id;
|
||||
g_cpu_priv[i].id = i;
|
||||
g_cpu_priv[i].ready = false;
|
||||
|
||||
/* Store private CPU in TSS */
|
||||
|
||||
tss = x86_64_cpu_tss_get(i);
|
||||
tss->cpu = &g_cpu_priv[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We want to fail early when NCPUS doesn't match the number
|
||||
* of availalbe CPUs
|
||||
*/
|
||||
|
||||
/* Panic if not found */
|
||||
|
||||
PANIC();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set BSP ready flag */
|
||||
|
||||
g_cpu_priv[0].ready = true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_lopaic_to_cpu
|
||||
*
|
||||
* Description:
|
||||
* Get CPU index for a given Local APIC ID
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_loapic_to_cpu(uint8_t loapic)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
|
||||
{
|
||||
if (g_cpu_priv[i].loapic_id == loapic)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Panic if not found */
|
||||
|
||||
PANIC();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_to_loapic
|
||||
*
|
||||
* Description:
|
||||
* Get Local APIC ID for a given CPU index
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_cpu_to_loapic(uint8_t cpu)
|
||||
{
|
||||
return g_cpu_priv[cpu].loapic_id;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_ready_set
|
||||
*
|
||||
* Description:
|
||||
* Set CPU ready flag
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_ready_set(uint8_t cpu)
|
||||
{
|
||||
spin_lock(&g_ap_boot);
|
||||
|
||||
if (!g_cpu_priv[cpu].ready)
|
||||
{
|
||||
g_cpu_priv[cpu].ready = true;
|
||||
g_cpu_count++;
|
||||
}
|
||||
|
||||
spin_unlock(&g_ap_boot);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_ready_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU ready flag
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool x86_64_cpu_ready_get(uint8_t cpu)
|
||||
{
|
||||
struct intel64_cpu_s *priv = &g_cpu_priv[cpu];
|
||||
bool ready;
|
||||
|
||||
spin_lock(&g_ap_boot);
|
||||
ready = priv->ready;
|
||||
spin_unlock(&g_ap_boot);
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_count_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU counter
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_cpu_count_get(void)
|
||||
{
|
||||
uint8_t count;
|
||||
|
||||
spin_lock(&g_ap_boot);
|
||||
count = g_cpu_count;
|
||||
spin_unlock(&g_ap_boot);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_priv_set
|
||||
*
|
||||
* Description:
|
||||
* Save CPU private data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_priv_set(uint8_t cpu)
|
||||
{
|
||||
/* Store private data pointer to GSBASE */
|
||||
|
||||
write_gsbase((uintptr_t)&g_cpu_priv[cpu]);
|
||||
}
|
154
arch/x86_64/src/intel64/intel64_cpu.h
Normal file
154
arch/x86_64/src/intel64/intel64_cpu.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
/****************************************************************************
|
||||
* arch/x86_64/src/intel64/intel64_cpu.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_X86_64_SRC_INTEL64_INTEL64_CPU_H
|
||||
#define __ARCH_X86_64_SRC_INTEL64_INTEL64_CPU_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <arch/arch.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize the TSS
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_tss_init(int cpu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_tss_now_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU TSS data associated with the current CPU
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct tss_s *x86_64_cpu_tss_now_get(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize CPU data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_init(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_lopaic_to_cpu
|
||||
*
|
||||
* Description:
|
||||
* Get CPU index for a given Local APIC ID
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_loapic_to_cpu(uint8_t loapic);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_to_loapic
|
||||
*
|
||||
* Description:
|
||||
* Get Local APIC ID for a given CPU index
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_cpu_to_loapic(uint8_t cpu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_ready_set
|
||||
*
|
||||
* Description:
|
||||
* Set CPU ready flag
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_ready_set(uint8_t cpu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_ready_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU ready flag
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool x86_64_cpu_ready_get(uint8_t cpu);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_count_get
|
||||
*
|
||||
* Description:
|
||||
* Get CPU counter
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint8_t x86_64_cpu_count_get(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: x86_64_cpu_priv_set
|
||||
*
|
||||
* Description:
|
||||
* Save CPU private data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void x86_64_cpu_priv_set(uint8_t cpu);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_X86_64_SRC_INTEL64_INTEL64_CPU_H */
|
|
@ -68,8 +68,8 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
* Nested interrupts are not supported.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(g_current_regs == NULL);
|
||||
g_current_regs = regs;
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
up_set_current_regs(regs);
|
||||
|
||||
/* Deliver the IRQ */
|
||||
|
||||
|
@ -82,7 +82,7 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
* returning from the interrupt.
|
||||
*/
|
||||
|
||||
if (regs != g_current_regs)
|
||||
if (regs != up_current_regs())
|
||||
{
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
/* Make sure that the address environment for the previously
|
||||
|
@ -108,13 +108,13 @@ static uint64_t *common_handler(int irq, uint64_t *regs)
|
|||
* switch occurred during interrupt processing.
|
||||
*/
|
||||
|
||||
regs = (uint64_t *)g_current_regs;
|
||||
regs = (uint64_t *)up_current_regs();
|
||||
|
||||
/* Set g_current_regs to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
g_current_regs = NULL;
|
||||
up_set_current_regs(NULL);
|
||||
return regs;
|
||||
}
|
||||
#endif
|
||||
|
@ -145,8 +145,8 @@ uint64_t *isr_handler(uint64_t *regs, uint64_t irq)
|
|||
return regs;
|
||||
#else
|
||||
|
||||
DEBUGASSERT(g_current_regs == NULL);
|
||||
g_current_regs = regs;
|
||||
DEBUGASSERT(up_current_regs() == NULL);
|
||||
up_set_current_regs(regs);
|
||||
|
||||
switch (irq)
|
||||
{
|
||||
|
@ -174,13 +174,13 @@ uint64_t *isr_handler(uint64_t *regs, uint64_t irq)
|
|||
|
||||
/* Maybe we need a context switch */
|
||||
|
||||
regs = (uint64_t *)g_current_regs;
|
||||
regs = (uint64_t *)up_current_regs();
|
||||
|
||||
/* Set g_current_regs to NULL to indicate that we are no longer in an
|
||||
* interrupt handler.
|
||||
*/
|
||||
|
||||
g_current_regs = NULL;
|
||||
up_set_current_regs(NULL);
|
||||
return regs;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
.global g_idle_topstack /* The end of the idle stack, the start of the heap */
|
||||
.global g_mb_info_struct
|
||||
.global g_mb_magic
|
||||
.global g_cpu_count
|
||||
|
||||
/* These are the page tables */
|
||||
.global g_pdpt_low
|
||||
|
@ -283,6 +284,9 @@ start64:
|
|||
jmp *%rbx
|
||||
.size __pmode_entry, . - __pmode_entry
|
||||
|
||||
g_cpu_count:
|
||||
.long 1
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __revoke_low_memory
|
||||
*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
@ -39,16 +40,13 @@
|
|||
#include <nuttx/spinlock.h>
|
||||
|
||||
#include "x86_64_internal.h"
|
||||
#include "intel64_cpu.h"
|
||||
#include "intel64.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define UART_BASE 0x3f8
|
||||
|
||||
#define IRQ_STACK_SIZE 0x2000
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
@ -71,14 +69,6 @@ static inline void up_idtinit(void);
|
|||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
volatile uint64_t *g_current_regs;
|
||||
|
||||
uint8_t g_interrupt_stack[IRQ_STACK_SIZE] aligned_data(16);
|
||||
uint8_t *g_interrupt_stack_end = g_interrupt_stack + IRQ_STACK_SIZE - 16;
|
||||
|
||||
uint8_t g_isr_stack[IRQ_STACK_SIZE] aligned_data(16);
|
||||
uint8_t *g_isr_stack_end = g_isr_stack + IRQ_STACK_SIZE - 16;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
@ -171,49 +161,6 @@ void up_ioapic_unmask_pin(unsigned int pin)
|
|||
cur & ~(IOAPIC_PIN_DISABLE));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_init_ist
|
||||
*
|
||||
* Description:
|
||||
* Initialize the Interrupt Stack Table
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void up_ist_init(void)
|
||||
{
|
||||
struct gdt_entry_s tss_l;
|
||||
uint64_t tss_h;
|
||||
|
||||
memset(&tss_l, 0, sizeof(tss_l));
|
||||
memset(&tss_h, 0, sizeof(tss_h));
|
||||
|
||||
tss_l.limit_low = (((104 - 1) & 0xffff)); /* Segment limit = TSS size - 1 */
|
||||
|
||||
tss_l.base_low = ((uintptr_t)g_ist64 & 0x00ffffff); /* Low address 1 */
|
||||
tss_l.base_high = (((uintptr_t)g_ist64 & 0xff000000) >> 24); /* Low address 2 */
|
||||
|
||||
tss_l.P = 1;
|
||||
|
||||
/* Set type as IST */
|
||||
|
||||
tss_l.AC = 1;
|
||||
tss_l.EX = 1;
|
||||
|
||||
tss_h = (((uintptr_t)g_ist64 >> 32) & 0xffffffff); /* High address */
|
||||
|
||||
g_gdt64[X86_GDT_ISTL_SEL_NUM] = tss_l;
|
||||
|
||||
/* memcpy used to handle type punning compiler warning */
|
||||
|
||||
memcpy((void *)&g_gdt64[X86_GDT_ISTH_SEL_NUM],
|
||||
(void *)&tss_h, sizeof(g_gdt64[0]));
|
||||
|
||||
g_ist64->IST1 = (uintptr_t)g_interrupt_stack_end;
|
||||
g_ist64->IST2 = (uintptr_t)g_isr_stack_end;
|
||||
|
||||
asm volatile ("mov $0x30, %%ax; ltr %%ax":::"memory", "rax");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_deinit_8259
|
||||
*
|
||||
|
@ -486,21 +433,19 @@ static inline void up_idtinit(void)
|
|||
|
||||
void up_irqinitialize(void)
|
||||
{
|
||||
/* Initialize the IST */
|
||||
/* Initialize the TSS */
|
||||
|
||||
up_ist_init();
|
||||
|
||||
#ifndef CONFIG_ARCH_INTEL64_DISABLE_INT_INIT
|
||||
/* Disable 8259 PIC */
|
||||
|
||||
up_deinit_8259();
|
||||
#endif
|
||||
x86_64_cpu_tss_init(0);
|
||||
|
||||
/* Initialize the APIC */
|
||||
|
||||
up_apic_init();
|
||||
|
||||
#ifndef CONFIG_ARCH_INTEL64_DISABLE_INT_INIT
|
||||
/* Disable 8259 PIC */
|
||||
|
||||
up_deinit_8259();
|
||||
|
||||
/* Initialize the IOAPIC */
|
||||
|
||||
up_ioapic_init();
|
||||
|
|
|
@ -111,7 +111,7 @@ void backtrace(uint64_t rbp)
|
|||
|
||||
void up_dump_register(void *dumpregs)
|
||||
{
|
||||
volatile uint64_t *regs = dumpregs ? dumpregs : g_current_regs;
|
||||
volatile uint64_t *regs = dumpregs ? dumpregs : up_current_regs();
|
||||
uint64_t mxcsr;
|
||||
uint64_t cr2;
|
||||
|
||||
|
|
|
@ -46,5 +46,5 @@
|
|||
|
||||
void x86_64_savestate(uint64_t *regs)
|
||||
{
|
||||
x86_64_copystate(regs, (uint64_t *)g_current_regs);
|
||||
x86_64_copystate(regs, (uint64_t *)up_current_regs());
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||
{
|
||||
sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver);
|
||||
sinfo("rtcb=%p g_current_regs=%p\n", this_task(), g_current_regs);
|
||||
sinfo("rtcb=%p g_current_regs=%p\n", this_task(), up_current_regs());
|
||||
|
||||
/* Refuse to handle nested signal actions */
|
||||
|
||||
|
@ -91,7 +91,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||
* signalling itself for some reason.
|
||||
*/
|
||||
|
||||
if (!g_current_regs)
|
||||
if (!up_current_regs())
|
||||
{
|
||||
/* In this case just deliver the signal with a function call
|
||||
* now.
|
||||
|
@ -120,16 +120,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||
* have been delivered.
|
||||
*/
|
||||
|
||||
tcb->xcp.saved_rip = g_current_regs[REG_RIP];
|
||||
tcb->xcp.saved_rip = up_current_regs()[REG_RIP];
|
||||
tcb->xcp.saved_rsp = tcb->xcp.regs[REG_RSP];
|
||||
tcb->xcp.saved_rflags = g_current_regs[REG_RFLAGS];
|
||||
tcb->xcp.saved_rflags = up_current_regs()[REG_RFLAGS];
|
||||
|
||||
/* Then set up to vector to the trampoline with interrupts
|
||||
* disabled
|
||||
*/
|
||||
|
||||
g_current_regs[REG_RIP] = (uint64_t)x86_64_sigdeliver;
|
||||
g_current_regs[REG_RFLAGS] = 0;
|
||||
up_current_regs()[REG_RIP] = (uint64_t)x86_64_sigdeliver;
|
||||
up_current_regs()[REG_RFLAGS] = 0;
|
||||
|
||||
/* And make sure that the saved context in the TCB
|
||||
* is the same as the interrupt return context.
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "x86_64_internal.h"
|
||||
|
||||
#include "intel64_cpu.h"
|
||||
#include "intel64_lowsetup.h"
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -129,6 +130,8 @@ void __nxstart(void)
|
|||
{
|
||||
uint64_t *dest = NULL;
|
||||
|
||||
/* This is only for BSP core. */
|
||||
|
||||
/* Do some checking on CPU compatibilities at the top of this function.
|
||||
* BSS cleanup can be optimized with vector instructions, so we need to
|
||||
* enable SSE at this point.
|
||||
|
@ -161,6 +164,10 @@ void __nxstart(void)
|
|||
acpi_init(g_acpi_rsdp);
|
||||
#endif
|
||||
|
||||
/* Initialize CPU data (BSP and APs) */
|
||||
|
||||
x86_64_cpu_init();
|
||||
|
||||
/* perform board-specific initializations */
|
||||
|
||||
x86_64_boardinitialize();
|
||||
|
@ -171,12 +178,18 @@ void __nxstart(void)
|
|||
x86_64_earlyserialinit();
|
||||
#endif
|
||||
|
||||
/* Configure timer */
|
||||
|
||||
x86_64_timer_calibrate_freq();
|
||||
|
||||
#ifdef CONFIG_LIB_SYSCALL
|
||||
enable_syscall();
|
||||
#endif
|
||||
|
||||
/* Store CPU IDs */
|
||||
|
||||
x86_64_cpu_priv_set(0);
|
||||
|
||||
/* Start NuttX */
|
||||
|
||||
nx_start();
|
||||
|
|
Loading…
Reference in a new issue