1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under MIT License.
6 // Full license text is available in 'licenses/MIT.txt' file.
7 //
8
9 #include <callbacks.h>
10 #include "renode_imports.h"
11 #include "../tlib/include/unwind.h"
12
13 EXTERNAL(void, touch_host_block, uint64_t)
14
15 typedef struct {
16 uint64_t start;
17 uint64_t size;
18 void *host_pointer;
19 } __attribute__((packed)) host_memory_block_packed_t;
20
21 typedef struct {
22 uint64_t start;
23 uint64_t size;
24 void *host_pointer;
25 } host_memory_block_t;
26
27
28 typedef struct list_node_t {
29 host_memory_block_t* element;
30
31 struct list_node_t* prev;
32 struct list_node_t* next;
33 } list_node_t;
34
35 typedef struct {
36 list_node_t* guest_to_host_head;
37 list_node_t* host_to_guest_head;
38
39 uint32_t size;
40
41 host_memory_block_t *elements;
42
43 list_node_t *guest_to_host_nodes;
44 list_node_t *host_to_guest_nodes;
45 } host_memory_block_lists_t;
46
47 static host_memory_block_lists_t *lists;
48
move_to_head(list_node_t ** head,list_node_t * node)49 static void move_to_head(list_node_t** head, list_node_t* node)
50 {
51 if(*head == node)
52 {
53 // it's already at the top
54 return;
55 }
56
57 if(node->prev != NULL)
58 {
59 node->prev->next = node->next;
60 }
61
62 if(node->next != NULL)
63 {
64 node->next->prev = node->prev;
65 }
66
67 (*head)->prev = node;
68 node->prev = NULL;
69 node->next = *head;
70 *head = node;
71 }
72
tlib_guest_offset_to_host_ptr(uint64_t offset)73 void *tlib_guest_offset_to_host_ptr(uint64_t offset)
74 {
75 host_memory_block_lists_t *host_blocks_list_cached;
76 list_node_t *current_block;
77 try_find_block:
78 host_blocks_list_cached = lists;
79
80 if(host_blocks_list_cached != NULL)
81 {
82 current_block = host_blocks_list_cached->guest_to_host_head;
83 while(current_block != NULL)
84 {
85 if(offset >= current_block->element->start && offset <= (current_block->element->start + current_block->element->size - 1)) {
86 move_to_head(&host_blocks_list_cached->guest_to_host_head, current_block);
87 return current_block->element->host_pointer + (offset - current_block->element->start);
88 }
89
90 current_block = current_block->next;
91 }
92 }
93
94 touch_host_block(offset);
95 goto try_find_block;
96 }
97
tlib_host_ptr_to_guest_offset(void * ptr)98 uint64_t tlib_host_ptr_to_guest_offset(void *ptr)
99 {
100 host_memory_block_lists_t *host_blocks_list_cached;
101 list_node_t *current_block;
102
103 host_blocks_list_cached = lists;
104
105 if(host_blocks_list_cached != NULL)
106 {
107 current_block = host_blocks_list_cached->host_to_guest_head;
108 while(current_block != NULL)
109 {
110 if(ptr >= current_block->element->host_pointer && ptr <= (current_block->element->host_pointer + current_block->element->size - 1)) {
111 move_to_head(&host_blocks_list_cached->host_to_guest_head, current_block);
112 return current_block->element->start + (ptr - current_block->element->host_pointer);
113 }
114
115 current_block = current_block->next;
116 }
117 }
118
119 tlib_abort("Trying to translate pointer that was not alocated by us.");
120 return 0;
121 }
122
free_list(host_memory_block_lists_t ** lists)123 static void free_list(host_memory_block_lists_t **lists)
124 {
125 if(*lists == NULL)
126 {
127 return;
128 }
129
130 tlib_free((*lists)->elements);
131 tlib_free((*lists)->guest_to_host_nodes);
132 tlib_free((*lists)->host_to_guest_nodes);
133 tlib_free(*lists);
134
135 *lists = NULL;
136 }
137
renode_set_host_blocks(host_memory_block_packed_t * blocks,int count)138 void renode_set_host_blocks(host_memory_block_packed_t *blocks, int count)
139 {
140 int i;
141 host_memory_block_lists_t *old_mappings;
142 host_memory_block_lists_t *new_mappings;
143
144 old_mappings = lists;
145
146 new_mappings = tlib_malloc(sizeof(host_memory_block_lists_t));
147 new_mappings->size = count;
148 new_mappings->elements = tlib_malloc(sizeof(host_memory_block_t) * count);
149
150 new_mappings->guest_to_host_nodes = tlib_malloc(sizeof(list_node_t) * count);
151 new_mappings->guest_to_host_head = &new_mappings->guest_to_host_nodes[0];
152 new_mappings->host_to_guest_nodes = tlib_malloc(sizeof(list_node_t) * count);
153 new_mappings->host_to_guest_head = &new_mappings->host_to_guest_nodes[0];
154
155 for(i = 0; i < count; i++) {
156 new_mappings->elements[i].start = blocks[i].start;
157 new_mappings->elements[i].size = blocks[i].size;
158 new_mappings->elements[i].host_pointer = blocks[i].host_pointer;
159
160 new_mappings->guest_to_host_nodes[i].element = &new_mappings->elements[i];
161 new_mappings->host_to_guest_nodes[i].element = &new_mappings->elements[i];
162
163 if(i == 0)
164 {
165 new_mappings->guest_to_host_nodes[i].prev = NULL;
166 new_mappings->host_to_guest_nodes[i].prev = NULL;
167 }
168 else
169 {
170 new_mappings->guest_to_host_nodes[i].prev = &new_mappings->guest_to_host_nodes[i - 1];
171 new_mappings->host_to_guest_nodes[i].prev = &new_mappings->host_to_guest_nodes[i - 1];
172 }
173
174 if(i == count - 1)
175 {
176 new_mappings->guest_to_host_nodes[i].next = NULL;
177 new_mappings->host_to_guest_nodes[i].next = NULL;
178 }
179 else
180 {
181 new_mappings->guest_to_host_nodes[i].next = &new_mappings->guest_to_host_nodes[i + 1];
182 new_mappings->host_to_guest_nodes[i].next = &new_mappings->host_to_guest_nodes[i + 1];
183 }
184 }
185
186 lists = new_mappings;
187 free_list(&old_mappings);
188 }
189
EXC_VOID_2(renode_set_host_blocks,host_memory_block_packed_t *,blocks,int,count)190 EXC_VOID_2(renode_set_host_blocks, host_memory_block_packed_t *, blocks, int, count)
191
192 void renode_free_host_blocks()
193 {
194 free_list(&lists);
195 }
196
197 EXC_VOID_0(renode_free_host_blocks)
198