1 // SPDX-License-Identifier: GPL-2.0-only
3 * Author: Erik Kaneda <erik.kaneda@intel.com>
4 * Copyright 2020 Intel Corporation
8 * Each PRM service is an executable that is run in a restricted environment
9 * that is invoked by writing to the PlatformRtMechanism OperationRegion from
12 * init_prmt initializes the Platform Runtime Mechanism (PRM) services by
13 * processing data in the PRMT as well as registering an ACPI OperationRegion
14 * handler for the PlatformRtMechanism subtype.
17 #include <linux/kernel.h>
18 #include <linux/efi.h>
19 #include <linux/acpi.h>
20 #include <linux/prmt.h>
24 struct prm_mmio_addr_range
{
30 struct prm_mmio_info
{
32 struct prm_mmio_addr_range addr_ranges
[];
42 struct prm_context_buffer
{
43 char signature
[ACPI_NAMESEG_SIZE
];
47 u64 static_data_buffer
;
48 struct prm_mmio_info
*mmio_ranges
;
52 static LIST_HEAD(prm_module_list
);
54 struct prm_handler_info
{
56 efi_status_t (__efiapi
*handler_addr
)(u64
, void *);
57 u64 static_data_buffer_addr
;
58 u64 acpi_param_buffer_addr
;
60 struct list_head handler_list
;
63 struct prm_module_info
{
68 struct prm_mmio_info
*mmio_info
;
71 struct list_head module_list
;
72 struct prm_handler_info handlers
[] __counted_by(handler_count
);
75 static u64
efi_pa_va_lookup(efi_guid_t
*guid
, u64 pa
)
77 efi_memory_desc_t
*md
;
78 u64 pa_offset
= pa
& ~PAGE_MASK
;
79 u64 page
= pa
& PAGE_MASK
;
81 for_each_efi_memory_desc(md
) {
82 if ((md
->attribute
& EFI_MEMORY_RUNTIME
) &&
83 (md
->phys_addr
< pa
&& pa
< md
->phys_addr
+ PAGE_SIZE
* md
->num_pages
)) {
84 return pa_offset
+ md
->virt_addr
+ page
- md
->phys_addr
;
88 pr_warn("Failed to find VA for GUID: %pUL, PA: 0x%llx", guid
, pa
);
93 #define get_first_handler(a) ((struct acpi_prmt_handler_info *) ((char *) (a) + a->handler_info_offset))
94 #define get_next_handler(a) ((struct acpi_prmt_handler_info *) (sizeof(struct acpi_prmt_handler_info) + (char *) a))
97 acpi_parse_prmt(union acpi_subtable_headers
*header
, const unsigned long end
)
99 struct acpi_prmt_module_info
*module_info
;
100 struct acpi_prmt_handler_info
*handler_info
;
101 struct prm_handler_info
*th
;
102 struct prm_module_info
*tm
;
105 u32 module_info_size
= 0;
106 u64 mmio_range_size
= 0;
109 module_info
= (struct acpi_prmt_module_info
*) header
;
110 module_info_size
= struct_size(tm
, handlers
, module_info
->handler_info_count
);
111 tm
= kmalloc(module_info_size
, GFP_KERNEL
);
113 goto parse_prmt_out1
;
115 guid_copy(&tm
->guid
, (guid_t
*) module_info
->module_guid
);
116 tm
->major_rev
= module_info
->major_rev
;
117 tm
->minor_rev
= module_info
->minor_rev
;
118 tm
->handler_count
= module_info
->handler_info_count
;
119 tm
->updatable
= true;
121 if (module_info
->mmio_list_pointer
) {
123 * Each module is associated with a list of addr
124 * ranges that it can use during the service
126 mmio_count
= (u64
*) memremap(module_info
->mmio_list_pointer
, 8, MEMREMAP_WB
);
128 goto parse_prmt_out2
;
130 mmio_range_size
= struct_size(tm
->mmio_info
, addr_ranges
, *mmio_count
);
131 tm
->mmio_info
= kmalloc(mmio_range_size
, GFP_KERNEL
);
133 goto parse_prmt_out3
;
135 temp_mmio
= memremap(module_info
->mmio_list_pointer
, mmio_range_size
, MEMREMAP_WB
);
137 goto parse_prmt_out4
;
138 memmove(tm
->mmio_info
, temp_mmio
, mmio_range_size
);
140 tm
->mmio_info
= kmalloc(sizeof(*tm
->mmio_info
), GFP_KERNEL
);
142 goto parse_prmt_out2
;
144 tm
->mmio_info
->mmio_count
= 0;
147 INIT_LIST_HEAD(&tm
->module_list
);
148 list_add(&tm
->module_list
, &prm_module_list
);
150 handler_info
= get_first_handler(module_info
);
152 th
= &tm
->handlers
[cur_handler
];
154 guid_copy(&th
->guid
, (guid_t
*)handler_info
->handler_guid
);
156 (void *)efi_pa_va_lookup(&th
->guid
, handler_info
->handler_address
);
158 th
->static_data_buffer_addr
=
159 efi_pa_va_lookup(&th
->guid
, handler_info
->static_data_buffer_address
);
161 th
->acpi_param_buffer_addr
=
162 efi_pa_va_lookup(&th
->guid
, handler_info
->acpi_param_buffer_address
);
164 } while (++cur_handler
< tm
->handler_count
&& (handler_info
= get_next_handler(handler_info
)));
169 kfree(tm
->mmio_info
);
171 memunmap(mmio_count
);
179 #define GET_HANDLER 1
181 static void *find_guid_info(const guid_t
*guid
, u8 mode
)
183 struct prm_handler_info
*cur_handler
;
184 struct prm_module_info
*cur_module
;
187 list_for_each_entry(cur_module
, &prm_module_list
, module_list
) {
188 for (i
= 0; i
< cur_module
->handler_count
; ++i
) {
189 cur_handler
= &cur_module
->handlers
[i
];
190 if (guid_equal(guid
, &cur_handler
->guid
)) {
191 if (mode
== GET_MODULE
)
192 return (void *)cur_module
;
194 return (void *)cur_handler
;
202 static struct prm_module_info
*find_prm_module(const guid_t
*guid
)
204 return (struct prm_module_info
*)find_guid_info(guid
, GET_MODULE
);
207 static struct prm_handler_info
*find_prm_handler(const guid_t
*guid
)
209 return (struct prm_handler_info
*) find_guid_info(guid
, GET_HANDLER
);
212 /* In-coming PRM commands */
214 #define PRM_CMD_RUN_SERVICE 0
215 #define PRM_CMD_START_TRANSACTION 1
216 #define PRM_CMD_END_TRANSACTION 2
218 /* statuses that can be passed back to ASL */
220 #define PRM_HANDLER_SUCCESS 0
221 #define PRM_HANDLER_ERROR 1
222 #define INVALID_PRM_COMMAND 2
223 #define PRM_HANDLER_GUID_NOT_FOUND 3
224 #define UPDATE_LOCK_ALREADY_HELD 4
225 #define UPDATE_UNLOCK_WITHOUT_LOCK 5
227 int acpi_call_prm_handler(guid_t handler_guid
, void *param_buffer
)
229 struct prm_handler_info
*handler
= find_prm_handler(&handler_guid
);
230 struct prm_module_info
*module
= find_prm_module(&handler_guid
);
231 struct prm_context_buffer context
;
234 if (!module
|| !handler
)
237 memset(&context
, 0, sizeof(context
));
238 ACPI_COPY_NAMESEG(context
.signature
, "PRMC");
239 context
.identifier
= handler
->guid
;
240 context
.static_data_buffer
= handler
->static_data_buffer_addr
;
241 context
.mmio_ranges
= module
->mmio_info
;
243 status
= efi_call_acpi_prm_handler(handler
->handler_addr
,
247 return efi_status_to_err(status
);
249 EXPORT_SYMBOL_GPL(acpi_call_prm_handler
);
252 * This is the PlatformRtMechanism opregion space handler.
253 * @function: indicates the read/write. In fact as the PlatformRtMechanism
254 * message is driven by command, only write is meaningful.
258 * @value : it is an in/out parameter. It points to the PRM message buffer.
259 * @handler_context: not used
261 static acpi_status
acpi_platformrt_space_handler(u32 function
,
262 acpi_physical_address addr
,
263 u32 bits
, acpi_integer
*value
,
264 void *handler_context
,
265 void *region_context
)
267 struct prm_buffer
*buffer
= ACPI_CAST_PTR(struct prm_buffer
, value
);
268 struct prm_handler_info
*handler
;
269 struct prm_module_info
*module
;
271 struct prm_context_buffer context
;
273 if (!efi_enabled(EFI_RUNTIME_SERVICES
)) {
274 pr_err_ratelimited("PRM: EFI runtime services no longer available\n");
275 return AE_NO_HANDLER
;
279 * The returned acpi_status will always be AE_OK. Error values will be
280 * saved in the first byte of the PRM message buffer to be used by ASL.
282 switch (buffer
->prm_cmd
) {
283 case PRM_CMD_RUN_SERVICE
:
285 handler
= find_prm_handler(&buffer
->handler_guid
);
286 module
= find_prm_module(&buffer
->handler_guid
);
287 if (!handler
|| !module
)
290 if (!handler
->handler_addr
||
291 !handler
->static_data_buffer_addr
||
292 !handler
->acpi_param_buffer_addr
) {
293 buffer
->prm_status
= PRM_HANDLER_ERROR
;
297 ACPI_COPY_NAMESEG(context
.signature
, "PRMC");
298 context
.revision
= 0x0;
299 context
.reserved
= 0x0;
300 context
.identifier
= handler
->guid
;
301 context
.static_data_buffer
= handler
->static_data_buffer_addr
;
302 context
.mmio_ranges
= module
->mmio_info
;
304 status
= efi_call_acpi_prm_handler(handler
->handler_addr
,
305 handler
->acpi_param_buffer_addr
,
307 if (status
== EFI_SUCCESS
) {
308 buffer
->prm_status
= PRM_HANDLER_SUCCESS
;
310 buffer
->prm_status
= PRM_HANDLER_ERROR
;
311 buffer
->efi_status
= status
;
315 case PRM_CMD_START_TRANSACTION
:
317 module
= find_prm_module(&buffer
->handler_guid
);
321 if (module
->updatable
)
322 module
->updatable
= false;
324 buffer
->prm_status
= UPDATE_LOCK_ALREADY_HELD
;
327 case PRM_CMD_END_TRANSACTION
:
329 module
= find_prm_module(&buffer
->handler_guid
);
333 if (module
->updatable
)
334 buffer
->prm_status
= UPDATE_UNLOCK_WITHOUT_LOCK
;
336 module
->updatable
= true;
341 buffer
->prm_status
= INVALID_PRM_COMMAND
;
348 buffer
->prm_status
= PRM_HANDLER_GUID_NOT_FOUND
;
352 void __init
init_prmt(void)
354 struct acpi_table_header
*tbl
;
358 status
= acpi_get_table(ACPI_SIG_PRMT
, 0, &tbl
);
359 if (ACPI_FAILURE(status
))
362 mc
= acpi_table_parse_entries(ACPI_SIG_PRMT
, sizeof(struct acpi_table_prmt
) +
363 sizeof (struct acpi_table_prmt_header
),
364 0, acpi_parse_prmt
, 0);
367 * Return immediately if PRMT table is not present or no PRM module found.
372 pr_info("PRM: found %u modules\n", mc
);
374 if (!efi_enabled(EFI_RUNTIME_SERVICES
)) {
375 pr_err("PRM: EFI runtime services unavailable\n");
379 status
= acpi_install_address_space_handler(ACPI_ROOT_OBJECT
,
380 ACPI_ADR_SPACE_PLATFORM_RT
,
381 &acpi_platformrt_space_handler
,
383 if (ACPI_FAILURE(status
))
384 pr_alert("PRM: OperationRegion handler could not be installed\n");