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