esp32: emulate byte access for module text
Tested on ESP-EYE.
This commit is contained in:
parent
df44909b30
commit
f4e7845b85
51
arch/xtensa/include/loadstore.h
Normal file
51
arch/xtensa/include/loadstore.h
Normal file
@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/include/loadstore.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_XTENSA_INCLUDE_LOADSTORE_H
|
||||
#define __ARCH_XTENSA_INCLUDE_LOADSTORE_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Inline functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t l32i(const uint32_t *p);
|
||||
void s32i(uint32_t *p, uint32_t value);
|
||||
|
||||
#endif /* __ARCH_XTENSA_INCLUDE_LOADSTORE_H */
|
@ -267,7 +267,8 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs);
|
||||
uint32_t xtensa_enable_cpuint(uint32_t *shadow, uint32_t intmask);
|
||||
uint32_t xtensa_disable_cpuint(uint32_t *shadow, uint32_t intmask);
|
||||
void xtensa_panic(int xptcode, uint32_t *regs) noreturn_function;
|
||||
void xtensa_user(int exccause, uint32_t *regs) noreturn_function;
|
||||
void xtensa_user_panic(int exccause, uint32_t *regs) noreturn_function;
|
||||
uint32_t *xtensa_user(int exccause, uint32_t *regs);
|
||||
|
||||
/* Software interrupt handler */
|
||||
|
||||
|
@ -314,7 +314,7 @@ void xtensa_panic(int xptcode, uint32_t *regs)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void xtensa_user(int exccause, uint32_t *regs)
|
||||
void xtensa_user_panic(int exccause, uint32_t *regs)
|
||||
{
|
||||
#if CONFIG_TASK_NAME_SIZE > 0 && defined(CONFIG_DEBUG_ALERT)
|
||||
struct tcb_s *rtcb = running_task();
|
||||
|
76
arch/xtensa/src/common/xtensa_loadstore.S
Normal file
76
arch/xtensa/src/common/xtensa_loadstore.S
Normal file
@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/common/xtensa_loadstore.S
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include "xtensa_abi.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: l32i
|
||||
*
|
||||
* Description:
|
||||
* Execute a L32I instruction
|
||||
*
|
||||
* Entry Conditions:
|
||||
* A2 - a pointer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.global l32i
|
||||
.type l32i, @function
|
||||
.align 4
|
||||
|
||||
l32i:
|
||||
ENTRY0
|
||||
|
||||
l32i a2, a2, 0
|
||||
|
||||
RET0
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32i
|
||||
*
|
||||
* Description:
|
||||
* Execute a S32I instruction
|
||||
*
|
||||
* Entry Conditions:
|
||||
* A2 - a pointer
|
||||
* A3 - a value to store
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.global s32i
|
||||
.type s32i, @function
|
||||
.align 4
|
||||
|
||||
s32i:
|
||||
ENTRY0
|
||||
|
||||
s32i a3, a2, 0
|
||||
|
||||
RET0
|
@ -238,11 +238,30 @@ _xtensa_user_handler:
|
||||
rsr a6, EXCCAUSE /* Argument 1 (a6) = EXCCAUSE */
|
||||
mov a7, sp /* Argument 2 (a7) = pointer to register save area */
|
||||
call4 xtensa_user /* Call xtensa_user */
|
||||
mov a2, a6
|
||||
#endif
|
||||
|
||||
/* xtensa_user should not return */
|
||||
/* Restore registers in preparation to return from interrupt */
|
||||
|
||||
1: j 1b
|
||||
call0 _xtensa_context_restore /* (Preserves a2) */
|
||||
|
||||
/* Restore only level-specific regs (the rest were already restored) */
|
||||
|
||||
l32i a0, a2, (4 * REG_PS) /* Retrieve interruptee's PS */
|
||||
wsr a0, PS
|
||||
l32i a0, a2, (4 * REG_PC) /* Retrieve interruptee's PC */
|
||||
wsr a0, EPC_1
|
||||
l32i a0, a2, (4 * REG_A0) /* Retrieve interruptee's A0 */
|
||||
l32i sp, a2, (4 * REG_A1) /* Remove interrupt stack frame */
|
||||
l32i a2, a2, (4 * REG_A2) /* Retrieve interruptee's A2 */
|
||||
rsync /* Ensure PS and EPC written */
|
||||
|
||||
/* Return from exception. RFE returns from either the UserExceptionVector
|
||||
* or the KernelExceptionVector. RFE sets PS.EXCM back to 0, and then
|
||||
* jumps to the address in EPC[1]. PS.UM and PS.WOE are left unchanged.
|
||||
*/
|
||||
|
||||
rfe
|
||||
|
||||
/****************************************************************************
|
||||
* Name: _xtensa_syscall_handler
|
||||
@ -464,21 +483,21 @@ _xtensa_coproc_handler:
|
||||
#endif
|
||||
wsr a0, PS
|
||||
|
||||
/* Call xtensa_user, passing both the EXCCAUSE and a pointer to the
|
||||
/* Call xtensa_user_panic, passing both the EXCCAUSE and a pointer to the
|
||||
* beginning of the register save area.
|
||||
*/
|
||||
|
||||
#ifdef __XTENSA_CALL0_ABI__
|
||||
rsr a2, EXCCAUSE /* Argument 1 (a2) = EXCCAUSE */
|
||||
mov a3, sp /* Argument 2 (a2) = pointer to register save area */
|
||||
calx0 xtensa_user /* Call xtensa_user */
|
||||
calx0 xtensa_user_panic /* Call xtensa_user_panic */
|
||||
#else
|
||||
rsr a6, EXCCAUSE /* Argument 1 (a2) = EXCCAUSE */
|
||||
mov a7, sp /* Argument 2 (a2) = pointer to register save area */
|
||||
call4 xtensa_user /* Call xtensa_user */
|
||||
call4 xtensa_user_panic /* Call xtensa_user_panic */
|
||||
#endif
|
||||
|
||||
/* xtensa_user should not return */
|
||||
/* xtensa_user_panic should not return */
|
||||
|
||||
1: j 1b
|
||||
|
||||
|
@ -95,6 +95,7 @@ CHIP_ASRCS =
|
||||
CHIP_CSRCS = esp32_allocateheap.c esp32_clockconfig.c esp32_cpuint.c
|
||||
CHIP_CSRCS += esp32_gpio.c esp32_intdecode.c esp32_irq.c esp32_region.c
|
||||
CHIP_CSRCS += esp32_timerisr.c
|
||||
CHIP_CSRCS += esp32_user.c
|
||||
|
||||
# Configuration-dependent ESP32 files
|
||||
|
||||
@ -109,4 +110,5 @@ endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
|
||||
CHIP_CSRCS += esp32_modtext.c
|
||||
CMN_ASRCS += xtensa_loadstore.S
|
||||
endif
|
||||
|
302
arch/xtensa/src/esp32/esp32_user.c
Normal file
302
arch/xtensa/src/esp32/esp32_user.c
Normal file
@ -0,0 +1,302 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32/esp32_user.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <arch/loadstore.h>
|
||||
#include <arch/xtensa/core.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "xtensa.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_MODULE_TEXT
|
||||
extern uint32_t _smodtext;
|
||||
extern uint32_t _emodtext;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_MODULE_TEXT
|
||||
#ifdef CONFIG_ENDIAN_BIG
|
||||
#error not implemented
|
||||
#endif
|
||||
#if defined(CONFIG_BUILD_PROTECTED) || defined (CONFIG_BUILD_KERNEL)
|
||||
#error permission check not implemented
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: load_uint8
|
||||
*
|
||||
* Description:
|
||||
* Fetch a byte using 32-bit aligned access.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t load_uint8(const uint8_t *p)
|
||||
{
|
||||
const uint32_t *aligned;
|
||||
uint32_t value;
|
||||
unsigned int offset;
|
||||
|
||||
aligned = (const uint32_t *)(((uintptr_t)p) & ~3);
|
||||
value = l32i(aligned);
|
||||
offset = ((uintptr_t)p) & 3;
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
return value & 0xff;
|
||||
case 1:
|
||||
return (value >> 8) & 0xff;
|
||||
case 2:
|
||||
return (value >> 16) & 0xff;
|
||||
case 3:
|
||||
return (value >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/* not reached */
|
||||
|
||||
PANIC();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: store_uint8
|
||||
*
|
||||
* Description:
|
||||
* Store a byte using 32-bit aligned access.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void store_uint8(uint8_t *p, uint8_t v)
|
||||
{
|
||||
uint32_t *aligned;
|
||||
uint32_t value;
|
||||
unsigned int offset;
|
||||
|
||||
aligned = (uint32_t *)(((uintptr_t)p) & ~3);
|
||||
value = l32i(aligned);
|
||||
offset = ((uintptr_t)p) & 3;
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
value = (value & 0xffffff00) | v;
|
||||
break;
|
||||
case 1:
|
||||
value = (value & 0xffff00ff) | (v << 8);
|
||||
break;
|
||||
case 2:
|
||||
value = (value & 0xff00ffff) | (v << 16);
|
||||
break;
|
||||
case 3:
|
||||
value = (value & 0x00ffffff) | (v << 24);
|
||||
break;
|
||||
}
|
||||
|
||||
s32i(aligned, value);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: decode_s8i
|
||||
*
|
||||
* Description:
|
||||
* Decode S8I instruction using 32-bit aligned access.
|
||||
* Return non-zero on successful decoding.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int decode_s8i(const uint8_t *p, uint8_t *imm8, uint8_t *s,
|
||||
uint8_t *t)
|
||||
{
|
||||
/* 23 16 15 12 11 8 7 4 3 0
|
||||
* | imm8 |0 1 0 0| s | t |0 0 1 0|
|
||||
*/
|
||||
|
||||
uint8_t b0 = load_uint8(p);
|
||||
uint8_t b1 = load_uint8(p + 1);
|
||||
|
||||
if ((b0 & 0xf) == 2 && (b1 & 0xf0) == 0x40)
|
||||
{
|
||||
*t = b0 >> 4;
|
||||
*s = b1 & 0xf;
|
||||
*imm8 = load_uint8(p + 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: decode_l8ui
|
||||
*
|
||||
* Description:
|
||||
* Decode L8UI instruction using 32-bit aligned access.
|
||||
* Return non-zero on successful decoding.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int decode_l8ui(const uint8_t *p, uint8_t *imm8, uint8_t *s,
|
||||
uint8_t *t)
|
||||
{
|
||||
/* 23 16 15 12 11 8 7 4 3 0
|
||||
* | imm8 |0 0 0 0| s | t |0 0 1 0|
|
||||
*/
|
||||
|
||||
uint8_t b0 = load_uint8(p);
|
||||
uint8_t b1 = load_uint8(p + 1);
|
||||
|
||||
if ((b0 & 0xf) == 2 && (b1 & 0xf0) == 0)
|
||||
{
|
||||
*t = b0 >> 4;
|
||||
*s = b1 & 0xf;
|
||||
*imm8 = load_uint8(p + 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: advance_pc
|
||||
*
|
||||
* Description:
|
||||
* Advance PC register by the given value.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void advance_pc(uint32_t *regs, int diff)
|
||||
{
|
||||
uint32_t nextpc;
|
||||
|
||||
/* Advance to the next instruction. */
|
||||
|
||||
nextpc = regs[REG_PC] + diff;
|
||||
#ifdef XCHAL_HAVE_LOOPS
|
||||
/* See Xtensa ISA 4.3.2.4 Loopback Semantics */
|
||||
|
||||
if (regs[REG_LCOUNT] != 0 && nextpc == regs[REG_LEND])
|
||||
{
|
||||
regs[REG_LCOUNT]--;
|
||||
nextpc = regs[REG_LBEG];
|
||||
}
|
||||
|
||||
#endif
|
||||
regs[REG_PC] = nextpc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_user
|
||||
*
|
||||
* Description:
|
||||
* ESP32-specific user exception handler.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t *xtensa_user(int exccause, uint32_t *regs)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_USE_MODULE_TEXT
|
||||
/* Emulate byte access for module text.
|
||||
*
|
||||
* ESP32 only allows word-aligned accesses to the instruction memory
|
||||
* regions. A non-aligned access raises a LoadStoreErrorCause exception.
|
||||
* We catch those exception and emulate byte access here because it's
|
||||
* necessary in a few places during dynamic code loading:
|
||||
*
|
||||
* - memcpy as a part of read(2) when loading code from a file system.
|
||||
* - relocation needs to inspect and modify text.
|
||||
*
|
||||
* (thus binfo() is used below)
|
||||
*/
|
||||
|
||||
if (exccause == XCHAL_EXCCAUSE_LOAD_STORE_ERROR &&
|
||||
(uintptr_t)&_smodtext <= regs[REG_EXCVADDR] &&
|
||||
(uintptr_t)&_emodtext > regs[REG_EXCVADDR])
|
||||
{
|
||||
uint8_t *pc = (uint8_t *)regs[REG_PC];
|
||||
uint8_t imm8;
|
||||
uint8_t s;
|
||||
uint8_t t;
|
||||
|
||||
binfo("XCHAL_EXCCAUSE_LOAD_STORE_ERROR at %p, pc=%p\n",
|
||||
(FAR void *)regs[REG_EXCVADDR],
|
||||
pc);
|
||||
|
||||
if (decode_s8i(pc, &imm8, &s, &t))
|
||||
{
|
||||
binfo("Emulating S8I imm8=%u, s=%u (%p), t=%u (%p)\n",
|
||||
(unsigned int)imm8,
|
||||
(unsigned int)s,
|
||||
(void *)regs[REG_A0 + s],
|
||||
(unsigned int)t,
|
||||
(void *)regs[REG_A0 + t]);
|
||||
|
||||
DEBUGASSERT(regs[REG_A0 + s] + imm8 == regs[REG_EXCVADDR]);
|
||||
store_uint8(((uint8_t *)regs[REG_A0 + s]) + imm8,
|
||||
regs[REG_A0 + t]);
|
||||
advance_pc(regs, 3);
|
||||
return regs;
|
||||
}
|
||||
else if (decode_l8ui(pc, &imm8, &s, &t))
|
||||
{
|
||||
binfo("Emulating L8UI imm8=%u, s=%u (%p), t=%u (%p)\n",
|
||||
(unsigned int)imm8,
|
||||
(unsigned int)s,
|
||||
(void *)regs[REG_A0 + s],
|
||||
(unsigned int)t,
|
||||
(void *)regs[REG_A0 + t]);
|
||||
|
||||
DEBUGASSERT(regs[REG_A0 + s] + imm8 == regs[REG_EXCVADDR]);
|
||||
regs[REG_A0 + t] = load_uint8(((uint8_t *)regs[REG_A0 + s]) +
|
||||
imm8);
|
||||
advance_pc(regs, 3);
|
||||
return regs;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/* xtensa_user_panic never returns. */
|
||||
|
||||
xtensa_user_panic(exccause, regs);
|
||||
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user