440 lines
11 KiB
C
440 lines
11 KiB
C
/// @file shm.c
|
|
/// @brief
|
|
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
|
|
/// See LICENSE.md for details.
|
|
///! @cond Doxygen_Suppress
|
|
|
|
// ============================================================================
|
|
// Setup the logging for this file (do this before any other include).
|
|
#include "sys/kernel_levels.h" // Include kernel log levels.
|
|
#define __DEBUG_HEADER__ "[IPCshm]" ///< Change header.
|
|
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
|
|
#include "io/debug.h" // Include debugging functions.
|
|
// ============================================================================
|
|
|
|
#include "sys/shm.h"
|
|
#include "system/panic.h"
|
|
#include "process/process.h"
|
|
#include "sys/errno.h"
|
|
#include "string.h"
|
|
#include "assert.h"
|
|
#include "stdio.h"
|
|
|
|
#if 0
|
|
struct shmid_ds *head = NULL;
|
|
static ushort shm_descriptor = 0;
|
|
|
|
int syscall_shmctl(int *args)
|
|
{
|
|
int shmid = args[0];
|
|
int cmd = args[1];
|
|
|
|
// TODO: for IPC_STAT
|
|
// struct shmid_ds * buf = (struct shmid_ds *) args[2];
|
|
|
|
struct shmid_ds *myshmid_ds = find_shm_fromid(shmid);
|
|
|
|
if (myshmid_ds == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
// Upgrade shm info.
|
|
myshmid_ds->shm_lpid = scheduler_get_current_process()->pid;
|
|
myshmid_ds->shm_ctime = time(NULL);
|
|
|
|
switch (cmd) {
|
|
case IPC_RMID:
|
|
if (myshmid_ds->shm_nattch == 0) {
|
|
kfree(myshmid_ds->shm_location);
|
|
|
|
// Manage list.
|
|
if (myshmid_ds == head) {
|
|
head = head->next;
|
|
} else {
|
|
// Finding the previous shmid_ds.
|
|
struct shmid_ds *prev = head;
|
|
while (prev->next != myshmid_ds) {
|
|
prev = prev->next;
|
|
}
|
|
prev->next = myshmid_ds->next;
|
|
}
|
|
kfree(myshmid_ds);
|
|
} else {
|
|
(myshmid_ds->shm_perm).mode |= SHM_DEST;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case IPC_STAT:
|
|
break;
|
|
case IPC_SET:
|
|
break;
|
|
case SHM_LOCK:
|
|
break;
|
|
case SHM_UNLOCK:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Get shared memory segment.
|
|
int syscall_shmget(int *args)
|
|
{
|
|
int flags = args[2];
|
|
key_t key = (key_t)args[0];
|
|
size_t size = (size_t)args[1];
|
|
|
|
struct shmid_ds *shmid_ds;
|
|
|
|
if (flags & IPC_EXCL) {
|
|
return -1;
|
|
}
|
|
|
|
if (flags & IPC_CREAT) {
|
|
shmid_ds = find_shm_fromkey(key);
|
|
|
|
if (shmid_ds != NULL) {
|
|
return -1;
|
|
}
|
|
|
|
shmid_ds = kmalloc(sizeof(struct shmid_ds));
|
|
pr_default("\n[SHM] shmget() shmid_ds : 0x%p", shmid_ds);
|
|
|
|
shmid_ds->shm_location = kmalloc_align(size);
|
|
pr_default("\n[SHM] shmget() Location : 0x%p",
|
|
shmid_ds->shm_location);
|
|
pr_default("\n[SHM] shmget() physLocation : 0x%p",
|
|
paging_virtual_to_physical(get_current_page_directory(),
|
|
shmid_ds->shm_location));
|
|
|
|
shmid_ds->next = head;
|
|
head = shmid_ds;
|
|
|
|
shmid_ds->shm_segsz = size;
|
|
shmid_ds->shm_atime = 0;
|
|
shmid_ds->shm_dtime = 0;
|
|
shmid_ds->shm_ctime = 0;
|
|
shmid_ds->shm_cpid = scheduler_get_current_process()->pid;
|
|
shmid_ds->shm_lpid = scheduler_get_current_process()->pid;
|
|
shmid_ds->shm_nattch = 0;
|
|
|
|
// No user implementation.
|
|
(shmid_ds->shm_perm).cuid = 0;
|
|
// No group implementation.
|
|
(shmid_ds->shm_perm).cgid = 0;
|
|
// No user implementation
|
|
(shmid_ds->shm_perm).uid = 0;
|
|
// No group implementation.
|
|
(shmid_ds->shm_perm).gid = 0;
|
|
(shmid_ds->shm_perm).mode = flags & 0777;
|
|
(shmid_ds->shm_perm).seq = shm_descriptor++;
|
|
(shmid_ds->shm_perm).key = key;
|
|
} else {
|
|
shmid_ds = find_shm_fromkey(key);
|
|
pr_default("\n[SHM] shmget() shmid_ds found : 0x%p", shmid_ds);
|
|
|
|
if (shmid_ds == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if ((flags & 0777) > ((shmid_ds->shm_perm).mode & 0777)) {
|
|
return -1;
|
|
}
|
|
shmid_ds->shm_lpid = scheduler_get_current_process()->pid;
|
|
}
|
|
|
|
return (shmid_ds->shm_perm).seq;
|
|
}
|
|
|
|
// Attach shared memory segment.
|
|
void *syscall_shmat(int *args)
|
|
{
|
|
int shmid = args[0];
|
|
void *shmaddr = (void *)args[1];
|
|
|
|
// TODO: for more settings
|
|
// int flags = args[2];
|
|
|
|
struct shmid_ds *myshmid_ds = find_shm_fromid(shmid);
|
|
pr_default("\n[SHM] shmat() shmid_ds found : 0x%p", myshmid_ds);
|
|
|
|
if (myshmid_ds == NULL) {
|
|
return (void *)-1;
|
|
}
|
|
|
|
void *shm_start = myshmid_ds->shm_location;
|
|
|
|
if (shmaddr == NULL) {
|
|
void *ret = kmalloc_align(myshmid_ds->shm_segsz);
|
|
|
|
uint32_t shm_vaddr_start = (uint32_t)ret & 0xfffff000;
|
|
uint32_t shm_vaddr_end =
|
|
((uint32_t)ret + myshmid_ds->shm_segsz) & 0xfffff000;
|
|
|
|
uint32_t shm_paddr_start = (uint32_t)paging_virtual_to_physical(
|
|
get_current_page_directory(), shm_start);
|
|
|
|
free_map_region(get_current_page_directory(), shm_vaddr_start,
|
|
shm_vaddr_end, true);
|
|
|
|
while (shm_vaddr_start <= shm_vaddr_end) {
|
|
paging_allocate_page(get_current_page_directory(), shm_vaddr_start,
|
|
shm_paddr_start / PAGE_SIZE, true, true);
|
|
shm_vaddr_start += PAGE_SIZE;
|
|
shm_paddr_start += PAGE_SIZE;
|
|
}
|
|
|
|
pr_default("\n[SHM] shmat() vaddr : 0x%p", ret);
|
|
pr_default("\n[SHM] shmat() paddr : 0x%p",
|
|
(void *)shm_paddr_start);
|
|
pr_default("\n[SHM] shmat() paddr after map: 0x%p",
|
|
paging_virtual_to_physical(get_current_page_directory(),
|
|
ret));
|
|
|
|
// Upgrade shm info.
|
|
myshmid_ds->shm_lpid = scheduler_get_current_process()->pid;
|
|
(myshmid_ds->shm_nattch)++;
|
|
myshmid_ds->shm_atime = time(NULL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
return (void *)-1;
|
|
}
|
|
|
|
// Detach shared memory segment.
|
|
int syscall_shmdt(int *args)
|
|
{
|
|
void *shmaddr = (void *)args[0];
|
|
|
|
if (shmaddr == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
struct shmid_ds *myshmid_ds = find_shm_fromvaddr(shmaddr);
|
|
pr_default("\n[SHM] shmdt() shmid_ds found : 0x%p", myshmid_ds);
|
|
|
|
if (myshmid_ds == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
// ===== Test ==============================================================
|
|
uint32_t shm_vaddr_start = (uint32_t)shmaddr & 0xfffff000;
|
|
uint32_t shm_vaddr_end =
|
|
((uint32_t)shmaddr + myshmid_ds->shm_segsz) & 0xfffff000;
|
|
|
|
free_map_region(get_current_page_directory(), shm_vaddr_start,
|
|
shm_vaddr_end, false);
|
|
|
|
while (shm_vaddr_start <= shm_vaddr_end) {
|
|
paging_allocate_page(get_current_page_directory(), shm_vaddr_start,
|
|
shm_vaddr_start / PAGE_SIZE, true, true);
|
|
shm_vaddr_start += PAGE_SIZE;
|
|
}
|
|
// =========================================================================
|
|
|
|
kfree(shmaddr);
|
|
|
|
// Upgrade shm info.
|
|
myshmid_ds->shm_lpid = scheduler_get_current_process()->pid;
|
|
(myshmid_ds->shm_nattch)--;
|
|
myshmid_ds->shm_dtime = time(NULL);
|
|
|
|
// Manage SHM_DEST flag on.
|
|
if (myshmid_ds->shm_nattch == 0 && (myshmid_ds->shm_perm).mode & SHM_DEST) {
|
|
kfree(myshmid_ds->shm_location);
|
|
|
|
// Manage list.
|
|
if (myshmid_ds == head) {
|
|
head = head->next;
|
|
} else {
|
|
// Finding the previous shmid_ds.
|
|
struct shmid_ds *prev = head;
|
|
while (prev->next != myshmid_ds) {
|
|
prev = prev->next;
|
|
}
|
|
prev->next = myshmid_ds->next;
|
|
}
|
|
kfree(myshmid_ds);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
|
|
{
|
|
int error;
|
|
|
|
__asm__("movl %0, %%ecx\n"
|
|
"movl %1, %%ebx\n"
|
|
"movl %2, %%edx\n"
|
|
"movl $6, %%eax\n"
|
|
"int $80\n"
|
|
:
|
|
: "r"(shmid), "r"(cmd), "r"(buf));
|
|
__asm__("movl %%eax, %0\n\t"
|
|
: "=r"(error));
|
|
|
|
return error;
|
|
}
|
|
|
|
int shmget(key_t key, size_t size, int flags)
|
|
{
|
|
int id;
|
|
|
|
__asm__("movl %0, %%ecx\n"
|
|
"movl %1, %%ebx\n"
|
|
"movl %2, %%edx\n"
|
|
"movl $3, %%eax\n"
|
|
"int $80\n"
|
|
:
|
|
: "r"(key), "r"(size), "r"(flags));
|
|
__asm__("movl %%eax, %0\n\t"
|
|
: "=r"(id));
|
|
|
|
return id;
|
|
}
|
|
|
|
void *shmat(int shmid, void *shmaddr, int flag)
|
|
{
|
|
void *addr;
|
|
|
|
__asm__("movl %0, %%ecx\n"
|
|
"movl %1, %%ebx\n"
|
|
"movl %2, %%edx\n"
|
|
"movl $4, %%eax\n"
|
|
"int $80\n"
|
|
:
|
|
: "r"(shmid), "r"(shmaddr), "r"(flag));
|
|
// The kernel is serving my system call
|
|
|
|
// Now I have the control
|
|
__asm__("movl %%eax, %0\n\t"
|
|
: "=r"(addr));
|
|
|
|
return addr;
|
|
}
|
|
|
|
int shmdt(void *shmaddr)
|
|
{
|
|
int error;
|
|
|
|
__asm__("movl %0, %%ecx\n"
|
|
"movl $5, %%eax\n"
|
|
"int $80\n"
|
|
:
|
|
: "r"(shmaddr));
|
|
__asm__("movl %%eax, %0\n\t"
|
|
: "=r"(error));
|
|
|
|
return error;
|
|
}
|
|
|
|
struct shmid_ds *find_shm_fromid(int shmid)
|
|
{
|
|
struct shmid_ds *res = head;
|
|
|
|
while (res != NULL) {
|
|
if ((res->shm_perm).seq == shmid) {
|
|
return res;
|
|
}
|
|
res = res->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct shmid_ds *find_shm_fromkey(key_t key)
|
|
{
|
|
struct shmid_ds *res = head;
|
|
|
|
while (res != NULL) {
|
|
if ((res->shm_perm).key == key) {
|
|
return res;
|
|
}
|
|
res = res->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct shmid_ds *find_shm_fromvaddr(void *shmvaddr)
|
|
{
|
|
void *shmpaddr =
|
|
paging_virtual_to_physical(get_current_page_directory(), shmvaddr);
|
|
void *paddr;
|
|
struct shmid_ds *res = head;
|
|
|
|
while (res != NULL) {
|
|
paddr = paging_virtual_to_physical(get_current_page_directory(),
|
|
res->shm_location);
|
|
if (paddr == shmpaddr) {
|
|
return res;
|
|
}
|
|
res = res->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
|
|
{
|
|
TODO("Not implemented");
|
|
return 0;
|
|
}
|
|
|
|
long sys_shmget(key_t key, size_t size, int flag)
|
|
{
|
|
TODO("Not implemented");
|
|
return 0;
|
|
}
|
|
|
|
long sys_shmdt(const void *shmaddr)
|
|
{
|
|
TODO("Not implemented");
|
|
return 0;
|
|
}
|
|
|
|
long sys_shmctl(int shmid, int cmd, struct shmid_ds *buf)
|
|
{
|
|
TODO("Not implemented");
|
|
return 0;
|
|
}
|
|
|
|
ssize_t procipc_shm_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
|
|
{
|
|
if (!file) {
|
|
pr_err("Received a NULL file.\n");
|
|
return -ENOENT;
|
|
}
|
|
size_t buffer_len = 0, read_pos = 0, write_count = 0, ret = 0;
|
|
struct semid_ds *entry = NULL;
|
|
char buffer[BUFSIZ];
|
|
|
|
// Prepare a buffer.
|
|
memset(buffer, 0, BUFSIZ);
|
|
// Prepare the header.
|
|
ret = sprintf(buffer, "key shmid ...\n");
|
|
|
|
// Implementation goes here...
|
|
sprintf(buffer + ret, "\n");
|
|
|
|
// Perform read.
|
|
buffer_len = strlen(buffer);
|
|
read_pos = offset;
|
|
if (read_pos < buffer_len) {
|
|
while ((write_count < nbyte) && (read_pos < buffer_len)) {
|
|
buf[write_count] = buffer[read_pos];
|
|
// Move the pointers.
|
|
++read_pos, ++write_count;
|
|
}
|
|
}
|
|
return write_count;
|
|
}
|
|
|
|
///! @endcond
|