PatchworkOS
Loading...
Searching...
No Matches
shmem.c
Go to the documentation of this file.
1#include <kernel/ipc/shmem.h>
2
3#include <kernel/fs/ctl.h>
4#include <kernel/fs/sysfs.h>
5#include <kernel/fs/vfs.h>
6#include <kernel/log/panic.h>
7#include <kernel/mem/pmm.h>
8#include <kernel/mem/vmm.h>
10
11#include <errno.h>
12#include <stdatomic.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/list.h>
17
20
22{
23 if (shmem == NULL)
24 {
25 return;
26 }
27
28 if (shmem->pageAmount > 0)
29 {
30 assert(shmem->pages != NULL);
31 for (uint64_t i = 0; i < shmem->pageAmount; i++)
32 {
33 pmm_free(shmem->pages[i]);
34 }
35 shmem->pageAmount = 0;
36 shmem->pages = NULL;
37 }
38 free(shmem);
39}
40
42{
43 shmem_object_t* shmem = malloc(sizeof(shmem_object_t));
44 if (shmem == NULL)
45 {
46 return NULL;
47 }
49 shmem->pageAmount = 0;
50 shmem->pages = NULL;
51 lock_init(&shmem->lock);
52
53 return shmem;
54}
55
56static void shmem_vmm_callback(void* private)
57{
58 shmem_object_t* shmem = private;
59 if (shmem == NULL)
60 {
61 return;
62 }
63
64 DEREF(shmem);
65}
66
68 pml_flags_t flags)
69{
70 shmem->pages = malloc(sizeof(void*) * pageAmount);
71 if (shmem->pages == NULL)
72 {
73 return NULL;
74 }
75 shmem->pageAmount = pageAmount;
76
77 for (uint64_t i = 0; i < pageAmount; i++)
78 {
79 shmem->pages[i] = pmm_alloc();
80 if (shmem->pages[i] == NULL)
81 {
82 for (uint64_t j = 0; j < i; j++)
83 {
84 pmm_free(shmem->pages[j]);
85 }
86
87 free(shmem->pages);
88 shmem->pages = NULL;
89 shmem->pageAmount = 0;
90 return NULL;
91 }
92 }
93
94 void* virtAddr =
95 vmm_map_pages(space, address, shmem->pages, shmem->pageAmount, flags, shmem_vmm_callback, REF(shmem));
96 if (virtAddr == NULL)
97 {
98 for (uint64_t i = 0; i < shmem->pageAmount; i++)
99 {
100 pmm_free(shmem->pages[i]);
101 }
102
103 free(shmem->pages);
104 shmem->pages = NULL;
105 shmem->pageAmount = 0;
106 return NULL;
107 }
108
109 return virtAddr;
110}
111
113{
115 if (shmem == NULL)
116 {
117 return ERR;
118 }
119
120 file->private = shmem;
121 return 0;
122}
123
125{
126 shmem_object_t* shmem = file->private;
127 if (shmem == NULL)
128 {
129 return;
130 }
131
132 DEREF(shmem);
133}
134
135static void* shmem_mmap(file_t* file, void* address, uint64_t length, uint64_t* offset, pml_flags_t flags)
136{
137 shmem_object_t* shmem = file->private;
138 if (shmem == NULL)
139 {
140 errno = EINVAL;
141 return NULL;
142 }
143
144 LOCK_SCOPE(&shmem->lock);
145
146 process_t* process = sched_process_unsafe();
147 space_t* space = &process->space;
148
150 if (pageAmount == 0)
151 {
152 errno = EINVAL;
153 return NULL;
154 }
155
156 if (shmem->pageAmount == 0) // First call to mmap()
157 {
158 if (*offset != 0)
159 {
160 errno = EINVAL;
161 return NULL;
162 }
163
164 assert(shmem->pages == NULL);
165 return shmem_object_allocate_pages(shmem, pageAmount, space, address, flags);
166 }
167 else
168 {
169 assert(shmem->pages != NULL);
170
171 if (*offset >= shmem->pageAmount * PAGE_SIZE)
172 {
173 errno = EINVAL;
174 return NULL;
175 }
176
177 if (*offset % PAGE_SIZE != 0)
178 {
179 errno = EINVAL;
180 return NULL;
181 }
182
183 uint64_t pageOffset = *offset / PAGE_SIZE;
184 uint64_t availablePages = shmem->pageAmount - pageOffset;
185 return vmm_map_pages(space, address, &shmem->pages[pageOffset], MIN(pageAmount, availablePages), flags,
186 shmem_vmm_callback, REF(shmem));
187 }
188}
189
191 .open = shmem_open,
192 .close = shmem_close,
193 .mmap = shmem_mmap,
194};
195
196void shmem_init(void)
197{
198 shmemDir = sysfs_dir_new(NULL, "shmem", NULL, NULL);
199 if (shmemDir == NULL)
200 {
201 panic(NULL, "Failed to create /dev/shmem directory");
202 }
203
205 if (newFile == NULL)
206 {
208 panic(NULL, "Failed to create /dev/shmem/new file");
209 }
210}
#define assert(expression)
Definition assert.h:29
void shmem_init(void)
Initializes the shared memory subsystem.
Definition shmem.c:196
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
void pmm_free(void *address)
Frees a single physical page.
Definition pmm.c:211
void * pmm_alloc(void)
Allocates a single physical page.
Definition pmm.c:162
void * vmm_map_pages(space_t *space, void *virtAddr, void **pages, uint64_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:285
process_t * sched_process_unsafe(void)
Retrieves the process of the currently running thread without disabling interrupts.
Definition sched.c:180
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:80
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void ref_init(ref_t *ref, void *free)
Initialize a reference counter.
Definition ref.h:92
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#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
Memory page size.
Definition proc.h:140
#define BYTES_TO_PAGES(amount)
Convert bytes to pages.
Definition proc.h:151
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uintptr_t address
Definition hpet.c:12
static dentry_t * file
Definition log_file.c:17
static uint64_t pageAmount
Definition pmm.c:42
static dentry_t * shmemDir
Definition shmem.c:18
static void shmem_object_free(shmem_object_t *shmem)
Definition shmem.c:21
static shmem_object_t * shmem_object_new(void)
Definition shmem.c:41
static void shmem_close(file_t *file)
Definition shmem.c:124
static uint64_t shmem_open(file_t *file)
Definition shmem.c:112
static dentry_t * newFile
Definition shmem.c:19
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:67
static file_ops_t fileOps
Definition shmem.c:190
static void * shmem_mmap(file_t *file, void *address, uint64_t length, uint64_t *offset, pml_flags_t flags)
Definition shmem.c:135
static void shmem_vmm_callback(void *private)
Definition shmem.c:56
__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:83
void * private
Definition dentry.h:94
File operations structure.
Definition file.h:57
uint64_t(* open)(file_t *file)
Definition file.h:58
File structure.
Definition file.h:37
A entry in a page table without a specified address or callback ID.
Process structure.
Definition process.h:53
space_t space
Definition process.h:59
Represents a shared memory object.
Definition shmem.h:36
void ** pages
Definition shmem.h:39
uint64_t pageAmount
Definition shmem.h:38
lock_t lock
Definition shmem.h:40
ref_t ref
Definition shmem.h:37
Virtual address space structure.
Definition space.h:79
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted SysFS instance.
Definition sysfs.c:174
dentry_t * sysfs_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 SysFS instance.
Definition sysfs.c:216