1/* 2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7/* 8 * LoadStoreErrorCause: Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit 9 * LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner 10 * 11 * xxxx xxxx = imm8 field 12 * yyyy = imm4 field 13 * ssss = s field 14 * tttt = t field 15 * 16 * 16 0 17 * ------------------- 18 * L32I.N yyyy ssss tttt 1000 19 * S32I.N yyyy ssss tttt 1001 20 * 21 * 23 0 22 * ----------------------------- 23 * L8UI xxxx xxxx 0000 ssss tttt 0010 <- LoadStoreError 24 * L16UI xxxx xxxx 0001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment 25 * L16SI xxxx xxxx 1001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment 26 * L32I xxxx xxxx 0010 ssss tttt 0010 <- LoadStoreAlignment 27 * 28 * S8I xxxx xxxx 0100 ssss tttt 0010 <- LoadStoreError 29 * S16I xxxx xxxx 0101 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment 30 * S32I xxxx xxxx 0110 ssss tttt 0010 <- LoadStoreAlignment 31 * 32 * ******* UNSUPPORTED ******* 33 * 34 * L32E 0000 1001 rrrr ssss tttt 0000 35 * S32E 0100 1001 rrrr ssss tttt 0000 36 * ----------------------------- 37 */ 38 39#include "xtensa_rtos.h" 40#include "sdkconfig.h" 41#include "soc/soc.h" 42 43#define LOADSTORE_HANDLER_STACK_SZ 8 44 .section .bss, "aw" 45 .balign 16 46LoadStoreHandlerStack: 47 .rept LOADSTORE_HANDLER_STACK_SZ 48 .word 0 49 .endr 50 51 52/* LoadStoreErrorCause handler: 53 * 54 * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region 55 * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause 56 */ 57 58 .global LoadStoreErrorHandler 59 .section .iram1, "ax" 60 61 .literal_position 62 63 .balign 4 64LoadStoreErrorHandler: 65 .type LoadStoreErrorHandler, @function 66 67 wsr a0, depc // Save return address in depc 68 mov a0, sp 69 movi sp, LoadStoreHandlerStack 70 s32i a0, sp, 0x04 // Since a0 contains value of a1 71 s32i a2, sp, 0x08 72 s32i a3, sp, 0x0c 73 s32i a4, sp, 0x10 74 75 rsr a0, sar // Save SAR in a0 to restore later 76 77 /* Check whether the address lies in the valid range */ 78 rsr a3, excvaddr 79 movi a4, _iram_text_end // End of code section of IRAM 80 bge a3, a4, 1f 81 movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region 82 blt a3, a4, .LS_wrong_opcode 83 movi a4, SOC_CACHE_APP_HIGH 84 bge a3, a4, .LS_wrong_opcode 85 j 2f 86 871: 88 movi a4, SOC_IRAM_HIGH // End of IRAM address range 89 bge a3, a4, .LS_wrong_opcode 90 912: 92 /* Examine the opcode which generated the exception */ 93 /* Note: Instructions are in this order to avoid pipeline stalls. */ 94 rsr a2, epc1 95 movi a4, ~3 96 ssa8l a2 // sar is now correct shift for aligned read 97 and a2, a2, a4 // a2 now 4-byte aligned address of instruction 98 l32i a4, a2, 0 99 l32i a2, a2, 4 100 101 src a2, a2, a4 // a2 now instruction that failed 102 bbci a2, 1, .LS_wrong_opcode 103 bbsi a2, 14, .LSE_store_op // Store instruction 104 105 /* l8/l16ui/l16si */ 106 movi a4, ~3 107 and a4, a3, a4 // a4 now word aligned read address 108 109 ssa8l a3 // sar is now shift to extract a3's byte 110 l32i a4, a4, 0 // perform the actual read 111 srl a4, a4 // shift right correct distance 112 extui a3, a2, 12, 4 113 bnez a3, 1f // l16ui/l16si 114 extui a4, a4, 0, 8 // mask off bits needed for an l8 115 j 2f 116 1171: 118 extui a4, a4, 0, 16 119 bbci a2, 15, 2f // l16ui 120 121 /* Sign adjustment */ 122 slli a4, a4, 16 123 srai a4, a4, 16 // a4 contains the value 124 1252: 126 /* a4 contains the value */ 127 rsr a3, epc1 128 addi a3, a3, 3 129 wsr a3, epc1 130 wsr a0, sar 131 rsr a0, excsave1 132 133 extui a2, a2, 3, 5 134 blti a2, 10, .LSE_stack_reg 135 136 movi a3, .LS_jumptable_base 137 addx8 a2, a2, a3 // a2 is now the address to jump to 138 l32i a3, sp, 0x0c 139 jx a2 140 141.LSE_stack_reg: 142 addx2 a2, a2, sp 143 s32i a4, a2, 0 144 145 /* Restore all values */ 146 l32i a4, sp, 0x10 147 l32i a3, sp, 0x0c 148 l32i a2, sp, 0x08 149 l32i a1, sp, 0x04 150 rfe 151 152.LSE_store_op: 153 s32i a5, a1, 0x14 154 s32i a6, a1, 0x18 155 156 /* a2 -> instruction that caused the error */ 157 /* a3 -> unaligned address */ 158 extui a4, a2, 4, 4 159 blti a4, 7, 1f 160 movi a5, .LSE_store_reg 161 addx8 a5, a4, a5 162 jx a5 163 1641: 165 addx4 a4, a4, sp 166 l32i a4, a4, 0 167 168.LSE_store_data: 169 /* a4 contains the value */ 170 rsr a6, epc1 171 addi a6, a6, 3 172 wsr a6, epc1 173 174 ssa8b a3 175 movi a5, -1 176 bbsi a2, 12, 1f // s16 177 extui a4, a4, 0, 8 178 movi a6, 0xff 179 j 2f 1801: 181 extui a4, a4, 0, 16 182 movi a6, 0xffff 1832: 184 sll a4, a4 // shift the value to proper offset 185 sll a6, a6 186 xor a5, a5, a6 // a5 contains the mask 187 188 movi a6, ~3 189 and a3, a3, a6 // a3 has the aligned address 190 l32i a6, a3, 0 // a6 contains the data at the aligned address 191 and a6, a6, a5 192 or a4, a6, a4 193 s32i a4, a3, 0 194 195 /* Restore registers */ 196 wsr a0, sar 197 198 l32i a6, sp, 0x18 199 l32i a5, sp, 0x14 200 l32i a4, sp, 0x10 201 l32i a3, sp, 0x0c 202 l32i a2, sp, 0x08 203 l32i a1, sp, 0x04 204 rsr a0, excsave1 205 206 rfe 207 208.LSE_store_reg: 209 .org .LSE_store_reg + (7 * 8) 210 mov a4, a7 211 j .LSE_store_data 212 213 .org .LSE_store_reg + (8 * 8) 214 mov a4, a8 215 j .LSE_store_data 216 217 .org .LSE_store_reg + (9 * 8) 218 mov a4, a9 219 j .LSE_store_data 220 221 .org .LSE_store_reg + (10 * 8) 222 mov a4, a10 223 j .LSE_store_data 224 225 .org .LSE_store_reg + (11 * 8) 226 mov a4, a11 227 j .LSE_store_data 228 229 .org .LSE_store_reg + (12 * 8) 230 mov a4, a12 231 j .LSE_store_data 232 233 .org .LSE_store_reg + (13 * 8) 234 mov a4, a13 235 j .LSE_store_data 236 237 .org .LSE_store_reg + (14 * 8) 238 mov a4, a14 239 j .LSE_store_data 240 241 .org .LSE_store_reg + (15 * 8) 242 mov a4, a15 243 j .LSE_store_data 244 245 246/* LoadStoreAlignmentCause handler: 247 * 248 * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region 249 * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause 250 */ 251 252 .global AlignmentErrorHandler 253 .section .iram1, "ax" 254 255 .literal_position 256 257 .balign 4 258AlignmentErrorHandler: 259 .type AlignmentErrorHandler, @function 260 261 wsr a0, depc // Save return address in depc 262 mov a0, sp 263 movi sp, LoadStoreHandlerStack 264 s32i a0, sp, 0x04 // Since a0 contains value of a1 265 s32i a2, sp, 0x08 266 s32i a3, sp, 0x0c 267 s32i a4, sp, 0x10 268 269 rsr a0, sar // Save SAR in a0 to restore later 270 271 /* Check whether the address lies in the valid range */ 272 rsr a3, excvaddr 273 movi a4, _iram_text_end // End of code section of IRAM 274 bge a3, a4, 1f 275 movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region 276 blt a3, a4, .LS_wrong_opcode 277 movi a4, SOC_CACHE_APP_HIGH 278 bge a3, a4, .LS_wrong_opcode 279 j 2f 280 2811: 282 movi a4, SOC_IRAM_HIGH // End of IRAM address range 283 bge a3, a4, .LS_wrong_opcode 284 2852: 286 /* Examine the opcode which generated the exception */ 287 /* Note: Instructions are in this order to avoid pipeline stalls. */ 288 rsr a2, epc1 289 movi a4, ~3 290 ssa8l a2 // sar is now correct shift for aligned read 291 and a2, a2, a4 // a2 now 4-byte aligned address of instruction 292 l32i a4, a2, 0 293 l32i a2, a2, 4 294 295 /* a2 has the instruction that caused the error */ 296 src a2, a2, a4 297 extui a4, a2, 0, 4 298 addi a4, a4, -9 299 beqz a4, .LSA_store_op 300 bbsi a2, 14, .LSA_store_op 301 302 ssa8l a3 // a3 contains the unaligned address 303 movi a4, ~3 304 and a4, a3, a4 // a4 has the aligned address 305 l32i a3, a4, 0 306 l32i a4, a4, 4 307 src a4, a4, a3 308 309 rsr a3, epc1 310 addi a3, a3, 2 311 bbsi a2, 3, 1f // l32i.n 312 bbci a2, 1, .LS_wrong_opcode 313 addi a3, a3, 1 314 315 bbsi a2, 13, 1f // l32 316 extui a4, a4, 0, 16 317 bbci a2, 15, 1f // l16ui 318 319 /* Sign adjustment */ 320 slli a4, a4, 16 321 srai a4, a4, 16 // a4 contains the value 322 3231: 324 wsr a3, epc1 325 wsr a0, sar 326 rsr a0, excsave1 327 328 extui a2, a2, 4, 4 329 blti a2, 5, .LSA_stack_reg // a3 contains the target register 330 331 movi a3, .LS_jumptable_base 332 slli a2, a2, 4 333 add a2, a2, a3 // a2 is now the address to jump to 334 l32i a3, sp, 0x0c 335 jx a2 336 337.LSA_stack_reg: 338 addx4 a2, a2, sp 339 s32i a4, a2, 0 340 341 /* Restore all values */ 342 l32i a4, sp, 0x10 343 l32i a3, sp, 0x0c 344 l32i a2, sp, 0x08 345 l32i a1, sp, 0x04 346 rfe 347 348/* Store instruction */ 349.LSA_store_op: 350 s32i a5, sp, 0x14 351 s32i a6, sp, 0x18 352 s32i a7, sp, 0x1c 353 354 /* a2 -> instruction that caused the error */ 355 /* a3 -> unaligned address */ 356 extui a4, a2, 4, 4 357 blti a4, 8, 1f 358 movi a5, .LSA_store_reg 359 addx8 a5, a4, a5 360 jx a5 361 3621: 363 addx4 a4, a4, sp 364 l32i a4, a4, 0 // a4 contains the value 365 366.LSA_store_data: 367 movi a6, 0 368 369 rsr a7, epc1 370 addi a7, a7 ,2 371 bbsi a2, 3, 1f // s32i.n 372 bbci a2, 1, .LS_wrong_opcode 373 374 addi a7, a7, 1 375 bbsi a2, 13, 1f // s32i 376 377 movi a5, -1 378 extui a4, a4, 0, 16 379 slli a6, a5, 16 // 0xffff0000 380 3811: 382 wsr a7, epc1 383 movi a5, ~3 384 and a5, a3, a5 // a5 has the aligned address 385 386 ssa8b a3 387 movi a3, -1 388 src a7, a6, a3 389 src a3, a3, a6 390 391 /* Store data on lower address */ 392 l32i a6, a5, 0 393 and a6, a6, a7 394 sll a7, a4 395 or a6, a6, a7 396 s32i a6, a5, 0 397 398 /* Store data on higher address */ 399 l32i a7, a5, 4 400 srl a6, a4 401 and a3, a7, a3 402 or a3, a3, a6 403 s32i a3, a5, 4 404 405 /* Restore registers */ 406 wsr a0, sar 407 rsr a0, excsave1 408 409 l32i a7, sp, 0x1c 410 l32i a6, sp, 0x18 411 l32i a5, sp, 0x14 412 l32i a4, sp, 0x10 413 l32i a3, sp, 0x0c 414 l32i a2, sp, 0x08 415 l32i a1, sp, 0x04 416 rfe 417 418.LSA_store_reg: 419 .org .LSA_store_reg + (8 * 8) 420 mov a4, a8 421 j .LSA_store_data 422 423 .org .LSA_store_reg + (9 * 8) 424 mov a4, a9 425 j .LSA_store_data 426 427 .org .LSA_store_reg + (10 * 8) 428 mov a4, a10 429 j .LSA_store_data 430 431 .org .LSA_store_reg + (11 * 8) 432 mov a4, a11 433 j .LSA_store_data 434 435 .org .LSA_store_reg + (12 * 8) 436 mov a4, a12 437 j .LSA_store_data 438 439 .org .LSA_store_reg + (13 * 8) 440 mov a4, a13 441 j .LSA_store_data 442 443 .org .LSA_store_reg + (14 * 8) 444 mov a4, a14 445 j .LSA_store_data 446 447 .org .LSA_store_reg + (15 * 8) 448 mov a4, a15 449 j .LSA_store_data 450 451/* 452 * Common routines for both the exception handlers 453 */ 454 .balign 4 455.LS_jumptable: 456 /* The first 5 entries (80 bytes) of this table are unused (registers 457 a0..a4 are handled separately above). Rather than have a whole bunch 458 of wasted space, just pretend that the table starts 80 bytes 459 earlier in memory. */ 460 .set .LS_jumptable_base, .LS_jumptable - (16 * 5) 461 462 .org .LS_jumptable_base + (16 * 5) 463 mov a5, a4 464 l32i a4, sp, 0x10 465 l32i a2, sp, 0x08 466 l32i a1, sp, 0x04 467 rfe 468 469 .org .LS_jumptable_base + (16 * 6) 470 mov a6, a4 471 l32i a4, sp, 0x10 472 l32i a2, sp, 0x08 473 l32i a1, sp, 0x04 474 rfe 475 476 .org .LS_jumptable_base + (16 * 7) 477 mov a7, a4 478 l32i a4, sp, 0x10 479 l32i a2, sp, 0x08 480 l32i a1, sp, 0x04 481 rfe 482 483 .org .LS_jumptable_base + (16 * 8) 484 mov a8, a4 485 l32i a4, sp, 0x10 486 l32i a2, sp, 0x08 487 l32i a1, sp, 0x04 488 rfe 489 490 .org .LS_jumptable_base + (16 * 9) 491 mov a9, a4 492 l32i a4, sp, 0x10 493 l32i a2, sp, 0x08 494 l32i a1, sp, 0x04 495 rfe 496 497 .org .LS_jumptable_base + (16 * 10) 498 mov a10, a4 499 l32i a4, sp, 0x10 500 l32i a2, sp, 0x08 501 l32i a1, sp, 0x04 502 rfe 503 504 .org .LS_jumptable_base + (16 * 11) 505 mov a11, a4 506 l32i a4, sp, 0x10 507 l32i a2, sp, 0x08 508 l32i a1, sp, 0x04 509 rfe 510 511 .org .LS_jumptable_base + (16 * 12) 512 mov a12, a4 513 l32i a4, sp, 0x10 514 l32i a2, sp, 0x08 515 l32i a1, sp, 0x04 516 rfe 517 518 .org .LS_jumptable_base + (16 * 13) 519 mov a13, a4 520 l32i a4, sp, 0x10 521 l32i a2, sp, 0x08 522 l32i a1, sp, 0x04 523 rfe 524 525 .org .LS_jumptable_base + (16 * 14) 526 mov a14, a4 527 l32i a4, sp, 0x10 528 l32i a2, sp, 0x08 529 l32i a1, sp, 0x04 530 rfe 531 532 .org .LS_jumptable_base + (16 * 15) 533 mov a15, a4 534 l32i a4, sp, 0x10 535 l32i a2, sp, 0x08 536 l32i a1, sp, 0x04 537 rfe 538 539.LS_wrong_opcode: 540 /* Reaches here if the address is in invalid range or the opcode isn't supported. 541 * Restore registers and jump back to _xt_user_exc 542 */ 543 wsr a0, sar 544 l32i a4, sp, 0x10 545 l32i a3, sp, 0x0c 546 l32i a2, sp, 0x08 547 l32i a1, sp, 0x04 548 rsr a0, depc 549 ret // Equivalent to jx a0 550