1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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  *      http://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 #define TLOG_TAG "vmm_obj_ipc"
18 
19 #include <inttypes.h>
20 #include <lib/tipc/tipc.h>
21 #include <lib/vmm_obj/vmm_obj.h>
22 #include <lk/macros.h>
23 #include <sys/auxv.h>
24 #include <sys/mman.h>
25 #include <trusty_log.h>
26 #include <uapi/err.h>
27 #include <uapi/mm.h>
28 
29 #define PAGE_SIZE getauxval(AT_PAGESZ)
30 
vmm_obj_map_ro(const char * port,const void ** base_out,size_t * size_out)31 int vmm_obj_map_ro(const char* port, const void** base_out, size_t* size_out) {
32     int rc;
33     handle_t chan;
34     handle_t memref = INVALID_IPC_HANDLE;
35     ipc_msg_info_t msg_inf;
36     uevent_t evt;
37     uint64_t size64;
38     size_t size;
39     void* base;
40 
41     if (!base_out) {
42         TLOGE("Unexpected NULL base pointer\n");
43         rc = ERR_INVALID_ARGS;
44         goto err_null_base_out;
45     }
46     if (!size_out) {
47         TLOGE("Unexpected NULL size pointer\n");
48         rc = ERR_INVALID_ARGS;
49         goto err_null_size_out;
50     }
51 
52     rc = tipc_connect(&chan, port);
53     if (rc < 0) {
54         goto err_connect;
55     }
56 
57     do {
58         rc = wait(chan, &evt, INFINITE_TIME);
59         if (rc != NO_ERROR) {
60             TLOGE("Failed to wait for reply (%d)\n", rc);
61             goto err_wait;
62         }
63         if (evt.event & IPC_HANDLE_POLL_HUP) {
64             TLOGE("Service closed connection\n");
65             rc = ERR_CHANNEL_CLOSED;
66             goto err_wait;
67         }
68     } while (!(evt.event & IPC_HANDLE_POLL_MSG));
69 
70     rc = get_msg(chan, &msg_inf);
71     if (rc) {
72         TLOGE("Failed to get message (%d)\n", rc);
73         goto err_get;
74     }
75 
76     if (msg_inf.len != sizeof(size64)) {
77         TLOGE("Received message of invalid size (%zd)\n", msg_inf.len);
78         rc = ERR_BAD_LEN;
79         goto err_msg_len;
80     }
81 
82     struct iovec iov = {
83             .iov_base = &size64,
84             .iov_len = sizeof(size64),
85     };
86     ipc_msg_t msg = {
87             .iov = &iov,
88             .num_iov = 1,
89             .handles = &memref,
90             .num_handles = 1,
91     };
92     rc = read_msg(chan, msg_inf.id, 0, &msg);
93     if (rc != (int)sizeof(size64)) {
94         TLOGE("Failed to read message (%d)\n", rc);
95         if (rc >= 0) {
96             rc = ERR_BAD_LEN;
97         }
98         goto err_read;
99     }
100 
101     if (memref == INVALID_IPC_HANDLE) {
102         TLOGE("Received invalid memref handle\n");
103         rc = ERR_BAD_HANDLE;
104         goto err_invalid_memref;
105     }
106 
107     size = (size_t)size64;
108     if (size64 != (uint64_t)size) {
109         TLOGE("Size too big for size_t (%" PRIu64 ")\n", size64);
110         rc = ERR_TOO_BIG;
111         goto err_size_too_big;
112     }
113 
114     size_t aligned_size = round_up(size, PAGE_SIZE);
115     base = mmap(0, aligned_size, MMAP_FLAG_PROT_READ, 0, memref, 0);
116     if (base == MAP_FAILED) {
117         TLOGE("Failed to map device tree blob\n");
118         rc = ERR_BAD_HANDLE;
119         goto err_mmap;
120     }
121 
122     *base_out = base;
123     *size_out = size;
124     rc = NO_ERROR;
125 
126 err_mmap:
127 err_size_too_big:
128 err_invalid_memref:
129 err_read:
130     close(memref);
131 err_msg_len:
132     put_msg(chan, msg_inf.id);
133 err_get:
134 err_wait:
135     close(chan);
136 err_connect:
137 err_null_size_out:
138 err_null_base_out:
139     return rc;
140 }
141