PatchworkOS  3984a1d
A non-POSIX operating system.
Loading...
Searching...
No Matches
shmem.c
Go to the documentation of this file.
1#include <kernel/fs/ctl.h>
2#include <kernel/fs/devfs.h>
3#include <kernel/fs/vfs.h>
4#include <kernel/log/log.h>
5#include <kernel/log/panic.h>
6#include <kernel/mem/pmm.h>
7#include <kernel/mem/vmm.h>
10#include <kernel/sched/sched.h>
11#include <kernel/sync/lock.h>
12#include <kernel/utils/ref.h>
13
14#include <errno.h>
15#include <stdlib.h>
16
17#include <sys/list.h>
18/**
19 * @brief Shared Memory
20 * @defgroup modules_ipc_shmem Shared Memory
21 * @ingroup modules_ipc
22 *
23 * Shared memory is exposed in the `/dev/shmem` directory. Shared memory allows multiple processes to share a section of
24 * memory for inter-process communication (IPC).
25 *
26 * ## Creating Shared Memory
27 *
28 * Shared memory objects are created using the `/dev/shmem/new` file. Opening this file using `open()` will create a new
29 * anonymous shared memory object and return a file descriptor to it.
30 *
31 * ## Using Shared Memory
32 *
33 * Shared memory objects can be mapped to the current process's address space using the `mmap()` system call. The first
34 * call to `mmap()` will decide the size of the shared memory object. Subsequent calls to `mmap()` will map the existing
35 * shared memory object.
36 *
37 * @{
38 */
39
40/**
41 * @brief Represents a shared memory object.
42 */
50
53
55{
56 if (shmem == NULL)
57 {
58 return;
59 }
60
61 if (shmem->pageAmount > 0)
62 {
63 assert(shmem->pages != NULL);
64 for (uint64_t i = 0; i < shmem->pageAmount; i++)
65 {
66 pmm_free(shmem->pages[i]);
67 }
68 shmem->pageAmount = 0;
69 shmem->pages = NULL;
70 }
71 free(shmem);
72}
73
75{
76 shmem_object_t* shmem = malloc(sizeof(shmem_object_t));
77 if (shmem == NULL)
78 {
79 return NULL;
80 }
82 shmem->pageAmount = 0;
83 shmem->pages = NULL;
84 lock_init(&shmem->lock);
85
86 return shmem;
87}
88
89static void shmem_vmm_callback(void* private)
90{
91 shmem_object_t* shmem = private;
92 if (shmem == NULL)
93 {
94 return;
95 }
96
97 UNREF(shmem);
98}
99
102{
103 shmem->pages = malloc(sizeof(void*) * pageAmount);
104 if (shmem->pages == NULL)
105 {
106 return NULL;
107 }
108 shmem->pageAmount = pageAmount;
109
110 for (uint64_t i = 0; i < pageAmount; i++)
111 {
112 shmem->pages[i] = pmm_alloc();
113 if (shmem->pages[i] == NULL)
114 {
115 for (uint64_t j = 0; j < i; j++)
116 {
117 pmm_free(shmem->pages[j]);
118 }
119
120 free(shmem->pages);
121 shmem->pages = NULL;
122 shmem->pageAmount = 0;
123 return NULL;
124 }
125 }
126
127 void* virtAddr =
128 vmm_map_pages(space, address, shmem->pages, shmem->pageAmount, flags, shmem_vmm_callback, REF(shmem));
129 if (virtAddr == NULL)
130 {
131 for (uint64_t i = 0; i < shmem->pageAmount; i++)
132 {
133 pmm_free(shmem->pages[i]);
134 }
135
136 free(shmem->pages);
137 shmem->pages = NULL;
138 shmem->pageAmount = 0;
139 return NULL;
140 }
141
142 return virtAddr;
143}
144
146{
148 if (shmem == NULL)
149 {
150 return ERR;
151 }
152
153 file->private = shmem;
154 return 0;
155}
156
157static void shmem_close(file_t* file)
158{
159 shmem_object_t* shmem = file->private;
160 if (shmem == NULL)
161 {
162 return;
163 }
164
165 UNREF(shmem);
166}
167
168static void* shmem_mmap(file_t* file, void* address, size_t length, size_t* offset, pml_flags_t flags)
169{
170 shmem_object_t* shmem = file->private;
171 if (shmem == NULL)
172 {
173 errno = EINVAL;
174 return NULL;
175 }
176
177 LOCK_SCOPE(&shmem->lock);
178
179 process_t* process = sched_process_unsafe();
180 space_t* space = &process->space;
181
183 if (pageAmount == 0)
184 {
185 errno = EINVAL;
186 return NULL;
187 }
188
189 if (shmem->pageAmount == 0) // First call to mmap()
190 {
191 if (*offset != 0)
192 {
193 errno = EINVAL;
194 return NULL;
195 }
196
197 assert(shmem->pages == NULL);
198 return shmem_object_allocate_pages(shmem, pageAmount, space, address, flags);
199 }
200 else
201 {
202 assert(shmem->pages != NULL);
203
204 if (*offset >= shmem->pageAmount * PAGE_SIZE)
205 {
206 errno = EINVAL;
207 return NULL;
208 }
209
210 if (*offset % PAGE_SIZE != 0)
211 {
212 errno = EINVAL;
213 return NULL;
214 }
215
219 shmem_vmm_callback, REF(shmem));
220 }
221}
222
224 .open = shmem_open,
225 .close = shmem_close,
226 .mmap = shmem_mmap,
227};
228
230{
231 shmemDir = devfs_dir_new(NULL, "shmem", NULL, NULL);
232 if (shmemDir == NULL)
233 {
234 LOG_ERR("failed to create /dev/shmem directory");
235 return ERR;
236 }
237
239 if (newFile == NULL)
240 {
242 LOG_ERR("failed to create /dev/shmem/new file");
243 return ERR;
244 }
245
246 return 0;
247}
248
249static void shmem_deinit(void)
250{
251 UNREF(newFile);
252 newFile = NULL;
254 shmemDir = NULL;
255}
256
257/** @} */
258
260{
261 switch (event->type)
262 {
264 if (shmem_init() == ERR)
265 {
266 return ERR;
267 }
268 break;
270 shmem_deinit();
271 break;
272 default:
273 break;
274 }
275
276 return 0;
277}
278
279MODULE_INFO("Shared Memory", "Kai Norberg", "Implements shared memory for inter-process communication", OS_VERSION,
280 "MIT", "BOOT_ALWAYS");
#define assert(expression)
Definition assert.h:29
int64_t y
Definition main.c:153
dentry_t * devfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted devfs instance.
Definition devfs.c:86
dentry_t * devfs_file_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, const file_ops_t *fileOps, void *private)
Create a new file inside a mounted devfs instance.
Definition devfs.c:125
#define LOG_ERR(format,...)
Definition log.h:93
void pmm_free(void *address)
Frees a single physical page.
Definition pmm.c:220
void * pmm_alloc(void)
Allocates a single physical page.
Definition pmm.c:171
void * vmm_map_pages(space_t *space, void *virtAddr, void **pages, size_t pageAmount, pml_flags_t flags, space_callback_func_t func, void *private)
Maps an array of physical pages to virtual memory in a given address space.
Definition vmm.c:280
#define MODULE_INFO(_name, _author, _description, _version, _licence, _deviceTypes)
Macro to define module information.
Definition module.h:200
@ MODULE_EVENT_LOAD
Definition module.h:239
@ MODULE_EVENT_UNLOAD
Definition module.h:245
process_t * sched_process_unsafe(void)
Retrieves the process of the currently running thread without disabling interrupts.
Definition sched.c:632
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:87
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
#define REF(ptr)
Increment reference count.
Definition ref.h:80
static void ref_init(ref_t *ref, void *callback)
Initialize a reference counter.
Definition ref.h:107
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:95
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define MIN(x, y)
Definition math.h:16
#define PAGE_SIZE
The size of a memory page in bytes.
Definition proc.h:103
#define BYTES_TO_PAGES(amount)
Convert a size in bytes to pages.
Definition proc.h:111
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uintptr_t address
Mapped virtual address of the HPET registers.
Definition hpet.c:95
static dentry_t * shmemDir
Definition shmem.c:51
static void shmem_deinit(void)
Definition shmem.c:249
static void shmem_object_free(shmem_object_t *shmem)
Definition shmem.c:54
static void * shmem_mmap(file_t *file, void *address, size_t length, size_t *offset, pml_flags_t flags)
Definition shmem.c:168
static shmem_object_t * shmem_object_new(void)
Definition shmem.c:74
static void shmem_close(file_t *file)
Definition shmem.c:157
static uint64_t shmem_open(file_t *file)
Definition shmem.c:145
static dentry_t * newFile
Definition shmem.c:52
static void * shmem_object_allocate_pages(shmem_object_t *shmem, uint64_t pageAmount, space_t *space, void *address, pml_flags_t flags)
Definition shmem.c:100
static file_ops_t fileOps
Definition shmem.c:223
static void shmem_vmm_callback(void *private)
Definition shmem.c:89
static uint64_t shmem_init(void)
Definition shmem.c:229
static uint64_t offset
Definition screen.c:19
static const path_flag_t flags[]
Definition path.c:46
static uint64_t pageAmount
Definition pmm.c:44
uint64_t _module_procedure(const module_event_t *event)
Definition shmem.c:259
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
Directory entry structure.
Definition dentry.h:153
File operations structure.
Definition file.h:54
uint64_t(* open)(file_t *file)
Definition file.h:55
File structure.
Definition file.h:39
void * private
Definition file.h:46
A simple ticket lock implementation.
Definition lock.h:44
module_event_type_t type
Definition module.h:268
A entry in a page table without a specified address or callback ID.
Process structure.
Definition process.h:72
space_t space
Definition process.h:80
Reference counting structure.
Definition ref.h:52
Represents a shared memory object.
Definition shmem.c:44
void ** pages
Definition shmem.c:47
uint64_t pageAmount
Definition shmem.c:46
lock_t lock
Definition shmem.c:48
ref_t ref
Definition shmem.c:45
Virtual address space structure.
Definition space.h:79