mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 02:24:18 +00:00
Merge "Read-only xlat tables for BL31 memory" into integration
This commit is contained in:
commit
020ce8c9f6
15 changed files with 267 additions and 16 deletions
8
Makefile
8
Makefile
|
@ -621,6 +621,12 @@ ifeq ($(MEASURED_BOOT),1)
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
|
||||
ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
|
||||
$(error "ALLOW_RO_XLAT_TABLES requires translation tables library v2")
|
||||
endif
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Process platform overrideable behaviour
|
||||
################################################################################
|
||||
|
@ -748,6 +754,7 @@ endif
|
|||
# Build options checks
|
||||
################################################################################
|
||||
|
||||
$(eval $(call assert_boolean,ALLOW_RO_XLAT_TABLES))
|
||||
$(eval $(call assert_boolean,COLD_BOOT_SINGLE_CPU))
|
||||
$(eval $(call assert_boolean,CREATE_KEYS))
|
||||
$(eval $(call assert_boolean,CTX_INCLUDE_AARCH32_REGS))
|
||||
|
@ -815,6 +822,7 @@ endif
|
|||
# platform to overwrite the default options
|
||||
################################################################################
|
||||
|
||||
$(eval $(call add_define,ALLOW_RO_XLAT_TABLES))
|
||||
$(eval $(call add_define,ARM_ARCH_MAJOR))
|
||||
$(eval $(call add_define,ARM_ARCH_MINOR))
|
||||
$(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -345,6 +345,16 @@ int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
|
|||
size_t size, uint32_t attr);
|
||||
int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr);
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
/*
|
||||
* Change the memory attributes of the memory region encompassing the higher
|
||||
* level translation tables to secure read-only data.
|
||||
*
|
||||
* Return 0 on success, a negative error code on error.
|
||||
*/
|
||||
int xlat_make_tables_readonly(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Query the memory attributes of a memory page in a set of translation tables.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -70,6 +70,9 @@ struct xlat_ctx {
|
|||
*/
|
||||
uint64_t (*tables)[XLAT_TABLE_ENTRIES];
|
||||
int tables_num;
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
bool readonly_tables;
|
||||
#endif
|
||||
/*
|
||||
* Keep track of how many regions are mapped in each table. The base
|
||||
* table can't be unmapped so it isn't needed to keep track of it.
|
||||
|
@ -122,6 +125,14 @@ struct xlat_ctx {
|
|||
/* do nothing */
|
||||
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
#define XLAT_CTX_INIT_TABLE_ATTR() \
|
||||
.readonly_tables = false,
|
||||
#else
|
||||
#define XLAT_CTX_INIT_TABLE_ATTR()
|
||||
/* do nothing */
|
||||
#endif
|
||||
|
||||
#define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \
|
||||
_xlat_tables_count, _virt_addr_space_size, \
|
||||
_phy_addr_space_size, _xlat_regime, _section_name)\
|
||||
|
@ -142,22 +153,63 @@ struct xlat_ctx {
|
|||
XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \
|
||||
\
|
||||
static xlat_ctx_t _ctx_name##_xlat_ctx = { \
|
||||
.va_max_address = (_virt_addr_space_size) - 1UL, \
|
||||
.pa_max_address = (_phy_addr_space_size) - 1ULL, \
|
||||
.va_max_address = (_virt_addr_space_size) - 1UL, \
|
||||
.mmap = _ctx_name##_mmap, \
|
||||
.mmap_num = (_mmap_count), \
|
||||
.base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\
|
||||
.tables = _ctx_name##_xlat_tables, \
|
||||
.tables_num = _xlat_tables_count, \
|
||||
XLAT_CTX_INIT_TABLE_ATTR() \
|
||||
XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \
|
||||
.next_table = 0, \
|
||||
.base_table = _ctx_name##_base_xlat_table, \
|
||||
.base_table_entries = \
|
||||
GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size),\
|
||||
.tables = _ctx_name##_xlat_tables, \
|
||||
.tables_num = _xlat_tables_count, \
|
||||
XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \
|
||||
.xlat_regime = (_xlat_regime), \
|
||||
.max_pa = 0U, \
|
||||
.max_va = 0U, \
|
||||
.next_table = 0, \
|
||||
.base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\
|
||||
.initialized = false, \
|
||||
.xlat_regime = (_xlat_regime) \
|
||||
}
|
||||
|
||||
#define REGISTER_XLAT_CONTEXT_RO_BASE_TABLE(_ctx_name, _mmap_count, \
|
||||
_xlat_tables_count, _virt_addr_space_size, \
|
||||
_phy_addr_space_size, _xlat_regime, _section_name)\
|
||||
CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(_phy_addr_space_size), \
|
||||
assert_invalid_physical_addr_space_sizefor_##_ctx_name);\
|
||||
\
|
||||
static mmap_region_t _ctx_name##_mmap[_mmap_count + 1]; \
|
||||
\
|
||||
static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count] \
|
||||
[XLAT_TABLE_ENTRIES] \
|
||||
__aligned(XLAT_TABLE_SIZE) __section(_section_name); \
|
||||
\
|
||||
static uint64_t _ctx_name##_base_xlat_table \
|
||||
[GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \
|
||||
__aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)\
|
||||
* sizeof(uint64_t)) \
|
||||
__section(".rodata"); \
|
||||
\
|
||||
XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \
|
||||
\
|
||||
static xlat_ctx_t _ctx_name##_xlat_ctx = { \
|
||||
.pa_max_address = (_phy_addr_space_size) - 1ULL, \
|
||||
.va_max_address = (_virt_addr_space_size) - 1UL, \
|
||||
.mmap = _ctx_name##_mmap, \
|
||||
.mmap_num = (_mmap_count), \
|
||||
.tables = _ctx_name##_xlat_tables, \
|
||||
.tables_num = _xlat_tables_count, \
|
||||
XLAT_CTX_INIT_TABLE_ATTR() \
|
||||
XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \
|
||||
.next_table = 0, \
|
||||
.base_table = _ctx_name##_base_xlat_table, \
|
||||
.base_table_entries = \
|
||||
GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size),\
|
||||
.max_pa = 0U, \
|
||||
.max_va = 0U, \
|
||||
.base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\
|
||||
.initialized = false, \
|
||||
.xlat_regime = (_xlat_regime) \
|
||||
}
|
||||
|
||||
#endif /*__ASSEMBLER__*/
|
||||
|
|
|
@ -236,6 +236,11 @@ int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
|
|||
*/
|
||||
void arm_free_init_memory(void);
|
||||
|
||||
/*
|
||||
* Make the higher level translation tables read-only
|
||||
*/
|
||||
void arm_xlat_make_tables_readonly(void);
|
||||
|
||||
/*
|
||||
* Mandatory functions required in ARM standard platforms
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -30,7 +30,7 @@ loop_\op:
|
|||
dc \op, x0
|
||||
add x0, x0, x2
|
||||
cmp x0, x1
|
||||
b.lo loop_\op
|
||||
b.lo loop_\op
|
||||
dsb sy
|
||||
exit_loop_\op:
|
||||
ret
|
||||
|
@ -140,7 +140,7 @@ loop3_\_op:
|
|||
level_done:
|
||||
add x10, x10, #2 // increment cache number
|
||||
cmp x3, x10
|
||||
b.hi loop1
|
||||
b.hi loop1
|
||||
msr csselr_el1, xzr // select cache level 0 in csselr
|
||||
dsb sy // barrier to complete final cache operation
|
||||
isb
|
||||
|
|
37
lib/xlat_tables_v2/ro_xlat_tables.mk
Normal file
37
lib/xlat_tables_v2/ro_xlat_tables.mk
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# Copyright (c) 2020, ARM Limited. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
ifeq (${USE_DEBUGFS}, 1)
|
||||
$(error "Debugfs requires functionality from the dynamic translation \
|
||||
library and is incompatible with ALLOW_RO_XLAT_TABLES.")
|
||||
endif
|
||||
|
||||
ifeq (${ARCH},aarch32)
|
||||
ifeq (${RESET_TO_SP_MIN},1)
|
||||
$(error "RESET_TO_SP_MIN requires functionality from the dynamic \
|
||||
translation library and is incompatible with \
|
||||
ALLOW_RO_XLAT_TABLES.")
|
||||
endif
|
||||
else # if AArch64
|
||||
ifeq (${PLAT},tegra)
|
||||
$(error "Tegra requires functionality from the dynamic translation \
|
||||
library and is incompatible with ALLOW_RO_XLAT_TABLES.")
|
||||
endif
|
||||
ifeq (${RESET_TO_BL31},1)
|
||||
$(error "RESET_TO_BL31 requires functionality from the dynamic \
|
||||
translation library and is incompatible with \
|
||||
ALLOW_RO_XLAT_TABLES.")
|
||||
endif
|
||||
ifeq (${SPD},trusty)
|
||||
$(error "Trusty requires functionality from the dynamic translation \
|
||||
library and is incompatible with ALLOW_RO_XLAT_TABLES.")
|
||||
endif
|
||||
ifeq (${SPM_MM},1)
|
||||
$(error "SPM_MM requires functionality to change memory region \
|
||||
attributes, which is not possible once the translation tables \
|
||||
have been made read-only.")
|
||||
endif
|
||||
endif
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
||||
# Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
@ -13,3 +13,7 @@ XLAT_TABLES_LIB_SRCS := $(addprefix lib/xlat_tables_v2/, \
|
|||
|
||||
XLAT_TABLES_LIB_V2 := 1
|
||||
$(eval $(call add_define,XLAT_TABLES_LIB_V2))
|
||||
|
||||
ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
|
||||
include lib/xlat_tables_v2/ro_xlat_tables.mk
|
||||
endif
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
@ -24,8 +25,14 @@ uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
|
|||
* Allocate and initialise the default translation context for the BL image
|
||||
* currently executing.
|
||||
*/
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
REGISTER_XLAT_CONTEXT_RO_BASE_TABLE(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES,
|
||||
PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
|
||||
EL_REGIME_INVALID, "xlat_table");
|
||||
#else
|
||||
REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES,
|
||||
PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE);
|
||||
#endif
|
||||
|
||||
void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size,
|
||||
unsigned int attr)
|
||||
|
@ -119,6 +126,75 @@ int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr)
|
|||
return xlat_change_mem_attributes_ctx(&tf_xlat_ctx, base_va, size, attr);
|
||||
}
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
/* Change the memory attributes of the descriptors which resolve the address
|
||||
* range that belongs to the translation tables themselves, which are by default
|
||||
* mapped as part of read-write data in the BL image's memory.
|
||||
*
|
||||
* Since the translation tables map themselves via these level 3 (page)
|
||||
* descriptors, any change applied to them with the MMU on would introduce a
|
||||
* chicken and egg problem because of the break-before-make sequence.
|
||||
* Eventually, it would reach the descriptor that resolves the very table it
|
||||
* belongs to and the invalidation (break step) would cause the subsequent write
|
||||
* (make step) to it to generate an MMU fault. Therefore, the MMU is disabled
|
||||
* before making the change.
|
||||
*
|
||||
* No assumption is made about what data this function needs, therefore all the
|
||||
* caches are flushed in order to ensure coherency. A future optimization would
|
||||
* be to only flush the required data to main memory.
|
||||
*/
|
||||
int xlat_make_tables_readonly(void)
|
||||
{
|
||||
assert(tf_xlat_ctx.initialized == true);
|
||||
#ifdef __aarch64__
|
||||
if (tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME) {
|
||||
disable_mmu_el1();
|
||||
} else if (tf_xlat_ctx.xlat_regime == EL3_REGIME) {
|
||||
disable_mmu_el3();
|
||||
} else {
|
||||
assert(tf_xlat_ctx.xlat_regime == EL2_REGIME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Flush all caches. */
|
||||
dcsw_op_all(DCCISW);
|
||||
#else /* !__aarch64__ */
|
||||
assert(tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME);
|
||||
/* On AArch32, we flush the caches before disabling the MMU. The reason
|
||||
* for this is that the dcsw_op_all AArch32 function pushes some
|
||||
* registers onto the stack under the assumption that it is writing to
|
||||
* cache, which is not true with the MMU off. This would result in the
|
||||
* stack becoming corrupted and a wrong/junk value for the LR being
|
||||
* restored at the end of the routine.
|
||||
*/
|
||||
dcsw_op_all(DC_OP_CISW);
|
||||
disable_mmu_secure();
|
||||
#endif
|
||||
|
||||
int rc = xlat_change_mem_attributes_ctx(&tf_xlat_ctx,
|
||||
(uintptr_t)tf_xlat_ctx.tables,
|
||||
tf_xlat_ctx.tables_num * XLAT_TABLE_SIZE,
|
||||
MT_RO_DATA | MT_SECURE);
|
||||
|
||||
#ifdef __aarch64__
|
||||
if (tf_xlat_ctx.xlat_regime == EL1_EL0_REGIME) {
|
||||
enable_mmu_el1(0U);
|
||||
} else {
|
||||
assert(tf_xlat_ctx.xlat_regime == EL3_REGIME);
|
||||
enable_mmu_el3(0U);
|
||||
}
|
||||
#else /* !__aarch64__ */
|
||||
enable_mmu_svc_mon(0U);
|
||||
#endif
|
||||
|
||||
if (rc == 0) {
|
||||
tf_xlat_ctx.readonly_tables = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* PLAT_RO_XLAT_TABLES */
|
||||
|
||||
/*
|
||||
* If dynamic allocation of new regions is disabled then by the time we call the
|
||||
* function enabling the MMU, we'll have registered all the memory regions to
|
||||
|
|
|
@ -207,6 +207,13 @@ USE_FCONF_BASED_IO := 0
|
|||
# Build option to choose whether Trusted Firmware uses library at ROM
|
||||
USE_ROMLIB := 0
|
||||
|
||||
# Build option to choose whether the xlat tables of BL images can be read-only.
|
||||
# Note that this only serves as a higher level option to PLAT_RO_XLAT_TABLES,
|
||||
# which is the per BL-image option that actually enables the read-only tables
|
||||
# API. The reason for having this additional option is to have a common high
|
||||
# level makefile where we can check for incompatible features/build options.
|
||||
ALLOW_RO_XLAT_TABLES := 0
|
||||
|
||||
# Chain of trust.
|
||||
COT := tbbr
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ ifeq (${ARCH},aarch32)
|
|||
ifeq (${RESET_TO_SP_MIN},1)
|
||||
BL32_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
|
||||
endif
|
||||
else # if AArch64
|
||||
else # AArch64
|
||||
ifeq (${RESET_TO_BL31},1)
|
||||
BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
|
||||
endif
|
||||
|
@ -301,6 +301,17 @@ else # if AArch64
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
|
||||
ifeq (${ARCH},aarch32)
|
||||
BL32_CFLAGS += -DPLAT_RO_XLAT_TABLES=1
|
||||
else # AArch64
|
||||
BL31_CFLAGS += -DPLAT_RO_XLAT_TABLES=1
|
||||
ifeq (${SPD},tspd)
|
||||
BL32_CFLAGS += -DPLAT_RO_XLAT_TABLES=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (${USE_DEBUGFS},1)
|
||||
BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
|
||||
endif
|
||||
|
|
|
@ -155,6 +155,14 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq (${ALLOW_RO_XLAT_TABLES}, 1)
|
||||
ifeq (${JUNO_AARCH32_EL3_RUNTIME}, 1)
|
||||
BL32_CFLAGS += -DPLAT_RO_XLAT_TABLES=1
|
||||
else
|
||||
BL31_CFLAGS += -DPLAT_RO_XLAT_TABLES=1
|
||||
endif
|
||||
endif
|
||||
|
||||
# Add the FDT_SOURCES and options for Dynamic Config
|
||||
FDT_SOURCES += plat/arm/board/juno/fdts/${PLAT}_fw_config.dts
|
||||
TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
|
||||
|
|
|
@ -256,9 +256,14 @@ void arm_bl31_plat_runtime_setup(void)
|
|||
|
||||
/* Initialize the runtime console */
|
||||
arm_console_runtime_init();
|
||||
|
||||
#if RECLAIM_INIT_CODE
|
||||
arm_free_init_memory();
|
||||
#endif
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
arm_xlat_make_tables_readonly();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if RECLAIM_INIT_CODE
|
||||
|
|
|
@ -25,6 +25,26 @@
|
|||
* conflicts with the definition in plat/common. */
|
||||
#pragma weak plat_get_syscnt_freq2
|
||||
|
||||
/*******************************************************************************
|
||||
* Changes the memory attributes for the region of mapped memory where the BL
|
||||
* image's translation tables are located such that the tables will have
|
||||
* read-only permissions.
|
||||
******************************************************************************/
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
void arm_xlat_make_tables_readonly(void)
|
||||
{
|
||||
int rc = xlat_make_tables_readonly();
|
||||
|
||||
if (rc != 0) {
|
||||
ERROR("Failed to make translation tables read-only at EL%u.\n",
|
||||
get_current_el());
|
||||
panic();
|
||||
}
|
||||
|
||||
INFO("Translation tables are now read-only at EL%u.\n",
|
||||
get_current_el());
|
||||
}
|
||||
#endif
|
||||
|
||||
void arm_setup_romlib(void)
|
||||
{
|
||||
|
|
|
@ -167,6 +167,10 @@ void arm_sp_min_plat_runtime_setup(void)
|
|||
{
|
||||
/* Initialize the runtime console */
|
||||
arm_console_runtime_init();
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
arm_xlat_make_tables_readonly();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -79,4 +79,8 @@ void tsp_plat_arch_setup(void)
|
|||
|
||||
setup_page_tables(bl_regions, plat_arm_get_mmap());
|
||||
enable_mmu_el1(0);
|
||||
|
||||
#if PLAT_RO_XLAT_TABLES
|
||||
arm_xlat_make_tables_readonly();
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue