kopia lustrzana https://github.com/micropython/micropython
293 wiersze
12 KiB
C
293 wiersze
12 KiB
C
/*
|
|
* This file is part of the MicroPython project, http://micropython.org/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2023 Alessandro Gatti
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
|
|
// Vector table
|
|
|
|
void mtvec_table(void) __attribute__((naked, section(".text.mtvec"), aligned(256)));
|
|
|
|
// Default interrupts
|
|
|
|
#define ASSIGN_EMPTY_MACHINE_INTERRUPT(interrupt_name) \
|
|
void interrupt_name(void) __attribute__((alias("mtvec_nop")))
|
|
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_ssi);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_msi);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_sti);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_mti);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_sei);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_mei);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq0);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq1);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq2);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq3);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq4);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq5);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq6);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq7);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq8);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq9);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq10);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq11);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq12);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq13);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq14);
|
|
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq15);
|
|
|
|
void mtvec_table(void) {
|
|
__asm volatile (
|
|
".org mtvec_table + 0 \n"
|
|
"jal zero, mtvec_exception \n" // Exception Handler
|
|
".org mtvec_table + 4 \n"
|
|
"jal zero, mtvec_ssi \n" // Supervisor Software Interrupt
|
|
".org mtvec_table + 12 \n"
|
|
"jal zero, mtvec_msi \n" // Machine Software Interrupt
|
|
".org mtvec_table + 20 \n"
|
|
"jal zero, mtvec_sti \n" // Supervisor Timer Interrupt
|
|
".org mtvec_table + 28 \n"
|
|
"jal zero, mtvec_mti \n" // Machine Timer Interrupt
|
|
".org mtvec_table + 36 \n"
|
|
"jal zero, mtvec_sei \n" // Supervisor External Interrupt
|
|
".org mtvec_table + 44 \n"
|
|
"jal zero, mtvec_mei \n" // Machine External Interrupt
|
|
// Not sure how many platform interrupts QEMU handles...
|
|
".org mtvec_table + 48 \n"
|
|
"jal mtvec_plat_irq0 \n" // Platform Interrupt #0
|
|
"jal mtvec_plat_irq1 \n" // Platform Interrupt #1
|
|
"jal mtvec_plat_irq2 \n" // Platform Interrupt #2
|
|
"jal mtvec_plat_irq3 \n" // Platform Interrupt #3
|
|
"jal mtvec_plat_irq4 \n" // Platform Interrupt #4
|
|
"jal mtvec_plat_irq5 \n" // Platform Interrupt #5
|
|
"jal mtvec_plat_irq6 \n" // Platform Interrupt #6
|
|
"jal mtvec_plat_irq7 \n" // Platform Interrupt #7
|
|
"jal mtvec_plat_irq8 \n" // Platform Interrupt #8
|
|
"jal mtvec_plat_irq9 \n" // Platform Interrupt #9
|
|
"jal mtvec_plat_irq10 \n" // Platform Interrupt #10
|
|
"jal mtvec_plat_irq11 \n" // Platform Interrupt #11
|
|
"jal mtvec_plat_irq12 \n" // Platform Interrupt #12
|
|
"jal mtvec_plat_irq13 \n" // Platform Interrupt #13
|
|
"jal mtvec_plat_irq14 \n" // Platform Interrupt #14
|
|
"jal mtvec_plat_irq15 \n" // Platform Interrupt #15
|
|
:
|
|
:
|
|
: "memory"
|
|
);
|
|
}
|
|
|
|
volatile uint32_t registers_copy[35] = { 0 };
|
|
|
|
const char *exception_causes[] = {
|
|
"Reserved", // 0
|
|
"Supervisor software interrupt", // 1
|
|
"Machine software interrupt", // 2
|
|
"Supervisor timer interrupt", // 3
|
|
"Machine timer interrupt", // 4
|
|
"Supervisor external interrupt", // 5
|
|
"Machine external interrupt", // 6
|
|
"Designated for platform use", // 7
|
|
"Instruction address misaligned", // 8
|
|
"Instruction address fault", // 9
|
|
"Illegal instruction", // 10
|
|
"Breakpoint", // 11
|
|
"Load address misaligned", // 12
|
|
"Load address fault", // 13
|
|
"Store/AMO address misaligned", // 14
|
|
"Store/AMO access fault", // 15
|
|
"Environment call from U-mode", // 16
|
|
"Environment call from S-mode", // 17
|
|
"Environment call from M-mode", // 18
|
|
"Instruction page fault", // 19
|
|
"Load page fault", // 20
|
|
"Store/AMO page fault", // 21
|
|
"Designated for custom use" // 22
|
|
};
|
|
|
|
const char *lookup_cause(uint32_t mcause) {
|
|
if (mcause & 0x80000000) {
|
|
switch (mcause & 0x7FFFFFFF) {
|
|
case 1:
|
|
return exception_causes[1];
|
|
case 3:
|
|
return exception_causes[2];
|
|
case 5:
|
|
return exception_causes[3];
|
|
case 7:
|
|
return exception_causes[4];
|
|
case 9:
|
|
return exception_causes[5];
|
|
case 11:
|
|
return exception_causes[6];
|
|
default:
|
|
return (mcause >= 16) ?
|
|
exception_causes[7] :
|
|
exception_causes[0];
|
|
}
|
|
}
|
|
|
|
switch (mcause) {
|
|
case 0:
|
|
return exception_causes[8];
|
|
case 1:
|
|
return exception_causes[9];
|
|
case 2:
|
|
return exception_causes[10];
|
|
case 3:
|
|
return exception_causes[11];
|
|
case 4:
|
|
return exception_causes[12];
|
|
case 5:
|
|
return exception_causes[13];
|
|
case 6:
|
|
return exception_causes[14];
|
|
case 7:
|
|
return exception_causes[15];
|
|
case 8:
|
|
return exception_causes[16];
|
|
case 9:
|
|
return exception_causes[17];
|
|
case 11:
|
|
return exception_causes[18];
|
|
case 12:
|
|
return exception_causes[19];
|
|
case 13:
|
|
return exception_causes[20];
|
|
case 15:
|
|
return exception_causes[21];
|
|
default: {
|
|
if ((mcause >= 24 && mcause <= 31) ||
|
|
(mcause >= 48 && mcause <= 63)) {
|
|
return exception_causes[22];
|
|
}
|
|
|
|
return exception_causes[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma GCC push_options
|
|
#pragma GCC optimize ("align-functions=4")
|
|
|
|
__attribute__((interrupt("machine"), weak)) void mtvec_nop(void) {
|
|
}
|
|
|
|
__attribute__((interrupt("machine"), weak)) void mtvec_exception(void) {
|
|
__asm volatile (
|
|
"csrrw x31, mscratch, x31 \n" // Save X31
|
|
"la x31, registers_copy \n" // Load target address
|
|
"sw x1, 0(x31) \n" // Save X1
|
|
"sw x2, 4(x31) \n" // Save X2
|
|
"sw x3, 8(x31) \n" // Save X3
|
|
"sw x4, 12(x31) \n" // Save X4
|
|
"sw x5, 16(x31) \n" // Save X5
|
|
"sw x6, 20(x31) \n" // Save X6
|
|
"sw x7, 24(x31) \n" // Save X7
|
|
"sw x8, 28(x31) \n" // Save X8
|
|
"sw x9, 32(x31) \n" // Save X9
|
|
"sw x10, 36(x31) \n" // Save X10
|
|
"sw x11, 40(x31) \n" // Save X11
|
|
"sw x12, 44(x31) \n" // Save X12
|
|
"sw x13, 48(x31) \n" // Save X13
|
|
"sw x14, 52(x31) \n" // Save X14
|
|
"sw x15, 56(x31) \n" // Save X15
|
|
"sw x16, 60(x31) \n" // Save X16
|
|
"sw x17, 64(x31) \n" // Save X17
|
|
"sw x18, 68(x31) \n" // Save X18
|
|
"sw x19, 72(x31) \n" // Save X19
|
|
"sw x20, 76(x31) \n" // Save X20
|
|
"sw x21, 80(x31) \n" // Save X21
|
|
"sw x22, 84(x31) \n" // Save X22
|
|
"sw x23, 88(x31) \n" // Save X23
|
|
"sw x24, 92(x31) \n" // Save X24
|
|
"sw x25, 98(x31) \n" // Save X25
|
|
"sw x26, 100(x31) \n" // Save X26
|
|
"sw x27, 104(x31) \n" // Save X27
|
|
"sw x28, 108(x31) \n" // Save X28
|
|
"sw x29, 112(x31) \n" // Save X29
|
|
"sw x30, 116(x31) \n" // Save X30
|
|
"csrr x30, mscratch \n" // Retrieve X31
|
|
"sw x30, 120(x31) \n" // Save X31
|
|
"csrr x30, mepc \n" // Load MEPC
|
|
"sw x30, 124(x31) \n" // Save MEPC
|
|
"csrr x30, mcause \n" // Load MCAUSE
|
|
"sw x30, 128(x31) \n" // Save MCAUSE
|
|
"csrr x30, mtval \n" // Load MTVAL
|
|
"sw x30, 132(x31) \n" // Save MTVAL
|
|
"csrr x30, mstatus \n" // Load MSTATUS
|
|
"sw x30, 138(x31) \n" // Save MSTATUS
|
|
"lw x30, 116(x31) \n" // Restore X30
|
|
"lw x31, 120(x31) \n" // Restore X31
|
|
:
|
|
:
|
|
: "memory"
|
|
);
|
|
|
|
printf("\nMACHINE EXCEPTION CAUGHT:\n\n");
|
|
|
|
printf(" RA=%08lX SP=%08lX GP=%08lX TP=%08lX T0=%08lX T1=%08lX\n",
|
|
registers_copy[0], registers_copy[1], registers_copy[2],
|
|
registers_copy[3], registers_copy[4], registers_copy[5]);
|
|
printf(" T2=%08lX S0=%08lX S1=%08lX A0=%08lX A1=%08lX A2=%08lX\n",
|
|
registers_copy[6], registers_copy[7], registers_copy[8],
|
|
registers_copy[9], registers_copy[10], registers_copy[11]);
|
|
printf(" A3=%08lX A4=%08lX A5=%08lX A6=%08lX A7=%08lX S2=%08lX\n",
|
|
registers_copy[12], registers_copy[13], registers_copy[14],
|
|
registers_copy[15], registers_copy[16], registers_copy[17]);
|
|
printf(" S3=%08lX S4=%08lX S5=%08lX S6=%08lX S7=%08lX S8=%08lX\n",
|
|
registers_copy[18], registers_copy[19], registers_copy[20],
|
|
registers_copy[21], registers_copy[22], registers_copy[23]);
|
|
printf(" S9=%08lX S10=%08lX S11=%08lX T3=%08lX T4=%08lX T5=%08lX\n",
|
|
registers_copy[24], registers_copy[25], registers_copy[26],
|
|
registers_copy[27], registers_copy[28], registers_copy[29]);
|
|
printf(" T6=%08lX\n\n", registers_copy[30]);
|
|
|
|
printf(" MEPC=%08lX MTVAL=%08lX MSTATUS=%08lx MCAUSE=%08lx (%s)\n",
|
|
registers_copy[31], registers_copy[33], registers_copy[34],
|
|
registers_copy[32], lookup_cause(registers_copy[32]));
|
|
|
|
exit(-1);
|
|
}
|
|
|
|
#pragma GCC pop_options
|
|
|
|
void set_interrupt_table(void) {
|
|
__asm volatile (
|
|
"csrrci s0, mstatus, 8 \n" // S0 = MSTATUS & ~MIE
|
|
"csrw mstatus, s0 \n" // Global machine interrupts are disabled
|
|
"csrw mie, zero \n" // Disable machine interrupts
|
|
"csrw mip, zero \n" // Clear pending machine interrupts
|
|
"addi s0, %0, 1 \n" // Vectored machine interrupts enabled
|
|
"csrw mtvec, s0 \n" // Set new machine vector table
|
|
"csrrsi s0, mstatus, 8 \n" // S0 = MSTATUS | MIE
|
|
"csrw mstatus, s0 \n" // Global machine interrupts are enabled
|
|
:
|
|
: "r" (mtvec_table)
|
|
: "memory"
|
|
);
|
|
}
|