diff --git a/.build b/.build index d1f0c9fa..67742076 100644 --- a/.build +++ b/.build @@ -1 +1 @@ -2230 +2329 diff --git a/Makefile b/Makefile index 4c8f617f..2513309e 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,8 @@ $(ISO): limine.conf $(LIMINE_TOOL) buildgen $(BUILD_DIR)/kernel.elf disk userspa @cp -r src/userspace/apps/filemanager/fm.elf $(DISK_DIR)/rd/emr/system/ @cp -r src/userspace/apps/template/template.elf $(DISK_DIR)/rd/emr/system/ @cp -r src/userspace/apps/gears/gears.elf $(DISK_DIR)/rd/bin/gears.elf + @cp -r src/userspace/apps/doom/doom.elf $(DISK_DIR)/rd/bin/doom.elf + @cp -r src/userspace/apps/doom/doom1.wad $(DISK_DIR)/rd/bin/doom1.wad @echo "[MK] copying other binarys..." # delete those using make binclean @@ -111,6 +113,7 @@ $(ISO): limine.conf $(LIMINE_TOOL) buildgen $(BUILD_DIR)/kernel.elf disk userspa @cp src/userspace/bin/ps/ps.elf $(DISK_DIR)/rd/bin/ @cp src/userspace/bin/meminfo/meminfo.elf $(DISK_DIR)/rd/bin/ @cp src/userspace/bin/dofetch/dofetch.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/apps/test_libc/test_libc.emx/app.elf $(DISK_DIR)/rd/bin/test_libc.elf # libs arent copied anymore due merge conflicts in prs #@echo "[MK] copying libs..." @@ -210,6 +213,8 @@ binclean: @rm -f $(DISK_DIR)/rd/emr/system/desktop.elf @rm -f $(DISK_DIR)/rd/emr/system/login.elf @rm -f $(DISK_DIR)/rd/emr/system/gears.elf + @rm -f $(DISK_DIR)/rd/bin/doom.elf + @rm -f $(DISK_DIR)/rd/bin/doom1.wad @rm -f $(DISK_DIR)/rd/emr/system/libraries/cursor.elf @rm -f $(DISK_DIR)/rd/emr/system/libraries/libemxfb0.a @rm -f $(DISK_DIR)/rd/emr/system/libraries/libfont8x12.a diff --git a/dsk/rd/emr/system/fm.elf b/dsk/rd/emr/system/fm.elf index f44f795e..364bf9db 100755 Binary files a/dsk/rd/emr/system/fm.elf and b/dsk/rd/emr/system/fm.elf differ diff --git a/dsk/rd/emr/system/sysinfo.elf b/dsk/rd/emr/system/sysinfo.elf index c1975c69..752d80df 100755 Binary files a/dsk/rd/emr/system/sysinfo.elf and b/dsk/rd/emr/system/sysinfo.elf differ diff --git a/dsk/rd/emr/system/template.elf b/dsk/rd/emr/system/template.elf index a2b2d16f..39e33250 100755 Binary files a/dsk/rd/emr/system/template.elf and b/dsk/rd/emr/system/template.elf differ diff --git a/dsk/rd/emr/system/terminal.emx/app.elf b/dsk/rd/emr/system/terminal.emx/app.elf index c83895be..69f99124 100755 Binary files a/dsk/rd/emr/system/terminal.emx/app.elf and b/dsk/rd/emr/system/terminal.emx/app.elf differ diff --git a/shared/ebuild.h b/shared/ebuild.h index b465991b..4bb7df27 100644 --- a/shared/ebuild.h +++ b/shared/ebuild.h @@ -1,4 +1,4 @@ #pragma once // this file will always be regenerated when building emexOS // if you want to disable it goto /tools/genbuild.sh -#define ___EMEX_BUILD "26MY.01.2230" +#define ___EMEX_BUILD "26MY.01.2329" diff --git a/shared/types.h b/shared/types.h index 638b9a44..55221fd9 100644 --- a/shared/types.h +++ b/shared/types.h @@ -18,6 +18,8 @@ typedef signed long i64; typedef unsigned long size_t; typedef long ssize_t; +typedef long off_t; + typedef u8 uint8_t; typedef u16 uint16_t; diff --git a/src/kernel/file_systems/vfs/commands.c b/src/kernel/file_systems/vfs/commands.c index 81b902e9..279ed2dd 100644 --- a/src/kernel/file_systems/vfs/commands.c +++ b/src/kernel/file_systems/vfs/commands.c @@ -119,6 +119,33 @@ ssize_t fs_write(int fd, const void *buf, size_t cnt) { return file->node->ops->write(file, buf, cnt); } +off_t fs_lseek(int fd, off_t offset, int whence) { + fs_file *file = fs_get_file(fd); + if (!file) + return -1; + + off_t new_pos = file->pos; + switch (whence) { + case SEEK_SET: + new_pos = offset; + break; + case SEEK_CUR: + new_pos += offset; + break; + case SEEK_END: + new_pos = (off_t)file->node->size + offset; + break; + default: + return -1; + } + + if (new_pos < 0) + return -1; + + file->pos = (u64)new_pos; + return new_pos; +} + int fs_mkdir(const char *path) { char ppath[FS_MAX_PATH]; char dname[64]; diff --git a/src/kernel/file_systems/vfs/vfs.h b/src/kernel/file_systems/vfs/vfs.h index b137ac61..c1fa2104 100644 --- a/src/kernel/file_systems/vfs/vfs.h +++ b/src/kernel/file_systems/vfs/vfs.h @@ -136,6 +136,8 @@ int fs_open(const char *path, int flags); int fs_close(int fd); ssize_t fs_read(int fd, void *buf, size_t cnt); ssize_t fs_write(int fd, const void *buf, size_t cnt); +off_t fs_lseek(int fd, off_t offset, int whence); + int fs_mkdir(const char *path); int fs_unlink(const char *path); int fs_listdir(const char *path, _emx_kdirent_t *buf, int max_entries); diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h index 6b9aaad4..e8e18899 100644 --- a/src/kernel/mem/mem.h +++ b/src/kernel/mem/mem.h @@ -1,8 +1,8 @@ #ifndef MEM_H #define MEM_H -#include #include +#include typedef struct limine_memmap_response limine_memmap_response_t; typedef struct limine_hhdm_response limine_hhdm_response_t; @@ -18,65 +18,66 @@ typedef struct limine_framebuffer limine_framebuffer_t; #define GRAPHICS_SIZE 1024 * 1024 * 32 #define ULIME_START (GRAPHICS_START + GRAPHICS_SIZE) -#define ULIME_META_SIZE (1024 * 1024 * 2) //2mb +#define ULIME_META_SIZE (1024 * 1024 * 2) // 2mb -#define KLIME_SIZE_SLAB (1024 * 1024 * 8) -#define KLIME_SIZE_IO (1024 * 1024 * 4) -#define KLIME_SIZE_DMA (1024 * 1024 * 2) -#define KLIME_SIZE_NOTHEAP (PAGE_SIZE + PAGE_SIZE + KLIME_SIZE_SLAB + KLIME_SIZE_IO + KLIME_SIZE_DMA) +#define KLIME_SIZE_SLAB (1024 * 1024 * 8) +#define KLIME_SIZE_IO (1024 * 1024 * 4) +#define KLIME_SIZE_DMA (1024 * 1024 * 2) +#define KLIME_SIZE_NOTHEAP \ + (PAGE_SIZE + PAGE_SIZE + KLIME_SIZE_SLAB + KLIME_SIZE_IO + KLIME_SIZE_DMA) #define KLIME_SIZE_HEAP HEAP_SIZE - KLIME_SIZE_NOTHEAP #define KLIME_OFFSET_SLAB_META PAGE_SIZE #define KLIME_OFFSET_SLAB_DATA KLIME_OFFSET_SLAB_META + PAGE_SIZE -#define KLIME_OFFSET_IO KLIME_OFFSET_SLAB_DATA + KLIME_SIZE_SLAB -#define KLIME_OFFSET_DMA KLIME_OFFSET_IO + KLIME_SIZE_IO -#define KLIME_OFFSET_HEAP KLIME_OFFSET_DMA + KLIME_SIZE_DMA +#define KLIME_OFFSET_IO KLIME_OFFSET_SLAB_DATA + KLIME_SIZE_SLAB +#define KLIME_OFFSET_DMA KLIME_OFFSET_IO + KLIME_SIZE_IO +#define KLIME_OFFSET_HEAP KLIME_OFFSET_DMA + KLIME_SIZE_DMA -#define GLIME_SIZE_META (PAGE_SIZE * 256) //2mb +#define GLIME_SIZE_META (PAGE_SIZE * 256) // 2mb #define GLIME_HEAP_SIZE (GRAPHICS_SIZE - GLIME_SIZE_META) #define PAGE_SIZE 4096 -#define FRAME_FREE 0x00 // Frame is available -#define FRAME_USED 0x01 // Frame is allocated -#define FRAME_KERNEL 0x02 // Frame contains kernel data/code -#define FRAME_USER 0x04 // Frame belongs to user process -#define FRAME_DMA 0x08 // Frame used for DMA operations -#define FRAME_SHARED 0x10 // Frame shared between processes -#define FRAME_COW 0x20 // Copy-on-write frame -#define FRAME_CACHE 0x40 // Frame used for disk cache -#define FRAME_GUARD 0x80 // Guard page (for stack overflow) +#define FRAME_FREE 0x00 // Frame is available +#define FRAME_USED 0x01 // Frame is allocated +#define FRAME_KERNEL 0x02 // Frame contains kernel data/code +#define FRAME_USER 0x04 // Frame belongs to user process +#define FRAME_DMA 0x08 // Frame used for DMA operations +#define FRAME_SHARED 0x10 // Frame shared between processes +#define FRAME_COW 0x20 // Copy-on-write frame +#define FRAME_CACHE 0x40 // Frame used for disk cache +#define FRAME_GUARD 0x80 // Guard page (for stack overflow) typedef struct glime_request { - limine_framebuffer_response_t *fbr; - u64 virt; - u64 size; + limine_framebuffer_response_t *fbr; + u64 virt; + u64 size; } glime_request_t; typedef struct glime_response { - u64 *start_framebuffer; - u64 width; - u64 height; - u64 pitch; - u16 bpp; - u16 memory_model; - u8 red_mask_size; - u8 red_mask_shift; - u8 green_mask_size; - u8 green_mask_shift; - u8 blue_mask_size; - u8 blue_mask_shift; + u64 *start_framebuffer; + u64 width; + u64 height; + u64 pitch; + u16 bpp; + u16 memory_model; + u8 red_mask_size; + u8 red_mask_shift; + u8 green_mask_size; + u8 green_mask_shift; + u8 blue_mask_size; + u8 blue_mask_shift; } glime_response_t; typedef struct klime_request { - limine_hhdm_response_t *hpr; - u64 phys; - u64 virt; - u64 size; + limine_hhdm_response_t *hpr; + u64 phys; + u64 virt; + u64 size; } klime_request_t; typedef struct klime_response { - u64 *ptr; - u64 size; + u64 *ptr; + u64 size; } klime_response_t; #endif diff --git a/src/kernel/packages/cpio/cpio.c b/src/kernel/packages/cpio/cpio.c index 6635ca0f..18fb2a10 100644 --- a/src/kernel/packages/cpio/cpio.c +++ b/src/kernel/packages/cpio/cpio.c @@ -1,10 +1,10 @@ #include "cpio.h" -#include -#include -#include #include +#include #include +#include +#include #include // path transform for user_id folder replacement @@ -12,223 +12,250 @@ static char _t_from[64] = {0}; static char _t_to[128] = {0}; void cpio_set_user_transform(const char *from, const char *to) { - if (!from || !to) return; - str_copy(_t_from, from); - str_copy(_t_to, to); + if (!from || !to) + return; + str_copy(_t_from, from); + str_copy(_t_to, to); } -static u32 parse_hex8(const char **p) -{ - u32 val = 0; - for (int i = 0; i < 8; i++) { - char c = (*p)[i]; - u32 n; - if (c >= '0' && c <= '9') n = (u32)(c - '0'); - else if (c >= 'a' && c <= 'f') n = (u32)(c - 'a' + 10); - else if (c >= 'A' && c <= 'F') n = (u32)(c - 'A' + 10); - else n = 0; - val = (val << 4) | n; - } - *p += 8; - return val; +static u32 parse_hex8(const char **p) { + u32 val = 0; + for (int i = 0; i < 8; i++) { + char c = (*p)[i]; + u32 n; + if (c >= '0' && c <= '9') + n = (u32)(c - '0'); + else if (c >= 'a' && c <= 'f') + n = (u32)(c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + n = (u32)(c - 'A' + 10); + else + n = 0; + val = (val << 4) | n; + } + *p += 8; + return val; } -static inline u64 align4(u64 n){ return (n + 3) & ~(u64)3; } +static inline u64 align4(u64 n) { return (n + 3) & ~(u64)3; } // pub iterators // -void cpio_iter_init(cpio_iter_t *iter, const u8 *data, u64 size) -{ - if (!iter) return; - iter->base = data; - iter->size = size; - iter->offset = 0; +void cpio_iter_init(cpio_iter_t *iter, const u8 *data, u64 size) { + if (!iter) + return; + iter->base = data; + iter->size = size; + iter->offset = 0; } -int cpio_iter_next(cpio_iter_t *iter, cpio_entry_t *entry) -{ - if (!iter || !entry) return CPIO_ERR_TRUNC; +int cpio_iter_next(cpio_iter_t *iter, cpio_entry_t *entry) { + if (!iter || !entry) + return CPIO_ERR_TRUNC; - u64 off = iter->offset; + u64 off = iter->offset; - if (off+CPIO_HEADER_SIZE > iter->size) return CPIO_ERR_TRUNC; + if (off + CPIO_HEADER_SIZE > iter->size) + return CPIO_ERR_TRUNC; - const char *hdr = (const char *)(iter->base + off); + const char *hdr = (const char *)(iter->base + off); - if (!(hdr[0]=='0' && hdr[1]=='7' && hdr[2]=='0' && - hdr[3]=='7' && hdr[4]=='0' && (hdr[5]=='1' || hdr[5]=='2'))) + if (!(hdr[0] == '0' && hdr[1] == '7' && hdr[2] == '0' && hdr[3] == '7' && + hdr[4] == '0' && (hdr[5] == '1' || hdr[5] == '2'))) return CPIO_ERR_MAGIC; - const char *p = hdr + 6; - entry->ino = parse_hex8(&p); - entry->mode = parse_hex8(&p); - entry->uid = parse_hex8(&p); - entry->gid = parse_hex8(&p); - entry->nlink = parse_hex8(&p); - entry->mtime = parse_hex8(&p); - entry->filesize = parse_hex8(&p); - entry->devmajor = parse_hex8(&p); - entry->devminor = parse_hex8(&p); - entry->rdevmajor = parse_hex8(&p); - entry->rdevminor = parse_hex8(&p); - entry->namesize = parse_hex8(&p); - parse_hex8(&p); // crc field / ignored - - off += CPIO_HEADER_SIZE; - - if (off+ entry->namesize > iter->size) return CPIO_ERR_TRUNC; - entry->name = (const char *)(iter->base + off); - - off = iter->offset + align4(CPIO_HEADER_SIZE + entry->namesize); - - if (str_equals(entry->name, CPIO_TRAILER)){ - iter->offset = off; - - return CPIO_ERR_EOF; - } - - if (off + entry->filesize > iter->size) return CPIO_ERR_TRUNC; - entry->data = iter->base + off; - iter->offset = off + align4(entry->filesize); - - return CPIO_OK; + const char *p = hdr + 6; + entry->ino = parse_hex8(&p); + entry->mode = parse_hex8(&p); + entry->uid = parse_hex8(&p); + entry->gid = parse_hex8(&p); + entry->nlink = parse_hex8(&p); + entry->mtime = parse_hex8(&p); + entry->filesize = parse_hex8(&p); + entry->devmajor = parse_hex8(&p); + entry->devminor = parse_hex8(&p); + entry->rdevmajor = parse_hex8(&p); + entry->rdevminor = parse_hex8(&p); + entry->namesize = parse_hex8(&p); + parse_hex8(&p); // crc field / ignored + + off += CPIO_HEADER_SIZE; + + if (off + entry->namesize > iter->size) + return CPIO_ERR_TRUNC; + entry->name = (const char *)(iter->base + off); + + off = iter->offset + align4(CPIO_HEADER_SIZE + entry->namesize); + + if (str_equals(entry->name, CPIO_TRAILER)) { + iter->offset = off; + + return CPIO_ERR_EOF; + } + + if (off + entry->filesize > iter->size) + return CPIO_ERR_TRUNC; + entry->data = iter->base + off; + iter->offset = off + align4(entry->filesize); + + return CPIO_OK; } #define CPIO_MAX_ENTRIES 512 typedef struct { - cpio_entry_t e; - char path[256]; + cpio_entry_t e; + char path[256]; } cpio_staged_t; static cpio_staged_t _staged[CPIO_MAX_ENTRIES]; -static void make_path(char *out, const char *base, const char *name) -{ - // strip leading "./" or lone "." - if (name[0] == '.' && name[1] == '/') name += 2; - if (name[0] == '.' && name[1] == '\0') { str_copy(out, base); return; } - - // apply user_id transform on first path component - char tname[256]; - if (_t_from[0]) { - int fl = str_len(_t_from); - if (str_starts_with(name, _t_from) && - (name[fl] == '/' || name[fl] == '\0')) { - str_copy(tname, _t_to); - if (name[fl] == '/') str_append(tname, name + fl); - name = tname; - } +static void make_path(char *out, const char *base, const char *name) { + // strip leading "./" or lone "." + if (name[0] == '.' && name[1] == '/') + name += 2; + if (name[0] == '.' && name[1] == '\0') { + str_copy(out, base); + return; + } + + // apply user_id transform on first path component + char tname[256]; + if (_t_from[0]) { + int fl = str_len(_t_from); + if (str_starts_with(name, _t_from) && + (name[fl] == '/' || name[fl] == '\0')) { + str_copy(tname, _t_to); + if (name[fl] == '/') + str_append(tname, name + fl); + name = tname; } - - if (str_equals(base, "/")) { - out[0] = '/'; - str_copy(out + 1, name); - } else { - str_copy(out, base); - int bl = str_len(out); - if (bl > 0 && out[bl-1] != '/') str_append(out, "/"); - str_append(out, name); - } - // remove trailing slash unless root - int l = str_len(out); - if (l >1 && out[l-1] == '/') out[l-1] = '\0'; + } + + if (str_equals(base, "/")) { + out[0] = '/'; + str_copy(out + 1, name); + } else { + str_copy(out, base); + int bl = str_len(out); + if (bl > 0 && out[bl - 1] != '/') + str_append(out, "/"); + str_append(out, name); + } + // remove trailing slash unless root + int l = str_len(out); + if (l > 1 && out[l - 1] == '/') + out[l - 1] = '\0'; } -int cpio_extract_to_vfs(const u8 *data, u64 size, const char *base_path) -{ - if (!data || size == 0 || !base_path) return CPIO_ERR_TRUNC; +int cpio_extract_to_vfs(const u8 *data, u64 size, const char *base_path) { + if (!data || size == 0 || !base_path) + return CPIO_ERR_TRUNC; - cpio_iter_t iter; - cpio_entry_t entry; - cpio_iter_init(&iter, data, size); + cpio_iter_t iter; + cpio_entry_t entry; + cpio_iter_init(&iter, data, size); - int total = 0; - int staged = 0; + int total = 0; + int staged = 0; - // self explaining i think... reading archive.... - print("\n", white()); - log("[CPIO]", "reading archive...\n", d); - - while (staged < CPIO_MAX_ENTRIES) { - int rc = cpio_iter_next(&iter, &entry); - if (rc == CPIO_ERR_EOF) break; - if (rc != CPIO_OK) { log("[CPIO]", "parse error\n", error); return rc; } - - const char *n = entry.name; - //strips "./" or "." - if (n[0]=='.' && n[1]=='\0') continue; - if (n[0]=='.' && n[1]=='/' && n[2]=='\0') continue; - if (!cpio_is_file(&entry) && !cpio_is_dir(&entry) && !cpio_is_symlink(&entry)) continue; - - cpio_staged_t *s = &_staged[staged]; - s->e = entry; - make_path(s->path, base_path, entry.name); - - if (cpio_is_dir(&entry)) { - log("[CPIO]",DIR_PREFIX, d);} - else { - log("[CPIO]",FILE_PREFIX, d);} - print(s->path, white()); - if (cpio_is_file(&entry) && entry.filesize > 0) { - char buf[20]; - str_copy(buf, " ("); - str_append_uint(buf, entry.filesize); // shows how many bytes a file has - str_append(buf, "B)"); - print(buf, white()); - } - print("\n", white()); - staged++; - } - print("\n", white()); + // self explaining i think... reading archive.... + print("\n", white()); + log("[CPIO]", "reading archive...\n", d); - // only now create all directorys - // (just made it so it looks better...) - for (int i = 0; i < staged; i++) { - if (cpio_is_dir(&_staged[i].e)) { - fs_mkdir(_staged[i].path); - total++; - } + while (staged < CPIO_MAX_ENTRIES) { + int rc = cpio_iter_next(&iter, &entry); + if (rc == CPIO_ERR_EOF) + break; + if (rc != CPIO_OK) { + log("[CPIO]", "parse error\n", error); + return rc; } - // this writes the files but it can also overwrite files - for (int i = 0; i < staged; i++) - { - cpio_staged_t *s = &_staged[i]; - if (!cpio_is_file(&s->e) && !cpio_is_symlink(&s->e)) continue; - - int fd = fs_open(s->path, O_CREAT | O_WRONLY); - if (fd < 0) continue; - if (s->e.filesize > 0) - fs_write(fd, (void *)s->e.data, s->e.filesize); - fs_close(fd); - total++; + const char *n = entry.name; + // strips "./" or "." + if (n[0] == '.' && n[1] == '\0') + continue; + if (n[0] == '.' && n[1] == '/' && n[2] == '\0') + continue; + if (!cpio_is_file(&entry) && !cpio_is_dir(&entry) && + !cpio_is_symlink(&entry)) + continue; + + cpio_staged_t *s = &_staged[staged]; + s->e = entry; + make_path(s->path, base_path, entry.name); + + if (cpio_is_dir(&entry)) { + log("[CPIO]", DIR_PREFIX, d); + } else { + log("[CPIO]", FILE_PREFIX, d); } - - char buf[32]; - str_copy(buf, ""); - str_append_uint(buf, (u32)total); - log("[CPIO]", "extracted ", d); - print(buf, white()); - print(" entries\n", white()); - - return total; + print(s->path, white()); + if (cpio_is_file(&entry) && entry.filesize > 0) { + char buf[20]; + str_copy(buf, " ("); + str_append_uint(buf, entry.filesize); // shows how many bytes a file has + str_append(buf, "B)"); + print(buf, white()); + } + print("\n", white()); + staged++; + } + print("\n", white()); + + // only now create all directorys + // (just made it so it looks better...) + for (int i = 0; i < staged; i++) { + if (cpio_is_dir(&_staged[i].e)) { + fs_mkdir(_staged[i].path); + total++; + } + } + + // this writes the files but it can also overwrite files + for (int i = 0; i < staged; i++) { + cpio_staged_t *s = &_staged[i]; + if (!cpio_is_file(&s->e) && !cpio_is_symlink(&s->e)) + continue; + + int fd = fs_open(s->path, O_CREAT | O_WRONLY); + if (fd < 0) + continue; + if (s->e.filesize > 0) + fs_write(fd, (void *)s->e.data, s->e.filesize); + fs_close(fd); + total++; + } + + char buf[32]; + str_copy(buf, ""); + str_append_uint(buf, (u32)total); + log("[CPIO]", "extracted ", d); + print(buf, white()); + print(" entries\n", white()); + + return total; } -int cpio_find(const u8 *data, u64 size, const char *name, cpio_entry_t *entry) -{ - if (!data || !name || !entry) return CPIO_ERR_TRUNC; - - cpio_iter_t iter; - cpio_iter_init(&iter, data, size); - - while (1) { - int rc = cpio_iter_next(&iter, entry); - if (rc == CPIO_ERR_EOF) return CPIO_ERR_EOF; - if (rc != CPIO_OK) return rc; - - const char *n = entry->name; - if (n[0]=='.' && n[1]=='/') n += 2; - if (str_equals(n, name)) return CPIO_OK; - } +int cpio_find(const u8 *data, u64 size, const char *name, cpio_entry_t *entry) { + if (!data || !name || !entry) + return CPIO_ERR_TRUNC; + + cpio_iter_t iter; + cpio_iter_init(&iter, data, size); + + while (1) { + int rc = cpio_iter_next(&iter, entry); + if (rc == CPIO_ERR_EOF) + return CPIO_ERR_EOF; + if (rc != CPIO_OK) + return rc; + + const char *n = entry->name; + if (n[0] == '.' && n[1] == '/') + n += 2; + if (str_equals(n, name)) + return CPIO_OK; + } } diff --git a/src/kernel/user/syscalls.c b/src/kernel/user/syscalls.c index 3d81ab59..b40bad3f 100644 --- a/src/kernel/user/syscalls.c +++ b/src/kernel/user/syscalls.c @@ -7,6 +7,8 @@ #include // #include #include +#include +#include #include #include #include @@ -201,6 +203,11 @@ u64 scall_write(ulime_proc_t *proc, u64 fd, u64 buf, u64 count) { return (u64)ret; } +u64 scall_gettime(ulime_proc_t *proc, u64 flags, u64 a2, u64 a3) { + (void)proc; (void)flags; (void)a2; (void)a3; + return (u64)timer_get_milliseconds(); +} + u64 scall_exit(ulime_proc_t *proc, u64 exit_code, u64 arg2, u64 arg3) { (void)arg2; (void)arg3; @@ -547,6 +554,11 @@ u64 scall_close(ulime_proc_t *proc, u64 fd, u64 arg2, u64 arg3) { return (u64)fs_close((int)fd); } +u64 scall_lseek(ulime_proc_t *proc, u64 fd, u64 offset, u64 whence) { + (void)proc; + return (u64)fs_lseek((int)fd, (off_t)offset, (int)whence); +} + u64 scall_getdents(ulime_proc_t *proc, u64 path_ptr, u64 buf_ptr, u64 max_entries) { (void)proc; @@ -991,6 +1003,7 @@ void _init_syscalls_table(ulime_t *ulime_ptr) { // ulime->syscalls[READ] = scall_read; ulime_ptr->syscalls[OPEN] = scall_open; ulime_ptr->syscalls[CLOSE] = scall_close; + ulime_ptr->syscalls[LSEEK] = scall_lseek; ulime_ptr->syscalls[GETPID] = scall_getpid; ulime_ptr->syscalls[BRK] = scall_brk; ulime_ptr->syscalls[EXIT] = scall_exit; @@ -1012,6 +1025,7 @@ void _init_syscalls_table(ulime_t *ulime_ptr) { ulime_ptr->syscalls[WAITPID] = scall_waitpid; ulime_ptr->syscalls[GETUID] = scall_getuid; ulime_ptr->syscalls[GETGID] = scall_getgid; + ulime_ptr->syscalls[GETTIME] = scall_gettime; // emex specific ulime_ptr->syscalls[EMXREBOOT] = scall_reboot; diff --git a/src/kernel/user/system/calls.h b/src/kernel/user/system/calls.h index e7ba301d..81d57366 100644 --- a/src/kernel/user/system/calls.h +++ b/src/kernel/user/system/calls.h @@ -6,11 +6,14 @@ #if X86_64 == 1 #define EXIT 60 +#define LSEEK 8 + #define WRITE 1 #define WRITEV 20 #define READ 0 #define READV 19 +#define GETTIME 13 // #define __GETPID 391 #define GETPID 39 // # call_getpid; diff --git a/src/userspace/Makefile b/src/userspace/Makefile index c24a46d0..94dc6d60 100644 --- a/src/userspace/Makefile +++ b/src/userspace/Makefile @@ -49,7 +49,7 @@ clean: @$(MAKE) -C apps/system clean @$(MAKE) -C apps/system/stinf clean @$(MAKE) -C apps/shell clean - @$(MAKE) -C apps/terminal + @$(MAKE) -C apps/terminal clean @$(MAKE) -C apps/login clean @$(MAKE) -C apps/desktop clean @$(MAKE) -C apps/sysinfo clean diff --git a/src/userspace/apps/desktop/desktop.c b/src/userspace/apps/desktop/desktop.c index f6376e8d..5798cd05 100644 --- a/src/userspace/apps/desktop/desktop.c +++ b/src/userspace/apps/desktop/desktop.c @@ -319,7 +319,7 @@ static void render_band(input_state_t *is) int main(void) { - mkdir(DT_DIR); + mkdir(DT_DIR, 0755); int fd; fd = open(DT_CMD, O_WRONLY | O_CREAT); if (fd >= 0) close(fd); diff --git a/src/userspace/apps/terminal/terminal.emx/app.elf b/src/userspace/apps/terminal/terminal.emx/app.elf deleted file mode 100755 index c83895be..00000000 Binary files a/src/userspace/apps/terminal/terminal.emx/app.elf and /dev/null differ diff --git a/src/userspace/apps/terminal/terminal.o b/src/userspace/apps/terminal/terminal.o deleted file mode 100644 index 0246f2b1..00000000 Binary files a/src/userspace/apps/terminal/terminal.o and /dev/null differ diff --git a/src/userspace/apps/test_libc/Makefile b/src/userspace/apps/test_libc/Makefile new file mode 100644 index 00000000..5e864d4e --- /dev/null +++ b/src/userspace/apps/test_libc/Makefile @@ -0,0 +1,27 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +all: clean test_libc.emx/app.elf + +test_libc.emx/app.elf: test_libc.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + mkdir -p test_libc.emx + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o test_libc.o $(LIBC)/build/libc.a -o $@ + +test_libc.o: test_libc.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o test_libc.emx/app.elf + +.PHONY: all clean diff --git a/src/userspace/apps/test_libc/test_libc.c b/src/userspace/apps/test_libc/test_libc.c new file mode 100644 index 00000000..482f813a --- /dev/null +++ b/src/userspace/apps/test_libc/test_libc.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +static void cleanup_test(void) { + printf("atexit handler called!\n"); +} + +int compare_ints(const void *a, const void *b) { + return (*(int*)a - *(int*)b); +} + +int main(int argc, char **argv) { + (void)argc; (void)argv; + printf("Testing extended stdio.h\n"); + + FILE *f = fopen("/tmp/test.txt", "w+"); + if (!f) { + perror("fopen"); + // fallback to / if /tmp doesn't exist + f = fopen("/test.txt", "w+"); + if (!f) { + perror("fopen (fallback)"); + return 1; + } + } + + fprintf(f, "Hello, world!\nThis is a test of fseek and ftell.\n"); + long pos = ftell(f); + printf("Current position after write: %ld\n", pos); + + rewind(f); + printf("Position after rewind: %ld\n", ftell(f)); + + char buf[128]; + if (fgets(buf, sizeof(buf), f)) { + printf("Read 1st line: %s", buf); + } + + fseek(f, 0, SEEK_END); + printf("Position at end: %ld\n", ftell(f)); + + long end_pos = ftell(f); + if (end_pos > 5) { + fseek(f, -6, SEEK_END); + printf("Position at end-6: %ld\n", ftell(f)); + if (fgets(buf, sizeof(buf), f)) { + printf("Read last 5 chars: %s", buf); + } + } + + printf("Testing ungetc:\n"); + rewind(f); + int c = fgetc(f); + printf("Got char: '%c'\n", c); + ungetc('X', f); + c = fgetc(f); + printf("Got char after ungetc('X'): '%c'\n", c); + c = fgetc(f); + printf("Next char: '%c'\n", c); + + fclose(f); + printf("Testing sscanf:\n"); + int val1; unsigned int val2; char str_buf[64]; + const char *input = "123 0xABC hello"; + int matched = sscanf(input, "%d %x %s", &val1, &val2, str_buf); + printf("Matched %d items. val1=%d, val2=0x%x, str_buf='%s'\n", matched, val1, val2, str_buf); + + printf("Testing tmpfile and remove:\n"); + FILE *tmp = tmpfile(); + if (tmp) { + fprintf(tmp, "Temporary data"); + rewind(tmp); + fgets(str_buf, sizeof(str_buf), tmp); + printf("Read from tmpfile: '%s'\n", str_buf); + fclose(tmp); + } + + printf("Testing stdlib features:\n"); + atexit(cleanup_test); + + srand(45); + printf("Rand: %d %d %d\n", rand(), rand(), rand()); + + int arr[] = { 42, 7, 100, 3, 25 }; + qsort(arr, 5, sizeof(int), compare_ints); + printf("Sorted array: %d %d %d %d %d\n", arr[0], arr[1], arr[2], arr[3], arr[4]); + + div_t d = div(33, 10); + printf("div(33, 10): quot=%d rem=%d\n", d.quot, d.rem); + + printf("Testing time support:\n"); + time_t t = time(NULL); + printf("Current time (seconds since boot): %ld\n", t); + + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) { + printf("gettimeofday: %ld sec, %ld usec\n", tv.tv_sec, tv.tv_usec); + } + + printf("Test complete.\n"); + + return 0; +} diff --git a/src/userspace/apps/test_libc/test_libc.emx/app.elf b/src/userspace/apps/test_libc/test_libc.emx/app.elf new file mode 100755 index 00000000..26681a7a Binary files /dev/null and b/src/userspace/apps/test_libc/test_libc.emx/app.elf differ diff --git a/src/userspace/apps/test_libc/test_libc.o b/src/userspace/apps/test_libc/test_libc.o new file mode 100644 index 00000000..0b4f4807 Binary files /dev/null and b/src/userspace/apps/test_libc/test_libc.o differ diff --git a/src/userspace/libc/Makefile b/src/userspace/libc/Makefile index 5294d41a..9ead854f 100644 --- a/src/userspace/libc/Makefile +++ b/src/userspace/libc/Makefile @@ -7,7 +7,7 @@ CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ -fno-PIE -fno-pic -m64 -march=x86-64 -mno-red-zone -Wall -Wextra \ -std=gnu11 -I$(INC) -Isrc -SRCS := src/errno.c src/string.c src/stdlib.c src/unistd.c src/fcntl.c src/stdio.c src/dirent.c src/ioctl.c src/system.c src/wait.c src/sinfo.c src/math.c +SRCS := src/errno.c src/string.c src/stdlib.c src/unistd.c src/fcntl.c src/stdio.c src/dirent.c src/ioctl.c src/system.c src/wait.c src/sinfo.c src/math.c src/time.c src/stat.c OBJS := $(patsubst src/%.c, $(BLD)/%.o, $(SRCS)) all: $(BLD)/libc.a $(BLD)/crt0.o diff --git a/src/userspace/libc/include/assert.h b/src/userspace/libc/include/assert.h new file mode 100644 index 00000000..b770304b --- /dev/null +++ b/src/userspace/libc/include/assert.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +#ifdef NDEBUG +#define assert(ignore) ((void)0) +#else +#define assert(expr) ((expr) ? (void)0 : (printf("Assertion failed: %s, file %s, line %d\n", #expr, __FILE__, __LINE__), abort())) +#endif diff --git a/src/userspace/libc/include/ctype.h b/src/userspace/libc/include/ctype.h index 6f70f09b..9abed1c2 100644 --- a/src/userspace/libc/include/ctype.h +++ b/src/userspace/libc/include/ctype.h @@ -1 +1,12 @@ #pragma once + +static inline int isdigit(int c) { return (unsigned)c - '0' < 10; } +static inline int isspace(int c) { return c == ' ' || (unsigned)c - '\t' < 5; } +static inline int isupper(int c) { return (unsigned)c - 'A' < 26; } +static inline int islower(int c) { return (unsigned)c - 'a' < 26; } +static inline int isalpha(int c) { return ((unsigned)c | 32) - 'a' < 26; } +static inline int isalnum(int c) { return isalpha(c) || isdigit(c); } +static inline int isprint(int c) { return (unsigned)c - 0x20 < 95; } +static inline int isxdigit(int c) { return isdigit(c) || ((unsigned)c | 32) - 'a' < 6; } +static inline int tolower(int c) { return isupper(c) ? c + 32 : c; } +static inline int toupper(int c) { return islower(c) ? c - 32 : c; } diff --git a/src/userspace/libc/include/inttypes.h b/src/userspace/libc/include/inttypes.h new file mode 100644 index 00000000..59952e45 --- /dev/null +++ b/src/userspace/libc/include/inttypes.h @@ -0,0 +1,26 @@ +#pragma once +#include + +#define PRId8 "d" +#define PRIi8 "i" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" + +#define PRId16 "d" +#define PRIi16 "i" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" + +#define PRId32 "d" +#define PRIi32 "i" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" + +#define PRId64 "ld" +#define PRIi64 "li" +#define PRIu64 "lu" +#define PRIx64 "lx" +#define PRIX64 "LX" diff --git a/src/userspace/libc/include/stdbool.h b/src/userspace/libc/include/stdbool.h index abc7c42d..8b64d6be 100644 --- a/src/userspace/libc/include/stdbool.h +++ b/src/userspace/libc/include/stdbool.h @@ -2,3 +2,4 @@ #define bool _Bool #define true 1 #define false 0 +#define __bool_true_false_are_defined 1 diff --git a/src/userspace/libc/include/stdio.h b/src/userspace/libc/include/stdio.h index e91a023d..71b98b7f 100644 --- a/src/userspace/libc/include/stdio.h +++ b/src/userspace/libc/include/stdio.h @@ -3,12 +3,17 @@ #include #define EOF (-1) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 typedef struct { int _fd; int _flags; int _eof; int _err; + int _ungetc_char; + int _has_ungetc; } FILE; @@ -27,10 +32,25 @@ int fclose(FILE *f); size_t fread(void *buf, size_t sz, size_t n, FILE *f); size_t fwrite(const void *buf, size_t sz, size_t n, FILE *f); char *fgets(char *buf, int n, FILE *f); + +int fgetc(FILE *f); +#define getc(f) fgetc(f) +int getchar(void); +int ungetc(int c, FILE *f); + int fputc(int c, FILE *f); int fputs(const char *s, FILE *f); + +long ftell(FILE *f); +int fseek(FILE *f, long offset, int whence); +void rewind(FILE *f); + +int fflush(FILE *f); + int feof(FILE *f); int ferror(FILE *f); +void clearerr(FILE *f); + int fprintf(FILE *f, const char *fmt, ...); int vfprintf(FILE *f, const char *fmt, va_list ap); @@ -41,4 +61,32 @@ int printf(const char *fmt, ...); int vprintf(const char *fmt, va_list ap); int snprintf(char *buf, size_t size, const char *fmt, ...); int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); -int remove(const char *path); // file or directory \ No newline at end of file + +int scanf(const char *fmt, ...); +int fscanf(FILE *f, const char *fmt, ...); +int sscanf(const char *str, const char *fmt, ...); +int vscanf(const char *fmt, va_list ap); +int vfscanf(FILE *f, const char *fmt, va_list ap); +int vsscanf(const char *str, const char *fmt, va_list ap); + +typedef long fpos_t; +int fgetpos(FILE *f, fpos_t *pos); +int fsetpos(FILE *f, const fpos_t *pos); + +int fileno(FILE *f); +FILE *fdopen(int fd, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *f); + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 +#define BUFSIZ 1024 +int setvbuf(FILE *f, char *buf, int mode, size_t size); +void setbuf(FILE *f, char *buf); + +#define L_tmpnam 256 +char *tmpnam(char *s); +FILE *tmpfile(void); + +int remove(const char *path); // file or directory +int rename(const char *oldpath, const char *newpath); \ No newline at end of file diff --git a/src/userspace/libc/include/stdlib.h b/src/userspace/libc/include/stdlib.h index 8709ea8c..6dbc65ae 100644 --- a/src/userspace/libc/include/stdlib.h +++ b/src/userspace/libc/include/stdlib.h @@ -1,6 +1,10 @@ #pragma once #include +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#define RAND_MAX 32767 + void *malloc(size_t n); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t n); @@ -8,16 +12,38 @@ void free (void *ptr); void exit(int status) __attribute__((noreturn)); void abort(void) __attribute__((noreturn)); +int atexit(void (*func)(void)); int atoi(const char *s); long atol(const char *s); +long long atoll(const char *s); +double atof(const char *s); + long strtol(const char *s, char **end, int base); +unsigned long strtoul(const char *s, char **end, int base); +long long strtoll(const char *s, char **end, int base); +unsigned long long strtoull(const char *s, char **end, int base); int abs(int x); long labs(long x); +long long llabs(long long x); -// for screen clear command -//int system(const char *cmd); +typedef struct { int quot; int rem; } div_t; +typedef struct { long quot; long rem; } ldiv_t; +typedef struct { long long quot; long long rem; } lldiv_t; -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 +div_t div(int numer, int denom); +ldiv_t ldiv(long numer, long denom); +lldiv_t lldiv(long long numer, long long denom); + +int rand(void); +void srand(unsigned int seed); + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); +void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); + +char *getenv(const char *name); +int setenv(const char *name, const char *value, int overwrite); +int unsetenv(const char *name); + +int system(const char *command); diff --git a/src/userspace/libc/include/strings.h b/src/userspace/libc/include/strings.h new file mode 100644 index 00000000..d0abc474 --- /dev/null +++ b/src/userspace/libc/include/strings.h @@ -0,0 +1,5 @@ +#pragma once +#include + +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); diff --git a/src/userspace/libc/include/sys/stat.h b/src/userspace/libc/include/sys/stat.h new file mode 100644 index 00000000..3021a323 --- /dev/null +++ b/src/userspace/libc/include/sys/stat.h @@ -0,0 +1,29 @@ +#pragma once +#include + +struct stat { + dev_t st_dev; /* ID of device containing file */ + ino_t st_ino; /* Inode number */ + mode_t st_mode; /* File type and mode */ + nlink_t st_nlink; /* Number of hard links */ + uid_t st_uid; /* User ID of owner */ + gid_t st_gid; /* Group ID of owner */ + dev_t st_rdev; /* Device ID (if special file) */ + off_t st_size; /* Total size, in bytes */ + long st_blksize; /* Block size for filesystem I/O */ + long st_blocks; /* Number of 512B blocks allocated */ + long st_atime; /* Time of last access */ + long st_mtime; /* Time of last modification */ + long st_ctime; /* Time of last status change */ +}; + +#define S_IFMT 0170000 +#define S_IFDIR 0040000 +#define S_IFREG 0100000 + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) + +int stat(const char *path, struct stat *buf); +int fstat(int fd, struct stat *buf); +int mkdir(const char *path, mode_t mode); diff --git a/src/userspace/libc/include/sys/types.h b/src/userspace/libc/include/sys/types.h index 34a484dc..5411b158 100644 --- a/src/userspace/libc/include/sys/types.h +++ b/src/userspace/libc/include/sys/types.h @@ -7,3 +7,6 @@ typedef unsigned long ino_t; // inode num typedef unsigned int mode_t; typedef unsigned int uid_t; typedef unsigned int gid_t; +typedef unsigned int useconds_t; +typedef unsigned int dev_t; +typedef unsigned int nlink_t; diff --git a/src/userspace/libc/include/time.h b/src/userspace/libc/include/time.h new file mode 100644 index 00000000..279d49db --- /dev/null +++ b/src/userspace/libc/include/time.h @@ -0,0 +1,17 @@ +#pragma once +#include + +typedef long time_t; + +struct timeval { + time_t tv_sec; + long tv_usec; +}; + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +time_t time(time_t *t); +int gettimeofday(struct timeval *tv, struct timezone *tz); diff --git a/src/userspace/libc/include/unistd.h b/src/userspace/libc/include/unistd.h index afce1802..71e667e6 100644 --- a/src/userspace/libc/include/unistd.h +++ b/src/userspace/libc/include/unistd.h @@ -8,10 +8,13 @@ ssize_t read(int fd, void *buf, size_t n); ssize_t write(int fd, const void *buf, size_t n); int close(int fd); +off_t lseek(int fd, off_t offset, int whence); + // filesystem int chdir(const char *path); -int mkdir(const char *path); +int usleep(useconds_t usec); +int mkdir(const char *path, mode_t mode); int rmdir(const char *path); char *getcwd(char *buf, size_t size); int unlink(const char *path); diff --git a/src/userspace/libc/src/_syscall.h b/src/userspace/libc/src/_syscall.h index c033e361..b5982ad5 100644 --- a/src/userspace/libc/src/_syscall.h +++ b/src/userspace/libc/src/_syscall.h @@ -3,7 +3,10 @@ #define _SCAL_READ 0 #define _SCAL_WRITE 1 #define _SCAL_OPEN 2 -#define _SCAL_CLOSE 3 +#define _SCAL_CLOSE 3 +#define _SCAL_LSEEK 8 +#define _SCAL_GETTIME 13 + #define _SCAL_BRK 12 #define _SCAL_GETPID 39 #define _SCAL_FORK 57 diff --git a/src/userspace/libc/src/math.c b/src/userspace/libc/src/math.c index 830a0b9e..5660491f 100644 --- a/src/userspace/libc/src/math.c +++ b/src/userspace/libc/src/math.c @@ -2,56 +2,53 @@ // @offihito - -double fabs(double x) { - return x < 0 ? -x : x; -} +double fabs(double x) { return x < 0 ? -x : x; } double sqrt(double x) { - if (x < 0) return 0; - double res; - __asm__ ("sqrtsd %1, %0" : "=x"(res) : "x"(x)); - return res; + if (x < 0) + return 0; + double res; + __asm__("sqrtsd %1, %0" : "=x"(res) : "x"(x)); + return res; } double sin(double x) { - double res; - __asm__ ("fsin" : "=t"(res) : "0"(x)); - return res; + double res; + __asm__("fsin" : "=t"(res) : "0"(x)); + return res; } double cos(double x) { - double res; - __asm__ ("fcos" : "=t"(res) : "0"(x)); - return res; + double res; + __asm__("fcos" : "=t"(res) : "0"(x)); + return res; } double pow(double x, double y) { - double res; - // x^y = 2^(y * log2(x)) - // This is a simplified x87 implementation - __asm__ ( - "fyl2x;" // st(1) = y * log2(x), pop st(0) - "fld %%st(0);" // duplicate y*log2(x) - "frndint;" // round to integer - "fsubr %%st(1), %%st(0);" // get fractional part - "f2xm1;" // 2^(fractional) - 1 - "fld1;" - "faddp;" // 2^(fractional) - "fscale;" // st(0) * 2^st(1) - "fstp %%st(1);" // pop integer part - : "=t"(res) - : "0"(x), "u"(y) - ); - return res; + double res; + // x^y = 2^(y * log2(x)) + // This is a simplified x87 implementation + __asm__("fyl2x;" // st(1) = y * log2(x), pop st(0) + "fld %%st(0);" // duplicate y*log2(x) + "frndint;" // round to integer + "fsubr %%st(1), %%st(0);" // get fractional part + "f2xm1;" // 2^(fractional) - 1 + "fld1;" + "faddp;" // 2^(fractional) + "fscale;" // st(0) * 2^st(1) + "fstp %%st(1);" // pop integer part + : "=t"(res) + : "0"(x), "u"(y)); + return res; } double floor(double x) { - if (x >= 0) { - return (double)(long)x; - } else { - long i = (long)x; - if (x == (double)i) return x; - return (double)(i - 1); - } + if (x >= 0) { + return (double)(long)x; + } else { + long i = (long)x; + if (x == (double)i) + return x; + return (double)(i - 1); + } } \ No newline at end of file diff --git a/src/userspace/libc/src/sinfo.c b/src/userspace/libc/src/sinfo.c index f8e3875b..7cd92f56 100644 --- a/src/userspace/libc/src/sinfo.c +++ b/src/userspace/libc/src/sinfo.c @@ -3,5 +3,5 @@ int sysinfo(struct sysinfo_t *info) { - (int) _sc1(_SCAL_SYSINFO, (long) info); + return (int) _sc1(_SCAL_SYSINFO, (long) info); } \ No newline at end of file diff --git a/src/userspace/libc/src/stat.c b/src/userspace/libc/src/stat.c new file mode 100644 index 00000000..9a1bf796 --- /dev/null +++ b/src/userspace/libc/src/stat.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int stat(const char *path, struct stat *buf) { + if (!buf) { errno = EINVAL; return -1; } + memset(buf, 0, sizeof(struct stat)); + // Stub implementation: everything is a regular file of size 0 + buf->st_mode = S_IFREG | 0644; + return 0; +} + +int fstat(int fd, struct stat *buf) { + if (!buf) { errno = EINVAL; return -1; } + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG | 0644; + return 0; +} diff --git a/src/userspace/libc/src/stdio.c b/src/userspace/libc/src/stdio.c index d3d69e9e..1547a01b 100644 --- a/src/userspace/libc/src/stdio.c +++ b/src/userspace/libc/src/stdio.c @@ -1,304 +1,703 @@ -#include +#include #include -#include +#include #include #include -#include -//#include - -static FILE _stdin = { ._fd = STDIN_FILENO, ._flags = _FILE_READ, ._eof = 0, ._err = 0 }; -static FILE _stdout = { ._fd = STDOUT_FILENO, ._flags = _FILE_WRITE, ._eof = 0, ._err = 0 }; -static FILE _stderr = { ._fd = STDERR_FILENO, ._flags = _FILE_WRITE, ._eof = 0, ._err = 0 }; - -FILE *stdin = &_stdin; +#include +// #include + +static FILE _stdin = {._fd = STDIN_FILENO, + ._flags = _FILE_READ, + ._eof = 0, + ._err = 0, + ._has_ungetc = 0}; +static FILE _stdout = {._fd = STDOUT_FILENO, + ._flags = _FILE_WRITE, + ._eof = 0, + ._err = 0, + ._has_ungetc = 0}; +static FILE _stderr = {._fd = STDERR_FILENO, + ._flags = _FILE_WRITE, + ._eof = 0, + ._err = 0, + ._has_ungetc = 0}; + +FILE *stdin = &_stdin; FILE *stdout = &_stdout; FILE *stderr = &_stderr; -FILE *fopen(const char *path, const char *mode) -{ - if (!path || !mode) { errno = EINVAL; return NULL; } - - int flags = 0; - int fflags = 0; - - // parse mode string - char m = mode[0]; - int plus = (mode[1] == '+') || (mode[2] == '+'); - - if (m == 'r') { - flags = plus ? O_RDWR : O_RDONLY; - fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_READ; - } else if (m == 'w') { - flags = plus ? (O_RDWR | O_CREAT) : (O_WRONLY | O_CREAT); - fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_WRITE; - } else if (m == 'a') { - flags = O_WRONLY | O_CREAT; - fflags = _FILE_WRITE; - } else { - errno = EINVAL; - return NULL; - } - - int fd = open(path, flags); - if (fd < 0) return NULL; // errno already set by open() +FILE *fopen(const char *path, const char *mode) { + if (!path || !mode) { + errno = EINVAL; + return NULL; + } + + int flags = 0; + int fflags = 0; + + // parse mode string + char m = mode[0]; + int plus = (mode[1] == '+') || (mode[2] == '+'); + + if (m == 'r') { + flags = plus ? O_RDWR : O_RDONLY; + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_READ; + } else if (m == 'w') { + flags = plus ? (O_RDWR | O_CREAT) : (O_WRONLY | O_CREAT); + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_WRITE; + } else if (m == 'a') { + flags = O_WRONLY | O_CREAT; + fflags = _FILE_WRITE; + } else { + errno = EINVAL; + return NULL; + } + + int fd = open(path, flags); + if (fd < 0) + return NULL; // errno already set by open() + + FILE *f = (FILE *)malloc(sizeof(FILE)); + if (!f) { + close(fd); + errno = ENOMEM; + return NULL; + } + + f->_fd = fd; + f->_flags = fflags; + f->_eof = 0; + f->_err = 0; + f->_has_ungetc = 0; + + return f; +} - FILE *f = (FILE *)malloc(sizeof(FILE)); - if (!f) { close(fd); errno = ENOMEM; return NULL; } +int fclose(FILE *f) { + if (!f) { + errno = EINVAL; + return EOF; + } + + // do not close the static standard streams + int is_std = (f == stdin || f == stdout || f == stderr); + + int r = 0; + if (!is_std) { + r = close(f->_fd); + free(f); + } + return r; +} - f->_fd = fd; - f->_flags = fflags; - f->_eof = 0; - f->_err = 0; +size_t fread(void *buf, size_t sz, size_t n, FILE *f) { + if (!f || !buf || !sz || !n) + return 0; + if (f->_eof || f->_err) + return 0; + if (!(f->_flags & _FILE_READ)) { + f->_err = 1; + return 0; + } + + size_t total = sz * n; + size_t done = 0; + unsigned char *p = (unsigned char *)buf; + + if (f->_has_ungetc && total > 0) { + *p++ = (unsigned char)f->_ungetc_char; + f->_has_ungetc = 0; + done++; + } + + if (done < total) { + ssize_t got = read(f->_fd, p, total - done); + if (got < 0) { + f->_err = 1; + } else { + done += (size_t)got; + if ((size_t)got < (total - (size_t)(p - (unsigned char *)buf))) + f->_eof = 1; + } + } - return f; + return done / sz; } -int fclose(FILE *f) -{ - if (!f) { errno = EINVAL; return EOF; } +size_t fwrite(const void *buf, size_t sz, size_t n, FILE *f) { + if (!f || !buf || !sz || !n) + return 0; + if (!(f->_flags & _FILE_WRITE)) { + f->_err = 1; + return 0; + } - // do not close the static standard streams - int is_std = (f == stdin || f == stdout || f == stderr); + size_t total = sz * n; + ssize_t written = write(f->_fd, buf, total); - int r = 0; - if (!is_std) { - r = close(f->_fd); - free(f); - } - return r; + if (written < 0) { + f->_err = 1; + return 0; + } + return (size_t)written / sz; } -size_t fread(void *buf, size_t sz, size_t n, FILE *f) -{ - if (!f || !buf || !sz || !n) return 0; - if (f->_eof || f->_err) return 0; - if (!(f->_flags & _FILE_READ)) { f->_err = 1; return 0; } +char *fgets(char *buf, int n, FILE *f) { + if (!f || !buf || n <= 0) + return NULL; + if (f->_eof || f->_err) + return NULL; + if (!(f->_flags & _FILE_READ)) { + f->_err = 1; + return NULL; + } + + int i = 0; + while (i < n - 1) { + int c = fgetc(f); + if (c == EOF) + break; + buf[i++] = (char)c; + if (c == '\n') + break; + } + + if (i == 0) + return NULL; + buf[i] = '\0'; + return buf; +} - size_t total = sz * n; - ssize_t got = read(f->_fd, buf, total); +int fgetc(FILE *f) { + if (!f) + return EOF; + if (f->_has_ungetc) { + f->_has_ungetc = 0; + return (unsigned char)f->_ungetc_char; + } + unsigned char c; + if (fread(&c, 1, 1, f) != 1) + return EOF; + return c; +} - if (got < 0) { f->_err = 1; return 0; } - if (got == 0 || (size_t)got < total) f->_eof = 1; +int getchar(void) { return fgetc(stdin); } - return (size_t)got / sz; // full elements read +int ungetc(int c, FILE *f) { + if (!f || c == EOF) + return EOF; + f->_ungetc_char = (unsigned char)c; + f->_has_ungetc = 1; + f->_eof = 0; + return (unsigned char)c; } -size_t fwrite(const void *buf, size_t sz, size_t n, FILE *f) -{ - if (!f || !buf || !sz || !n) return 0; - if (!(f->_flags & _FILE_WRITE)) { f->_err = 1; return 0; } +int fputc(int c, FILE *f) { + if (!f || !(f->_flags & _FILE_WRITE)) + return EOF; + unsigned char ch = (unsigned char)c; + ssize_t r = write(f->_fd, &ch, 1); + if (r != 1) { + f->_err = 1; + return EOF; + } + return (unsigned char)c; +} +int fputs(const char *s, FILE *f) { + if (!f || !s || !(f->_flags & _FILE_WRITE)) + return EOF; + size_t len = strlen(s); + ssize_t r = write(f->_fd, s, len); + if (r < 0) { + f->_err = 1; + return EOF; + } + return 0; +} +int feof(FILE *f) { return f ? f->_eof : 1; } +int ferror(FILE *f) { return f ? f->_err : 1; } +void clearerr(FILE *f) { + if (f) { + f->_err = 0; + f->_eof = 0; + } +} - size_t total = sz * n; - ssize_t written = write(f->_fd, buf, total); +long ftell(FILE *f) { + if (!f) + return -1; + off_t pos = lseek(f->_fd, 0, SEEK_CUR); + if (pos == (off_t)-1) + return -1; + if (f->_has_ungetc) + pos--; + return (long)pos; +} - if (written < 0) { f->_err = 1; return 0; } - return (size_t)written / sz; +int fgetpos(FILE *f, fpos_t *pos) { + if (!f || !pos) + return -1; + long p = ftell(f); + if (p == -1) + return -1; + *pos = (fpos_t)p; + return 0; } -char *fgets(char *buf, int n, FILE *f) -{ - if (!f || !buf || n <= 0) return NULL; - if (f->_eof || f->_err) return NULL; - if (!(f->_flags & _FILE_READ)) { f->_err = 1; return NULL; } +int fsetpos(FILE *f, const fpos_t *pos) { + if (!f || !pos) + return -1; + return fseek(f, (long)*pos, SEEK_SET); +} - int i = 0; - while (i < n - 1) { - char c; - ssize_t r = read(f->_fd, &c, 1); - if (r < 0) { f->_err = 1; break; } - if (r == 0) { f->_eof = 1; break; } - buf[i++] = c; - if (c == '\n') break; - } +int fseek(FILE *f, long offset, int whence) { + if (!f) + return -1; + f->_has_ungetc = 0; + off_t r = lseek(f->_fd, (off_t)offset, whence); + if (r == (off_t)-1) + return -1; + f->_eof = 0; + return 0; +} - if (i == 0) return NULL; - buf[i] = '\0'; - return buf; +void rewind(FILE *f) { + fseek(f, 0, SEEK_SET); + f->_err = 0; } +int fflush(FILE *f) { + (void)f; + return 0; +} -int fputc(int c, FILE *f) -{ - if (!f || !(f->_flags & _FILE_WRITE)) return EOF; - unsigned char ch = (unsigned char)c; - ssize_t r = write(f->_fd, &ch, 1); - if (r != 1) { f->_err = 1; return EOF; } - return (unsigned char)c; +int setvbuf(FILE *f, char *buf, int mode, size_t size) { + (void)f; + (void)buf; + (void)mode; + (void)size; + return 0; // successfully doing nothing } -int fputs(const char *s, FILE *f) -{ - if (!f || !s || !(f->_flags & _FILE_WRITE)) return EOF; - size_t len = strlen(s); - ssize_t r = write(f->_fd, s, len); - if (r < 0) { f->_err = 1; return EOF; } - return 0; + +void setbuf(FILE *f, char *buf) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ); } -int feof(FILE *f) { return f ? f->_eof : 1; } -int ferror(FILE *f) { return f ? f->_err : 1; } +int fileno(FILE *f) { return f ? f->_fd : -1; } + +FILE *fdopen(int fd, const char *mode) { + FILE *f = (FILE *)malloc(sizeof(FILE)); + if (!f) + return NULL; + f->_fd = fd; + f->_flags = (mode[0] == 'r') ? _FILE_READ : _FILE_WRITE; + f->_eof = 0; + f->_err = 0; + f->_has_ungetc = 0; + return f; +} -int vfprintf(FILE *f, const char *fmt, va_list ap) -{ - char buf[512]; - int len = vsnprintf(buf, sizeof(buf), fmt, ap); - if (len >= (int)sizeof(buf)) len = (int)sizeof(buf) - 1; - ssize_t r = write(f->_fd, buf, (size_t)len); - if (r < 0) { f->_err = 1; return -1; } - return len; +FILE *freopen(const char *path, const char *mode, FILE *f) { + if (!f) + return NULL; + close(f->_fd); + + int flags = 0; + int fflags = 0; + char m = mode[0]; + int plus = (mode[1] == '+') || (mode[2] == '+'); + + if (m == 'r') { + flags = plus ? O_RDWR : O_RDONLY; + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_READ; + } else if (m == 'w') { + flags = plus ? (O_RDWR | O_CREAT) : (O_WRONLY | O_CREAT); + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_WRITE; + } else if (m == 'a') { + flags = O_WRONLY | O_CREAT; + fflags = _FILE_WRITE; + } + + int fd = open(path, flags); + if (fd < 0) + return NULL; + + f->_fd = fd; + f->_flags = fflags; + f->_eof = 0; + f->_err = 0; + f->_has_ungetc = 0; + + return f; } -int fprintf(FILE *f, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int r = vfprintf(f, fmt, ap); - va_end(ap); - return r; +int vfprintf(FILE *f, const char *fmt, va_list ap) { + char buf[512]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (len >= (int)sizeof(buf)) + len = (int)sizeof(buf) - 1; + ssize_t r = write(f->_fd, buf, (size_t)len); + if (r < 0) { + f->_err = 1; + return -1; + } + return len; } -static int _uitoa(unsigned long v, int base, char *out) -{ - static const char _hex[] = "0123456789abcdef"; - char tmp[32]; - int len = 0; - if (v == 0) { out[0] = '0'; return 1; } - while (v) { tmp[len++] = _hex[v % (unsigned)base]; v /= (unsigned)base; } - for (int i = 0; i < len; i++) out[i] = tmp[len - 1 - i]; - return len; +int fprintf(FILE *f, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vfprintf(f, fmt, ap); + va_end(ap); + return r; } -int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) -{ - size_t pos = 0; - char tmp[32]; - int tlen; +static int _uitoa(unsigned long v, int base, char *out) { + static const char _hex[] = "0123456789abcdef"; + char tmp[32]; + int len = 0; + if (v == 0) { + out[0] = '0'; + return 1; + } + while (v) { + tmp[len++] = _hex[v % (unsigned)base]; + v /= (unsigned)base; + } + for (int i = 0; i < len; i++) + out[i] = tmp[len - 1 - i]; + return len; +} -#define _EMIT(c) do { if (buf && pos + 1 < size) buf[pos] = (c); pos++; } while (0) +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) { + size_t pos = 0; + char tmp[32]; + int tlen; + +#define _EMIT(c) \ + do { \ + if (buf && pos + 1 < size) \ + buf[pos] = (c); \ + pos++; \ + } while (0) + + for (const char *p = fmt; *p; p++) { + if (*p != '%') { + _EMIT(*p); + continue; + } + p++; + if (!*p) + break; + + // width and zero-pad + char pad = ' '; + int width = 0; + int is_long = 0; + + if (*p == '0') { + pad = '0'; + p++; + } + while (*p >= '1' && *p <= '9') { + width = width * 10 + (*p - '0'); + p++; + } + if (*p == 'l') { + is_long = 1; + p++; + } - for (const char *p = fmt; *p; p++) { - if (*p != '%') { _EMIT(*p); continue; } - p++; - if (!*p) break; - - // width and zero-pad - char pad = ' '; - int width = 0; - int is_long = 0; - - if (*p == '0') { pad = '0'; p++; } - while (*p >= '1' && *p <= '9') { width = width * 10 + (*p - '0'); p++; } - if (*p == 'l') { is_long = 1; p++; } - - switch (*p) { - case 's': { - const char *s = va_arg(ap, const char *); - if (!s) s = "(null)"; - while (*s) _EMIT(*s++); - break; - } - case 'd': { - long val = is_long ? va_arg(ap, long) : (long)va_arg(ap, int); - if (val < 0) { _EMIT('-'); val = -val; } - tlen = _uitoa((unsigned long)val, 10, tmp); - for (int i = tlen; i < width; i++) _EMIT(pad); - for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); - tlen = 0; - break; - } - case 'u': { - unsigned long val = is_long ? va_arg(ap, unsigned long) - : (unsigned long)va_arg(ap, unsigned int); - tlen = _uitoa(val, 10, tmp); - for (int i = tlen; i < width; i++) _EMIT(pad); - for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); - tlen = 0; - break; - } - case 'x': { - unsigned long val = is_long ? va_arg(ap, unsigned long) - : (unsigned long)va_arg(ap, unsigned int); - tlen = _uitoa(val, 16, tmp); - for (int i = tlen; i < width; i++) _EMIT(pad); - for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); - tlen = 0; - break; - } - case 'p': { - unsigned long val = (unsigned long)va_arg(ap, void *); - _EMIT('0'); _EMIT('x'); - tlen = _uitoa(val, 16, tmp); - for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); - tlen = 0; - break; - } - case 'c': { - _EMIT((char)va_arg(ap, int)); - break; - } - case '%': { - _EMIT('%'); - break; - } - default: { - _EMIT('%'); - if (is_long) _EMIT('l'); - _EMIT(*p); - break; - } - } + switch (*p) { + case 's': { + const char *s = va_arg(ap, const char *); + if (!s) + s = "(null)"; + while (*s) + _EMIT(*s++); + break; } + case 'i': + case 'd': { + long val = is_long ? va_arg(ap, long) : (long)va_arg(ap, int); + if (val < 0) { + _EMIT('-'); + val = -val; + } + tlen = _uitoa((unsigned long)val, 10, tmp); + for (int i = tlen; i < width; i++) + _EMIT(pad); + for (int i = 0; i < tlen; i++) + _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'u': { + unsigned long val = is_long ? va_arg(ap, unsigned long) + : (unsigned long)va_arg(ap, unsigned int); + tlen = _uitoa(val, 10, tmp); + for (int i = tlen; i < width; i++) + _EMIT(pad); + for (int i = 0; i < tlen; i++) + _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'x': { + unsigned long val = is_long ? va_arg(ap, unsigned long) + : (unsigned long)va_arg(ap, unsigned int); + tlen = _uitoa(val, 16, tmp); + for (int i = tlen; i < width; i++) + _EMIT(pad); + for (int i = 0; i < tlen; i++) + _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'p': { + unsigned long val = (unsigned long)va_arg(ap, void *); + _EMIT('0'); + _EMIT('x'); + tlen = _uitoa(val, 16, tmp); + for (int i = 0; i < tlen; i++) + _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'c': { + _EMIT((char)va_arg(ap, int)); + break; + } + case '%': { + _EMIT('%'); + break; + } + default: { + _EMIT('%'); + if (is_long) + _EMIT('l'); + _EMIT(*p); + break; + } + } + } - if (buf && size > 0) buf[pos < size ? pos : size - 1] = '\0'; - return (int)pos; + if (buf && size > 0) + buf[pos < size ? pos : size - 1] = '\0'; + return (int)pos; #undef _EMIT } - int snprintf(char *buf, size_t size, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - int r = vsnprintf(buf, size, fmt, ap); - va_end(ap); - return r; + va_list ap; + va_start(ap, fmt); + int r = vsnprintf(buf, size, fmt, ap); + va_end(ap); + return r; } int vprintf(const char *fmt, va_list ap) { - char buf[512]; - int len = vsnprintf(buf, sizeof(buf), fmt, ap); - // clamp to actual buffer size to avoid overrun - if (len >= (int)sizeof(buf)) len = (int)sizeof(buf) - 1; - write(STDOUT_FILENO, buf, (size_t)len); - return len; + char buf[512]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + // clamp to actual buffer size to avoid overrun + if (len >= (int)sizeof(buf)) + len = (int)sizeof(buf) - 1; + write(STDOUT_FILENO, buf, (size_t)len); + return len; } int printf(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - int r = vprintf(fmt, ap); - va_end(ap); - return r; + va_list ap; + va_start(ap, fmt); + int r = vprintf(fmt, ap); + va_end(ap); + return r; } int putchar(int c) { - char ch = (char)c; - write(STDOUT_FILENO, &ch, 1); - return (unsigned char)ch; + char ch = (char)c; + write(STDOUT_FILENO, &ch, 1); + return (unsigned char)ch; } int puts(const char *s) { - write(STDOUT_FILENO, s, strlen(s)); - write(STDOUT_FILENO, "\n", 1); - return 0; + write(STDOUT_FILENO, s, strlen(s)); + write(STDOUT_FILENO, "\n", 1); + return 0; } void perror(const char *s) { - // "prefix: error message\n" - if (s && s[0] != '\0') { - write(STDERR_FILENO, s, strlen(s)); - write(STDERR_FILENO, ": ", 2); + // "prefix: error message\n" + if (s && s[0] != '\0') { + write(STDERR_FILENO, s, strlen(s)); + write(STDERR_FILENO, ": ", 2); + } + const char *msg = strerror(errno); + write(STDERR_FILENO, msg, strlen(msg)); + write(STDERR_FILENO, "\n", 1); +} + +int rename(const char *oldpath, const char *newpath) { + (void)oldpath; + (void)newpath; + errno = ENOSYS; + return -1; +} + +int remove(const char *path) { + int r = unlink(path); + if (r < 0 && errno == EISDIR) { + r = rmdir(path); + } + return r; +} + +char *tmpnam(char *s) { + static char buf[L_tmpnam]; + static int counter = 0; + if (!s) + s = buf; + snprintf(s, L_tmpnam, "/tmp/tmp%d", counter++); + return s; +} + +FILE *tmpfile(void) { + char name[L_tmpnam]; + tmpnam(name); + return fopen(name, "w+"); +} + +static int _isspace(int c) { + return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || + c == '\v'); +} + +int vsscanf(const char *str, const char *fmt, va_list ap) { + int count = 0; + const char *p = str; + for (const char *f = fmt; *f; f++) { + if (_isspace(*f)) { + while (*p && _isspace(*p)) + p++; + continue; + } + if (*f != '%') { + if (*p == *f) + p++; + else + break; + continue; + } + f++; + if (*f == '%') { + if (*p == '%') + p++; + else + break; + continue; + } + while (*p && _isspace(*p)) + p++; + if (!*p) + break; + switch (*f) { + case 'c': { + char *c = va_arg(ap, char *); + *c = *p++; + count++; + break; + } + case 's': { + char *s = va_arg(ap, char *); + while (*p && !_isspace(*p)) + *s++ = *p++; + *s = '\0'; + count++; + break; + } + case 'i': + case 'd': { + int *d = va_arg(ap, int *); + long val = 0; + int sign = 1; + if (*p == '-') { + sign = -1; + p++; + } + if (!(*p >= '0' && *p <= '9')) + goto done; + while (*p >= '0' && *p <= '9') + val = val * 10 + (*p++ - '0'); + *d = (int)(val * sign); + count++; + break; + } + case 'u': { + unsigned int *u = va_arg(ap, unsigned int *); + unsigned long val = 0; + while (*p >= '0' && *p <= '9') + val = val * 10 + (*p++ - '0'); + *u = (unsigned int)val; + count++; + break; + } + case 'x': { + unsigned int *x = va_arg(ap, unsigned int *); + unsigned long val = 0; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + p += 2; + while (1) { + if (*p >= '0' && *p <= '9') + val = val * 16 + (*p++ - '0'); + else if (*p >= 'a' && *p <= 'f') + val = val * 16 + (*p++ - 'a' + 10); + else if (*p >= 'A' && *p <= 'F') + val = val * 16 + (*p++ - 'A' + 10); + else + break; + } + *x = (unsigned int)val; + count++; + break; } - const char *msg = strerror(errno); - write(STDERR_FILENO, msg, strlen(msg)); - write(STDERR_FILENO, "\n", 1); + default: + goto done; + } + } +done: + return count; +} + +int sscanf(const char *str, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vsscanf(str, fmt, ap); + va_end(ap); + return r; +} + +int vfscanf(FILE *f, const char *fmt, va_list ap) { + char buf[1024]; + if (!fgets(buf, sizeof(buf), f)) + return 0; + return vsscanf(buf, fmt, ap); +} + +int fscanf(FILE *f, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vfscanf(f, fmt, ap); + va_end(ap); + return r; +} + +int vscanf(const char *fmt, va_list ap) { return vfscanf(stdin, fmt, ap); } + +int scanf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vscanf(fmt, ap); + va_end(ap); + return r; } \ No newline at end of file diff --git a/src/userspace/libc/src/stdlib.c b/src/userspace/libc/src/stdlib.c index 3afff677..fc67d568 100644 --- a/src/userspace/libc/src/stdlib.c +++ b/src/userspace/libc/src/stdlib.c @@ -6,6 +6,15 @@ // bump allocator via brk static char *_heap = NULL; +static void (*_atexit_funcs[32])(void); +static int _atexit_count = 0; + +int atexit(void (*func)(void)) { + if (_atexit_count >= 32) return -1; + _atexit_funcs[_atexit_count++] = func; + return 0; +} + void *malloc(size_t n) { if (!n) return NULL; @@ -37,9 +46,17 @@ void free(void *ptr) { (void)ptr; } // no-op with bump allocator // _exit in unistd.c extern void _exit(int status) __attribute__((noreturn)); -void exit(int status) { _exit(status); __builtin_unreachable(); } +void exit(int status) { + for (int i = _atexit_count - 1; i >= 0; i--) { + if (_atexit_funcs[i]) _atexit_funcs[i](); + } + _exit(status); + __builtin_unreachable(); +} -void abort(void) { _exit(1); } +void abort(void) { + exit(EXIT_FAILURE); +} long strtol(const char *s, char **end, int base) { while (*s == ' ') s++; @@ -66,5 +83,80 @@ long strtol(const char *s, char **end, int base) { int atoi(const char *s) { return (int)strtol(s, NULL, 10); } long atol(const char *s) { return strtol(s, NULL, 10); } -int abs (int x) { return x < 0 ? -x : x; } -long labs(long x) { return x < 0 ? -x : x; } +long long atoll(const char *s) { return (long long)strtol(s, NULL, 10); } +double atof(const char *s) { (void)s; return 0.0; } // No float support yet + +unsigned long strtoul(const char *s, char **end, int base) { return (unsigned long)strtol(s, end, base); } +long long strtoll(const char *s, char **end, int base) { return (long long)strtol(s, end, base); } +unsigned long long strtoull(const char *s, char **end, int base) { return (unsigned long long)strtol(s, end, base); } + +int abs(int x) { return x < 0 ? -x : x; } +long labs(long x) { return x < 0 ? -x : x; } +long long llabs(long long x) { return x < 0 ? -x : x; } + +div_t div(int numer, int denom) { return (div_t){ numer / denom, numer % denom }; } +ldiv_t ldiv(long numer, long denom) { return (ldiv_t){ numer / denom, numer % denom }; } +lldiv_t lldiv(long long numer, long long denom) { return (lldiv_t){ numer / denom, numer % denom }; } + + +static unsigned long _next = 1; +int rand(void) { + _next = _next * 1103515245 + 12345; + return (int)((_next / 65536) % 32768); +} +void srand(unsigned int seed) { + _next = seed; +} + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + if (nmemb < 2) return; + for (size_t gap = nmemb / 2; gap > 0; gap /= 2) { + for (size_t i = gap; i < nmemb; i++) { + for (size_t j = i; j >= gap; j -= gap) { + char *a = (char *)base + (j - gap) * size; + char *b = (char *)base + j * size; + if (compar(a, b) <= 0) break; + for (size_t k = 0; k < size; k++) { char t = a[k]; a[k] = b[k]; b[k] = t; } + } + } + } +} + +void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + size_t l = 0, r = nmemb; + while (l < r) { + size_t m = l + (r - l) / 2; + const void *p = (const char *)base + m * size; + int res = compar(key, p); + if (res == 0) return (void *)p; + if (res < 0) r = m; + else l = m + 1; + } + return NULL; +} + +char **environ = NULL; + +char *getenv(const char *name) { + if (!environ || !name) return NULL; + size_t len = strlen(name); + for (char **p = environ; *p; p++) { + if (strncmp(*p, name, len) == 0 && (*p)[len] == '=') return *p + len + 1; + } + return NULL; +} + +int setenv(const char *name, const char *value, int overwrite) { + (void)name; (void)value; (void)overwrite; + errno = ENOSYS; return -1; +} + +int unsetenv(const char *name) { + (void)name; + errno = ENOSYS; return -1; +} + +int system(const char *command) { + (void)command; + errno = ENOSYS; return -1; +} diff --git a/src/userspace/libc/src/string.c b/src/userspace/libc/src/string.c index 4e2f60c6..df895d72 100644 --- a/src/userspace/libc/src/string.c +++ b/src/userspace/libc/src/string.c @@ -1,6 +1,7 @@ #include #include #include +#include void *memcpy(void *dst, const void *src, size_t n) { unsigned char *d = dst; const unsigned char *s = src; @@ -119,3 +120,19 @@ char *strdup(const char *s) { if (p) memcpy(p, s, n); return p; } + +int strcasecmp(const char *s1, const char *s2) { + while (*s1 && tolower((unsigned char)*s1) == tolower((unsigned char)*s2)) { + s1++; s2++; + } + return tolower((unsigned char)*s1) - tolower((unsigned char)*s2); +} + +int strncasecmp(const char *s1, const char *s2, size_t n) { + for (size_t i = 0; i < n; i++) { + if (tolower((unsigned char)s1[i]) != tolower((unsigned char)s2[i])) + return tolower((unsigned char)s1[i]) - tolower((unsigned char)s2[i]); + if (!s1[i]) return 0; + } + return 0; +} diff --git a/src/userspace/libc/src/time.c b/src/userspace/libc/src/time.c new file mode 100644 index 00000000..af2a018e --- /dev/null +++ b/src/userspace/libc/src/time.c @@ -0,0 +1,18 @@ +#include +#include "_syscall.h" + +time_t time(time_t *t) { + long ms = _sc1(_SCAL_GETTIME, 0); + time_t s = ms / 1000; + if (t) *t = s; + return s; +} + +int gettimeofday(struct timeval *tv, struct timezone *tz) { + if (!tv) return -1; + long ms = _sc1(_SCAL_GETTIME, 0); + tv->tv_sec = ms / 1000; + tv->tv_usec = (ms % 1000) * 1000; + (void)tz; + return 0; +} diff --git a/src/userspace/libc/src/unistd.c b/src/userspace/libc/src/unistd.c index 378f6718..00c34246 100644 --- a/src/userspace/libc/src/unistd.c +++ b/src/userspace/libc/src/unistd.c @@ -11,6 +11,10 @@ ssize_t write(int fd, const void *buf, size_t n) { return (ssize_t)_sc3(_SCAL_WRITE, fd, (long)buf, (long)n); } +off_t lseek(int fd, off_t offset, int whence) { + return (off_t)_sc3(_SCAL_LSEEK, fd, (long)offset, (long)whence); +} + pid_t getpid(void) { return (pid_t)_sc1(_SCAL_GETPID, 0); } pid_t fork(void) { return (pid_t)_sc0(_SCAL_FORK); } @@ -27,7 +31,7 @@ int execve(const char *path, char *const argv[], char *const envp[]) { int chdir(const char *path) { return (int)_sc1(_SCAL_CHDIR, (long)path); } -int mkdir(const char *path) { return (int)_sc1(_SCAL_MKDIR, (long)path); } +int mkdir(const char *path, mode_t mode) { (void)mode; return (int)_sc1(_SCAL_MKDIR, (long)path); } int rmdir(const char *path) { return (int)_sc1(_SCAL_UNLINK, (long)path); } @@ -37,3 +41,12 @@ char *getcwd(char *buf, size_t size) { long r = _sc2(_SCAL_GETCWD, (long)buf, (long)size); return (r > 0) ? buf : NULL; } + +int usleep(useconds_t usec) { + if (usec == 0) return 0; + long start_ms = _sc1(_SCAL_GETTIME, 0); + long target_ms = start_ms + (usec / 1000); + if (target_ms == start_ms) target_ms++; + while (_sc1(_SCAL_GETTIME, 0) < target_ms); + return 0; +} diff --git a/src/userspace/libs/libvad/libvad.a b/src/userspace/libs/libvad/libvad.a index 3d86519a..7e08ad8d 100644 Binary files a/src/userspace/libs/libvad/libvad.a and b/src/userspace/libs/libvad/libvad.a differ diff --git a/tools/build-doom.sh b/tools/build-doom.sh new file mode 100755 index 00000000..1f81176c --- /dev/null +++ b/tools/build-doom.sh @@ -0,0 +1,141 @@ +#!/bin/bash +set -e + +# Configuration +REPO_URL="https://github.com/ozkl/doomgeneric.git" +WAD_MIRRORS=( + "https://github.com/Doom-Generic/doomgeneric/raw/master/doom1.wad" + "https://github.com/varkon/linux-doom/raw/master/doom/doom1.wad" +) +APPS_DIR="src/userspace/apps" +DOOM_DIR="$APPS_DIR/doom" + +echo "[DOOM] Initializing Doom port..." + +mkdir -p "$DOOM_DIR" + +# 1. Clone doomgeneric source +if [ ! -f "$DOOM_DIR/doomgeneric.c" ]; then + echo "[DOOM] Cloning doomgeneric..." + TEMP_CLONE=$(mktemp -d) + git clone "$REPO_URL" "$TEMP_CLONE" + cp -r "$TEMP_CLONE/doomgeneric"/* "$DOOM_DIR/" + rm -rf "$TEMP_CLONE" +fi + +# 2. Get the WAD +if [ ! -f "$DOOM_DIR/doom1.wad" ]; then + echo "[DOOM] Downloading doom1.wad..." + DOWNLOADED=false + for url in "${WAD_MIRRORS[@]}"; do + if wget "$url" -O "$DOOM_DIR/doom1.wad"; then + DOWNLOADED=true + break + fi + done + if [ "$DOWNLOADED" = false ]; then + echo "[WARNING] Could not download doom1.wad automatically." + fi +fi + +# 3. Create EmexOS Backend with main loop and stubs +echo "[DOOM] Creating Doom backend for EmexOS..." +cat < "$DOOM_DIR/doom_emex.c" +#include "doomgeneric.h" +#include +#include +#include +#include + +void DG_Init() { + printf("Doom: Initializing EmexOS backend...\n"); +} + +void DG_DrawFrame() { + // Current framebuffer logic: stub +} + +void DG_SleepMs(uint32_t ms) { + usleep(ms * 1000); +} + +uint32_t DG_GetTicksMs() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +int DG_GetKey(int* pressed, unsigned char* key) { + (void)pressed; (void)key; + return 0; +} + +void DG_SetWindowTitle(const char * title) { + printf("Doom: %s\n", title); +} + +// Missing stubs +void I_InitJoystick() {} +void I_BindJoystickVariables() {} +void I_Endoom() {} + +int main(int argc, char **argv) { + doomgeneric_Create(argc, argv); + while (1) { + doomgeneric_Tick(); + } + return 0; +} +EOF + +# 4. Create Makefile +echo "[DOOM] Creating Makefile..." +cat < "$DOOM_DIR/Makefile" +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc +LIBGCC := \$(shell \$(CC) -print-libgcc-file-name) + +RESX := 320 +RESY := 200 + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \\ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-red-zone -Wall -Wextra \\ + -msoft-float -std=gnu11 \\ + -I\$(LIBC)/include -DDOOMGENERIC_RESX=\$(RESX) -DDOOMGENERIC_RESY=\$(RESY) + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +# Exclude other platform backends and unnecessary files +EXCLUDE := doomgeneric_allegro.c doomgeneric_emscripten.c doomgeneric_linuxvt.c \\ + doomgeneric_sdl.c doomgeneric_soso.c doomgeneric_sosox.c \\ + doomgeneric_win.c doomgeneric_xlib.c \\ + i_allegromusic.c i_allegrosound.c i_sdlmusic.c i_sdlsound.c \\ + i_cdmus.c i_endoom.c i_joystick.c + +SRCS := \$(filter-out \$(EXCLUDE), \$(wildcard *.c)) +OBJS := \$(SRCS:.c=.o) + +all: doom.elf + +doom.elf: \$(OBJS) \$(LIBC)/build/crt0.o \$(LIBC)/build/libc.a + \$(LD) \$(LDFLAGS) \$(LIBC)/build/crt0.o \$(OBJS) \$(LIBC)/build/libc.a \$(LIBGCC) -o \$@ + +%.o: %.c + \$(CC) \$(CFLAGS) -c \$< -o \$@ + +clean: + rm -f *.o doom.elf + +.PHONY: all clean +EOF + +# 5. Build +echo "[DOOM] Building..." +make -C "$DOOM_DIR" clean +if make -C "$DOOM_DIR"; then + echo "[DOOM] Porting complete! doom.elf created in $DOOM_DIR" +else + echo "[ERROR] Doom build failed." + exit 1 +fi