1 /** @file
2 * File managing the MMU for ARMv8 architecture in S-EL0
3 *
4 * Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-2-Clause-Patent
7 *
8 **/
9
10 #include <Uefi.h>
11 #include <IndustryStandard/ArmMmSvc.h>
12
13 #include <Library/ArmLib.h>
14 #include <Library/ArmMmuLib.h>
15 #include <Library/ArmSvcLib.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18
19 STATIC
20 EFI_STATUS
GetMemoryPermissions(IN EFI_PHYSICAL_ADDRESS BaseAddress,OUT UINT32 * MemoryAttributes)21 GetMemoryPermissions (
22 IN EFI_PHYSICAL_ADDRESS BaseAddress,
23 OUT UINT32 *MemoryAttributes
24 )
25 {
26 ARM_SVC_ARGS GetMemoryPermissionsSvcArgs = {0};
27
28 GetMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_GET_MEM_ATTRIBUTES_AARCH64;
29 GetMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
30 GetMemoryPermissionsSvcArgs.Arg2 = 0;
31 GetMemoryPermissionsSvcArgs.Arg3 = 0;
32
33 ArmCallSvc (&GetMemoryPermissionsSvcArgs);
34 if (GetMemoryPermissionsSvcArgs.Arg0 == ARM_SVC_SPM_RET_INVALID_PARAMS) {
35 *MemoryAttributes = 0;
36 return EFI_INVALID_PARAMETER;
37 }
38
39 *MemoryAttributes = GetMemoryPermissionsSvcArgs.Arg0;
40 return EFI_SUCCESS;
41 }
42
43 STATIC
44 EFI_STATUS
RequestMemoryPermissionChange(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINTN Permissions)45 RequestMemoryPermissionChange (
46 IN EFI_PHYSICAL_ADDRESS BaseAddress,
47 IN UINT64 Length,
48 IN UINTN Permissions
49 )
50 {
51 EFI_STATUS Status;
52 ARM_SVC_ARGS ChangeMemoryPermissionsSvcArgs = {0};
53
54 ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
55 ChangeMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
56 ChangeMemoryPermissionsSvcArgs.Arg2 = EFI_SIZE_TO_PAGES(Length);
57 ChangeMemoryPermissionsSvcArgs.Arg3 = Permissions;
58
59 ArmCallSvc (&ChangeMemoryPermissionsSvcArgs);
60
61 Status = ChangeMemoryPermissionsSvcArgs.Arg0;
62
63 switch (Status) {
64 case ARM_SVC_SPM_RET_SUCCESS:
65 Status = EFI_SUCCESS;
66 break;
67
68 case ARM_SVC_SPM_RET_NOT_SUPPORTED:
69 Status = EFI_UNSUPPORTED;
70 break;
71
72 case ARM_SVC_SPM_RET_INVALID_PARAMS:
73 Status = EFI_INVALID_PARAMETER;
74 break;
75
76 case ARM_SVC_SPM_RET_DENIED:
77 Status = EFI_ACCESS_DENIED;
78 break;
79
80 case ARM_SVC_SPM_RET_NO_MEMORY:
81 Status = EFI_BAD_BUFFER_SIZE;
82 break;
83
84 default:
85 Status = EFI_ACCESS_DENIED;
86 ASSERT (0);
87 }
88
89 return Status;
90 }
91
92 EFI_STATUS
ArmSetMemoryRegionNoExec(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length)93 ArmSetMemoryRegionNoExec (
94 IN EFI_PHYSICAL_ADDRESS BaseAddress,
95 IN UINT64 Length
96 )
97 {
98 EFI_STATUS Status;
99 UINT32 MemoryAttributes;
100 UINT32 CodePermission;
101
102 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
103 if (Status != EFI_INVALID_PARAMETER) {
104 CodePermission = SET_MEM_ATTR_CODE_PERM_XN << SET_MEM_ATTR_CODE_PERM_SHIFT;
105 return RequestMemoryPermissionChange (
106 BaseAddress,
107 Length,
108 MemoryAttributes | CodePermission
109 );
110 }
111 return EFI_INVALID_PARAMETER;
112 }
113
114 EFI_STATUS
ArmClearMemoryRegionNoExec(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length)115 ArmClearMemoryRegionNoExec (
116 IN EFI_PHYSICAL_ADDRESS BaseAddress,
117 IN UINT64 Length
118 )
119 {
120 EFI_STATUS Status;
121 UINT32 MemoryAttributes;
122 UINT32 CodePermission;
123
124 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
125 if (Status != EFI_INVALID_PARAMETER) {
126 CodePermission = SET_MEM_ATTR_CODE_PERM_XN << SET_MEM_ATTR_CODE_PERM_SHIFT;
127 return RequestMemoryPermissionChange (
128 BaseAddress,
129 Length,
130 MemoryAttributes & ~CodePermission
131 );
132 }
133 return EFI_INVALID_PARAMETER;
134 }
135
136 EFI_STATUS
ArmSetMemoryRegionReadOnly(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length)137 ArmSetMemoryRegionReadOnly (
138 IN EFI_PHYSICAL_ADDRESS BaseAddress,
139 IN UINT64 Length
140 )
141 {
142 EFI_STATUS Status;
143 UINT32 MemoryAttributes;
144 UINT32 DataPermission;
145
146 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
147 if (Status != EFI_INVALID_PARAMETER) {
148 DataPermission = SET_MEM_ATTR_DATA_PERM_RO << SET_MEM_ATTR_DATA_PERM_SHIFT;
149 return RequestMemoryPermissionChange (
150 BaseAddress,
151 Length,
152 MemoryAttributes | DataPermission
153 );
154 }
155 return EFI_INVALID_PARAMETER;
156 }
157
158 EFI_STATUS
ArmClearMemoryRegionReadOnly(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length)159 ArmClearMemoryRegionReadOnly (
160 IN EFI_PHYSICAL_ADDRESS BaseAddress,
161 IN UINT64 Length
162 )
163 {
164 EFI_STATUS Status;
165 UINT32 MemoryAttributes;
166 UINT32 PermissionRequest;
167
168 Status = GetMemoryPermissions (BaseAddress, &MemoryAttributes);
169 if (Status != EFI_INVALID_PARAMETER) {
170 PermissionRequest = SET_MEM_ATTR_MAKE_PERM_REQUEST (SET_MEM_ATTR_DATA_PERM_RW,
171 MemoryAttributes);
172 return RequestMemoryPermissionChange (
173 BaseAddress,
174 Length,
175 PermissionRequest
176 );
177 }
178 return EFI_INVALID_PARAMETER;
179 }
180