mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
hwstub: implement read/write data abort recovery
Change-Id: I1625873b6864584c40984723d82548ad242ee08e
This commit is contained in:
parent
2ee2a9697a
commit
2cdfc43f10
11 changed files with 308 additions and 43 deletions
|
@ -3,10 +3,12 @@ asm/arm/memcpy.S
|
||||||
asm/arm/memmove.S
|
asm/arm/memmove.S
|
||||||
asm/arm/memset.S
|
asm/arm/memset.S
|
||||||
asm/arm/atomic_rw.S
|
asm/arm/atomic_rw.S
|
||||||
|
asm/arm/system.S
|
||||||
#elif defined(CPU_MIPS)
|
#elif defined(CPU_MIPS)
|
||||||
asm/mips/memcpy.S
|
asm/mips/memcpy.S
|
||||||
asm/mips/memset.S
|
asm/mips/memset.S
|
||||||
asm/mips/atomic_rw.S
|
asm/mips/atomic_rw.S
|
||||||
|
asm/mips/system.S
|
||||||
#else
|
#else
|
||||||
#error "Unimplemented ISA"
|
#error "Unimplemented ISA"
|
||||||
#endif
|
#endif
|
||||||
|
|
57
utils/hwstub/stub/asm/arm/system.S
Normal file
57
utils/hwstub/stub/asm/arm/system.S
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Handling of data abort:
|
||||||
|
* the code can register a "longjmp" buffer to restore the context in case of
|
||||||
|
* fault */
|
||||||
|
.data
|
||||||
|
data_abort_jmp_ctx_ptr:
|
||||||
|
/* buffer contains in order: cpsr,r4-r11,sp,lr,pc */
|
||||||
|
.skip 48 /* = 4 * (cpsr + 11 registers) */
|
||||||
|
|
||||||
|
.text
|
||||||
|
/* Prototype: int set_data_abort_jmp()
|
||||||
|
* Return: 1 in case of data abort, 0 otherwise */
|
||||||
|
.global set_data_abort_jmp
|
||||||
|
set_data_abort_jmp:
|
||||||
|
mrs r2, cpsr
|
||||||
|
ldr r1, =data_abort_jmp_ctx_ptr
|
||||||
|
mov r0, #0
|
||||||
|
stmia r1, {r2,r4-r11,sp,lr,pc} /* see PC note below */
|
||||||
|
bx lr
|
||||||
|
mov r0, #1 /* <-- PC points here in stmia */
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.global data_abort_handler
|
||||||
|
data_abort_handler:
|
||||||
|
/* restore everything from context */
|
||||||
|
ldr r1, =data_abort_jmp_ctx_ptr
|
||||||
|
/* NOTE: we need to restore sp_sys and lr_sys, for this we need the
|
||||||
|
* LDM Rn, {}^
|
||||||
|
* variant, but we cannot restore PC from it because ^ has a different
|
||||||
|
* meaning and won't restore user/sys registers. On top of that, the
|
||||||
|
* non-PC ^ variant cannot do the register writeback, so on the PC restore,
|
||||||
|
* we reload all registers once again to avoid manually offseting the base
|
||||||
|
* register, it will trash sp_abt and lr_abr but those are unused anyway
|
||||||
|
* because we do not save the abort address and we don't use an abort stack */
|
||||||
|
ldmia r1, {r0,r4-r11,sp,lr}^ /* this variant cannot have writeback (r1!) */
|
||||||
|
msr spsr, r0
|
||||||
|
ldmia r1, {r0,r4-r11,sp,lr,pc}^ /* reload some registers but we don't care */
|
|
@ -20,7 +20,7 @@
|
||||||
#include "mips.h"
|
#include "mips.h"
|
||||||
|
|
||||||
.set noreorder
|
.set noreorder
|
||||||
.section .text, "ax", %progbits
|
.section .icode, "ax", %progbits
|
||||||
.global target_read8
|
.global target_read8
|
||||||
.type target_read8, %function
|
.type target_read8, %function
|
||||||
.global target_read16
|
.global target_read16
|
||||||
|
|
51
utils/hwstub/stub/asm/mips/system.S
Normal file
51
utils/hwstub/stub/asm/mips/system.S
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 by Marcin Bukat
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "mips.h"
|
||||||
|
|
||||||
|
/* Handling of data abort:
|
||||||
|
* the code can register a "longjmp" buffer to restore the context in case of
|
||||||
|
* fault */
|
||||||
|
.data
|
||||||
|
.global data_abort_jmp_ctx_ptr
|
||||||
|
data_abort_jmp_ctx_ptr:
|
||||||
|
/* buffer contains in order: s0-s7, sp, s8, ra */
|
||||||
|
.skip 44 /* = 4 * (9 callee saved registers + sp + ra) */
|
||||||
|
|
||||||
|
.set noreorder
|
||||||
|
.section .icode, "ax", %progbits
|
||||||
|
/* Prototype: int set_data_abort_jmp()
|
||||||
|
* Return: 1 in case of data abort, 0 otherwise */
|
||||||
|
.global set_data_abort_jmp
|
||||||
|
set_data_abort_jmp:
|
||||||
|
la v0, data_abort_jmp_ctx_ptr
|
||||||
|
sw s0, 0(v0)
|
||||||
|
sw s1, 4(v0)
|
||||||
|
sw s2, 8(v0)
|
||||||
|
sw s3, 12(v0)
|
||||||
|
sw s4, 16(v0)
|
||||||
|
sw s5, 20(v0)
|
||||||
|
sw s6, 24(v0)
|
||||||
|
sw s7, 28(v0)
|
||||||
|
sw sp, 32(v0)
|
||||||
|
sw s8, 36(v0)
|
||||||
|
sw ra, 40(v0)
|
||||||
|
jr ra
|
||||||
|
move v0, zero
|
||||||
|
.set reorder
|
|
@ -107,7 +107,7 @@ core_irq_setup:
|
||||||
mtc0 t1, C0_CAUSE # DC=1, IV=1
|
mtc0 t1, C0_CAUSE # DC=1, IV=1
|
||||||
mtc0 zero,C0_INTCTL # VS = 0
|
mtc0 zero,C0_INTCTL # VS = 0
|
||||||
|
|
||||||
# clear bss
|
clear_bss:
|
||||||
la t0, bssbegin
|
la t0, bssbegin
|
||||||
la t1, bssend
|
la t1, bssend
|
||||||
beq t0, t1, stack_setup
|
beq t0, t1, stack_setup
|
||||||
|
@ -119,7 +119,6 @@ clear_bss_loop:
|
||||||
addiu t0, 4
|
addiu t0, 4
|
||||||
|
|
||||||
stack_setup:
|
stack_setup:
|
||||||
# setup stack
|
|
||||||
la k0, irqstackend
|
la k0, irqstackend
|
||||||
la sp, stackend
|
la sp, stackend
|
||||||
la t0, stackbegin
|
la t0, stackbegin
|
||||||
|
@ -135,8 +134,72 @@ stack_munge_loop:
|
||||||
jr.hb t0
|
jr.hb t0
|
||||||
ei
|
ei
|
||||||
|
|
||||||
.set at
|
.extern data_abort_jmp_ctx_ptr
|
||||||
.set reorder
|
.global tlb_refill_handler
|
||||||
|
.section .exception.tlb_refill,"ax",%progbits
|
||||||
|
|
||||||
|
tlb_refill_handler:
|
||||||
|
la k1, data_abort_jmp_ctx_ptr
|
||||||
|
lw s0, 0(k1)
|
||||||
|
lw s1, 4(k1)
|
||||||
|
lw s2, 8(k1)
|
||||||
|
lw s3, 12(k1)
|
||||||
|
lw s4, 16(k1)
|
||||||
|
lw s5, 20(k1)
|
||||||
|
lw s6, 24(k1)
|
||||||
|
lw s7, 28(k1)
|
||||||
|
lw sp, 32(k1)
|
||||||
|
lw s8, 36(k1)
|
||||||
|
lw k1, 40(k1)
|
||||||
|
mtc0 k1, C0_EPC
|
||||||
|
ehb
|
||||||
|
li v0, 1
|
||||||
|
eret
|
||||||
|
nop
|
||||||
|
|
||||||
|
.global cache_error_handler
|
||||||
|
.section .exception.cache_error,"ax",%progbits
|
||||||
|
|
||||||
|
cache_error_handler:
|
||||||
|
la k1, data_abort_jmp_ctx_ptr
|
||||||
|
lw s0, 0(k1)
|
||||||
|
lw s1, 4(k1)
|
||||||
|
lw s2, 8(k1)
|
||||||
|
lw s3, 12(k1)
|
||||||
|
lw s4, 16(k1)
|
||||||
|
lw s5, 20(k1)
|
||||||
|
lw s6, 24(k1)
|
||||||
|
lw s7, 28(k1)
|
||||||
|
lw sp, 32(k1)
|
||||||
|
lw s8, 36(k1)
|
||||||
|
lw k1, 40(k1)
|
||||||
|
mtc0 k1, C0_EPC
|
||||||
|
ehb
|
||||||
|
li v0, 1
|
||||||
|
eret
|
||||||
|
nop
|
||||||
|
|
||||||
|
.global general_exception_handler
|
||||||
|
.section .exception.general_exception,"ax",%progbits
|
||||||
|
|
||||||
|
general_exception_handler:
|
||||||
|
la k1, data_abort_jmp_ctx_ptr
|
||||||
|
lw s0, 0(k1)
|
||||||
|
lw s1, 4(k1)
|
||||||
|
lw s2, 8(k1)
|
||||||
|
lw s3, 12(k1)
|
||||||
|
lw s4, 16(k1)
|
||||||
|
lw s5, 20(k1)
|
||||||
|
lw s6, 24(k1)
|
||||||
|
lw s7, 28(k1)
|
||||||
|
lw sp, 32(k1)
|
||||||
|
lw s8, 36(k1)
|
||||||
|
lw k1, 40(k1)
|
||||||
|
mtc0 k1, C0_EPC
|
||||||
|
ehb
|
||||||
|
li v0, 1
|
||||||
|
eret
|
||||||
|
nop
|
||||||
|
|
||||||
/* s0-s7 not saved as this are callee saved registers
|
/* s0-s7 not saved as this are callee saved registers
|
||||||
* CO_STATUS is not saved as nested interrupts are not supported
|
* CO_STATUS is not saved as nested interrupts are not supported
|
||||||
|
@ -149,10 +212,7 @@ stack_munge_loop:
|
||||||
.extern INT_UDC
|
.extern INT_UDC
|
||||||
|
|
||||||
.global irq_handler
|
.global irq_handler
|
||||||
.set mips32r2
|
.section .exception.irq,"ax",%progbits
|
||||||
.set noreorder
|
|
||||||
.set noat
|
|
||||||
.section .irq_vector,"ax",%progbits
|
|
||||||
|
|
||||||
irq_handler:
|
irq_handler:
|
||||||
move k1, sp
|
move k1, sp
|
||||||
|
|
|
@ -13,20 +13,13 @@ SECTIONS
|
||||||
{
|
{
|
||||||
.init.text :
|
.init.text :
|
||||||
{
|
{
|
||||||
_irqbase = .;
|
|
||||||
relocstart = .;
|
relocstart = .;
|
||||||
oc_codestart = .;
|
oc_codestart = .;
|
||||||
*(.init.text*)
|
KEEP(*(.init.text*))
|
||||||
} > IRAM
|
} > IRAM
|
||||||
|
|
||||||
.exception.text (IRAM_ORIG + 0x200) :
|
.icode :
|
||||||
{
|
{
|
||||||
*(.irq_vector*)
|
|
||||||
} > IRAM
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text*)
|
|
||||||
*(.icode*)
|
*(.icode*)
|
||||||
} > IRAM
|
} > IRAM
|
||||||
|
|
||||||
|
@ -35,20 +28,6 @@ SECTIONS
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
*(.data*)
|
*(.data*)
|
||||||
*(.rel.dyn)
|
*(.rel.dyn)
|
||||||
relocend = .;
|
|
||||||
} > IRAM
|
|
||||||
|
|
||||||
.stack (NOLOAD) :
|
|
||||||
{
|
|
||||||
. = ALIGN(4);
|
|
||||||
stackbegin = .;
|
|
||||||
oc_stackstart = .;
|
|
||||||
. += 0x2000;
|
|
||||||
stackend = .;
|
|
||||||
irqstackbegin = .;
|
|
||||||
. += 0x400;
|
|
||||||
irqstackend = .;
|
|
||||||
oc_stackend = .;
|
|
||||||
} > IRAM
|
} > IRAM
|
||||||
|
|
||||||
.bss (NOLOAD) :
|
.bss (NOLOAD) :
|
||||||
|
@ -58,8 +37,51 @@ SECTIONS
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.scommon*)
|
*(.scommon*)
|
||||||
|
. = ALIGN(4);
|
||||||
bssend = .;
|
bssend = .;
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.exception.tlb_refill (IRAM_ORIG + 0x1000) :
|
||||||
|
{
|
||||||
|
_irqbase = .;
|
||||||
|
KEEP(*(.exception.tlb_refill))
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.exception.cache_error (IRAM_ORIG + 0x1100) :
|
||||||
|
{
|
||||||
|
KEEP(*(.exception.cache_error))
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.exception.general_exception (IRAM_ORIG + 0x1180) :
|
||||||
|
{
|
||||||
|
KEEP(*(.exception.general_exception))
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.exception.irq (IRAM_ORIG + 0x1200) :
|
||||||
|
{
|
||||||
|
KEEP(*(.exception.irq))
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text*)
|
||||||
|
. = ALIGN(16);
|
||||||
|
relocend = .;
|
||||||
|
} > IRAM
|
||||||
|
|
||||||
|
.stack (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
stackbegin = .;
|
||||||
oc_codeend = .;
|
oc_codeend = .;
|
||||||
|
oc_stackstart = .;
|
||||||
|
. += 0x2000;
|
||||||
|
stackend = .;
|
||||||
|
|
||||||
|
irqstackbegin = .;
|
||||||
|
. += 0x400;
|
||||||
|
irqstackend = .;
|
||||||
|
oc_stackend = .;
|
||||||
oc_bufferstart = .;
|
oc_bufferstart = .;
|
||||||
} > IRAM
|
} > IRAM
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "usb_drv.h"
|
#include "usb_drv.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
extern unsigned char oc_codestart[];
|
extern unsigned char oc_codestart[];
|
||||||
extern unsigned char oc_codeend[];
|
extern unsigned char oc_codeend[];
|
||||||
|
@ -420,18 +421,41 @@ static void handle_read(struct usb_ctrlrequest *req)
|
||||||
{
|
{
|
||||||
if(id != last_id)
|
if(id != last_id)
|
||||||
return usb_drv_stall(EP_CONTROL, true, true);
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
|
||||||
if(req->bRequest == HWSTUB_READ2_ATOMIC)
|
if(req->bRequest == HWSTUB_READ2_ATOMIC)
|
||||||
|
{
|
||||||
|
if(set_data_abort_jmp() == 0)
|
||||||
{
|
{
|
||||||
if(!read_atomic(usb_buffer, (void *)last_addr, req->wLength))
|
if(!read_atomic(usb_buffer, (void *)last_addr, req->wLength))
|
||||||
return usb_drv_stall(EP_CONTROL, true, true);
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
logf("trapped read data abort in [0x%x,0x%x]\n", last_addr,
|
||||||
|
last_addr + req->wLength);
|
||||||
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(set_data_abort_jmp() == 0)
|
||||||
|
{
|
||||||
memcpy(usb_buffer, (void *)last_addr, req->wLength);
|
memcpy(usb_buffer, (void *)last_addr, req->wLength);
|
||||||
asm volatile("nop" : : : "memory");
|
asm volatile("nop" : : : "memory");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("trapped read data abort in [0x%x,0x%x]\n", last_addr,
|
||||||
|
last_addr + req->wLength);
|
||||||
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
usb_drv_send(EP_CONTROL, usb_buffer, req->wLength);
|
usb_drv_send(EP_CONTROL, usb_buffer, req->wLength);
|
||||||
usb_drv_recv(EP_CONTROL, NULL, 0);
|
usb_drv_recv(EP_CONTROL, NULL, 0);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static bool write_atomic(void *dst, void *src, size_t sz)
|
static bool write_atomic(void *dst, void *src, size_t sz)
|
||||||
{
|
{
|
||||||
|
@ -452,13 +476,37 @@ static void handle_write(struct usb_ctrlrequest *req)
|
||||||
int sz_hdr = sizeof(struct hwstub_write_req_t);
|
int sz_hdr = sizeof(struct hwstub_write_req_t);
|
||||||
if(size < sz_hdr)
|
if(size < sz_hdr)
|
||||||
return usb_drv_stall(EP_CONTROL, true, true);
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
|
||||||
if(req->bRequest == HWSTUB_WRITE_ATOMIC)
|
if(req->bRequest == HWSTUB_WRITE_ATOMIC)
|
||||||
{
|
{
|
||||||
if(!write_atomic((void *)write->dAddress, usb_buffer + sz_hdr, size - sz_hdr))
|
if(set_data_abort_jmp() == 0)
|
||||||
|
{
|
||||||
|
if(!write_atomic((void *)write->dAddress,
|
||||||
|
usb_buffer + sz_hdr, size - sz_hdr))
|
||||||
return usb_drv_stall(EP_CONTROL, true, true);
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
memcpy((void *)write->dAddress, usb_buffer + sz_hdr, size - sz_hdr);
|
{
|
||||||
|
logf("trapped write data abort in [0x%x,0x%x]\n", write->dAddress,
|
||||||
|
write->dAddress + size - sz_hdr);
|
||||||
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(set_data_abort_jmp() == 0)
|
||||||
|
{
|
||||||
|
memcpy((void *)write->dAddress,
|
||||||
|
usb_buffer + sz_hdr, size - sz_hdr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logf("trapped write data abort in [0x%x,0x%x]\n", write->dAddress,
|
||||||
|
write->dAddress + size - sz_hdr);
|
||||||
|
return usb_drv_stall(EP_CONTROL, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
usb_drv_send(EP_CONTROL, NULL, 0);
|
usb_drv_send(EP_CONTROL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
ldr pc, =start
|
ldr pc, =start
|
||||||
ldr pc, =start
|
ldr pc, =start
|
||||||
ldr pc, =start
|
ldr pc, =start
|
||||||
ldr pc, =start
|
ldr pc, =data_abort_handler
|
||||||
ldr pc, =start
|
ldr pc, =start
|
||||||
ldr pc, =irq_handler
|
ldr pc, =irq_handler
|
||||||
ldr pc, =start
|
ldr pc, =start
|
||||||
|
|
|
@ -1,10 +1,29 @@
|
||||||
|
.section .vectors,"ax",%progbits
|
||||||
|
.code 32
|
||||||
|
/* most handlers are in DRAM which is too far away for a relative jump */
|
||||||
|
b start
|
||||||
|
b start
|
||||||
|
b start
|
||||||
|
b start
|
||||||
|
b data_abort_handler
|
||||||
|
b start
|
||||||
|
b start
|
||||||
|
b start
|
||||||
|
|
||||||
.section .text,"ax",%progbits
|
.section .text,"ax",%progbits
|
||||||
.code 32
|
.code 32
|
||||||
.align 0x04
|
.align 0x04
|
||||||
.global start
|
.global start
|
||||||
start:
|
start:
|
||||||
|
/* Save running address */
|
||||||
sub r7, pc, #8 /* Copy running address */
|
sub r7, pc, #8 /* Copy running address */
|
||||||
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
|
/* adjust the offset between start and beginning of the binary */
|
||||||
|
ldr r0, =_copystart
|
||||||
|
ldr r1, =start
|
||||||
|
add r7, r0
|
||||||
|
sub r7, r1
|
||||||
|
/* enter supervisor mode, disable IRQ/FIQ */
|
||||||
|
msr cpsr_c, #0xd3
|
||||||
/* The stub could be located at a virtual address so killing the MMU at
|
/* The stub could be located at a virtual address so killing the MMU at
|
||||||
* this point would be mere suicide. We assume that the remap location
|
* this point would be mere suicide. We assume that the remap location
|
||||||
* is identically mapped and kill the MMU after the copy */
|
* is identically mapped and kill the MMU after the copy */
|
||||||
|
@ -37,6 +56,9 @@ remap:
|
||||||
cmp r3, r2
|
cmp r3, r2
|
||||||
strhi r4, [r2], #4
|
strhi r4, [r2], #4
|
||||||
bhi 1b
|
bhi 1b
|
||||||
|
/* NOTE: we don't need an abort stack */
|
||||||
|
/* Switch to sys mode */
|
||||||
|
msr cpsr_c, #0xdf
|
||||||
/* jump to C code */
|
/* jump to C code */
|
||||||
ldr sp, =oc_stackend
|
ldr sp, =oc_stackend
|
||||||
b main
|
b main
|
||||||
|
|
|
@ -38,6 +38,7 @@ SECTIONS
|
||||||
{
|
{
|
||||||
_copystart = .;
|
_copystart = .;
|
||||||
oc_codestart = .;
|
oc_codestart = .;
|
||||||
|
*(.vectors);
|
||||||
*(.text*)
|
*(.text*)
|
||||||
*(.icode*)
|
*(.icode*)
|
||||||
*(.data*)
|
*(.data*)
|
||||||
|
|
|
@ -114,5 +114,7 @@ static inline int disable_interrupt_save(int mask)
|
||||||
return cpsr;
|
return cpsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int set_data_abort_jmp(void);
|
||||||
|
|
||||||
#endif /* __HWSTUB_SYSTEM__ */
|
#endif /* __HWSTUB_SYSTEM__ */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue