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