Andrew Walbran | b5ab43c | 2020-04-30 11:32:54 +0100 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2018 The Hafnium Authors. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * https://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "hf/ffa.h" |
| 18 | |
| 19 | #include "hf/mm.h" |
| 20 | #include "hf/static_assert.h" |
| 21 | |
| 22 | #include "vmapi/hf/call.h" |
| 23 | |
| 24 | #include "test/hftest.h" |
| 25 | #include "test/vmapi/ffa.h" |
| 26 | |
| 27 | static alignas(PAGE_SIZE) uint8_t send_page[PAGE_SIZE]; |
| 28 | static alignas(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE]; |
| 29 | static_assert(sizeof(send_page) == PAGE_SIZE, "Send page is not a page."); |
| 30 | static_assert(sizeof(recv_page) == PAGE_SIZE, "Recv page is not a page."); |
| 31 | |
| 32 | static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page; |
| 33 | static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page; |
| 34 | |
| 35 | struct mailbox_buffers set_up_mailbox(void) |
| 36 | { |
| 37 | ASSERT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func, |
| 38 | FFA_SUCCESS_32); |
| 39 | return (struct mailbox_buffers){ |
| 40 | .send = send_page, |
| 41 | .recv = recv_page, |
| 42 | }; |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | * Helper function to send memory to a VM then send a message with the retrieve |
| 47 | * request it needs to retrieve it. |
| 48 | */ |
| 49 | ffa_memory_handle_t send_memory_and_retrieve_request( |
| 50 | uint32_t share_func, void *tx_buffer, ffa_vm_id_t sender, |
| 51 | ffa_vm_id_t recipient, |
| 52 | struct ffa_memory_region_constituent constituents[], |
| 53 | uint32_t constituent_count, ffa_memory_region_flags_t flags, |
| 54 | enum ffa_data_access send_data_access, |
| 55 | enum ffa_data_access retrieve_data_access, |
| 56 | enum ffa_instruction_access send_instruction_access, |
| 57 | enum ffa_instruction_access retrieve_instruction_access) |
| 58 | { |
| 59 | uint32_t msg_size; |
| 60 | struct ffa_value ret; |
| 61 | ffa_memory_handle_t handle; |
| 62 | |
| 63 | /* Send the memory. */ |
| 64 | msg_size = ffa_memory_region_init( |
| 65 | tx_buffer, sender, recipient, constituents, constituent_count, |
| 66 | 0, flags, send_data_access, send_instruction_access, |
| 67 | FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, |
| 68 | FFA_MEMORY_OUTER_SHAREABLE); |
| 69 | switch (share_func) { |
| 70 | case FFA_MEM_DONATE_32: |
| 71 | ret = ffa_mem_donate(msg_size, msg_size); |
| 72 | break; |
| 73 | case FFA_MEM_LEND_32: |
| 74 | ret = ffa_mem_lend(msg_size, msg_size); |
| 75 | break; |
| 76 | case FFA_MEM_SHARE_32: |
| 77 | ret = ffa_mem_share(msg_size, msg_size); |
| 78 | break; |
| 79 | default: |
| 80 | FAIL("Invalid share_func %#x.\n", share_func); |
| 81 | /* Never reached, but needed to keep clang-analyser happy. */ |
| 82 | return 0; |
| 83 | } |
| 84 | EXPECT_EQ(ret.func, FFA_SUCCESS_32); |
| 85 | handle = ffa_mem_success_handle(ret); |
| 86 | |
| 87 | /* |
| 88 | * Send the appropriate retrieve request to the VM so that it can use it |
| 89 | * to retrieve the memory. |
| 90 | */ |
| 91 | msg_size = ffa_memory_retrieve_request_init( |
| 92 | tx_buffer, handle, sender, recipient, 0, 0, |
| 93 | retrieve_data_access, retrieve_instruction_access, |
| 94 | FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK, |
| 95 | FFA_MEMORY_OUTER_SHAREABLE); |
| 96 | EXPECT_EQ(ffa_msg_send(sender, recipient, msg_size, 0).func, |
| 97 | FFA_SUCCESS_32); |
| 98 | |
| 99 | return handle; |
| 100 | } |
| 101 | |
| 102 | /* |
| 103 | * Use the retrieve request from the receive buffer to retrieve a memory region |
| 104 | * which has been sent to us. Returns the sender, and the handle via a return |
| 105 | * parameter. |
| 106 | */ |
| 107 | ffa_vm_id_t retrieve_memory_from_message(void *recv_buf, void *send_buf, |
| 108 | struct ffa_value msg_ret, |
| 109 | ffa_memory_handle_t *handle) |
| 110 | { |
| 111 | uint32_t msg_size; |
| 112 | struct ffa_value ret; |
| 113 | struct ffa_memory_region *memory_region; |
| 114 | ffa_vm_id_t sender; |
| 115 | |
| 116 | EXPECT_EQ(msg_ret.func, FFA_MSG_SEND_32); |
| 117 | msg_size = ffa_msg_send_size(msg_ret); |
| 118 | sender = ffa_msg_send_sender(msg_ret); |
| 119 | |
| 120 | if (handle != NULL) { |
| 121 | struct ffa_memory_region *retrieve_request = |
| 122 | (struct ffa_memory_region *)recv_buf; |
| 123 | *handle = retrieve_request->handle; |
| 124 | } |
| 125 | memcpy_s(send_buf, HF_MAILBOX_SIZE, recv_buf, msg_size); |
| 126 | ffa_rx_release(); |
| 127 | ret = ffa_mem_retrieve_req(msg_size, msg_size); |
| 128 | EXPECT_EQ(ret.func, FFA_MEM_RETRIEVE_RESP_32); |
| 129 | memory_region = (struct ffa_memory_region *)recv_buf; |
| 130 | EXPECT_EQ(memory_region->receiver_count, 1); |
| 131 | EXPECT_EQ(memory_region->receivers[0].receiver_permissions.receiver, |
| 132 | hf_vm_get_id()); |
| 133 | |
| 134 | return sender; |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | * Use the retrieve request from the receive buffer to retrieve a memory region |
| 139 | * which has been sent to us, expecting it to fail with the given error code. |
| 140 | * Returns the sender. |
| 141 | */ |
| 142 | ffa_vm_id_t retrieve_memory_from_message_expect_fail(void *recv_buf, |
| 143 | void *send_buf, |
| 144 | struct ffa_value msg_ret, |
| 145 | int32_t expected_error) |
| 146 | { |
| 147 | uint32_t msg_size; |
| 148 | struct ffa_value ret; |
| 149 | ffa_vm_id_t sender; |
| 150 | |
| 151 | EXPECT_EQ(msg_ret.func, FFA_MSG_SEND_32); |
| 152 | msg_size = ffa_msg_send_size(msg_ret); |
| 153 | sender = ffa_msg_send_sender(msg_ret); |
| 154 | |
| 155 | memcpy_s(send_buf, HF_MAILBOX_SIZE, recv_buf, msg_size); |
| 156 | ffa_rx_release(); |
| 157 | ret = ffa_mem_retrieve_req(msg_size, msg_size); |
| 158 | EXPECT_FFA_ERROR(ret, expected_error); |
| 159 | |
| 160 | return sender; |
| 161 | } |