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