arch/x86: Add exception reporting code for Intel64
Fleshed out z_arch_esf_t and added code to build this frame when exceptions occur. Created a separate small stack for exceptions and shifted the initialization code to use this instead of the IRQ stack. Moved IRQ stack(s) to irq.c. Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
parent
a10f2601cc
commit
cdb9ac3895
7 changed files with 135 additions and 33 deletions
|
@ -23,4 +23,13 @@ config SYSTEM_WORKQUEUE_STACK_SIZE
|
||||||
config OFFLOAD_WORKQUEUE_STACK_SIZE
|
config OFFLOAD_WORKQUEUE_STACK_SIZE
|
||||||
default 8192
|
default 8192
|
||||||
|
|
||||||
|
config EXCEPTION_STACK_SIZE
|
||||||
|
int "Size of the exception stack(s)"
|
||||||
|
default 1024
|
||||||
|
help
|
||||||
|
The exception stack(s) (one per CPU) are used both for exception
|
||||||
|
processing and early kernel/CPU initialization. They need only
|
||||||
|
support limited call-tree depth and must fit into the low core,
|
||||||
|
so they are typically smaller than the ISR stacks.
|
||||||
|
|
||||||
endif # X86_LONGMODE
|
endif # X86_LONGMODE
|
||||||
|
|
|
@ -10,6 +10,7 @@ set_property(SOURCE intel64/locore.S PROPERTY LANGUAGE ASM)
|
||||||
|
|
||||||
zephyr_library_sources(
|
zephyr_library_sources(
|
||||||
intel64/locore.S
|
intel64/locore.S
|
||||||
intel64/irq_manage.c
|
intel64/irq.c
|
||||||
intel64/thread.c
|
intel64/thread.c
|
||||||
|
intel64/fatal.c
|
||||||
)
|
)
|
||||||
|
|
41
arch/x86/core/intel64/fatal.c
Normal file
41
arch/x86/core/intel64/fatal.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <ksched.h>
|
||||||
|
#include <kernel_structs.h>
|
||||||
|
#include <kernel_internal.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_DECLARE(os);
|
||||||
|
|
||||||
|
void z_x86_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
|
||||||
|
{
|
||||||
|
if (esf != NULL) {
|
||||||
|
LOG_ERR("RIP=%016lx RSP=%016lx RFLAGS=%016lx\n",
|
||||||
|
esf->rip, esf->rsp, esf->rflags);
|
||||||
|
|
||||||
|
LOG_ERR("RAX=%016lx RBX=%016lx RCX=%016lx RDX=%016lx\n",
|
||||||
|
esf->rax, esf->rbx, esf->rcx, esf->rdx);
|
||||||
|
|
||||||
|
LOG_ERR("RSI=%016lx RDI=%016lx RBP=%016lx RSP=%016lx\n",
|
||||||
|
esf->rsi, esf->rdi, esf->rbp, esf->rsp);
|
||||||
|
|
||||||
|
LOG_ERR("R8=%016lx R9=%016lx R10=%016lx R11=%016lx\n",
|
||||||
|
esf->r8, esf->r9, esf->r10, esf->r11);
|
||||||
|
|
||||||
|
LOG_ERR("R12=%016lx R13=%016lx R14=%016lx R15=%016lx\n",
|
||||||
|
esf->r12, esf->r13, esf->r14, esf->r15);
|
||||||
|
}
|
||||||
|
|
||||||
|
z_fatal_error(reason, esf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void z_x86_exception(const z_arch_esf_t *esf)
|
||||||
|
{
|
||||||
|
LOG_ERR("** CPU Exception %ld (code %ld/0x%lx) **\n",
|
||||||
|
esf->vector, esf->code, esf->code);
|
||||||
|
|
||||||
|
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
|
||||||
|
}
|
|
@ -26,6 +26,12 @@ unsigned char _irq_to_interrupt_vector[CONFIG_MAX_IRQ_LINES];
|
||||||
void (*x86_irq_funcs[NR_IRQ_VECTORS])(void *);
|
void (*x86_irq_funcs[NR_IRQ_VECTORS])(void *);
|
||||||
void *x86_irq_args[NR_IRQ_VECTORS];
|
void *x86_irq_args[NR_IRQ_VECTORS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char __aligned(STACK_ALIGN) ist[CONFIG_ISR_STACK_SIZE];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free IRQ vector at the specified priority, or return -1 if none left.
|
* Find a free IRQ vector at the specified priority, or return -1 if none left.
|
||||||
*/
|
*/
|
|
@ -9,6 +9,7 @@
|
||||||
#include <kernel_arch_data.h>
|
#include <kernel_arch_data.h>
|
||||||
#include <offsets_short.h>
|
#include <offsets_short.h>
|
||||||
#include <drivers/interrupt_controller/loapic.h>
|
#include <drivers/interrupt_controller/loapic.h>
|
||||||
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
.section .locore,"ax"
|
.section .locore,"ax"
|
||||||
.code32
|
.code32
|
||||||
|
@ -50,7 +51,7 @@ __start:
|
||||||
movw %ax, %fs
|
movw %ax, %fs
|
||||||
movw %ax, %gs
|
movw %ax, %gs
|
||||||
|
|
||||||
movl $(ist1 + CONFIG_ISR_STACK_SIZE), %esp
|
movl $(exception_stack + CONFIG_EXCEPTION_STACK_SIZE), %esp
|
||||||
|
|
||||||
/* transition to long mode, by the book. */
|
/* transition to long mode, by the book. */
|
||||||
|
|
||||||
|
@ -156,13 +157,13 @@ __swap:
|
||||||
movq %r14, _thread_offset_to_r14(%rsi)
|
movq %r14, _thread_offset_to_r14(%rsi)
|
||||||
movq %r15, _thread_offset_to_r15(%rsi)
|
movq %r15, _thread_offset_to_r15(%rsi)
|
||||||
|
|
||||||
movq $(ist1 + CONFIG_ISR_STACK_SIZE), %rsp
|
movq $(ist + CONFIG_ISR_STACK_SIZE), %rsp
|
||||||
|
|
||||||
/* fall through to __resume */
|
/* fall through to __resume */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry:
|
* Entry:
|
||||||
* RSP = top of ist1
|
* RSP = top of ist
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__resume:
|
__resume:
|
||||||
|
@ -226,22 +227,23 @@ gdt48:
|
||||||
.long gdt
|
.long gdt
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TSS - no privilege transitions (yet) so only used for IST1.
|
* TSS - no privilege transitions (yet) so only used for
|
||||||
|
* interrupt (IST1) and exception stack (IST7) locations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
tss: .long 0
|
tss: .long 0
|
||||||
.long 0, 0 /* RSP0 */
|
.long 0, 0 /* RSP0 */
|
||||||
.long 0, 0 /* RSP1 */
|
|
||||||
.long 0, 0 /* RSP2 */
|
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long (ist1 + CONFIG_ISR_STACK_SIZE), 0 /* IST1 */
|
.long 0, 0
|
||||||
.long 0, 0 /* IST2 */
|
.long 0, 0
|
||||||
.long 0, 0 /* IST3 */
|
.long (ist + CONFIG_ISR_STACK_SIZE), 0 /* IST1 */
|
||||||
.long 0, 0 /* IST4 */
|
.long 0, 0
|
||||||
.long 0, 0 /* IST5 */
|
.long 0, 0
|
||||||
.long 0, 0 /* IST6 */
|
.long 0, 0
|
||||||
.long 0, 0 /* IST7 */
|
.long 0, 0
|
||||||
|
.long 0, 0
|
||||||
|
.long (exception_stack + CONFIG_EXCEPTION_STACK_SIZE), 0 /* IST7 */
|
||||||
.long 0, 0
|
.long 0, 0
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
|
@ -259,14 +261,14 @@ tss: .long 0
|
||||||
|
|
||||||
.align 16
|
.align 16
|
||||||
idt:
|
idt:
|
||||||
IDT( 0, TRAP, 0); IDT( 1, TRAP, 0); IDT( 2, TRAP, 0); IDT( 3, TRAP, 0)
|
IDT( 0, TRAP, 7); IDT( 1, TRAP, 7); IDT( 2, TRAP, 7); IDT( 3, TRAP, 7)
|
||||||
IDT( 4, TRAP, 0); IDT( 5, TRAP, 0); IDT( 6, TRAP, 0); IDT( 7, TRAP, 0)
|
IDT( 4, TRAP, 7); IDT( 5, TRAP, 7); IDT( 6, TRAP, 7); IDT( 7, TRAP, 7)
|
||||||
IDT( 8, TRAP, 0); IDT( 9, TRAP, 0); IDT( 10, TRAP, 0); IDT( 11, TRAP, 0)
|
IDT( 8, TRAP, 7); IDT( 9, TRAP, 7); IDT( 10, TRAP, 7); IDT( 11, TRAP, 7)
|
||||||
IDT( 12, TRAP, 0); IDT( 13, TRAP, 0); IDT( 14, TRAP, 0); IDT( 15, TRAP, 0)
|
IDT( 12, TRAP, 7); IDT( 13, TRAP, 7); IDT( 14, TRAP, 7); IDT( 15, TRAP, 7)
|
||||||
IDT( 16, TRAP, 0); IDT( 17, TRAP, 0); IDT( 18, TRAP, 0); IDT( 19, TRAP, 0)
|
IDT( 16, TRAP, 7); IDT( 17, TRAP, 7); IDT( 18, TRAP, 7); IDT( 19, TRAP, 7)
|
||||||
IDT( 20, TRAP, 0); IDT( 21, TRAP, 0); IDT( 22, TRAP, 0); IDT( 23, TRAP, 0)
|
IDT( 20, TRAP, 7); IDT( 21, TRAP, 7); IDT( 22, TRAP, 7); IDT( 23, TRAP, 7)
|
||||||
IDT( 24, TRAP, 0); IDT( 25, TRAP, 0); IDT( 26, TRAP, 0); IDT( 27, TRAP, 0)
|
IDT( 24, TRAP, 7); IDT( 25, TRAP, 7); IDT( 26, TRAP, 7); IDT( 27, TRAP, 7)
|
||||||
IDT( 28, TRAP, 0); IDT( 29, TRAP, 0); IDT( 30, TRAP, 0); IDT( 31, TRAP, 0)
|
IDT( 28, TRAP, 7); IDT( 29, TRAP, 7); IDT( 30, TRAP, 7); IDT( 31, TRAP, 7)
|
||||||
|
|
||||||
IDT( 32, INTR, 1); IDT( 33, INTR, 1); IDT( 34, INTR, 1); IDT( 35, INTR, 1)
|
IDT( 32, INTR, 1); IDT( 33, INTR, 1); IDT( 34, INTR, 1); IDT( 35, INTR, 1)
|
||||||
IDT( 36, INTR, 1); IDT( 37, INTR, 1); IDT( 38, INTR, 1); IDT( 39, INTR, 1)
|
IDT( 36, INTR, 1); IDT( 37, INTR, 1); IDT( 38, INTR, 1); IDT( 39, INTR, 1)
|
||||||
|
@ -332,9 +334,31 @@ idt48:
|
||||||
#define EXCEPT_CODE(nr) vector_ ## nr: pushq $nr; jmp except
|
#define EXCEPT_CODE(nr) vector_ ## nr: pushq $nr; jmp except
|
||||||
#define EXCEPT(nr) vector_ ## nr: pushq $0; pushq $nr; jmp except
|
#define EXCEPT(nr) vector_ ## nr: pushq $0; pushq $nr; jmp except
|
||||||
|
|
||||||
except:
|
except: /*
|
||||||
/* save registers and dispatch to x86_exception() */
|
* finish struct NANO_ESF on stack. 'vector' .. 'ss' are
|
||||||
hlt
|
* already there from hardware trap and EXCEPT_*() stub.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pushq %r15
|
||||||
|
pushq %r14
|
||||||
|
pushq %r13
|
||||||
|
pushq %r12
|
||||||
|
pushq %r11
|
||||||
|
pushq %r10
|
||||||
|
pushq %r9
|
||||||
|
pushq %r8
|
||||||
|
pushq %rdi
|
||||||
|
pushq %rsi
|
||||||
|
pushq %rbp
|
||||||
|
pushq %rdx
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rax
|
||||||
|
|
||||||
|
movq %rsp, %rdi
|
||||||
|
call z_x86_exception
|
||||||
|
|
||||||
|
hlt /* should not return, but just in case .. */
|
||||||
|
|
||||||
EXCEPT ( 0); EXCEPT ( 1); EXCEPT ( 2); EXCEPT ( 3)
|
EXCEPT ( 0); EXCEPT ( 1); EXCEPT ( 2); EXCEPT ( 3)
|
||||||
EXCEPT ( 4); EXCEPT ( 5); EXCEPT ( 6); EXCEPT ( 7)
|
EXCEPT ( 4); EXCEPT ( 5); EXCEPT ( 6); EXCEPT ( 7)
|
||||||
|
@ -472,10 +496,10 @@ pdp: .long 0x00000183 /* 0x183 = G, 1GB, R/W, P */
|
||||||
.fill 4064, 1, 0
|
.fill 4064, 1, 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IST1 is used both during IRQ processing and early kernel initialization.
|
* The exception stack is used both for exceptions and early initialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 16
|
.align 16
|
||||||
ist1:
|
exception_stack:
|
||||||
.fill CONFIG_ISR_STACK_SIZE, 1, 0xFF
|
.fill CONFIG_EXCEPTION_STACK_SIZE, 1, 0xAA
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
|
#ifndef ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
|
||||||
#define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
|
#define ZEPHYR_ARCH_X86_INCLUDE_INTEL64_KERNEL_ARCH_THREAD_H_
|
||||||
|
|
||||||
#include <zephyr/types.h>
|
|
||||||
|
|
||||||
#ifndef _ASMLANGUAGE
|
#ifndef _ASMLANGUAGE
|
||||||
|
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The _callee_saved registers are unconditionally saved/restored across
|
* The _callee_saved registers are unconditionally saved/restored across
|
||||||
* context switches; the _thread_arch registers are only preserved when
|
* context switches; the _thread_arch registers are only preserved when
|
||||||
|
|
|
@ -43,11 +43,32 @@ static ALWAYS_INLINE unsigned int z_arch_irq_lock(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bogus ESF stuff until I figure out what to with it. I suspect
|
* the exception stack frame
|
||||||
* this is legacy cruft that we'll want to excise sometime soon, anyway.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct x86_esf {
|
struct x86_esf {
|
||||||
|
unsigned long rax;
|
||||||
|
unsigned long rbx;
|
||||||
|
unsigned long rcx;
|
||||||
|
unsigned long rdx;
|
||||||
|
unsigned long rbp;
|
||||||
|
unsigned long rsi;
|
||||||
|
unsigned long rdi;
|
||||||
|
unsigned long r8;
|
||||||
|
unsigned long r9;
|
||||||
|
unsigned long r10;
|
||||||
|
unsigned long r11;
|
||||||
|
unsigned long r12;
|
||||||
|
unsigned long r13;
|
||||||
|
unsigned long r14;
|
||||||
|
unsigned long r15;
|
||||||
|
unsigned long vector;
|
||||||
|
unsigned long code;
|
||||||
|
unsigned long rip;
|
||||||
|
unsigned long cs;
|
||||||
|
unsigned long rflags;
|
||||||
|
unsigned long rsp;
|
||||||
|
unsigned long ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct x86_esf z_arch_esf_t;
|
typedef struct x86_esf z_arch_esf_t;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue