Jelajahi Sumber

feat(gblibc): add malloc, brk, sbrk

greatbridf 2 tahun lalu
induk
melakukan
1ce4b3415e

+ 5 - 0
gblibc/include/stdlib.h

@@ -1,6 +1,8 @@
 #ifndef __GBLIBC_STDLIB_H_
 #define __GBLIBC_STDLIB_H_
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -9,6 +11,9 @@ int atoi(const char* str);
 
 void __attribute__((noreturn)) exit(int status);
 
+void* malloc(size_t size);
+void free(void* ptr);
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 0
gblibc/include/unistd.h

@@ -44,6 +44,9 @@ pid_t getsid(pid_t pid);
 pid_t tcgetpgrp(int fd);
 int tcsetpgrp(int fd, pid_t pgrp);
 
+int brk(void* addr);
+void* sbrk(ssize_t increment);
+
 #ifdef __cplusplus
 }
 #endif

+ 20 - 0
gblibc/private-include/priv-vars.h

@@ -0,0 +1,20 @@
+#ifndef __GBLIBC_PRIV_VARS_H_
+#define __GBLIBC_PRIV_VARS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void** __start_brk_location(void);
+void** __curr_brk_location(void);
+
+#undef start_brk
+#define start_brk (*__start_brk_location())
+#undef curr_brk
+#define curr_brk (*__curr_brk_location())
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 0
gblibc/private-include/syscall.h

@@ -7,6 +7,7 @@
 #define SYS_write (1)
 #define SYS_open (2)
 #define SYS_close (3)
+#define SYS_brk (12)
 #define SYS_ioctl (16)
 #define SYS_pipe (22)
 #define SYS_dup (32)

+ 122 - 0
gblibc/src/stdlib.c

@@ -1,5 +1,8 @@
+#include <priv-vars.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <syscall.h>
+#include <unistd.h>
 
 int atoi(const char* str)
 {
@@ -17,3 +20,122 @@ void __attribute__((noreturn)) exit(int status)
     for (;;)
         ;
 }
+
+#define MINIMUM_ALLOCATION_SIZE (8)
+#define MEM_ALLOCATED (1)
+struct mem {
+    uint32_t sz;
+    uint32_t flag;
+};
+
+static inline void _init_heap(void)
+{
+    sbrk(128 * 1024);
+    struct mem* first = start_brk;
+    first->sz = 0;
+    first->flag = 0;
+}
+
+static inline int _is_end(struct mem* p)
+{
+    return p->sz == 0;
+}
+
+static inline int _is_allocated(struct mem* p)
+{
+    return !!(p->flag & MEM_ALLOCATED);
+}
+
+static inline size_t _max(size_t a, size_t b)
+{
+    return a > b ? a : b;
+}
+
+static inline size_t _size(struct mem* from)
+{
+    if (!_is_end(from))
+        return from->sz;
+    
+    size_t sz = curr_brk - (void*)from;
+    if (sz < sizeof(struct mem))
+        return 0;
+
+    return sz - sizeof(struct mem);
+}
+
+static inline struct mem* _next(struct mem* p, size_t sz)
+{
+    return (void*)p + sizeof(struct mem) + sz;
+}
+
+static inline void _union(struct mem* p)
+{
+    if (_is_end(p))
+        return;
+
+    for (struct mem* next = _next(p, p->sz);
+        !(next->flag & MEM_ALLOCATED);
+        next = _next(p, p->sz)) {
+
+        if (_is_end(next)) {
+            p->sz = 0;
+            break;
+        }
+
+        p->sz += sizeof(struct mem);
+        p->sz += next->sz;
+    }
+}
+
+void* malloc(size_t size)
+{
+    if (curr_brk == start_brk)
+        _init_heap();
+
+    if (size < MINIMUM_ALLOCATION_SIZE)
+        size = MINIMUM_ALLOCATION_SIZE;
+
+    struct mem* p = start_brk;
+    size_t sz = 0;
+    for (;; p = _next(p, p->sz)) {
+        if (_is_allocated(p))
+            continue;
+
+        _union(p);
+
+        sz = _size(p);
+        if (_is_end(p)) {
+            if (sz < size + sizeof(struct mem))
+                sbrk(_max(128 * 1024, size + sizeof(struct mem)));
+
+            sz = p->sz = size;
+            struct mem* next = _next(p, size);
+            next->flag = 0;
+            next->sz = 0;
+
+            break;
+        }
+
+        if (sz >= size)
+            break;
+    }
+
+    p->flag |= MEM_ALLOCATED;
+
+    if (sz >= size + sizeof(struct mem) + MINIMUM_ALLOCATION_SIZE) {
+        p->sz = size;
+
+        struct mem* next = _next(p, size);
+        next->flag = 0;
+        next->sz = sz - size - sizeof(struct mem);
+    }
+
+    return _next(p, 0);
+}
+
+void free(void* ptr)
+{
+    struct mem* p = ptr - sizeof(struct mem);
+    p->flag &= ~MEM_ALLOCATED;
+    _union(p);
+}

+ 46 - 0
gblibc/src/unistd.c

@@ -1,4 +1,5 @@
 #include <errno.h>
+#include <priv-vars.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <sys/ioctl.h>
@@ -205,3 +206,48 @@ int ioctl(int fd, unsigned long request, ...)
 
     return ret;
 }
+
+static inline void* _sys_brk(void* addr)
+{
+    return (void*)syscall1(SYS_brk, (uint32_t)addr);
+}
+
+void** __start_brk_location(void)
+{
+    static void* __start_brk = NULL;
+    return &__start_brk;
+}
+void** __curr_brk_location(void)
+{
+    static void* __curr_brk = NULL;
+    return &__curr_brk;
+}
+
+int brk(void* addr)
+{
+    if (!curr_brk)
+        start_brk = curr_brk = _sys_brk(NULL);
+    
+    void* new_brk = _sys_brk(addr);
+    if (new_brk == curr_brk) {
+        errno = 0;
+        return -1;
+    }
+
+    if (new_brk != addr) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    return 0;
+}
+
+void* sbrk(ssize_t increment)
+{
+    if (!curr_brk)
+        start_brk = curr_brk = _sys_brk(NULL);
+
+    if (brk(curr_brk + increment) == 0)
+        return curr_brk += increment;
+    return (void*)-1;
+}

+ 9 - 2
include/kernel/mm.hpp

@@ -295,9 +295,16 @@ public:
 
     constexpr iterator_type find(void* lp)
     {
-        for (auto iter = this->begin(); iter != this->end(); ++iter)
-            if (lp >= iter->start && lp < iter->end())
+        for (auto iter = this->begin(); iter != this->end(); ++iter) {
+            void* start = iter->start;
+            void* end = iter->end();
+
+            if (start == end && lp == start)
+                return iter;
+
+            if (lp >= start && lp < end)
                 return iter;
+        }
 
         return this->end();
     }

+ 3 - 0
include/kernel/process.hpp

@@ -355,6 +355,9 @@ public:
     pid_t pgid;
     pid_t sid;
 
+    void* start_brk;
+    void* brk;
+
 public:
     // if waitlist is not empty or mutex in cv_wait
     // is locked, its behavior is undefined

+ 7 - 0
src/kernel/process.cpp

@@ -99,6 +99,8 @@ process::process(process&& val)
     , ppid(val.ppid)
     , pgid(val.pgid)
     , sid(val.sid)
+    , start_brk(val.start_brk)
+    , brk(val.brk)
 {
     if (current_process == &val)
         current_process = this;
@@ -113,6 +115,9 @@ process::process(const process& parent)
     this->pgid = parent.pgid;
     this->sid = parent.sid;
 
+    this->start_brk = parent.start_brk;
+    this->brk = parent.brk;
+
     for (auto& area : parent.mms) {
         if (area.is_kernel_space() || area.attr.in.system)
             continue;
@@ -135,6 +140,8 @@ process::process(pid_t _ppid,
     , ppid { _ppid }
     , pgid { 0 }
     , sid { 0 }
+    , start_brk(nullptr)
+    , brk(nullptr)
 {
 }
 

+ 24 - 0
src/kernel/syscall.cpp

@@ -435,6 +435,29 @@ int _syscall_getppid(interrupt_stack*)
     return current_process->ppid;
 }
 
+int _syscall_brk(interrupt_stack* data)
+{
+    void* brk = (void*)data->s_regs.edi;
+
+    if (brk < current_process->start_brk)
+        return (int)current_process->brk;
+
+    auto& mm = *current_process->mms.find(current_process->start_brk);
+
+    // TODO: unmap released heap memory
+    if (brk < current_process->brk)
+        return (int)(current_process->brk = brk);
+
+    ssize_t diff = align_up<12>((uint32_t)brk);
+    diff -= align_up<12>((uint32_t)current_process->brk);
+    diff /= 0x1000;
+    for (ssize_t i = 0; i < diff; ++i)
+        mm.append_page(empty_page, PAGE_COW, false);
+    current_process->brk = brk;
+
+    return (int)brk;
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = data->s_regs.eax;
@@ -457,6 +480,7 @@ void init_syscall(void)
     syscall_handlers[1] = _syscall_write;
     syscall_handlers[2] = _syscall_open;
     syscall_handlers[3] = _syscall_close;
+    syscall_handlers[12] = _syscall_brk;
     syscall_handlers[16] = _syscall_ioctl;
     syscall_handlers[22] = _syscall_pipe;
     syscall_handlers[32] = _syscall_dup;

+ 7 - 0
src/types/elf.cpp

@@ -149,6 +149,13 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
         null_ind, 0, 1, 0);
     assert(ret == GB_OK);
 
+    // map heap area
+    // TODO: randomize heap start address
+    current_process->start_brk = current_process->brk = (void*)0xa0000000;
+    ret = mmap(current_process->start_brk,
+        0, null_ind, 0, 1, 0);
+    assert(ret == GB_OK);
+
     d->eip = (void*)hdr.entry;
     d->sp = reinterpret_cast<uint32_t*>(types::elf::ELF_STACK_BOTTOM);
 

+ 1 - 9
user-space-program/sh.c

@@ -5,6 +5,7 @@
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdlib.h>
 
 int printf(const char* fmt, ...)
 {
@@ -21,15 +22,6 @@ int printf(const char* fmt, ...)
     return len;
 }
 
-void* malloc(size_t n)
-{
-    static char mems[1024];
-    static int pos;
-    int orig_pos = pos;
-    pos += n;
-    return mems + orig_pos;
-}
-
 // Parsed command representation
 #define EXEC  1
 #define REDIR 2