]> git.sur5r.net Git - freertos/commitdiff
ESP GCC port -- Added LoadStore Exception handlers.
authoryuhzheng <yuhzheng@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Fri, 31 Jan 2020 19:31:50 +0000 (19:31 +0000)
committeryuhzheng <yuhzheng@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Fri, 31 Jan 2020 19:31:50 +0000 (19:31 +0000)
https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/9 -- Handles LoadStoreErrorCause and LoadStoreAlignmentCause allowing to use 32-bit memory region (IRAM) as 8-bit or 16-bit memory region

git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2816 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

FreeRTOS/Source/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_loadstore_handler.S [new file with mode: 0644]
FreeRTOS/Source/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S

diff --git a/FreeRTOS/Source/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_loadstore_handler.S b/FreeRTOS/Source/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_loadstore_handler.S
new file mode 100644 (file)
index 0000000..f4312df
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+
+ Licensed 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.
+*/
+
+/*
+ *  LoadStoreErrorCause:     Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit
+ *  LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner
+ *
+ *          xxxx xxxx = imm8 field
+ *               yyyy = imm4 field
+ *               ssss = s field
+ *               tttt = t field
+ *
+ *                            16                0
+ *                            -------------------
+ *          L32I.N            yyyy ssss tttt 1000
+ *          S32I.N            yyyy ssss tttt 1001
+ *
+ *                  23                          0
+ *                  -----------------------------
+ *          L8UI    xxxx xxxx 0000 ssss tttt 0010               <- LoadStoreError
+ *          L16UI   xxxx xxxx 0001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
+ *          L16SI   xxxx xxxx 1001 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
+ *          L32I    xxxx xxxx 0010 ssss tttt 0010               <- LoadStoreAlignment
+ *
+ *          S8I     xxxx xxxx 0100 ssss tttt 0010               <- LoadStoreError
+ *          S16I    xxxx xxxx 0101 ssss tttt 0010               <- LoadStoreError, LoadStoreAlignment
+ *          S32I    xxxx xxxx 0110 ssss tttt 0010               <- LoadStoreAlignment
+ *
+ *                   ******* UNSUPPORTED *******
+ *
+ *          L32E    0000 1001 rrrr ssss tttt 0000
+ *          S32E    0100 1001 rrrr ssss tttt 0000
+ *                  -----------------------------
+ */
+
+#include "xtensa_rtos.h"
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+#define LOADSTORE_HANDLER_STACK_SZ      8
+    .section .bss, "aw"
+    .balign 16
+LoadStoreHandlerStack:
+    .rept LOADSTORE_HANDLER_STACK_SZ
+    .word 0
+    .endr
+
+
+/* LoadStoreErrorCause handler:
+ *
+ * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region
+ * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause
+ */
+
+    .global   LoadStoreErrorHandler
+    .section .iram1, "ax"
+
+    .literal_position
+
+    .balign 4
+LoadStoreErrorHandler:
+    .type   LoadStoreErrorHandler, @function
+
+    wsr     a0, depc                            // Save return address in depc
+    mov     a0, sp
+    movi    sp, LoadStoreHandlerStack
+    s32i    a0, sp, 0x04                        // Since a0 contains value of a1
+    s32i    a2, sp, 0x08
+    s32i    a3, sp, 0x0c
+    s32i    a4, sp, 0x10
+
+    rsr     a0, sar                             // Save SAR in a0 to restore later
+
+    /* Check whether the address lies in the valid range */
+    rsr     a3, excvaddr
+    movi    a4, _iram_end                       // End of code section of IRAM
+    bge     a3, a4, 1f
+    movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
+    blt     a3, a4, .LS_wrong_opcode
+    movi    a4, SOC_CACHE_APP_HIGH
+    bge     a3, a4, .LS_wrong_opcode
+    j       2f
+
+1:
+    movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
+    bge     a3, a4, .LS_wrong_opcode
+
+2:
+    /* Examine the opcode which generated the exception */
+    /* Note: Instructions are in this order to avoid pipeline stalls. */
+    rsr     a2, epc1
+    movi    a4, ~3
+    ssa8l   a2                                  // sar is now correct shift for aligned read
+    and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
+    l32i    a4, a2, 0
+    l32i    a2, a2, 4
+
+    src     a2, a2, a4                          // a2 now instruction that failed
+    bbci    a2, 1, .LS_wrong_opcode
+    bbsi    a2, 14, .LSE_store_op               // Store instruction
+
+    /* l8/l16ui/l16si */
+    movi    a4, ~3
+    and     a4, a3, a4                          // a4 now word aligned read address
+
+    ssa8l   a3                                  // sar is now shift to extract a3's byte
+    l32i    a4, a4, 0                           // perform the actual read
+    srl     a4, a4                              // shift right correct distance
+    extui   a3, a2, 12, 4
+    bnez    a3, 1f                              // l16ui/l16si
+    extui   a4, a4, 0, 8                        // mask off bits needed for an l8
+    j       2f
+
+1:
+    extui   a4, a4, 0, 16
+    bbci    a2, 15, 2f                          // l16ui
+
+    /* Sign adjustment */
+    slli    a4, a4, 16
+    srai    a4, a4, 16                          // a4 contains the value
+
+2:
+    /* a4 contains the value */
+    rsr     a3, epc1
+    addi    a3, a3, 3
+    wsr     a3, epc1
+    wsr     a0, sar
+    rsr     a0, excsave1
+
+    extui   a2, a2, 3, 5
+    blti    a2, 10, .LSE_stack_reg
+
+    movi    a3, .LS_jumptable_base
+    addx8   a2, a2, a3                          // a2 is now the address to jump to
+    l32i    a3, sp, 0x0c
+    jx      a2
+
+.LSE_stack_reg:
+    addx2   a2, a2, sp
+    s32i    a4, a2, 0
+
+    /* Restore all values */
+    l32i    a4, sp, 0x10
+    l32i    a3, sp, 0x0c
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+.LSE_store_op:
+    s32i    a5, a1, 0x14
+    s32i    a6, a1, 0x18
+
+    /* a2 -> instruction that caused the error */
+    /* a3 -> unaligned address */
+    extui   a4, a2, 4, 4
+    blti    a4, 7, 1f
+    movi    a5, .LSE_store_reg
+    addx8   a5, a4, a5
+    jx      a5
+
+1:
+    addx4   a4, a4, sp
+    l32i    a4, a4, 0
+
+.LSE_store_data:
+    /* a4 contains the value */
+    rsr     a6, epc1
+    addi    a6, a6, 3
+    wsr     a6, epc1
+
+    ssa8b   a3
+    movi    a5, -1
+    bbsi    a2, 12, 1f                          // s16
+    extui   a4, a4, 0, 8
+    movi    a6, 0xff
+    j       2f
+1:
+    extui   a4, a4, 0, 16
+    movi    a6, 0xffff
+2:
+    sll     a4, a4                              // shift the value to proper offset
+    sll     a6, a6
+    xor     a5, a5, a6                          // a5 contains the mask
+
+    movi    a6, ~3
+    and     a3, a3, a6                          // a3 has the aligned address
+    l32i    a6, a3, 0                           // a6 contains the data at the aligned address
+    and     a6, a6, a5
+    or      a4, a6, a4
+    s32i    a4, a3, 0
+
+    /* Restore registers */
+    wsr     a0, sar
+
+    l32i    a6, sp, 0x18
+    l32i    a5, sp, 0x14
+    l32i    a4, sp, 0x10
+    l32i    a3, sp, 0x0c
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rsr     a0, excsave1
+
+    rfe
+
+.LSE_store_reg:
+    .org .LSE_store_reg + (7 * 8)
+    mov     a4, a7
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (8 * 8)
+    mov     a4, a8
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (9 * 8)
+    mov     a4, a9
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (10 * 8)
+    mov     a4, a10
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (11 * 8)
+    mov     a4, a11
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (12 * 8)
+    mov     a4, a12
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (13 * 8)
+    mov     a4, a13
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (14 * 8)
+    mov     a4, a14
+    j .LSE_store_data
+
+    .org .LSE_store_reg + (15 * 8)
+    mov     a4, a15
+    j .LSE_store_data
+
+
+/* LoadStoreAlignmentCause handler:
+ *
+ * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region
+ * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause
+ */
+
+    .global   AlignmentErrorHandler
+    .section .iram1, "ax"
+
+    .literal_position
+
+    .balign 4
+AlignmentErrorHandler:
+    .type   AlignmentErrorHandler, @function
+
+    wsr     a0, depc                            // Save return address in depc
+    mov     a0, sp
+    movi    sp, LoadStoreHandlerStack
+    s32i    a0, sp, 0x04                        // Since a0 contains value of a1
+    s32i    a2, sp, 0x08
+    s32i    a3, sp, 0x0c
+    s32i    a4, sp, 0x10
+
+    rsr     a0, sar                             // Save SAR in a0 to restore later
+
+    /* Check whether the address lies in the valid range */
+    rsr     a3, excvaddr
+    movi    a4, _iram_end                       // End of code section of IRAM
+    bge     a3, a4, 1f
+    movi    a4, SOC_CACHE_APP_LOW               // Check if in APP cache region
+    blt     a3, a4, .LS_wrong_opcode
+    movi    a4, SOC_CACHE_APP_HIGH
+    bge     a3, a4, .LS_wrong_opcode
+    j       2f
+
+1:
+    movi    a4, SOC_IRAM_HIGH                   // End of IRAM address range
+    bge     a3, a4, .LS_wrong_opcode
+
+2:
+    /* Examine the opcode which generated the exception */
+    /* Note: Instructions are in this order to avoid pipeline stalls. */
+    rsr     a2, epc1
+    movi    a4, ~3
+    ssa8l   a2                                  // sar is now correct shift for aligned read
+    and     a2, a2, a4                          // a2 now 4-byte aligned address of instruction
+    l32i    a4, a2, 0
+    l32i    a2, a2, 4
+
+    /* a2 has the instruction that caused the error */
+    src     a2, a2, a4
+    extui   a4, a2, 0, 4
+    addi    a4, a4, -9
+    beqz    a4, .LSA_store_op
+    bbsi    a2, 14, .LSA_store_op
+
+    ssa8l   a3                                  // a3 contains the unaligned address
+    movi    a4, ~3
+    and     a4, a3, a4                          // a4 has the aligned address
+    l32i    a3, a4, 0
+    l32i    a4, a4, 4
+    src     a4, a4, a3
+
+    rsr     a3, epc1
+    addi    a3, a3, 2
+    bbsi    a2, 3, 1f                           // l32i.n
+    bbci    a2, 1, .LS_wrong_opcode
+    addi    a3, a3, 1
+
+    bbsi    a2, 13, 1f                          // l32
+    extui   a4, a4, 0, 16
+    bbci    a2, 15, 1f                          // l16ui
+
+    /* Sign adjustment */
+    slli    a4, a4, 16
+    srai    a4, a4, 16                          // a4 contains the value
+
+1:
+    wsr     a3, epc1
+    wsr     a0, sar
+    rsr     a0, excsave1
+
+    extui   a2, a2, 4, 4
+    blti    a2, 5, .LSA_stack_reg               // a3 contains the target register
+
+    movi    a3, .LS_jumptable_base
+    slli    a2, a2, 4
+    add     a2, a2, a3                          // a2 is now the address to jump to
+    l32i    a3, sp, 0x0c
+    jx      a2
+
+.LSA_stack_reg:
+    addx4   a2, a2, sp
+    s32i    a4, a2, 0
+
+    /* Restore all values */
+    l32i    a4, sp, 0x10
+    l32i    a3, sp, 0x0c
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+/* Store instruction */
+.LSA_store_op:
+    s32i    a5, sp, 0x14
+    s32i    a6, sp, 0x18
+    s32i    a7, sp, 0x1c
+
+    /* a2 -> instruction that caused the error */
+    /* a3 -> unaligned address */
+    extui   a4, a2, 4, 4
+    blti    a4, 8, 1f
+    movi    a5, .LSA_store_reg
+    addx8   a5, a4, a5
+    jx      a5
+
+1:
+    addx4   a4, a4, sp
+    l32i    a4, a4, 0                           // a4 contains the value
+
+.LSA_store_data:
+    movi    a6, 0
+
+    rsr     a7, epc1
+    addi    a7, a7 ,2
+    bbsi    a2, 3, 1f                           // s32i.n
+    bbci    a2, 1, .LS_wrong_opcode
+
+    addi    a7, a7, 1
+    bbsi    a2, 13, 1f                          // s32i
+
+    movi    a5, -1
+    extui   a4, a4, 0, 16
+    slli    a6, a5, 16                          // 0xffff0000
+
+1:
+    wsr     a7, epc1
+    movi    a5, ~3
+    and     a5, a3, a5                          // a5 has the aligned address
+
+    ssa8b   a3
+    movi    a3, -1
+    src     a7, a6, a3
+    src     a3, a3, a6
+
+    /* Store data on lower address */
+    l32i    a6, a5, 0
+    and     a6, a6, a7
+    sll     a7, a4
+    or      a6, a6, a7
+    s32i    a6, a5, 0
+
+    /* Store data on higher address */
+    l32i    a7, a5, 4
+    srl     a6, a4
+    and     a3, a7, a3
+    or      a3, a3, a6
+    s32i    a3, a5, 4
+
+    /* Restore registers */
+    wsr     a0, sar
+    rsr     a0, excsave1
+
+    l32i    a7, sp, 0x1c
+    l32i    a6, sp, 0x18
+    l32i    a5, sp, 0x14
+    l32i    a4, sp, 0x10
+    l32i    a3, sp, 0x0c
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+.LSA_store_reg:
+    .org .LSA_store_reg + (8 * 8)
+    mov     a4, a8
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (9 * 8)
+    mov     a4, a9
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (10 * 8)
+    mov     a4, a10
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (11 * 8)
+    mov     a4, a11
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (12 * 8)
+    mov     a4, a12
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (13 * 8)
+    mov     a4, a13
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (14 * 8)
+    mov     a4, a14
+    j       .LSA_store_data
+
+    .org .LSA_store_reg + (15 * 8)
+    mov     a4, a15
+    j       .LSA_store_data
+
+/*
+ * Common routines for both the exception handlers
+ */
+    .balign 4
+.LS_jumptable:
+    /*  The first 5 entries (80 bytes) of this table are unused (registers
+        a0..a4 are handled separately above).  Rather than have a whole bunch
+        of wasted space, just pretend that the table starts 80 bytes
+        earlier in memory. */
+    .set    .LS_jumptable_base, .LS_jumptable - (16 * 5)
+
+    .org    .LS_jumptable_base + (16 * 5)
+    mov     a5, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 6)
+    mov     a6, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 7)
+    mov     a7, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 8)
+    mov     a8, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 9)
+    mov     a9, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 10)
+    mov     a10, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 11)
+    mov     a11, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 12)
+    mov     a12, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 13)
+    mov     a13, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 14)
+    mov     a14, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+    .org    .LS_jumptable_base + (16 * 15)
+    mov     a15, a4
+    l32i    a4, sp, 0x10
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rfe
+
+.LS_wrong_opcode:
+    /* Reaches here if the address is in invalid range or the opcode isn't supported.
+     * Restore registers and jump back to _xt_user_exc
+     */
+    wsr     a0, sar
+    l32i    a4, sp, 0x10
+    l32i    a3, sp, 0x0c
+    l32i    a2, sp, 0x08
+    l32i    a1, sp, 0x04
+    rsr     a0, depc
+    ret                                         // Equivalent to jx a0
index 4ae14d5c65049221cba76ec361ecc8b237a2e7c7..5c8601d1c7e086ba89acb44861c43c7bb7096f63 100644 (file)
@@ -581,6 +581,11 @@ _UserExceptionVector:
 --------------------------------------------------------------------------------\r
 */\r
 \r
+#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY\r
+    .global   LoadStoreErrorHandler\r
+    .global   AlignmentErrorHandler\r
+#endif\r
+\r
     .section .iram1,"ax"\r
 \r
     #if XCHAL_HAVE_WINDOWED\r
@@ -602,6 +607,20 @@ _xt_to_coproc_exc:
     /* never returns here - call0 is used as a jump (see note at top) */\r
     #endif\r
 \r
+#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY\r
+    .align      4\r
+_call_loadstore_handler:\r
+    call0   LoadStoreErrorHandler\r
+    /* This will return only if wrong opcode or address out of range*/\r
+    j       .LS_exit\r
+\r
+    .align      4\r
+_call_alignment_handler:\r
+    call0   AlignmentErrorHandler\r
+    /* This will return only if wrong opcode or address out of range*/\r
+    addi    a0, a0, 1\r
+    j       .LS_exit\r
+#endif\r
 \r
 /*\r
 --------------------------------------------------------------------------------\r
@@ -631,6 +650,15 @@ _xt_user_exc:
     #endif\r
     beqi    a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc\r
 \r
+#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY\r
+    beqi    a0, EXCCAUSE_LOAD_STORE_ERROR, _call_loadstore_handler\r
+\r
+    addi    a0, a0, -1\r
+    beqi    a0, 8, _call_alignment_handler\r
+    addi    a0, a0, 1\r
+.LS_exit:\r
+#endif\r
+\r
     /* Handle all other exceptions. All can have user-defined handlers. */\r
     /* NOTE: we'll stay on the user stack for exception handling.       */\r
 \r