PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
mdl.c
Go to the documentation of this file.
1#include <kernel/mem/mdl.h>
3#include <kernel/mem/space.h>
5
6#include <errno.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/proc.h>
10
11void mdl_deinit(mdl_t* mdl)
12{
13 if (mdl == NULL)
14 {
15 return;
16 }
17
18 mdl->next = NULL;
19
20 for (size_t i = 0; i < mdl->amount; i++)
21 {
23 }
24 mdl->amount = 0;
25
26 if (mdl->segments != mdl->small)
27 {
28 free(mdl->segments);
29 }
30 mdl->segments = NULL;
31 mdl->capacity = 0;
32}
33
34void mdl_free_chain(mdl_t* mdl, void (*free)(void*))
35{
36 while (mdl != NULL)
37 {
38 mdl_t* next = mdl->next;
39 mdl_deinit(mdl);
40 if (free != NULL)
41 {
42 free(mdl);
43 }
44 mdl = next;
45 }
46}
47
48uint64_t mdl_from_region(mdl_t* mdl, mdl_t* prev, space_t* space, const void* addr, size_t size)
49{
50 if (mdl == NULL)
51 {
52 errno = EINVAL;
53 return ERR;
54 }
55 mdl_init(mdl, prev);
56
57 if (mdl_add(mdl, space, addr, size) == ERR)
58 {
59 mdl_deinit(mdl);
60 return ERR;
61 }
62
63 return 0;
64}
65
66static uint64_t mdl_push(mdl_t* mdl, phys_addr_t phys, size_t size)
67{
68 if (size > UINT32_MAX)
69 {
71 return ERR;
72 }
73
74 if (mdl == NULL)
75 {
76 errno = EINVAL;
77 return ERR;
78 }
79
80 if (mdl->amount == mdl->capacity)
81 {
82 uint32_t newCapacity = mdl->capacity + 4;
83 mdl_seg_t* newSegments;
84
85 if (mdl->segments == mdl->small)
86 {
87 newSegments = malloc(newCapacity * sizeof(mdl_seg_t));
88 if (newSegments != NULL)
89 {
90 memcpy(newSegments, mdl->small, sizeof(mdl->small));
91 }
92 }
93 else
94 {
95 newSegments = realloc(mdl->segments, newCapacity * sizeof(mdl_seg_t));
96 }
97
98 if (newSegments == NULL)
99 {
100 errno = ENOMEM;
101 return ERR;
102 }
103
104 mdl->segments = newSegments;
105 mdl->capacity = newCapacity;
106 }
107
108 mdl_seg_t* seg = &mdl->segments[mdl->amount];
109 pfn_t pfn = PHYS_TO_PFN(phys);
110 uint32_t offset = phys % PAGE_SIZE;
111 if (pmm_ref_inc(pfn, BYTES_TO_PAGES(offset + size)) == ERR)
112 {
113 errno = EFAULT;
114 return ERR;
115 }
116
117 seg->pfn = pfn;
118 seg->size = size;
119 seg->offset = offset;
120
121 mdl->amount++;
122 return 0;
123}
124
125uint64_t mdl_add(mdl_t* mdl, space_t* space, const void* addr, size_t size)
126{
127 const uint8_t* ptr = addr;
128 size_t remaining = size;
129
130 while (remaining > 0)
131 {
132 phys_addr_t phys = space_virt_to_phys(space, ptr);
133 if (phys == ERR)
134 {
135 return ERR;
136 }
137
138 size_t offset = phys % PAGE_SIZE;
139 size_t len = MIN(remaining, PAGE_SIZE - offset);
140
141 if (mdl_push(mdl, phys, len) == ERR)
142 {
143 return ERR;
144 }
145
146 ptr += len;
147 remaining -= len;
148 }
149
150 return 0;
151}
152
153uint64_t mdl_read(mdl_t* mdl, void* buffer, size_t count, size_t offset)
154{
155 if (mdl == NULL || buffer == NULL)
156 {
157 return 0;
158 }
159
160 size_t start = 0;
161 size_t i = 0;
162 for (; i < mdl->amount; i++)
163 {
164 mdl_seg_t* seg = &mdl->segments[i];
165 if (start + seg->size > offset)
166 {
167 break;
168 }
169 start += seg->size;
170 }
171
172 uint8_t* ptr = buffer;
173 size_t remaining = count;
174
175 size_t segOffset = offset - start;
176 while (remaining > 0 && i < mdl->amount)
177 {
178 mdl_seg_t* seg = &mdl->segments[i];
179 size_t toRead = MIN(remaining, seg->size - segOffset);
180 void* addr = PFN_TO_VIRT(seg->pfn) + seg->offset + segOffset;
181 memcpy(ptr, addr, toRead);
182
183 ptr += toRead;
184 remaining -= toRead;
185 segOffset = 0;
186 i++;
187 }
188
189 return count - remaining;
190}
191
192uint64_t mdl_write(mdl_t* mdl, const void* buffer, size_t count, size_t offset)
193{
194 if (mdl == NULL || buffer == NULL)
195 {
196 return 0;
197 }
198
199 size_t start = 0;
200 size_t i = 0;
201 for (; i < mdl->amount; i++)
202 {
203 mdl_seg_t* seg = &mdl->segments[i];
204 if (start + seg->size > offset)
205 {
206 break;
207 }
208 start += seg->size;
209 }
210
211 const uint8_t* ptr = buffer;
212 size_t remaining = count;
213
214 size_t segOffset = offset - start;
215 while (remaining > 0 && i < mdl->amount)
216 {
217 mdl_seg_t* seg = &mdl->segments[i];
218 size_t toWrite = MIN(remaining, seg->size - segOffset);
219 void* addr = PFN_TO_VIRT(seg->pfn) + seg->offset + segOffset;
220 memcpy(addr, ptr, toWrite);
221
222 ptr += toWrite;
223 remaining -= toWrite;
224 segOffset = 0;
225 i++;
226 }
227
228 return count - remaining;
229}
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static void start()
Definition main.c:542
uint64_t mdl_write(mdl_t *mdl, const void *buffer, size_t count, size_t offset)
Write to a Memory Descriptor List from a buffer.
Definition mdl.c:192
void mdl_free_chain(mdl_t *mdl, void(*free)(void *))
Free a Memory Descriptor List chain.
Definition mdl.c:34
void mdl_deinit(mdl_t *mdl)
Deinitialize a Memory Descriptor List.
Definition mdl.c:11
uint64_t mdl_from_region(mdl_t *mdl, mdl_t *prev, space_t *space, const void *addr, size_t size)
Initialize a Memory Descriptor List from a memory region.
Definition mdl.c:48
static void mdl_init(mdl_t *next, mdl_t *prev)
Initialize a Memory Descriptor List.
Definition mdl.h:69
uint64_t mdl_add(mdl_t *mdl, space_t *space, const void *addr, size_t size)
Add a memory region to the Memory Descriptor List.
Definition mdl.c:125
uint64_t mdl_read(mdl_t *mdl, void *buffer, size_t count, size_t offset)
Read from a Memory Descriptor List into a buffer.
Definition mdl.c:153
uintptr_t phys_addr_t
Physical address type.
#define PHYS_TO_PFN(_addr)
Convert a physical address to its PFN.
#define PFN_TO_VIRT(_pfn)
Convert a PFN to its identity mapped higher half virtual address.
size_t pfn_t
Page Frame Number type.
static void pmm_ref_dec(pfn_t pfn, size_t count)
Decrement the reference count of a physical region.
Definition pmm.h:149
uint64_t pmm_ref_inc(pfn_t pfn, size_t count)
Increment the reference count of a physical region.
Definition pmm.c:365
phys_addr_t space_virt_to_phys(space_t *space, const void *virtAddr)
Translate a virtual address to a physical address in the address space.
Definition space.c:670
#define EINVAL
Invalid argument.
Definition errno.h:142
#define EFAULT
Bad address.
Definition errno.h:102
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EOVERFLOW
Value too large for defined data type.
Definition errno.h:402
#define errno
Error number variable.
Definition errno.h:27
#define MIN(x, y)
Definition math.h:18
#define BYTES_TO_PAGES(amount)
Convert a size in bytes to pages.
Definition proc.h:107
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define PAGE_SIZE
The size of a memory page in bytes.
Definition PAGE_SIZE.h:8
static uint64_t offset
Definition screen.c:19
static uint64_t mdl_push(mdl_t *mdl, phys_addr_t phys, size_t size)
Definition mdl.c:66
static atomic_long next
Definition main.c:12
static atomic_long count
Definition main.c:11
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
#define UINT32_MAX
Definition stdint.h:70
_PUBLIC void * realloc(void *ptr, size_t size)
Definition realloc.c:13
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
Memory Descriptor List Segment structure.
Definition mdl.h:44
uint32_t offset
Offset in bytes within the first page.
Definition mdl.h:47
pfn_t pfn
Page frame number.
Definition mdl.h:45
uint32_t size
Size of the segment in bytes.
Definition mdl.h:46
Memory Descriptor List structure.
Definition mdl.h:55
uint32_t amount
Number of memory segments.
Definition mdl.h:59
struct mdl * next
Pointer to the next MDL.
Definition mdl.h:56
mdl_seg_t * segments
Pointer to segments array.
Definition mdl.h:58
uint32_t capacity
Capacity of the large array.
Definition mdl.h:60
mdl_seg_t small[MDL_SEGS_SMALL_MAX]
Statically allocated segments for small regions.
Definition mdl.h:57
Virtual address space structure.
Definition space.h:78