blob: 18dfd1991bd9fae8093bdac64a46a8e15f5c256b [file] [log] [blame]
Balint Dobszay5bf492f2024-07-29 17:21:32 +02001// SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![cfg_attr(not(test), no_std)]
5
6extern crate alloc;
7
8use alloc::string::String;
Andrew Walbran44029a02024-11-25 15:34:31 +00009use num_enum::{IntoPrimitive, TryFromPrimitive};
10use thiserror::Error;
Balint Dobszay5bf492f2024-07-29 17:21:32 +020011use uuid::Uuid;
12
13pub mod boot_info;
14pub mod memory_management;
15pub mod partition_info;
16
17pub const FFA_PAGE_SIZE: usize = 4096;
18
19#[derive(PartialEq, Clone, Copy)]
20pub enum Instance {
21 SecurePhysical,
22 SecureVirtual(u16),
23}
24
25/// FF-A v1.1, Table 12.2: Error status codes
Andrew Walbran44029a02024-11-25 15:34:31 +000026#[derive(Clone, Copy, Debug, Eq, Error, IntoPrimitive, PartialEq, TryFromPrimitive)]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020027#[repr(i32)]
28pub enum Error {
Andrew Walbran44029a02024-11-25 15:34:31 +000029 #[error("Not supported")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020030 NotSupported = -1,
Andrew Walbran44029a02024-11-25 15:34:31 +000031 #[error("Invalid parameters")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020032 InvalidParameters = -2,
Andrew Walbran44029a02024-11-25 15:34:31 +000033 #[error("No memory")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020034 NoMemory = -3,
Andrew Walbran44029a02024-11-25 15:34:31 +000035 #[error("Busy")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020036 Busy = -4,
Andrew Walbran44029a02024-11-25 15:34:31 +000037 #[error("Interrupted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020038 Interrupted = -5,
Andrew Walbran44029a02024-11-25 15:34:31 +000039 #[error("Denied")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020040 Denied = -6,
Andrew Walbran44029a02024-11-25 15:34:31 +000041 #[error("Retry")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020042 Retry = -7,
Andrew Walbran44029a02024-11-25 15:34:31 +000043 #[error("Aborted")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020044 Aborted = -8,
Andrew Walbran44029a02024-11-25 15:34:31 +000045 #[error("No data")]
Balint Dobszay5bf492f2024-07-29 17:21:32 +020046 NoData = -9,
47}
48
49/// FF-A v1.1: Function IDs
50#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
51#[repr(u32)]
52pub enum FuncId {
53 Error = 0x84000060,
54 Success32 = 0x84000061,
55 Success64 = 0xc4000061,
56 Interrupt = 0x84000062,
57 Version = 0x84000063,
58 Features = 0x84000064,
59 RxAcquire = 0x84000084,
60 RxRelease = 0x84000065,
61 RxTxMap32 = 0x84000066,
62 RxTxMap64 = 0xc4000066,
63 RxTxUnmap = 0x84000067,
64 PartitionInfoGet = 0x84000068,
65 IdGet = 0x84000069,
66 SpmIdGet = 0x84000085,
67 MsgWait = 0x8400006b,
68 Yield = 0x8400006c,
69 Run = 0x8400006d,
70 NormalWorldResume = 0x8400007c,
71 MsgSend2 = 0x84000086,
72 MsgSendDirectReq32 = 0x8400006f,
73 MsgSendDirectReq64 = 0xc400006f,
74 MsgSendDirectResp32 = 0x84000070,
75 MsgSendDirectResp64 = 0xc4000070,
76 MemDonate32 = 0x84000071,
77 MemDonate64 = 0xc4000071,
78 MemLend32 = 0x84000072,
79 MemLend64 = 0xc4000072,
80 MemShare32 = 0x84000073,
81 MemShare64 = 0xc4000073,
82 MemRetrieveReq32 = 0x84000074,
83 MemRetrieveReq64 = 0xc4000074,
84 MemRetrieveResp = 0x84000075,
85 MemRelinquish = 0x84000076,
86 MemReclaim = 0x84000077,
87 MemPermGet32 = 0x84000088,
88 MemPermGet64 = 0xc4000088,
89 MemPermSet32 = 0x84000089,
90 MemPermSet64 = 0xc4000089,
91 ConsoleLog32 = 0x8400008a,
92 ConsoleLog64 = 0xc400008a,
93}
94
95#[derive(Debug, Eq, PartialEq, Clone, Copy)]
96pub enum Interface {
97 Error {
98 target_info: u32,
99 error_code: Error,
100 },
101 Success {
102 target_info: u32,
103 result_regs: [u64; 6],
104 is_32bit: bool,
105 },
106 Interrupt {
107 endpoint_id: u32,
108 interrupt_id: u32,
109 },
110 Version {
111 input_version: u32,
112 },
113 VersionOut {
114 output_version: u32,
115 },
116 Features {
117 feat_id: u32,
118 input_properties: u32,
119 },
120 RxAcquire {
121 vm_id: u32,
122 },
123 RxRelease {
124 vm_id: u32,
125 },
126 RxTxMap {
127 tx_addr: u64,
128 rx_addr: u64,
129 page_cnt: u32,
130 is_32bit: bool,
131 },
132 RxTxUnmap {
133 id: u32,
134 },
135 PartitionInfoGet {
136 uuid: Uuid,
137 flags: u32,
138 },
139 IdGet,
140 SpmIdGet,
141 MsgWait,
142 Yield,
143 Run {
144 target_info: u32,
145 },
146 NormalWorldResume,
147 MsgSend2 {
148 sender_vm_id: u32,
149 flags: u32,
150 },
151 MsgSendDirectReq {
152 src_id: u16,
153 dst_id: u16,
154 flags: u32,
155 args: [u64; 5],
156 is_32bit: bool,
157 },
158 MsgSendDirectResp {
159 src_id: u16,
160 dst_id: u16,
161 flags: u32,
162 args: [u64; 5],
163 is_32bit: bool,
164 },
165 MemDonate {
166 total_len: u32,
167 frag_len: u32,
168 address: u64,
169 page_cnt: u32,
170 is_32bit: bool,
171 },
172 MemLend {
173 total_len: u32,
174 frag_len: u32,
175 address: u64,
176 page_cnt: u32,
177 is_32bit: bool,
178 },
179 MemShare {
180 total_len: u32,
181 frag_len: u32,
182 address: u64,
183 page_cnt: u32,
184 is_32bit: bool,
185 },
186 MemRetrieveReq {
187 total_len: u32,
188 frag_len: u32,
189 address: u64,
190 page_cnt: u32,
191 is_32bit: bool,
192 },
193 MemRetrieveResp {
194 total_len: u32,
195 frag_len: u32,
196 },
197 MemRelinquish,
198 MemReclaim {
199 handle: memory_management::Handle,
200 flags: u32,
201 },
202 MemPermGet {
203 base_addr: u64,
204 is_32bit: bool,
205 },
206 MemPermSet {
207 base_addr: u64,
208 page_cnt: u32,
209 mem_perm: u32,
210 is_32bit: bool,
211 },
212 ConsoleLog {
213 char_cnt: u32,
214 char_lists: [u64; 6],
215 is_32bit: bool,
216 },
217}
218
219impl TryFrom<[u64; 8]> for Interface {
220 type Error = ();
221
222 fn try_from(regs: [u64; 8]) -> Result<Self, ()> {
223 let fid = FuncId::try_from(regs[0] as u32).unwrap();
224
225 let msg = match fid {
226 FuncId::Error => Self::Error {
227 target_info: regs[1] as u32,
228 error_code: Error::try_from(regs[2] as i32).unwrap(),
229 },
230 FuncId::Success32 | FuncId::Success64 => {
231 let target_info = regs[1] as u32;
232 let mut result_regs = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
233 let mut is_32bit = false;
234
235 if fid == FuncId::Success32 {
236 result_regs[0] &= u32::MAX as u64;
237 result_regs[1] &= u32::MAX as u64;
238 result_regs[2] &= u32::MAX as u64;
239 result_regs[3] &= u32::MAX as u64;
240 result_regs[4] &= u32::MAX as u64;
241 result_regs[5] &= u32::MAX as u64;
242 is_32bit = true;
243 }
244
245 Self::Success {
246 target_info,
247 result_regs,
248 is_32bit,
249 }
250 }
251 FuncId::Interrupt => Self::Interrupt {
252 endpoint_id: regs[1] as u32,
253 interrupt_id: regs[2] as u32,
254 },
255 FuncId::Version => Self::Version {
256 input_version: regs[1] as u32,
257 },
258 FuncId::Features => Self::Features {
259 feat_id: regs[1] as u32,
260 input_properties: regs[2] as u32,
261 },
262 FuncId::RxAcquire => Self::RxAcquire {
263 vm_id: regs[1] as u32,
264 },
265 FuncId::RxRelease => Self::RxRelease {
266 vm_id: regs[1] as u32,
267 },
268 FuncId::RxTxMap32 | FuncId::RxTxMap64 => {
269 let mut tx_addr = regs[1];
270 let mut rx_addr = regs[2];
271 let page_cnt = regs[3] as u32;
272 let mut is_32bit = false;
273
274 if fid == FuncId::RxTxMap32 {
275 tx_addr &= u32::MAX as u64;
276 rx_addr &= u32::MAX as u64;
277 is_32bit = true;
278 }
279
280 Self::RxTxMap {
281 tx_addr,
282 rx_addr,
283 page_cnt,
284 is_32bit,
285 }
286 }
287 FuncId::RxTxUnmap => Self::RxTxUnmap { id: regs[1] as u32 },
288 FuncId::PartitionInfoGet => {
289 let uuid_words = [
290 regs[1] as u32,
291 regs[2] as u32,
292 regs[3] as u32,
293 regs[4] as u32,
294 ];
295 let mut bytes: [u8; 16] = [0; 16];
296 for (i, b) in uuid_words.iter().flat_map(|w| w.to_le_bytes()).enumerate() {
297 bytes[i] = b;
298 }
299 Self::PartitionInfoGet {
300 uuid: Uuid::from_bytes(bytes),
301 flags: regs[5] as u32,
302 }
303 }
304 FuncId::IdGet => Self::IdGet,
305 FuncId::SpmIdGet => Self::SpmIdGet,
306 FuncId::MsgWait => Self::MsgWait,
307 FuncId::Yield => Self::Yield,
308 FuncId::Run => Self::Run {
309 target_info: regs[1] as u32,
310 },
311 FuncId::NormalWorldResume => Self::NormalWorldResume,
312 FuncId::MsgSend2 => Self::MsgSend2 {
313 sender_vm_id: regs[1] as u32,
314 flags: regs[2] as u32,
315 },
316 FuncId::MsgSendDirectReq32 | FuncId::MsgSendDirectReq64 => {
317 let src_id = (regs[1] >> 16) as u16;
318 let dst_id = regs[1] as u16;
319 let flags = regs[2] as u32;
320 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
321 let mut is_32bit = false;
322
323 if fid == FuncId::MsgSendDirectReq32 {
324 args[0] &= u32::MAX as u64;
325 args[1] &= u32::MAX as u64;
326 args[2] &= u32::MAX as u64;
327 args[3] &= u32::MAX as u64;
328 args[4] &= u32::MAX as u64;
329 is_32bit = true;
330 }
331
332 Self::MsgSendDirectReq {
333 src_id,
334 dst_id,
335 flags,
336 args,
337 is_32bit,
338 }
339 }
340 FuncId::MsgSendDirectResp32 | FuncId::MsgSendDirectResp64 => {
341 let src_id = (regs[1] >> 16) as u16;
342 let dst_id = regs[1] as u16;
343 let flags = regs[2] as u32;
344 let mut args = [regs[3], regs[4], regs[5], regs[6], regs[7]];
345 let mut is_32bit = false;
346
347 if fid == FuncId::MsgSendDirectResp32 {
348 args[0] &= u32::MAX as u64;
349 args[1] &= u32::MAX as u64;
350 args[2] &= u32::MAX as u64;
351 args[3] &= u32::MAX as u64;
352 args[4] &= u32::MAX as u64;
353 is_32bit = true;
354 }
355
356 Self::MsgSendDirectResp {
357 src_id,
358 dst_id,
359 flags,
360 args,
361 is_32bit,
362 }
363 }
364 FuncId::MemDonate32 | FuncId::MemDonate64 => {
365 let total_len = regs[1] as u32;
366 let frag_len = regs[2] as u32;
367 let mut address = regs[3];
368 let page_cnt = regs[4] as u32;
369 let mut is_32bit = false;
370
371 if fid == FuncId::MemDonate32 {
372 address &= u32::MAX as u64;
373 is_32bit = true;
374 }
375
376 Self::MemDonate {
377 total_len,
378 frag_len,
379 address,
380 page_cnt,
381 is_32bit,
382 }
383 }
384 FuncId::MemLend32 | FuncId::MemLend64 => {
385 let total_len = regs[1] as u32;
386 let frag_len = regs[2] as u32;
387 let mut address = regs[3];
388 let page_cnt = regs[4] as u32;
389 let mut is_32bit = false;
390
391 if fid == FuncId::MemLend32 {
392 address &= u32::MAX as u64;
393 is_32bit = true;
394 }
395
396 Self::MemLend {
397 total_len,
398 frag_len,
399 address,
400 page_cnt,
401 is_32bit,
402 }
403 }
404 FuncId::MemShare32 | FuncId::MemShare64 => {
405 let total_len = regs[1] as u32;
406 let frag_len = regs[2] as u32;
407 let mut address = regs[3];
408 let page_cnt = regs[4] as u32;
409 let mut is_32bit = false;
410
411 if fid == FuncId::MemShare32 {
412 address &= u32::MAX as u64;
413 is_32bit = true;
414 }
415
416 Self::MemShare {
417 total_len,
418 frag_len,
419 address,
420 page_cnt,
421 is_32bit,
422 }
423 }
424 FuncId::MemRetrieveReq32 | FuncId::MemRetrieveReq64 => {
425 let total_len = regs[1] as u32;
426 let frag_len = regs[2] as u32;
427 let mut address = regs[3];
428 let page_cnt = regs[4] as u32;
429 let mut is_32bit = false;
430
431 if fid == FuncId::MemRetrieveReq32 {
432 address &= u32::MAX as u64;
433 is_32bit = true;
434 }
435
436 Self::MemRetrieveReq {
437 total_len,
438 frag_len,
439 address,
440 page_cnt,
441 is_32bit,
442 }
443 }
444 FuncId::MemRetrieveResp => Self::MemRetrieveResp {
445 total_len: regs[1] as u32,
446 frag_len: regs[2] as u32,
447 },
448 FuncId::MemRelinquish => Self::MemRelinquish,
449 FuncId::MemReclaim => Self::MemReclaim {
450 handle: memory_management::Handle::from([regs[1] as u32, regs[2] as u32]),
451 flags: regs[3] as u32,
452 },
453 FuncId::MemPermGet32 | FuncId::MemPermGet64 => {
454 let mut base_addr = regs[1];
455 let mut is_32bit = false;
456
457 if fid == FuncId::MemPermGet32 {
458 base_addr &= u32::MAX as u64;
459 is_32bit = true;
460 }
461
462 Self::MemPermGet {
463 base_addr,
464 is_32bit,
465 }
466 }
467 FuncId::MemPermSet32 | FuncId::MemPermSet64 => {
468 let mut base_addr = regs[1];
469 let page_cnt = regs[2] as u32;
470 let mem_perm = regs[3] as u32;
471 let mut is_32bit = false;
472
473 if fid == FuncId::MemPermSet32 {
474 base_addr &= u32::MAX as u64;
475 is_32bit = true;
476 }
477
478 Self::MemPermSet {
479 base_addr,
480 page_cnt,
481 mem_perm,
482 is_32bit,
483 }
484 }
485 FuncId::ConsoleLog32 | FuncId::ConsoleLog64 => {
486 let char_cnt = regs[1] as u32;
487 let mut char_lists = [regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]];
488 let mut is_32bit = false;
489
490 if fid == FuncId::ConsoleLog32 {
491 char_lists[0] &= u32::MAX as u64;
492 char_lists[1] &= u32::MAX as u64;
493 char_lists[2] &= u32::MAX as u64;
494 char_lists[3] &= u32::MAX as u64;
495 char_lists[4] &= u32::MAX as u64;
496 char_lists[5] &= u32::MAX as u64;
497 is_32bit = true;
498 }
499
500 Self::ConsoleLog {
501 char_cnt,
502 char_lists,
503 is_32bit,
504 }
505 }
506 };
507
508 Ok(msg)
509 }
510}
511
512impl Interface {
513 pub fn copy_to_array(&self, a: &mut [u64; 8]) {
514 a.fill(0);
515
516 match *self {
517 Interface::Error {
518 target_info,
519 error_code,
520 } => {
521 a[0] = FuncId::Error as u64;
522 a[1] = target_info as u64;
523 a[2] = error_code as u32 as u64;
524 }
525 Interface::Success {
526 target_info,
527 result_regs,
528 is_32bit,
529 } => {
530 a[1] = target_info as u64;
531 if is_32bit {
532 a[0] = FuncId::Success32 as u64;
533 a[2] = result_regs[0] & u32::MAX as u64;
534 a[3] = result_regs[1] & u32::MAX as u64;
535 a[4] = result_regs[2] & u32::MAX as u64;
536 a[5] = result_regs[3] & u32::MAX as u64;
537 a[6] = result_regs[4] & u32::MAX as u64;
538 a[7] = result_regs[5] & u32::MAX as u64;
539 } else {
540 a[0] = FuncId::Success64 as u64;
541 a[2] = result_regs[0];
542 a[3] = result_regs[1];
543 a[4] = result_regs[2];
544 a[5] = result_regs[3];
545 a[6] = result_regs[4];
546 a[7] = result_regs[5];
547 }
548 }
549 Interface::Interrupt {
550 endpoint_id,
551 interrupt_id,
552 } => {
553 a[0] = FuncId::Interrupt as u64;
554 a[1] = endpoint_id as u64;
555 a[2] = interrupt_id as u64;
556 }
557 Interface::Version { input_version } => {
558 a[0] = FuncId::Version as u64;
559 a[1] = input_version as u64;
560 }
561 Interface::VersionOut { output_version } => {
562 a[0] = output_version as u64;
563 }
564 Interface::Features {
565 feat_id,
566 input_properties,
567 } => {
568 a[0] = FuncId::Features as u64;
569 a[1] = feat_id as u64;
570 a[2] = input_properties as u64;
571 }
572 Interface::RxAcquire { vm_id } => {
573 a[0] = FuncId::RxAcquire as u64;
574 a[1] = vm_id as u64;
575 }
576 Interface::RxRelease { vm_id } => {
577 a[0] = FuncId::RxRelease as u64;
578 a[1] = vm_id as u64;
579 }
580 Interface::RxTxMap {
581 tx_addr,
582 rx_addr,
583 page_cnt,
584 is_32bit,
585 } => {
586 a[3] = page_cnt as u64;
587 if is_32bit {
588 a[0] = FuncId::RxTxMap32 as u64;
589 a[1] = tx_addr & u32::MAX as u64;
590 a[2] = rx_addr & u32::MAX as u64;
591 } else {
592 a[0] = FuncId::RxTxMap64 as u64;
593 a[1] = tx_addr;
594 a[2] = rx_addr;
595 }
596 }
597 Interface::RxTxUnmap { id } => {
598 a[0] = FuncId::RxTxUnmap as u64;
599 a[1] = id as u64;
600 }
601 Interface::PartitionInfoGet { uuid, flags } => {
602 let bytes = uuid.to_bytes_le();
603 a[0] = FuncId::PartitionInfoGet as u64;
604 a[1] = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u64;
605 a[2] = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as u64;
606 a[3] = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as u64;
607 a[4] = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]) as u64;
608 a[5] = flags as u64;
609 }
610 Interface::IdGet => a[0] = FuncId::IdGet as u64,
611 Interface::SpmIdGet => a[0] = FuncId::SpmIdGet as u64,
612 Interface::MsgWait => a[0] = FuncId::MsgWait as u64,
613 Interface::Yield => a[0] = FuncId::Yield as u64,
614 Interface::Run { target_info } => {
615 a[0] = FuncId::Run as u64;
616 a[1] = target_info as u64;
617 }
618 Interface::NormalWorldResume => a[0] = FuncId::NormalWorldResume as u64,
619 Interface::MsgSend2 {
620 sender_vm_id,
621 flags,
622 } => {
623 a[0] = FuncId::MsgSend2 as u64;
624 a[1] = sender_vm_id as u64;
625 a[2] = flags as u64;
626 }
627 Interface::MsgSendDirectReq {
628 src_id,
629 dst_id,
630 flags,
631 args,
632 is_32bit,
633 } => {
634 a[1] = (src_id as u64) << 16 | dst_id as u64;
635 a[2] = flags as u64;
636 if is_32bit {
637 a[0] = FuncId::MsgSendDirectReq32 as u64;
638 a[3] = args[0] & u32::MAX as u64;
639 a[4] = args[1] & u32::MAX as u64;
640 a[5] = args[2] & u32::MAX as u64;
641 a[6] = args[3] & u32::MAX as u64;
642 a[7] = args[4] & u32::MAX as u64;
643 } else {
644 a[0] = FuncId::MsgSendDirectReq64 as u64;
645 a[3] = args[0];
646 a[4] = args[1];
647 a[5] = args[2];
648 a[6] = args[3];
649 a[7] = args[4];
650 }
651 }
652 Interface::MsgSendDirectResp {
653 src_id,
654 dst_id,
655 flags,
656 args,
657 is_32bit,
658 } => {
659 a[1] = (src_id as u64) << 16 | dst_id as u64;
660 a[2] = flags as u64;
661 if is_32bit {
662 a[0] = FuncId::MsgSendDirectResp32 as u64;
663 a[3] = args[0] & u32::MAX as u64;
664 a[4] = args[1] & u32::MAX as u64;
665 a[5] = args[2] & u32::MAX as u64;
666 a[6] = args[3] & u32::MAX as u64;
667 a[7] = args[4] & u32::MAX as u64;
668 } else {
669 a[0] = FuncId::MsgSendDirectResp64 as u64;
670 a[3] = args[0];
671 a[4] = args[1];
672 a[5] = args[2];
673 a[6] = args[3];
674 a[7] = args[4];
675 }
676 }
677 Interface::MemDonate {
678 total_len,
679 frag_len,
680 address,
681 page_cnt,
682 is_32bit,
683 } => {
684 a[1] = total_len as u64;
685 a[2] = frag_len as u64;
686 a[4] = page_cnt as u64;
687 if is_32bit {
688 a[0] = FuncId::MemDonate32 as u64;
689 a[3] = address & u32::MAX as u64;
690 } else {
691 a[0] = FuncId::MemDonate64 as u64;
692 a[3] = address;
693 }
694 }
695 Interface::MemLend {
696 total_len,
697 frag_len,
698 address,
699 page_cnt,
700 is_32bit,
701 } => {
702 a[1] = total_len as u64;
703 a[2] = frag_len as u64;
704 a[4] = page_cnt as u64;
705 if is_32bit {
706 a[0] = FuncId::MemLend32 as u64;
707 a[3] = address & u32::MAX as u64;
708 } else {
709 a[0] = FuncId::MemLend64 as u64;
710 a[3] = address;
711 }
712 }
713 Interface::MemShare {
714 total_len,
715 frag_len,
716 address,
717 page_cnt,
718 is_32bit,
719 } => {
720 a[1] = total_len as u64;
721 a[2] = frag_len as u64;
722 a[4] = page_cnt as u64;
723 if is_32bit {
724 a[0] = FuncId::MemShare32 as u64;
725 a[3] = address & u32::MAX as u64;
726 } else {
727 a[0] = FuncId::MemShare64 as u64;
728 a[3] = address;
729 }
730 }
731 Interface::MemRetrieveReq {
732 total_len,
733 frag_len,
734 address,
735 page_cnt,
736 is_32bit,
737 } => {
738 a[1] = total_len as u64;
739 a[2] = frag_len as u64;
740 a[4] = page_cnt as u64;
741 if is_32bit {
742 a[0] = FuncId::MemRetrieveReq32 as u64;
743 a[3] = address & u32::MAX as u64;
744 } else {
745 a[0] = FuncId::MemRetrieveReq64 as u64;
746 a[3] = address;
747 }
748 }
749 Interface::MemRetrieveResp {
750 total_len,
751 frag_len,
752 } => {
753 a[0] = FuncId::MemRetrieveResp as u64;
754 a[1] = total_len as u64;
755 a[2] = frag_len as u64;
756 }
757 Interface::MemRelinquish => a[0] = FuncId::MemRelinquish as u64,
758 Interface::MemReclaim { handle, flags } => {
759 let handle_regs: [u32; 2] = handle.into();
760 a[0] = FuncId::MemReclaim as u64;
761 a[1] = handle_regs[0] as u64;
762 a[2] = handle_regs[1] as u64;
763 a[3] = flags as u64;
764 }
765 Interface::MemPermGet {
766 base_addr,
767 is_32bit,
768 } => {
769 if is_32bit {
770 a[0] = FuncId::MemPermGet32 as u64;
771 a[1] = base_addr & u32::MAX as u64;
772 } else {
773 a[0] = FuncId::MemPermGet64 as u64;
774 a[1] = base_addr;
775 }
776 }
777 Interface::MemPermSet {
778 base_addr,
779 page_cnt,
780 mem_perm,
781 is_32bit,
782 } => {
783 a[2] = page_cnt as u64;
784 a[3] = mem_perm as u64;
785
786 if is_32bit {
787 a[0] = FuncId::MemPermSet32 as u64;
788 a[1] = base_addr & u32::MAX as u64;
789 } else {
790 a[0] = FuncId::MemPermSet64 as u64;
791 a[1] = base_addr;
792 }
793 }
794 Interface::ConsoleLog {
795 char_cnt,
796 char_lists,
797 is_32bit,
798 } => {
799 a[1] = char_cnt as u64;
800 if is_32bit {
801 a[0] = FuncId::ConsoleLog32 as u64;
802 a[2] = char_lists[0] & u32::MAX as u64;
803 a[3] = char_lists[1] & u32::MAX as u64;
804 a[4] = char_lists[2] & u32::MAX as u64;
805 a[5] = char_lists[3] & u32::MAX as u64;
806 a[6] = char_lists[4] & u32::MAX as u64;
807 a[7] = char_lists[5] & u32::MAX as u64;
808 } else {
809 a[0] = FuncId::ConsoleLog64 as u64;
810 a[2] = char_lists[0];
811 a[3] = char_lists[1];
812 a[4] = char_lists[2];
813 a[5] = char_lists[3];
814 a[6] = char_lists[4];
815 a[7] = char_lists[5];
816 }
817 }
818 }
819 }
820
821 /// Helper function to create an FFA_SUCCESS interface without any arguments
822 pub fn success32_noargs() -> Self {
823 Self::Success {
824 target_info: 0,
825 result_regs: [0, 0, 0, 0, 0, 0],
826 is_32bit: true,
827 }
828 }
829}
830
831#[derive(Clone, Copy, Debug, PartialEq)]
832pub struct Version(pub u16, pub u16);
833
834impl From<u32> for Version {
835 fn from(val: u32) -> Self {
836 Self((val >> 16) as u16, val as u16)
837 }
838}
839
840impl From<Version> for u32 {
841 fn from(v: Version) -> Self {
842 (v.0 as u32) << 16 | v.1 as u32
843 }
844}
845
846pub fn parse_console_log(
847 char_cnt: u32,
848 char_lists: &[u64; 6],
849 is_32bit: bool,
850) -> Result<String, Error> {
851 const CHAR_COUNT_MASK: u32 = 0xff;
852 const LOG_32_MAX_MSG_LEN: usize = 24;
853 const LOG_64_MAX_MSG_LEN: usize = 48;
854
855 let mut msg_bytes = [0u8; LOG_64_MAX_MSG_LEN + 1];
856 let char_count = (char_cnt & CHAR_COUNT_MASK) as usize;
857 let (max_length, reg_size) = if is_32bit {
858 (LOG_32_MAX_MSG_LEN, 4)
859 } else {
860 (LOG_64_MAX_MSG_LEN, 8)
861 };
862
863 if char_count < 1 || char_count > max_length {
864 return Err(Error::InvalidParameters);
865 }
866
867 for i in 0..=5 {
868 msg_bytes[reg_size * i..reg_size * (i + 1)]
869 .copy_from_slice(&char_lists[i].to_le_bytes()[0..reg_size]);
870 }
871
872 String::from_utf8(msg_bytes.to_vec()).map_err(|_| Error::InvalidParameters)
873}