PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
mdl.h
Go to the documentation of this file.
1#pragma once
2
4#include <kernel/mem/pmm.h>
5#include <kernel/mem/pool.h>
6#include <kernel/mem/space.h>
7
8#include <errno.h>
9#include <stdlib.h>
10#include <sys/list.h>
11
12typedef struct process process_t;
13
14/**
15 * @brief Memory Descriptor List.
16 * @defgroup kernel_mem_mdl Memory Descriptor List
17 * @ingroup kernel_mem
18 *
19 * The Memory Descriptor List (MDL) is a structure used to describe non-contiguous physical memory, allowing it be
20 * accessed as a single contiguous block regardless of the loaded address space.
21 *
22 * ## I/O Operations
23 *
24 * The MDL structure is primarily used to describe memory regions for I/O operations. For example, if a process
25 * specifies a buffer to write to but that I/O operation is later completed while a different address space is loaded,
26 * the kernel would be unable to access the buffer directly.
27 *
28 * Instead, the kernel can create an MDL for the buffer, which describes the physical memory pages backing that buffer,
29 * allowing the I/O operation to be completed regardless of the currently loaded address space.
30 *
31 * @{
32 */
33
34/**
35 * @brief Amount of memory segments statically allocated for small MDLs.
36 */
37#define MDL_SEGS_SMALL_MAX 2
38
39/**
40 * @brief Memory Descriptor List Segment structure.
41 * @struct mdl_seg_t
42 */
43typedef struct mdl_seg
44{
45 pfn_t pfn; ///< Page frame number.
46 uint32_t size; ///< Size of the segment in bytes.
47 uint32_t offset; ///< Offset in bytes within the first page.
48} mdl_seg_t;
49
50/**
51 * @brief Memory Descriptor List structure.
52 * @struct mdl_t
53 */
54typedef struct mdl
55{
56 struct mdl* next; ///< Pointer to the next MDL.
57 mdl_seg_t small[MDL_SEGS_SMALL_MAX]; ///< Statically allocated segments for small regions.
58 mdl_seg_t* segments; ///< Pointer to segments array.
59 uint32_t amount; ///< Number of memory segments.
60 uint32_t capacity; ///< Capacity of the `large` array.
61} mdl_t;
62
63/**
64 * @brief Initialize a Memory Descriptor List.
65 *
66 * @param next Pointer to the MDL.
67 * @param prev Pointer to the previous MDL in the chain, or `NULL` if none.
68 */
69static inline void mdl_init(mdl_t* next, mdl_t* prev)
70{
71 if (prev != NULL)
72 {
73 prev->next = next;
74 }
75 next->next = NULL;
76 next->segments = next->small;
77 next->amount = 0;
78 next->capacity = MDL_SEGS_SMALL_MAX;
79}
80
81/**
82 * @brief Deinitialize a Memory Descriptor List.
83 *
84 * @param mdl Pointer to the MDL.
85 */
86void mdl_deinit(mdl_t* mdl);
87
88/**
89 * @brief Free a Memory Descriptor List chain.
90 *
91 * Will traverse the entire chain to deinitialize and free each MDL structure using the provided `free` function.
92 *
93 * @param mdl Pointer to the first MDL in the chain.
94 * @param free Function to free the MDL structure itself, or `NULL` to only deinitialize.
95 */
96void mdl_free_chain(mdl_t* mdl, void (*free)(void*));
97
98/**
99 * @brief Initialize a Memory Descriptor List from a memory region.
100 *
101 * @param mdl Pointer to the MDL.
102 * @param prev Pointer to the previous MDL in the chain, or `NULL` if none.
103 * @param space The address space of the region.
104 * @param addr The virtual address of the memory region.
105 * @param size The size of the memory region in bytes.
106 * @return On success, `0`. On failure, `ERR` and `errno` is set:
107 * - See `mdl_add()` for possible error codes.
108 */
109uint64_t mdl_from_region(mdl_t* mdl, mdl_t* prev, space_t* space, const void* addr, size_t size);
110
111/**
112 * @brief Add a memory region to the Memory Descriptor List.
113 *
114 * @param mdl Pointer to the MDL.
115 * @param space The address space of the user process.
116 * @param addr The virtual address of the memory region.
117 * @param size The size of the memory region in bytes.
118 * @return On success, `0`. On failure, `ERR` and `errno` is set to:
119 * - See `mdl_add()` for possible error codes.
120 */
121uint64_t mdl_add(mdl_t* mdl, space_t* space, const void* addr, size_t size);
122
123/**
124 * @brief Read from a Memory Descriptor List into a buffer.
125 *
126 * @param mdl The MDL to read from.
127 * @param buffer The buffer to read into.
128 * @param count Number of bytes to read.
129 * @param offset Offset within the MDL to start reading from.
130 * @return The number of bytes read.
131 */
132uint64_t mdl_read(mdl_t* mdl, void* buffer, size_t count, size_t offset);
133
134/**
135 * @brief Write to a Memory Descriptor List from a buffer.
136 *
137 * @param mdl The MDL to write to.
138 * @param buffer The buffer to write from.
139 * @param count Number of bytes to write.
140 * @param offset Offset within the MDL to start writing to.
141 * @return The number of bytes written.
142 */
143uint64_t mdl_write(mdl_t* mdl, const void* buffer, size_t count, size_t offset);
144
145/**
146 * @brief Memory Descriptor List Iterator structure.
147 * @struct mdl_iter_t
148 */
149typedef struct
150{
152 size_t segIndex;
153 size_t segOffset;
154} mdl_iter_t;
155
156/**
157 * @brief Create a Memory Descriptor List Iterator initializer.
158 *
159 * @param _mdl Pointer to the MDL to iterate over.
160 * @return MDL Iterator initializer.
161 */
162#define MDL_ITER_CREATE(_mdl) \
163 { \
164 .mdl = (_mdl), \
165 .segIndex = 0, \
166 .segOffset = 0, \
167 }
168
169/**
170 * @brief Get the next byte from a Memory Descriptor List Iterator.
171 *
172 * @param iter Pointer to the MDL Iterator.
173 * @param byte Pointer to store the retrieved byte.
174 * @return `true` if a byte was retrieved, `false` if the end of the MDL was reached.
175 */
176static inline bool mdl_iter_next(mdl_iter_t* iter, uint8_t* byte)
177{
178 if (iter->segIndex >= iter->mdl->amount)
179 {
180 return false;
181 }
182
183 mdl_seg_t* seg = &iter->mdl->segments[iter->segIndex];
184 uint8_t* addr = PFN_TO_VIRT(seg->pfn) + seg->offset + iter->segOffset;
185 *byte = *(addr);
186
187 iter->segOffset++;
188 if (iter->segOffset >= seg->size)
189 {
190 iter->segIndex++;
191 iter->segOffset = 0;
192 }
193
194 return true;
195}
196
197/**
198 * @brief Iterate over bytes within a Memory Descriptor List.
199 *
200 * @param _byte The iterator variable.
201 * @param _mdl Pointer to the MDL.
202 */
203#define MDL_FOR_EACH(_byte, _mdl) for (mdl_iter_t _iter = MDL_ITER_CREATE(_mdl); mdl_iter_next(&_iter, (_byte));)
204
205/** @} */
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
#define MDL_SEGS_SMALL_MAX
Amount of memory segments statically allocated for small MDLs.
Definition mdl.h:37
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
static bool mdl_iter_next(mdl_iter_t *iter, uint8_t *byte)
Get the next byte from a Memory Descriptor List Iterator.
Definition mdl.h:176
#define PFN_TO_VIRT(_pfn)
Convert a PFN to its identity mapped higher half virtual address.
size_t pfn_t
Page Frame Number type.
#define NULL
Pointer error value.
Definition NULL.h:25
static uint64_t offset
Definition screen.c:19
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
_PUBLIC void free(void *ptr)
Definition free.c:11
Memory Descriptor List Iterator structure.
Definition mdl.h:150
size_t segOffset
Definition mdl.h:153
mdl_t * mdl
Definition mdl.h:151
size_t segIndex
Definition mdl.h:152
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
Process structure.
Definition process.h:76
Virtual address space structure.
Definition space.h:78