arm: add software reboot for QEMU
This simulates a reboot by jumping back to the address stored in the reset vector in vector table found at address 0. It is supported from interrupt/exception level, which means that sys_arch_reboot() in this case finds out if it is called from thread mode or handler mode, and in the latter case, it unwinds the nested exception stack as needed. Change-Id: Ib67f850f8411f1ee8fc592a5f31f2f70d0af14a4 Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
This commit is contained in:
parent
62c65d7f00
commit
c5bb958db4
2 changed files with 96 additions and 10 deletions
|
@ -27,6 +27,7 @@
|
||||||
#include <toolchain.h>
|
#include <toolchain.h>
|
||||||
#include <sections.h>
|
#include <sections.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
#include <offsets.h>
|
||||||
#include "vector_table.h"
|
#include "vector_table.h"
|
||||||
|
|
||||||
_ASM_FILE_PROLOGUE
|
_ASM_FILE_PROLOGUE
|
||||||
|
@ -87,3 +88,53 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
b _PrepC
|
b _PrepC
|
||||||
|
|
||||||
|
#if defined(CONFIG_SOC_TI_LM3S6965_QEMU)
|
||||||
|
|
||||||
|
GTEXT(_do_software_reboot)
|
||||||
|
SECTION_FUNC(TEXT,_do_software_reboot)
|
||||||
|
|
||||||
|
eors r0, r0
|
||||||
|
|
||||||
|
/* move exception table back to 0 */
|
||||||
|
ldr r1, =0xe000e000
|
||||||
|
str r0, [r1, #0xd08] /* VTOR */
|
||||||
|
|
||||||
|
ldr r0, [r0, #4]
|
||||||
|
bx r0
|
||||||
|
|
||||||
|
|
||||||
|
GTEXT(_force_exit_one_nested_irq)
|
||||||
|
SECTION_FUNC(TEXT,_force_exit_one_nested_irq)
|
||||||
|
|
||||||
|
ldr r0, =_SCS_ICSR_RETTOBASE
|
||||||
|
ldr r1, =_SCS_ICSR
|
||||||
|
ldr r1, [r1]
|
||||||
|
ands.w r0, r1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If Z flag is set, we are nested, so un-nest one level and get back to
|
||||||
|
* this function to unwind the next level; else, exit the last interrupt
|
||||||
|
* by jumping to reboot code.
|
||||||
|
*/
|
||||||
|
ittee eq
|
||||||
|
ldreq lr, =0xfffffff1
|
||||||
|
ldreq r2, =_force_exit_one_nested_irq
|
||||||
|
ldrne lr, =0xfffffffd
|
||||||
|
ldrne r2, =_do_software_reboot
|
||||||
|
|
||||||
|
ldr ip, =_interrupt_stack
|
||||||
|
add.w ip, #(__tESF_SIZEOF * 2) /* enough for a stack frame */
|
||||||
|
ldr r1, =0xfffffffe
|
||||||
|
and.w r2, r1
|
||||||
|
str r2, [ip, #(6 * 4)]
|
||||||
|
ldr r2, =0x01000000
|
||||||
|
str r2, [ip, #(7 * 4)]
|
||||||
|
|
||||||
|
ite eq
|
||||||
|
moveq sp, ip
|
||||||
|
msrne PSP, ip
|
||||||
|
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -30,20 +30,38 @@
|
||||||
|
|
||||||
#define SCB_AIRCR_VECTKEY_EN_W 0x05FA
|
#define SCB_AIRCR_VECTKEY_EN_W 0x05FA
|
||||||
|
|
||||||
/**
|
#if defined(CONFIG_SOC_TI_LM3S6965_QEMU)
|
||||||
*
|
/*
|
||||||
* @brief Reset the system
|
* QEMU is missing the support for rebooting through the SYSRESETREQ mechanism.
|
||||||
*
|
* Just jump back to __reset() of the image in flash, which address can
|
||||||
* This routine resets the processor.
|
* _always_ be found in the vector table reset slot located at address 0x4.
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
*/
|
||||||
void sys_arch_reboot(int type)
|
|
||||||
|
static void software_reboot(void)
|
||||||
|
{
|
||||||
|
extern void _do_software_reboot(void);
|
||||||
|
extern void _force_exit_one_nested_irq(void);
|
||||||
|
/*
|
||||||
|
* force enable interrupts locked via PRIMASK if somehow disabled: the
|
||||||
|
* boot code does not enable them
|
||||||
|
*/
|
||||||
|
__asm__ volatile("cpsie i" :::);
|
||||||
|
|
||||||
|
if (_ScbIsInThreadMode()) {
|
||||||
|
_do_software_reboot();
|
||||||
|
} else {
|
||||||
|
__asm__ volatile(
|
||||||
|
"ldr r0, =_force_exit_one_nested_irq\n\t"
|
||||||
|
"bx r0\n\t"
|
||||||
|
:::);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define DO_REBOOT() software_reboot()
|
||||||
|
#else
|
||||||
|
static void reboot_through_sysresetreq(void)
|
||||||
{
|
{
|
||||||
union __aircr reg;
|
union __aircr reg;
|
||||||
|
|
||||||
ARG_UNUSED(type);
|
|
||||||
|
|
||||||
reg.val = __scs.scb.aircr.val;
|
reg.val = __scs.scb.aircr.val;
|
||||||
reg.bit.vectkey = SCB_AIRCR_VECTKEY_EN_W;
|
reg.bit.vectkey = SCB_AIRCR_VECTKEY_EN_W;
|
||||||
reg.bit.sysresetreq = 1;
|
reg.bit.sysresetreq = 1;
|
||||||
|
@ -54,6 +72,23 @@ void sys_arch_reboot(int type)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#define DO_REBOOT() reboot_through_sysresetreq()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Reset the system
|
||||||
|
*
|
||||||
|
* This routine resets the processor.
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sys_arch_reboot(int type)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(type);
|
||||||
|
DO_REBOOT();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue