summaryrefslogtreecommitdiff
path: root/core/minute-ia/panic.c
blob: 0898e4e71773772897b2d250d67187f28919f280 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "common.h"
#include "console.h"
#include "cpu.h"
#include "host_command.h"
#include "panic.h"
#include "printf.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"

/*
 * This array maps an interrupt vector number to the corresponding
 * exception name. See see "Intel 64 and IA-32 Architectures Software
 * Developer's Manual", Volume 3A, Section 6.15.
 */
const static char *panic_reason[] = {
	"Divide By Zero",
	"Debug Exception",
	"NMI Interrupt",
	"Breakpoint Exception",
	"Overflow Exception",
	"BOUND Range Exceeded Exception",
	"Invalid Opcode Exception",
	"Device Not Available Exception",
	"Double Fault Exception",
	"Coprocessor Segment Overrun",
	"Invalid TSS Exception",
	"Segment Not Present",
	"Stack Fault Exception",
	"General Protection Fault",
	"Page Fault",
	"Reserved",
	"Math Fault",
	"Alignment Check Exception",
	"Machine Check Exception",
	"SIMD Floating Point Exception",
	"Virtualization Exception",
};

/*
 * Print panic data. This may be called either from the report_panic
 * procedure (below) while handling a panic, or from the panicinfo
 * console command.
 */
void panic_data_print(const struct panic_data *pdata)
{
	if (pdata->x86.vector == ISH_WDT_VEC)
		panic_printf("Reason: Watchdog Expiration\n");
	else if (pdata->x86.vector <= 20)
		panic_printf("Reason: %s\n", panic_reason[pdata->x86.vector]);
	else
		panic_printf("Interrupt vector number: 0x%08X (unknown)\n",
			     pdata->x86.vector);
	panic_printf("\n");
	panic_printf("Error Code = 0x%08X\n", pdata->x86.error_code);
	panic_printf("EIP        = 0x%08X\n", pdata->x86.eip);
	panic_printf("CS         = 0x%08X\n", pdata->x86.cs);
	panic_printf("EFLAGS     = 0x%08X\n", pdata->x86.eflags);
	panic_printf("EAX        = 0x%08X\n", pdata->x86.eax);
	panic_printf("EBX        = 0x%08X\n", pdata->x86.ebx);
	panic_printf("ECX        = 0x%08X\n", pdata->x86.ecx);
	panic_printf("EDX        = 0x%08X\n", pdata->x86.edx);
	panic_printf("ESI        = 0x%08X\n", pdata->x86.esi);
	panic_printf("EDI        = 0x%08X\n", pdata->x86.edi);
}

/**
 * Default exception handler, which reports a panic.
 *
 * The first parameter should be pushed by a software routine aware of
 * the interrupt vector number (see DEFINE_EXN_HANDLER macro in
 * interrupts.c).
 *
 * The remaining parameters (error_code, eip, cs, eflags) are in the
 * order pushed to the stack by hardware: see "Intel 64 and IA-32
 * Architectures Software Developer's Manual", Volume 3A, Figure 6-4.
 */
__attribute__ ((noreturn)) void __keep exception_panic(
	uint32_t vector,
	uint32_t error_code,
	uint32_t eip,
	uint32_t cs,
	uint32_t eflags)
{
	/*
	 * If a panic were to occur during the reset procedure, we want
	 * to make sure that this panic will certainly cause a hard
	 * reset, rather than aontaskfw reset. Track if paniced once
	 * already.
	 */
	static int panic_once;

	register uint32_t eax asm("eax");
	register uint32_t ebx asm("ebx");
	register uint32_t ecx asm("ecx");
	register uint32_t edx asm("edx");
	register uint32_t esi asm("esi");
	register uint32_t edi asm("edi");

	/* Save registers to global panic structure */
	PANIC_DATA_PTR->x86.eax = eax;
	PANIC_DATA_PTR->x86.ebx = ebx;
	PANIC_DATA_PTR->x86.ecx = ecx;
	PANIC_DATA_PTR->x86.edx = edx;
	PANIC_DATA_PTR->x86.esi = esi;
	PANIC_DATA_PTR->x86.edi = edi;

	/* Save stack data to global panic structure */
	PANIC_DATA_PTR->x86.vector = vector;
	PANIC_DATA_PTR->x86.error_code = error_code;
	PANIC_DATA_PTR->x86.eip = eip;
	PANIC_DATA_PTR->x86.cs = cs;
	PANIC_DATA_PTR->x86.eflags = eflags;

	/* Initialize panic data */
	PANIC_DATA_PTR->arch = PANIC_ARCH_X86;
	PANIC_DATA_PTR->struct_version = 2;
	PANIC_DATA_PTR->magic = PANIC_DATA_MAGIC;

	/* Display the panic and reset */
	if (panic_once)
		panic_printf("\nWhile resetting from a panic, another panic"
			     " occurred!");

	panic_printf("\n========== PANIC ==========\n");
	panic_data_print(PANIC_DATA_PTR);
	panic_printf("\n");
	panic_printf("Resetting system...\n");
	panic_printf("===========================\n");

	if (panic_once) {
		system_reset(SYSTEM_RESET_HARD);
	} else if (vector == ISH_WDT_VEC) {
		panic_once = 1;
		system_reset(SYSTEM_RESET_AP_WATCHDOG);
	} else {
		panic_once = 1;
		system_reset(0);
	}

	__builtin_unreachable();
}

#ifdef CONFIG_SOFTWARE_PANIC
void software_panic(uint32_t reason, uint32_t info)
{
	/* TODO: store panic log */
	while (1)
		continue;
}

void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception)
{
}

void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception)
{
}
#endif