First rough implementation of shared memory.

This commit is contained in:
Enrico Fraccaroli (Galfurian)
2023-08-16 11:49:52 -04:00
parent 07d603f47a
commit dde6e6bc9e
7 changed files with 225 additions and 59 deletions
+144 -6
View File
@@ -16,8 +16,10 @@
#include "sys/shm.h"
#include "assert.h"
#include "fcntl.h"
#include "mem/kheap.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/errno.h"
#include "sys/list_head.h"
@@ -34,7 +36,7 @@ typedef struct {
/// @brief The shared memory data strcutre.
struct shmid_ds shmid;
/// Where shm created is memorized.
void *shm_location;
page_t *shm_location;
/// Reference inside the list of shared memory management structures.
list_head list;
} shm_info_t;
@@ -68,6 +70,9 @@ static inline shm_info_t *__shm_info_alloc(key_t key, size_t size, int shmflg)
shm_info->shmid.shm_cpid = 0;
shm_info->shmid.shm_lpid = 0;
shm_info->shmid.shm_nattch = 0;
// Allocate the memory.
uint32_t order = find_nearest_order_greater(0, size);
shm_info->shm_location = _alloc_pages(GFP_KERNEL, order);
// Return the shared memory structure.
return shm_info;
}
@@ -77,6 +82,8 @@ static inline shm_info_t *__shm_info_alloc(key_t key, size_t size, int shmflg)
static inline void __shm_info_dealloc(shm_info_t *shm_info)
{
assert(shm_info && "Received a NULL pointer.");
// Free the shared memory.
__free_pages(shm_info->shm_location);
// Deallocate the shmid memory.
kfree(shm_info);
}
@@ -147,14 +154,119 @@ int shm_init()
return 0;
}
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
long sys_shmget(key_t key, size_t size, int shmflg)
{
return 0;
shm_info_t *shm_info = NULL;
// Need to find a unique key.
if (key == IPC_PRIVATE) {
// Exit when i find a unique key.
do {
key = (int)-rand();
} while (__list_find_shm_info_by_key(key));
// We have a unique key, create the shared memory.
shm_info = __shm_info_alloc(key, size, shmflg);
// Add the shared memory to the list.
__list_add_shm_info(shm_info);
} else {
// Get the shared memory if it exists.
shm_info = __list_find_shm_info_by_key(key);
// Check if no shared memory exists for the given key and the flags did not specify IPC_CREAT.
if (!shm_info && !(shmflg & IPC_CREAT)) {
pr_err("No shared memory exists for the given key and the flags did not specify IPC_CREAT.\n");
return -ENOENT;
}
// Check if IPC_CREAT and IPC_EXCL were specified, but a shared memory already exists for key.
if (shm_info && (shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
pr_err("IPC_CREAT and IPC_EXCL were specified, but a shared memory already exists for key.\n");
return -EEXIST;
}
// Check if the shared memory exists for the given key, but the calling
// process does not have permission to access the set.
if (shm_info && !ipc_valid_permissions(shmflg, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return -EACCES;
}
// If the shared memory does not exist we need to create a new one.
if (shm_info == NULL) {
// Create the shared memory.
shm_info = __shm_info_alloc(key, size, shmflg);
// Add the shared memory to the list.
__list_add_shm_info(shm_info);
}
}
// Return the id of the shared memory.
return shm_info->id;
}
long sys_shmget(key_t key, size_t size, int flag)
static inline int __find_vm_free_area(mm_struct_t *mm, size_t length, uintptr_t *vm_start)
{
return 0;
// Get the stack.
vm_area_struct_t *area, *prev_area;
list_for_each_prev_decl(it, &mm->mmap_list)
{
area = list_entry(it, vm_area_struct_t, vm_list);
assert(area && "There is a NULL area in the list.");
// Check the previous segment.
if (area->vm_list.prev != &mm->mmap_list) {
prev_area = list_entry(area->vm_list.prev, vm_area_struct_t, vm_list);
assert(prev_area && "There is a NULL area in the list.");
// Compute the available space.
unsigned available_space = area->vm_start - prev_area->vm_end;
// If the space is enough, return the address.
if (available_space >= length) {
*vm_start = area->vm_start - length;
return 0;
}
}
}
return 1;
}
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
{
shm_info_t *shm_info = NULL;
task_struct *task = NULL;
// The id is less than zero.
if (shmid < 0) {
pr_err("The id is less than zero.\n");
return (void *)-EINVAL;
}
// Get the shared memory if it exists.
shm_info = __list_find_shm_info_by_id(shmid);
// Check if no shared memory exists for the given key and the flags did not specify IPC_CREAT.
if (!shm_info) {
pr_err("No shared memory exists for the given id and the flags did not specify IPC_CREAT.\n");
return (void *)-ENOENT;
}
// Check if the shared memory exists for the given key, but the calling
// process does not have permission to access the set.
if ((shmflg & SHM_RDONLY) && !ipc_valid_permissions(O_RDONLY, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return (void *)-EACCES;
}
if (!ipc_valid_permissions(O_RDWR, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return (void *)-EACCES;
}
// Get the calling task.
task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
uint32_t phy_start = get_physical_address_from_page(shm_info->shm_location);
uint32_t vm_start;
__find_vm_free_area(
task->mm,
shm_info->shmid.shm_segsz,
&vm_start);
mem_upd_vm_area(
task->mm->pgd,
vm_start,
phy_start,
shm_info->shmid.shm_segsz,
MM_RW | MM_PRESENT | MM_USER | MM_UPDADDR);
return (void *)vm_start;
}
long sys_shmdt(const void *shmaddr)
@@ -164,6 +276,32 @@ long sys_shmdt(const void *shmaddr)
long sys_shmctl(int shmid, int cmd, struct shmid_ds *buf)
{
shm_info_t *shm_info = NULL;
task_struct *task = NULL;
// Search for the shared memory.
shm_info = __list_find_shm_info_by_id(shmid);
// The shared memory doesn't exist.
if (!shm_info) {
pr_err("The shared memory doesn't exist.\n");
return -EINVAL;
}
// Get the calling task.
task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
if (cmd == IPC_RMID) {
// Remove the shared memory; any processes blocked is awakened (errno set to EIDRM); no argument required.
if ((shm_info->shmid.shm_perm.uid != task->uid) && (shm_info->shmid.shm_perm.cuid != task->uid)) {
pr_err("The calling process is not the creator or the owner of the shared memory.\n");
return -EPERM;
}
// Remove the set from the list.
__list_remove_shm_info(shm_info);
// Delete the set.
__shm_info_dealloc(shm_info);
}
return 0;
}
@@ -187,7 +325,7 @@ ssize_t procipc_shm_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte
// Prepare the header.
ret = sprintf(buffer, "key shmid perms segsz uid gid cuid cgid atime dtime ctime cpid lpid nattch\n");
// Iterate through the list of shmaphore set.
// Iterate through the list of shared memory.
list_for_each_decl(it, &shm_list)
{
// Get the current entry.
+1 -1
View File
@@ -447,7 +447,7 @@ void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
return 0;
}
long sys_shmget(key_t key, size_t size, int flag)
int sys_shmget(key_t key, size_t size, int flag)
{
return 0;
}