/*
 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
 * Copyright (C) 2015-2024 Cadence Design Systems, Inc.
 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * https://www.FreeRTOS.org
 * https://github.com/FreeRTOS
 *
 */

#include "xtensa_rtos.h"
#include "portmacro.h"
#include "asm-offsets.h"

#include <xtensa/hal.h>

/*******************************************************************************

_xt_mpu_restore

    !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!

Restores task's MPU state

Entry Conditions:
    A0  = Return address in caller.

*******************************************************************************/
#if portUSING_MPU_WRAPPERS

#if XCHAL_HAVE_XEA3 && (!defined __XTENSA_CALL0_ABI__)
#define A2      a10
#define A3      a11
#define A4      a12
#define A5      a13
#define A6      a14
#else
#define A2      a2
#define A3      a3
#define A4      a4
#define A5      a5
#define A6      a6
#endif

    .altmacro

    .macro  mpu_set_entry  entry
    /*
     * Load both first and last entry for a range to avoid memory access
     * when region is partially modified which may result in a TLB multihit.
     */
    l32i    A3, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AT_OFF)
    l32i    A4, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AS_OFF)
    l32i    A5, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AT_OFF)
    l32i    A6, A2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AS_OFF)
    wptlb   A3, A4
    wptlb   A5, A6
    .endm

    .section "privileged_functions"
    .global _xt_mpu_restore
    .type   _xt_mpu_restore,@function
    .align  4
_xt_mpu_restore:

    movi    A2, pxCurrentTCB
    l32i    A2, A2, 0
    beqz    A2, .Lset

    movi    A3, g_num_used_mpu_entries
    l32i    A3, A3, 0
    movi    A4, .Lset

    /*
     * A3 = .Lset - 18 * g_num_used_mpu_entries -- is the address of code
     * that loads MPU entries of the first g_num_used_mpu_entries regions.
     * 18 is the size of piece of code generated by one mpu_set_entry macro
     */
    slli    A5, A3, 4
    addx2   A5, A3, A5
    sub     A3, A4, A5

    jx      A3

    .begin no-transform

    /* Load MPU entries from last to first (not in MPU order,
     * in pxCurrentTCB->xMPUSettings order).
     */
    .set i, 1
    .rept portNUM_MAX_SWAPPED_MPU_PAIRS
    mpu_set_entry %i
    .set i, i+1
    .endr
.Lset:
    .end no-transform
    isync

    ret

#ifdef portALIGN_SECTIONS
    .section privileged_functions
    .align  XCHAL_MPU_ALIGN

    .section privileged_data
    .align  XCHAL_MPU_ALIGN

    .section freertos_system_calls
    .align  XCHAL_MPU_ALIGN

    .section .text
    .align  XCHAL_MPU_ALIGN

    .section .data
    .align  XCHAL_MPU_ALIGN

    .section .literal
    .align  XCHAL_MPU_ALIGN

    .section .bss
    .align  XCHAL_MPU_ALIGN

    .section .rodata
    .align  XCHAL_MPU_ALIGN

    .section private_region1
    .align  XCHAL_MPU_ALIGN
    .section private_region2
    .align  XCHAL_MPU_ALIGN
    .section private_region3
    .align  XCHAL_MPU_ALIGN
    .section private_stack
    .align  XCHAL_MPU_ALIGN
#endif

#endif // portUSING_MPU_WRAPPERS
