+ 内存管理与按需分页(Demand Paging)
+ 键盘输入
+ 多进程
-+ 47个常见的Linux/POSIX系统调用([附录1](#appendix1))
++ 50个常见的Linux/POSIX系统调用([附录1](#appendix1))
+ 用户模式
+ 信号机制
+ PCI 3.0
+ [ECMA-119 (ISO9660)](https://www.ecma-international.org/publications-and-standards/standards/ecma-119/)
+ Rock Ridge Interchange Protocol (RRIP: IEEE P1282)
+ System Use Sharing Protocol (SUSP: IEEE P1281)
++ Tool Interface Standard (TIS) Portable Formats Specification (Version 1.1)
**免责声明:PCI相关的标准最终解释权归PCI-SIG所有。此处提供的副本仅供个人学习使用。任何商用目的须向PCI-SIG购买。**
2. `write(2)`
2. `open(2)`
2. `close(2)`
-2. `mkdir(2)`※
+2. `mkdir(2)`
2. `lseek(2)`
2. `readdir(2)`
2. `readlink(2)`※
2. `ioctl(2)`
2. `getpgid(2)`
2. `setpgid(2)`
+2. `mmap(2)`
+2. `munmap(2)`
+2. `execve(2)`
**LunaixOS自有**
+ Memory management & demand paging
+ PS/2 Keyboard support
+ Muti-tasking and task management
-+ 47 commonly used POSIX syscall([See Appendix 1](#appendix1))
++ 50 commonly used POSIX syscall([See Appendix 1](#appendix1))
+ User Space
+ Signal
+ PCI 3.0
+ [ECMA-119 (ISO9660)](https://www.ecma-international.org/publications-and-standards/standards/ecma-119/)
+ Rock Ridge Interchange Protocol (RRIP: IEEE P1282)
+ System Use Sharing Protocol (SUSP: IEEE P1281)
++ Tool Interface Standard (TIS) Portable Formats Specification (Version 1.1)
**DISCLAIMER: All rights of PCI-related specification is reserved by PCI-SIG. It is provided ONLY for learning purpose. Any commercial use should purchase a copy from PCI-SIG**
2. `write(2)`
2. `open(2)`
2. `close(2)`
-2. `mkdir(2)`※
+2. `mkdir(2)`
2. `lseek(2)`
2. `readdir(2)`
2. `readlink(2)`※
2. `setxattr(2)`※
2. `fgetxattr(2)`※
2. `fsetxattr(2)`※
-2. `ioctl(2)`※
+2. `ioctl(2)`
2. `getpgid(2)`
2. `setpgid(2)`
+2. `mmap(2)`
+2. `munmap(2)`
+2. `execve(2)`
**LunaixOS**
bx_enh_dbg.ini
machine/
draft/
-iso_inspect/
\ No newline at end of file
+iso_inspect/
+unused/
\ No newline at end of file
{
"name": "OS-DEV",
"includePath": [
- "${workspaceFolder}/includes"
+ "${workspaceFolder}/includes",
+ "${workspaceFolder}/usr/includes"
],
"compilerArgs": [
"-ffreestanding",
movl %eax, %cr3
movl %cr0, %eax
- orl $0x80010000, %eax /* 开启分页与地址转换 (CR0.PG=1, CR0.WP=1) */
+ orl $0x80000000, %eax /* 开启分页与地址转换 (CR0.PG=1, CR0.WP=0) */
andl $0xfffffffb, %eax
orl $0x2, %eax /* 启用x87 FPU (CR0.MP=1, CR0.EM=0) */
movl %eax, %cr0
CC := i686-elf-gcc
AS := i686-elf-as
+AR := i686-elf-ar
ARCH_OPT := -D__ARCH_IA32 -include flags.h
-fno-cse-follow-jumps\
-fno-cse-skip-blocks\
-fno-optimize-strlen\
- -fno-tree-builtin-call-dce
+ -fno-inline-functions-called-once \
+ -fno-inline-functions \
+ -fno-inline-small-functions \
+ -fno-indirect-inlining
CFLAGS := -std=gnu99 -ffreestanding $(O) $(OFLAGS) $(W) $(ARCH_OPT)
LDFLAGS := -ffreestanding $(O) -nostdlib -lgcc
\ No newline at end of file
OBJECT_DIR := $(BUILD_DIR)/obj
BIN_DIR := $(BUILD_DIR)/bin
ISO_DIR := $(BUILD_DIR)/iso
+USR_DIR := $(BUILD_DIR)/usr
ISO_BOOT_DIR := $(ISO_DIR)/boot
ISO_GRUB_DIR := $(ISO_BOOT_DIR)/grub
-INCLUDES_DIR := includes
\ No newline at end of file
+INCLUDES := -Iincludes -Iusr/includes
\ No newline at end of file
OS_ARCH := x86
-OS_NAME = lunaix
-OS_BIN = $(OS_NAME).bin
-OS_ISO = $(OS_NAME).iso
\ No newline at end of file
+OS_NAME := lunaix
+OS_BIN := $(OS_NAME).bin
+OS_ISO := $(OS_NAME).iso
+
+USR_LIB := liblxusrt.a
\ No newline at end of file
char c;
if (sdbg_state == SDBG_STATE_WAIT_BRK) {
- (param)->eflags &= ~(1 << 8);
+ (param)->execp->eflags &= ~(1 << 8);
sdbg_state = SDBG_STATE_INSESSION;
- sdbg_printf("[%p:%p] Break point reached.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Break point reached.\n",
+ param->execp->cs,
+ param->execp->eip);
}
while (1) {
switch (c) {
case SDBG_CLNT_HI:
if (sdbg_state == SDBG_STATE_START) {
- sdbg_printf(
- "[%p:%p] Session started.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Session started.\n",
+ param->execp->cs,
+ param->execp->eip);
sdbg_state = SDBG_STATE_INSESSION;
} else {
- sdbg_printf(
- "[%p:%p] Session resumed.\n", param->cs, param->eip);
+ sdbg_printf("[%p:%p] Session resumed.\n",
+ param->execp->cs,
+ param->execp->eip);
}
break;
case SDBG_CLNT_RREG:
serial_tx_buffer(SERIAL_COM1, (char*)param, sizeof(isr_param));
break;
case SDBG_CLNT_STEP:
- ((isr_param*)param)->eflags |= (1 << 8); // set TF flags
+ ((isr_param*)param)->execp->eflags |= (1 << 8); // set TF flags
sdbg_state = SDBG_STATE_WAIT_BRK;
return;
case SDBG_CLNT_BRKP:
gdbstub_loop(isr_param* param)
{
/* Translate vector to signal */
- switch (param->vector) {
+ switch (param->execp->vector) {
case 1:
gdb_state.signum = 5;
break;
gdb_state.registers[GDB_CPU_I386_REG_ECX] = param->registers.ecx;
gdb_state.registers[GDB_CPU_I386_REG_EDX] = param->registers.edx;
gdb_state.registers[GDB_CPU_I386_REG_EBX] = param->registers.ebx;
- gdb_state.registers[GDB_CPU_I386_REG_ESP] = param->registers.esp;
+ gdb_state.registers[GDB_CPU_I386_REG_ESP] = param->esp;
gdb_state.registers[GDB_CPU_I386_REG_EBP] = param->registers.ebp;
gdb_state.registers[GDB_CPU_I386_REG_ESI] = param->registers.esi;
gdb_state.registers[GDB_CPU_I386_REG_EDI] = param->registers.edi;
- gdb_state.registers[GDB_CPU_I386_REG_PC] = param->eip;
- gdb_state.registers[GDB_CPU_I386_REG_CS] = param->cs;
- gdb_state.registers[GDB_CPU_I386_REG_PS] = param->eflags;
- gdb_state.registers[GDB_CPU_I386_REG_SS] = param->ss;
+ gdb_state.registers[GDB_CPU_I386_REG_PC] = param->execp->eip;
+ gdb_state.registers[GDB_CPU_I386_REG_CS] = param->execp->cs;
+ gdb_state.registers[GDB_CPU_I386_REG_PS] = param->execp->eflags;
+ gdb_state.registers[GDB_CPU_I386_REG_SS] = param->execp->ss;
gdb_state.registers[GDB_CPU_I386_REG_DS] = param->registers.ds;
gdb_state.registers[GDB_CPU_I386_REG_ES] = param->registers.es;
gdb_state.registers[GDB_CPU_I386_REG_FS] = param->registers.fs;
param->registers.ecx = gdb_state.registers[GDB_CPU_I386_REG_ECX];
param->registers.edx = gdb_state.registers[GDB_CPU_I386_REG_EDX];
param->registers.ebx = gdb_state.registers[GDB_CPU_I386_REG_EBX];
- param->registers.esp = gdb_state.registers[GDB_CPU_I386_REG_ESP];
+ param->esp = gdb_state.registers[GDB_CPU_I386_REG_ESP];
param->registers.ebp = gdb_state.registers[GDB_CPU_I386_REG_EBP];
param->registers.esi = gdb_state.registers[GDB_CPU_I386_REG_ESI];
param->registers.edi = gdb_state.registers[GDB_CPU_I386_REG_EDI];
- param->eip = gdb_state.registers[GDB_CPU_I386_REG_PC];
- param->cs = gdb_state.registers[GDB_CPU_I386_REG_CS];
- param->eflags = gdb_state.registers[GDB_CPU_I386_REG_PS];
- param->ss = gdb_state.registers[GDB_CPU_I386_REG_SS];
+ param->execp->eip = gdb_state.registers[GDB_CPU_I386_REG_PC];
+ param->execp->cs = gdb_state.registers[GDB_CPU_I386_REG_CS];
+ param->execp->eflags = gdb_state.registers[GDB_CPU_I386_REG_PS];
+ param->execp->ss = gdb_state.registers[GDB_CPU_I386_REG_SS];
param->registers.ds = gdb_state.registers[GDB_CPU_I386_REG_DS];
param->registers.es = gdb_state.registers[GDB_CPU_I386_REG_ES];
param->registers.fs = gdb_state.registers[GDB_CPU_I386_REG_FS];
// synchronized way. And we don't want these irq queue up at our APIC and
// confuse the CPU after ACK with APIC.
serial_disable_irq(SERIAL_COM1);
- if (param->vector == 1 || param->vector == 3) {
+ struct exec_param* execp = param->execp;
+ if (execp->vector == 1 || execp->vector == 3) {
goto cont;
}
void
sdbg_imm(const isr_param* param)
{
+ struct exec_param* execp = param->execp;
kprintf(KDEBUG "Quick debug mode\n");
kprintf(KDEBUG "cs=%p eip=%p eax=%p ebx=%p\n",
- param->cs,
- param->eip,
+ execp->cs,
+ execp->eip,
param->registers.eax,
param->registers.ebx);
kprintf(KDEBUG "ecx=%p edx=%p edi=%p esi=%p\n",
param->registers.edi,
param->registers.esi);
kprintf(KDEBUG "u.esp=%p k.esp=%p ebp=%p ps=%p\n",
- param->registers.esp,
param->esp,
+ execp->esp,
param->registers.ebp,
- param->eflags);
+ execp->eflags);
kprintf(KDEBUG "ss=%p ds=%p es=%p fs=%p gs=%p\n",
- param->ss,
+ execp->ss,
param->registers.ds,
param->registers.es,
param->registers.fs,
struct ahci_driver *pos, *n;
llist_for_each(pos, n, &ahcis, ahci_drvs)
{
- if (pos->id == param->vector) {
+ if (pos->id == param->execp->vector) {
hba = &pos->hba;
goto proceed;
}
#ifndef __ASM__
#include <hal/cpu.h>
+
+struct exec_param;
+
typedef struct
{
+ unsigned int depth;
struct
{
reg32 eax;
reg32 es;
reg32 fs;
reg32 gs;
- reg32 esp;
} __attribute__((packed)) registers;
+ union
+ {
+ reg32 esp;
+ volatile struct exec_param* execp;
+ };
+} __attribute__((packed)) isr_param;
+
+struct exec_param
+{
+ isr_param saved_prev_ctx;
unsigned int vector;
unsigned int err_code;
unsigned int eip;
unsigned int eflags;
unsigned int esp;
unsigned int ss;
-} __attribute__((packed)) isr_param;
+} __attribute__((packed));
+
+#define ISR_PARAM_SIZE sizeof(isr_param)
void
intr_handler(isr_param* param);
"subl $4, %1\n"
"jnz 1b" ::"r"((ptr_t)data),
"r"((len & ~0x3))
- : "%al");
+ : "%eax");
}
int
#define MEM_1MB 0x100000
#define MEM_4MB 0x400000
+#define USER_START 0x400000
+
#define KSTACK_SIZE MEM_1MB
-#define KSTACK_START ((0x3FFFFFU - KSTACK_SIZE) + 1)
-#define KSTACK_TOP 0x3FFFF0U
+#define KSTACK_START (USER_START - KSTACK_SIZE)
+#define KSTACK_TOP ((USER_START - 1) & ~0xf)
#define KERNEL_MM_BASE 0xC0000000
#define UDATA_SEG 0x23
#define TSS_SEG 0x28
-#define USER_START 0x400000
-#define USTACK_SIZE 0x100000
+#define USTACK_SIZE MEM_4MB
#define USTACK_TOP 0x9ffffff0
#define USTACK_END (0x9fffffff - USTACK_SIZE + 1)
-#define UMMAP_AREA 0x4D000000
+#define UMMAP_START 0x4D000000
+#define UMMAP_END (USTACK_END - MEM_4MB)
#ifndef __ASM__
#include <stddef.h>
__llist_add(elem, head, head->next);
}
+static inline void
+llist_insert_after(struct llist_header* head, struct llist_header* elem)
+{
+ __llist_add(elem, head, head->next);
+}
+
static inline void
llist_delete(struct llist_header* elem)
{
--- /dev/null
+#ifndef __LUNAIX_ELF_H
+#define __LUNAIX_ELF_H
+
+#include <lunaix/types.h>
+
+typedef unsigned int elf32_ptr_t;
+typedef unsigned short elf32_hlf_t;
+typedef unsigned int elf32_off_t;
+typedef unsigned int elf32_swd_t;
+typedef unsigned int elf32_wrd_t;
+
+#define ET_NONE 0
+#define ET_EXEC 2
+
+#define PT_LOAD 1
+
+#define PF_X 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+
+#define EM_NONE 0
+#define EM_386 3
+
+#define EV_CURRENT 1
+
+// [0x7f, 'E', 'L', 'F']
+#define ELFMAGIC 0x464c457fU
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EI_CLASS 4
+#define EI_DATA 5
+
+struct elf32_ehdr
+{
+ u8_t e_ident[16];
+ elf32_hlf_t e_type;
+ elf32_hlf_t e_machine;
+ elf32_wrd_t e_version;
+ elf32_ptr_t e_entry;
+ elf32_off_t e_phoff;
+ elf32_off_t e_shoff;
+ elf32_wrd_t e_flags;
+ elf32_hlf_t e_ehsize;
+ elf32_hlf_t e_phentsize;
+ elf32_hlf_t e_phnum;
+ elf32_hlf_t e_shentsize;
+ elf32_hlf_t e_shnum;
+ elf32_hlf_t e_shstrndx;
+};
+
+struct elf32_phdr
+{
+ elf32_wrd_t p_type;
+ elf32_off_t p_offset;
+ elf32_ptr_t p_va;
+ elf32_ptr_t p_pa;
+ elf32_wrd_t p_filesz;
+ elf32_wrd_t p_memsz;
+ elf32_wrd_t p_flags;
+ elf32_wrd_t p_align;
+};
+
+#define SIZE_EHDR sizeof(struct elf32_ehdr)
+#define SIZE_PHDR sizeof(struct elf32_phdr)
+
+static inline int
+elf_check_exec(struct elf32_ehdr* ehdr)
+{
+ return *(u32_t*)(ehdr->e_ident) == ELFMAGIC &&
+ ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
+ ehdr->e_ident[EI_DATA] == ELFDATA2LSB && ehdr->e_type == ET_EXEC &&
+ ehdr->e_machine == EM_386;
+}
+#endif /* __LUNAIX_ELF_H */
+++ /dev/null
-#ifndef __LUNAIX_FCTRL_H
-#define __LUNAIX_FCTRL_H
-
-#include <lunaix/dirent.h>
-#include <lunaix/syscall.h>
-#include <stddef.h>
-
-__LXSYSCALL2(int, open, const char*, path, int, options)
-
-__LXSYSCALL1(int, mkdir, const char*, path)
-__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
-
-__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
-
-__LXSYSCALL4(int,
- readlinkat,
- int,
- dirfd,
- const char*,
- pathname,
- char*,
- buf,
- size_t,
- size)
-
-__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
-
-__LXSYSCALL4(int,
- mount,
- const char*,
- source,
- const char*,
- target,
- const char*,
- fstype,
- int,
- options)
-
-__LXSYSCALL1(int, unmount, const char*, target)
-
-__LXSYSCALL4(int,
- getxattr,
- const char*,
- path,
- const char*,
- name,
- void*,
- value,
- size_t,
- len)
-
-__LXSYSCALL4(int,
- setxattr,
- const char*,
- path,
- const char*,
- name,
- void*,
- value,
- size_t,
- len)
-
-__LXSYSCALL4(int,
- fgetxattr,
- int,
- fd,
- const char*,
- name,
- void*,
- value,
- size_t,
- len)
-
-__LXSYSCALL4(int,
- fsetxattr,
- int,
- fd,
- const char*,
- name,
- void*,
- value,
- size_t,
- len)
-
-#endif /* __LUNAIX_FCTRL_H */
#ifndef __LUNAIX_FOPTIONS_H
#define __LUNAIX_FOPTIONS_H
-#define FO_CREATE 0x1
-#define FO_APPEND 0x2
-#define FO_DIRECT 0x4
-
-#define FSEEK_SET 0x1
-#define FSEEK_CUR 0x2
-#define FSEEK_END 0x3
-
-#define MNT_RO 0x1
+#include <fcntl_defs.h>
#endif /* __LUNAIX_FOPTIONS_H */
#include <lunaix/ds/llist.h>
#include <lunaix/ds/lru.h>
#include <lunaix/ds/mutex.h>
-#include <lunaix/process.h>
#include <lunaix/status.h>
#include <stdatomic.h>
#define FSTYPE_ROFS 0x1
-#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
-#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
-
#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
#define VFS_VALID_CHAR(chr) \
void
vfs_ref_dnode(struct v_dnode* dnode);
+void
+vfs_ref_file(struct v_file* file);
+
void
vfs_unref_dnode(struct v_dnode* dnode);
#ifndef __LUNAIX_IOCTL_H
#define __LUNAIX_IOCTL_H
-#include <lunaix/syscall.h>
-
-#define IOREQ(cmd, arg_num) ((((cmd)&0xffff) << 8) | ((arg_num)&0xff))
-
-#define IOCMD(req) ((req) >> 8)
-
-#define IOARGNUM(req) ((req)&0xff)
-
-#define TIOCGPGRP IOREQ(1, 0)
-#define TIOCSPGRP IOREQ(1, 1)
-#define TIOCCLSBUF IOREQ(2, 0)
-#define TIOCFLUSH IOREQ(3, 0)
-
-__LXSYSCALL2_VARG(int, ioctl, int, fd, int, req);
+#include <sys/ioctl_defs.h>
#endif /* __LUNAIX_IOCTL_H */
--- /dev/null
+#ifndef __LUNAIX_LOADER_H
+#define __LUNAIX_LOADER_H
+
+#include <lunaix/elf.h>
+#include <lunaix/process.h>
+#include <lunaix/types.h>
+
+#define LD_STAT_FKUP 0x1U
+
+#define MAX_VAR_PAGES 8
+#define DEFAULT_HEAP_PAGES 16
+
+struct ld_info
+{
+ struct elf32_ehdr ehdr_out;
+ ptr_t base;
+ ptr_t end;
+ ptr_t mem_sz;
+
+ ptr_t stack_top;
+ ptr_t entry;
+};
+
+struct ld_param
+{
+ struct proc_info* proc;
+ ptr_t vms_mnt;
+
+ struct ld_info info;
+ int status;
+};
+
+struct usr_exec_param
+{
+ int argc;
+ char** argv;
+ int envc;
+ char** envp;
+ struct ld_info info;
+} PACKED;
+
+#ifndef __USR_WRAPPER__
+int
+elf_load(struct ld_param* ldparam, struct v_file* elfile);
+
+int
+exec_load_byname(struct ld_param* param,
+ const char* filename,
+ const char** argv,
+ const char** envp);
+
+int
+exec_load(struct ld_param* param,
+ struct v_file* executable,
+ const char** argv,
+ const char** envp);
+
+void
+ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms);
+#endif
+
+#endif /* __LUNAIX_LOADER_H */
+++ /dev/null
-#ifndef __LUNAIX_UNISTD_H
-#define __LUNAIX_UNISTD_H
-
-#include <lunaix/syscall.h>
-#include <lunaix/types.h>
-#include <stddef.h>
-
-__LXSYSCALL(pid_t, fork)
-
-__LXSYSCALL1(int, sbrk, void*, addr)
-
-__LXSYSCALL1(void*, brk, unsigned long, size)
-
-__LXSYSCALL(pid_t, getpid)
-
-__LXSYSCALL(pid_t, getppid)
-
-__LXSYSCALL(pid_t, getpgid)
-
-__LXSYSCALL2(pid_t, setpgid, pid_t, pid, pid_t, pgid)
-
-__LXSYSCALL1(void, _exit, int, status)
-
-__LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
-
-__LXSYSCALL(int, pause)
-
-__LXSYSCALL2(int, kill, pid_t, pid, int, signum)
-
-__LXSYSCALL1(unsigned int, alarm, unsigned int, seconds)
-
-__LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
-
-__LXSYSCALL1(int, rmdir, const char*, pathname)
-
-__LXSYSCALL3(int, read, int, fd, void*, buf, unsigned int, count)
-
-__LXSYSCALL3(int, write, int, fd, void*, buf, unsigned int, count)
-
-__LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
-
-__LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
-
-__LXSYSCALL1(int, unlink, const char*, pathname)
-
-__LXSYSCALL1(int, close, int, fd)
-
-__LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
-
-__LXSYSCALL1(int, dup, int, oldfd)
-
-__LXSYSCALL1(int, fsync, int, fildes)
-
-__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
-
-__LXSYSCALL1(int, chdir, const char*, path)
-
-__LXSYSCALL1(int, fchdir, int, fd)
-
-__LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
-
-__LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
-
-#endif /* __LUNAIX_UNISTD_H */
+++ /dev/null
-#ifndef __LUNAIX_LXSIGNAL_H
-#define __LUNAIX_LXSIGNAL_H
-
-#include <lunaix/types.h>
-
-int
-signal_send(pid_t pid, int signum);
-
-#endif /* __LUNAIX_LXSIGNAL_H */
+++ /dev/null
-#ifndef __LUNAIX_DMM_H
-#define __LUNAIX_DMM_H
-// Dynamic Memory (i.e., heap) Manager
-
-#include <lunaix/mm/mm.h>
-#include <lunaix/process.h>
-#include <stddef.h>
-
-#define M_ALLOCATED 0x1
-#define M_PREV_FREE 0x2
-
-#define M_NOT_ALLOCATED 0x0
-#define M_PREV_ALLOCATED 0x0
-
-#define CHUNK_S(header) ((header) & ~0x3)
-#define CHUNK_PF(header) ((header)&M_PREV_FREE)
-#define CHUNK_A(header) ((header)&M_ALLOCATED)
-
-#define PACK(size, flags) (((size) & ~0x3) | (flags))
-
-#define SW(p, w) (*((u32_t*)(p)) = w)
-#define LW(p) (*((u32_t*)(p)))
-
-#define HPTR(bp) ((u32_t*)(bp)-1)
-#define BPTR(bp) ((uint8_t*)(bp) + WSIZE)
-#define FPTR(hp, size) ((u32_t*)(hp + size - WSIZE))
-#define NEXT_CHK(hp) ((uint8_t*)(hp) + CHUNK_S(LW(hp)))
-
-#define BOUNDARY 4
-#define WSIZE 4
-
-#define HEAP_INIT_SIZE 4096
-
-int
-dmm_init(heap_context_t* heap);
-
-int
-lxbrk(heap_context_t* heap, void* addr, int user);
-
-void*
-lxsbrk(heap_context_t* heap, size_t size, int user);
-
-void*
-lx_malloc_internal(heap_context_t* heap, size_t size);
-
-void
-lx_free_internal(void* ptr);
-
-#endif /* __LUNAIX_DMM_H */
+++ /dev/null
-#ifndef __LUNAIX_KALLOC_H
-#define __LUNAIX_KALLOC_H
-
-#include <stddef.h>
-
-int
-kalloc_init();
-
-/**
- * @brief Allocate a contiguous and un-initialized memory region in kernel heap.
- *
- * @remarks
- * This is NOT the same as kmalloc in Linux!
- * LunaixOS does NOT guarantee the continuity in physical pages.
- *
- * @param size
- * @return void*
- */
-void*
-lxmalloc(size_t size);
-
-/**
- * @brief Allocate a contiguous and initialized memory region in kernel heap.
- * @param size
- * @return void*
- */
-void*
-lxcalloc(size_t n, size_t elem);
-
-/**
- * @brief Free the memory region allocated by kmalloc
- *
- * @param size
- * @return void*
- */
-void
-lxfree(void* ptr);
-
-#endif /* __LUNAIX_KALLOC_H */
#include <lunaix/ds/llist.h>
#include <lunaix/ds/mutex.h>
+#include <lunaix/fs.h>
+#include <lunaix/types.h>
-typedef struct
-{
- void* start;
- void* brk;
- void* max_addr;
- mutex_t lock;
-} heap_context_t;
+#include <sys/mann_flags.h>
/**
* @brief 私有区域,该区域中的页无法进行任何形式的共享。
*
*/
-#define REGION_PRIVATE 0x0
+#define REGION_PRIVATE MAP_EXCLUSIVE
/**
* @brief
* 读共享区域,该区域中的页可以被两个进程之间读共享,但任何写操作须应用Copy-On-Write
+ * 等价于 POSIX 的 MAP_PRIVATE
*
*/
-#define REGION_RSHARED 0x1
+#define REGION_RSHARED MAP_PRIVATE
/**
* @brief
* 写共享区域,该区域中的页可以被两个进程之间读共享,任何的写操作无需执行Copy-On-Write
- *
+ * 等价于 POSIX 的 MAP_SHARED
*/
-#define REGION_WSHARED 0x2
+#define REGION_WSHARED MAP_SHARED
#define REGION_PERM_MASK 0x1c
#define REGION_MODE_MASK 0x3
-#define REGION_READ (1 << 2)
-#define REGION_WRITE (1 << 3)
-#define REGION_EXEC (1 << 4)
+#define REGION_READ PROT_READ
+#define REGION_WRITE PROT_WRITE
+#define REGION_EXEC PROT_EXEC
+#define REGION_ANON MAP_ANON
#define REGION_RW REGION_READ | REGION_WRITE
-#define REGION_TYPE_CODE (1 << 16);
-#define REGION_TYPE_GENERAL (2 << 16);
-#define REGION_TYPE_HEAP (3 << 16);
-#define REGION_TYPE_STACK (4 << 16);
+#define REGION_TYPE_CODE (1 << 16)
+#define REGION_TYPE_GENERAL (2 << 16)
+#define REGION_TYPE_HEAP (3 << 16)
+#define REGION_TYPE_STACK (4 << 16)
+#define REGION_TYPE_VARS (5 << 16)
+
+struct proc_mm;
struct mm_region
{
- struct llist_header head;
- unsigned long start;
- unsigned long end;
- unsigned int attr;
+ struct llist_header head; // must be first field!
+ struct proc_mm* proc_vms;
+
+ // file mapped to this region
+ struct v_file* mfile;
+ // mapped file offset
+ off_t foff;
+ // mapped file length
+ u32_t flen;
+
+ ptr_t start;
+ ptr_t end;
+ u32_t attr;
+
+ void** index; // fast reference, to accelerate access to this very region.
+
+ void* data;
+ // When a page is mapped and required initialize
+ int (*init_page)(struct mm_region*, void*, off_t);
+ // when a region is copied
+ void (*region_copied)(struct mm_region*);
+ // when a region is unmapped
+ void (*destruct_region)(struct mm_region*);
+};
+
+static inline void
+mm_index(void** index, struct mm_region* target)
+{
+ *index = (void*)target;
+ target->index = index;
+}
+
+typedef struct llist_header vm_regions_t;
+
+struct proc_mm
+{
+ vm_regions_t regions;
+ struct mm_region* heap;
+ struct mm_region* stack;
+ pid_t pid;
};
#endif /* __LUNAIX_MM_H */
--- /dev/null
+#ifndef __LUNAIX_MMAP_H
+#define __LUNAIX_MMAP_H
+
+#include <lunaix/fs.h>
+#include <lunaix/mm/region.h>
+#include <lunaix/types.h>
+
+struct mmap_param
+{
+ ptr_t vms_mnt; // vm mount point
+ struct proc_mm* pvms; // process vm
+ off_t offset; // mapped file offset
+ size_t mlen; // mapped memory length
+ size_t flen; // mapped file length
+ u32_t proct; // protections
+ u32_t flags; // other options
+ u32_t type; // region type
+};
+
+int
+mem_adjust_inplace(vm_regions_t* regions,
+ struct mm_region* region,
+ ptr_t newend);
+
+int
+mem_map(void** addr_out,
+ struct mm_region** created,
+ void* addr,
+ struct v_file* file,
+ struct mmap_param* param);
+
+int
+mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length);
+
+void
+mem_unmap_region(ptr_t mnt, struct mm_region* region);
+
+void
+mem_sync_pages(ptr_t mnt,
+ struct mm_region* region,
+ ptr_t start,
+ ptr_t length,
+ int options);
+
+int
+mem_msync(ptr_t mnt,
+ vm_regions_t* regions,
+ ptr_t addr,
+ size_t length,
+ int options);
+
+#endif /* __LUNAIX_MMAP_H */
#define PTE_NULL 0
-#define P2V(paddr) ((uintptr_t)(paddr) + KERNEL_MM_BASE)
-#define V2P(vaddr) ((uintptr_t)(vaddr)-KERNEL_MM_BASE)
+#define P2V(paddr) ((ptr_t)(paddr) + KERNEL_MM_BASE)
+#define V2P(vaddr) ((ptr_t)(vaddr)-KERNEL_MM_BASE)
-#define PG_ALIGN(addr) ((uintptr_t)(addr)&0xFFFFF000UL)
+#define PG_ALIGN(addr) ((ptr_t)(addr)&0xFFFFF000UL)
+#define PG_ALIGNED(addr) (!((ptr_t)(addr)&0x00000FFFUL))
-#define L1_INDEX(vaddr) (u32_t)(((uintptr_t)(vaddr)&0xFFC00000UL) >> 22)
-#define L2_INDEX(vaddr) (u32_t)(((uintptr_t)(vaddr)&0x003FF000UL) >> 12)
-#define PG_OFFSET(vaddr) (u32_t)((uintptr_t)(vaddr)&0x00000FFFUL)
+#define L1_INDEX(vaddr) (u32_t)(((ptr_t)(vaddr)&0xFFC00000UL) >> 22)
+#define L2_INDEX(vaddr) (u32_t)(((ptr_t)(vaddr)&0x003FF000UL) >> 12)
+#define PG_OFFSET(vaddr) (u32_t)((ptr_t)(vaddr)&0x00000FFFUL)
#define GET_PT_ADDR(pde) PG_ALIGN(pde)
#define GET_PG_ADDR(pte) PG_ALIGN(pte)
-#define PG_DIRTY(pte) ((pte & (1 << 6)) >> 6)
-#define PG_ACCESSED(pte) ((pte & (1 << 5)) >> 5)
-
#define IS_CACHED(entry) ((entry & 0x1))
#define PG_PRESENT (0x1)
+#define PG_DIRTY (1 << 6)
+#define PG_ACCESSED (1 << 5)
#define PG_WRITE (0x1 << 1)
#define PG_ALLOW_USER (0x1 << 2)
#define PG_WRITE_THROUGH (1 << 3)
#define PG_DISABLE_CACHE (1 << 4)
#define PG_PDE_4MB (1 << 7)
+#define PG_IS_DIRTY(pte) ((pte)&PG_DIRTY)
+#define PG_IS_ACCESSED(pte) ((pte)&PG_ACCESSED)
+#define PG_IS_PRESENT(pte) ((pte)&PG_PRESENT)
+
#define NEW_L1_ENTRY(flags, pt_addr) \
(PG_ALIGN(pt_addr) | (((flags) | PG_WRITE_THROUGH) & 0xfff))
#define NEW_L2_ENTRY(flags, pg_addr) (PG_ALIGN(pg_addr) | ((flags)&0xfff))
#define HAS_FLAGS(entry, flags) ((PG_ENTRY_FLAGS(entry) & (flags)) == flags)
#define CONTAINS_FLAGS(entry, flags) (PG_ENTRY_FLAGS(entry) & (flags))
-#define PG_PREM_R PG_PRESENT
-#define PG_PREM_RW PG_PRESENT | PG_WRITE
-#define PG_PREM_UR PG_PRESENT | PG_ALLOW_USER
-#define PG_PREM_URW PG_PRESENT | PG_WRITE | PG_ALLOW_USER
+#define PG_PREM_R (PG_PRESENT)
+#define PG_PREM_RW (PG_PRESENT | PG_WRITE)
+#define PG_PREM_UR (PG_PRESENT | PG_ALLOW_USER)
+#define PG_PREM_URW (PG_PRESENT | PG_WRITE | PG_ALLOW_USER)
// 用于对PD进行循环映射,因为我们可能需要对PD进行频繁操作,我们在这里禁用TLB缓存
#define T_SELF_REF_PERM PG_PREM_RW | PG_DISABLE_CACHE | PG_WRITE_THROUGH
typedef struct
{
// 虚拟页地址
- uintptr_t va;
+ ptr_t va;
// 物理页码(如果不存在映射,则为0)
u32_t pn;
// 物理页地址(如果不存在映射,则为0)
- uintptr_t pa;
+ ptr_t pa;
// 映射的flags
uint16_t flags;
// PTE地址
/* 四个页挂载点,两个页目录挂载点: 用于临时创建&编辑页表 */
#define PG_MOUNT_RANGE(l1_index) (701 <= l1_index && l1_index <= 703)
-#define PD_MOUNT_1 (KERNEL_MM_BASE + MEM_4MB)
-#define PG_MOUNT_BASE (PD_MOUNT_1 + MEM_4MB)
+#define VMS_MOUNT_1 (KERNEL_MM_BASE + MEM_4MB)
+#define PG_MOUNT_BASE (VMS_MOUNT_1 + MEM_4MB)
#define PG_MOUNT_1 (PG_MOUNT_BASE)
#define PG_MOUNT_2 (PG_MOUNT_BASE + 0x1000)
#define PG_MOUNT_3 (PG_MOUNT_BASE + 0x2000)
#define PG_MOUNT_4 (PG_MOUNT_BASE + 0x3000)
-#define PD_REFERENCED L2_BASE_VADDR
+#define VMS_SELF L2_BASE_VADDR
#define CURPROC_PTE(vpn) \
- (&((x86_page_table*)(PD_MOUNT_1 | (((vpn)&0xffc00) << 2))) \
+ (&((x86_page_table*)(VMS_MOUNT_1 | (((vpn)&0xffc00) << 2))) \
->entry[(vpn)&0x3ff])
#define PTE_MOUNTED(mnt, vpn) \
(((x86_page_table*)((mnt) | (((vpn)&0xffc00) << 2)))->entry[(vpn)&0x3ff])
#include <lunaix/mm/mm.h>
+struct mm_region*
+region_create(ptr_t start, ptr_t end, u32_t attr);
+
+struct mm_region*
+region_create_range(ptr_t start, size_t length, u32_t attr);
+
+void
+region_add(vm_regions_t* lead, struct mm_region* vmregion);
+
void
-region_add(struct mm_region* proc,
- unsigned long start,
- unsigned long end,
- unsigned int attr);
+region_release(struct mm_region* region);
void
-region_release_all(struct mm_region* proc);
+region_release_all(vm_regions_t* lead);
struct mm_region*
-region_get(struct mm_region* proc, unsigned long vaddr);
+region_get(vm_regions_t* lead, unsigned long vaddr);
void
-region_copy(struct mm_region* src, struct mm_region* dest);
+region_copy(struct proc_mm* src, struct proc_mm* dest);
#endif /* __LUNAIX_REGION_H */
vmm_del_mapping(uintptr_t mnt, uintptr_t va);
/**
- * @brief 查找一个映射
+ * @brief 在当前虚拟地址空间里查找一个映射
*
* @param va 虚拟地址
- * @return v_mapping 映射相关属性
+ * @param mapping 映射相关属性
*/
int
vmm_lookup(uintptr_t va, v_mapping* mapping);
+/**
+ * @brief 在指定的虚拟地址空间里查找一个映射
+ *
+ * @param mnt 地址空间锚定点
+ * @param va 虚拟地址
+ * @param mapping 映射相关属性
+ * @return int
+ */
+int
+vmm_lookupat(ptr_t mnt, uintptr_t va, v_mapping* mapping);
+
/**
* @brief (COW) 为虚拟页创建副本。
*
void*
vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr);
+/**
+ * @brief 将当前地址空间的虚拟地址转译为物理地址。
+ *
+ * @param va 虚拟地址
+ * @return void*
+ */
void*
vmm_v2p(void* va);
+/**
+ * @brief 将指定地址空间的虚拟地址转译为物理地址
+ *
+ * @param mnt 地址空间锚定点
+ * @param va 虚拟地址
+ * @return void*
+ */
+void*
+vmm_v2pat(ptr_t mnt, void* va);
+
#endif /* __LUNAIX_VMM_H */
#include <lunaix/ds/waitq.h>
#include <lunaix/fs.h>
#include <lunaix/mm/mm.h>
+#include <lunaix/mm/region.h>
#include <lunaix/signal.h>
#include <lunaix/timer.h>
#include <lunaix/types.h>
#define PROC_FINPAUSE 1
-struct proc_mm
-{
- heap_context_t u_heap;
- struct mm_region regions;
-};
-
struct proc_sigstate
{
isr_param proc_regs;
pid_t pid; // offset = 0
struct proc_info* parent; // offset = 4
isr_param intr_ctx; // offset = 8
- uintptr_t ustack_top; // offset = 84
- void* page_table; // offset = 88
- void* fxstate; // offset = 92
+ uintptr_t ustack_top; // offset = 84 -> 56 -> 60
+ void* page_table; // offset = 88 -> 60 -> 64
+ void* fxstate; // offset = 92 -> 64 -> 68
/* ---- critical section end ---- */
#ifndef __LUNAIX_SIGNAL_H
#define __LUNAIX_SIGNAL_H
-#include <lunaix/syscall.h>
+#include <signal_defs.h>
#define _SIG_NUM 16
#define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig)))
-#define _SIGSEGV 1
-#define _SIGALRM 2
-#define _SIGCHLD 3
-#define _SIGCLD _SIGCHLD
-#define _SIGINT 4
-#define _SIGKILL 5
-#define _SIGSTOP 6
-#define _SIGCONT 7
-#define _SIGTERM 8
+#define _SIGSEGV SIGSEGV
+#define _SIGALRM SIGALRM
+#define _SIGCHLD SIGCHLD
+#define _SIGCLD SIGCLD
+#define _SIGINT SIGINT
+#define _SIGKILL SIGKILL
+#define _SIGSTOP SIGSTOP
+#define _SIGCONT SIGCONT
+#define _SIGTERM SIGTERM
#define __SIGNAL(num) (1 << (num))
#define __SIGSET(bitmap, num) (bitmap = bitmap | __SIGNAL(num))
#define _SIGNAL_UNMASKABLE (__SIGNAL(_SIGKILL) | __SIGNAL(_SIGSTOP))
-#define _SIG_BLOCK 1
-#define _SIG_UNBLOCK 2
-#define _SIG_SETMASK 3
-
-typedef unsigned int sigset_t;
-typedef void (*sighandler_t)(int);
-
-__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler);
-
-__LXSYSCALL1(int, sigpending, sigset_t, *set);
-__LXSYSCALL1(int, sigsuspend, const sigset_t, *mask);
-
-__LXSYSCALL3(int,
- sigprocmask,
- int,
- how,
- const sigset_t,
- *set,
- sigset_t,
- *oldset);
+#define _SIG_BLOCK SIG_BLOCK
+#define _SIG_UNBLOCK SIG_UNBLOCK
+#define _SIG_SETMASK SIG_SETMASK
#endif /* __LUNAIX_SIGNAL_H */
// 除法 v/(2^k) 向下取整
#define FLOOR(v, k) ((v) >> (k))
-// 获取v最近的最大k倍数
+// 获取v最近的最大k倍数 (k=2^n)
#define ROUNDUP(v, k) (((v) + (k)-1) & ~((k)-1))
// 获取v最近的最小k倍数 (k=2^m)
*
*/
#define ILOG2(x) \
- __builtin_constant_p(x) ? ((x) == 0 ? 0 \
- : ((x) & (1ul << 31)) ? 31 \
- : ((x) & (1ul << 30)) ? 30 \
- : ((x) & (1ul << 29)) ? 29 \
- : ((x) & (1ul << 28)) ? 28 \
- : ((x) & (1ul << 27)) ? 27 \
- : ((x) & (1ul << 26)) ? 26 \
- : ((x) & (1ul << 25)) ? 25 \
- : ((x) & (1ul << 24)) ? 24 \
- : ((x) & (1ul << 23)) ? 23 \
- : ((x) & (1ul << 22)) ? 22 \
- : ((x) & (1ul << 21)) ? 21 \
- : ((x) & (1ul << 20)) ? 20 \
- : ((x) & (1ul << 19)) ? 19 \
- : ((x) & (1ul << 18)) ? 18 \
- : ((x) & (1ul << 17)) ? 17 \
- : ((x) & (1ul << 16)) ? 16 \
- : ((x) & (1ul << 15)) ? 15 \
- : ((x) & (1ul << 14)) ? 14 \
- : ((x) & (1ul << 13)) ? 13 \
- : ((x) & (1ul << 12)) ? 12 \
- : ((x) & (1ul << 11)) ? 11 \
- : ((x) & (1ul << 10)) ? 10 \
- : ((x) & (1ul << 9)) ? 9 \
- : ((x) & (1ul << 8)) ? 8 \
- : ((x) & (1ul << 7)) ? 7 \
- : ((x) & (1ul << 6)) ? 6 \
- : ((x) & (1ul << 5)) ? 5 \
- : ((x) & (1ul << 4)) ? 4 \
- : ((x) & (1ul << 3)) ? 3 \
- : ((x) & (1ul << 2)) ? 2 \
- : ((x) & (1ul << 1)) ? 1 \
- : 0) \
- : (31 - __builtin_clz(x))
+ (__builtin_constant_p(x) ? ((x) == 0 ? 0 \
+ : ((x) & (1ul << 31)) ? 31 \
+ : ((x) & (1ul << 30)) ? 30 \
+ : ((x) & (1ul << 29)) ? 29 \
+ : ((x) & (1ul << 28)) ? 28 \
+ : ((x) & (1ul << 27)) ? 27 \
+ : ((x) & (1ul << 26)) ? 26 \
+ : ((x) & (1ul << 25)) ? 25 \
+ : ((x) & (1ul << 24)) ? 24 \
+ : ((x) & (1ul << 23)) ? 23 \
+ : ((x) & (1ul << 22)) ? 22 \
+ : ((x) & (1ul << 21)) ? 21 \
+ : ((x) & (1ul << 20)) ? 20 \
+ : ((x) & (1ul << 19)) ? 19 \
+ : ((x) & (1ul << 18)) ? 18 \
+ : ((x) & (1ul << 17)) ? 17 \
+ : ((x) & (1ul << 16)) ? 16 \
+ : ((x) & (1ul << 15)) ? 15 \
+ : ((x) & (1ul << 14)) ? 14 \
+ : ((x) & (1ul << 13)) ? 13 \
+ : ((x) & (1ul << 12)) ? 12 \
+ : ((x) & (1ul << 11)) ? 11 \
+ : ((x) & (1ul << 10)) ? 10 \
+ : ((x) & (1ul << 9)) ? 9 \
+ : ((x) & (1ul << 8)) ? 8 \
+ : ((x) & (1ul << 7)) ? 7 \
+ : ((x) & (1ul << 6)) ? 6 \
+ : ((x) & (1ul << 5)) ? 5 \
+ : ((x) & (1ul << 4)) ? 4 \
+ : ((x) & (1ul << 3)) ? 3 \
+ : ((x) & (1ul << 2)) ? 2 \
+ : ((x) & (1ul << 1)) ? 1 \
+ : 0) \
+ : (31 - __builtin_clz(x)))
#define __USER__ __attribute__((section(".usrtext")))
if (!(cond)) { \
__assert_fail(msg, __FILE__, __LINE__); \
}
+
+#define fail(msg) __assert_fail(msg, __FILE__, __LINE__);
+
void
__assert_fail(const char* expr, const char* file, unsigned int line)
__attribute__((noinline, noreturn));
#define ENOTDEV -24
#define EOVERFLOW -25
#define ENOTBLK -26
+#define ENOEXEC -27
+#define E2BIG -28
#endif /* __LUNAIX_CODE_H */
#define __SYSCALL_read 21
#define __SYSCALL_write 22
-#define __SYSCALL_readdir 23
+#define __SYSCALL_sys_readdir 23
#define __SYSCALL_mkdir 24
#define __SYSCALL_lseek 25
#define __SYSCALL_geterrno 26
#define __SYSCALL_syslog 51
+#define __SYSCALL_sys_mmap 52
+#define __SYSCALL_munmap 53
+
+#define __SYSCALL_execve 54
+
#define __SYSCALL_MAX 0x100
#ifndef __ASM__
asmlinkage rettype __lxsys_##name( \
__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4))
+#define __DEFINE_LXSYSCALL5( \
+ rettype, name, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
+ asmlinkage rettype __lxsys_##name( \
+ __PARAM_MAP5(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5))
+
#define __SYSCALL_INTERRUPTIBLE(code) \
asm("sti"); \
{ code }; \
return (rettype)v;
#define __LXSYSCALL(rettype, name) \
- static rettype name() \
+ rettype name() \
{ \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL1(rettype, name, t1, p1) \
- static rettype name(__PARAM_MAP1(t1, p1)) \
+ rettype name(__PARAM_MAP1(t1, p1)) \
{ \
asm("" ::"b"(p1)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL2(rettype, name, t1, p1, t2, p2) \
- static rettype name(__PARAM_MAP2(t1, p1, t2, p2)) \
+ rettype name(__PARAM_MAP2(t1, p1, t2, p2)) \
{ \
asm("\n" ::"b"(p1), "c"(p2)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL3(rettype, name, t1, p1, t2, p2, t3, p3) \
- static rettype name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3)) \
+ rettype name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3)) \
{ \
asm("\n" ::"b"(p1), "c"(p2), "d"(p3)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
#define __LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4) \
- static rettype name(__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4)) \
+ rettype name(__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4)) \
{ \
asm("\n" ::"b"(p1), "c"(p2), "d"(p3), "D"(p4)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
+#define __LXSYSCALL5(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
+ rettype name(__PARAM_MAP5(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5)) \
+ { \
+ asm("" ::"r"(p5), "b"(p1), "c"(p2), "d"(p3), "D"(p4), "S"(p5)); \
+ ___DOINT33(__SYSCALL_##name, rettype) \
+ }
+
#define __LXSYSCALL2_VARG(rettype, name, t1, p1, t2, p2) \
- __attribute__((noinline)) static rettype name( \
- __PARAM_MAP2(t1, p1, t2, p2), ...) \
+ __attribute__((noinline)) rettype name(__PARAM_MAP2(t1, p1, t2, p2), ...) \
{ \
/* No inlining! This depends on the call frame assumption */ \
void* _last = (void*)&p2 + sizeof(void*); \
asm("\n" ::"b"(p1), "c"(p2), "d"(_last)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
-#endif
+#endif
#endif /* __LUNAIX_SYSCALL_H */
--- /dev/null
+#ifndef __LUNAIX_SYSCALL_UTILS_H
+#define __LUNAIX_SYSCALL_UTILS_H
+
+#include <lunaix/process.h>
+#include <lunaix/syscall.h>
+
+#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
+#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
+
+#endif /* __LUNAIX_SYSCALL_UTILS_H */
#define __LUNAIX_TYPES_H
#include <stdarg.h>
-#include <stddef.h>
#include <stdint.h>
-
-#define PEXITTERM 0x100
-#define PEXITSTOP 0x200
-#define PEXITSIG 0x400
-
-#define PEXITNUM(flag, code) (flag | (code & 0xff))
-
-#define WNOHANG 1
-#define WUNTRACED 2
-#define WEXITSTATUS(wstatus) ((wstatus & 0xff))
-#define WIFSTOPPED(wstatus) ((wstatus & PEXITSTOP))
-#define WIFEXITED(wstatus) \
- ((wstatus & PEXITTERM) && ((char)WEXITSTATUS(wstatus) >= 0))
-
-#define WIFSIGNALED(wstatus) ((wstatus & PEXITSIG))
+#include <sys/types.h>
#define PACKED __attribute__((packed))
typedef unsigned int u32_t;
typedef unsigned long long u64_t;
typedef unsigned long ptr_t;
-typedef signed long ssize_t;
-typedef int32_t pid_t;
typedef int64_t lba_t;
#endif /* __LUNAIX_TYPES_H */
.global debug_resv
debug_resv:
.skip 16
+ tmp_store:
+ .skip 4
#endif
.section .bss
.skip 128
tmp_stack:
+/*
+ This perhaps the ugliest part in the project.
+ It contains code to handle arbitrary depth of
+ nested interrupt and all those corner cases and
+ nasty gotchas.
+
+ Be aware the twists, offsets and hidden dependencies!
+
+*/
+
.section .text
.global interrupt_wrapper
interrupt_wrapper:
/*
Stack layout (layout of struct isr_param)
- msa: [ss]
- [esp]
- eflags > offset = 48 + 16 = 64
- cs
- eip
- err_code
- vector > offset = 28 + 16 + 4 = 48
+ msa: [ss] > 76
+ [esp] > 72
+ eflags > 68
+ cs > 64
+ eip > 60
+ err_code > 56
+ vector > offset = 52
+ [saved_prev_ctx] > offset = 0
+ ---
esp
gs
fs
es
- ds > offset = 7 * 4 = 28
+ ds > offset = 7 * 4 = 28 + 4
esi
ebp
edi
edx
ecx
ebx
- lsa: eax > offset = 0
+ eax
+ lsa: depth > offset = 0
las: Least Significant Address
msa: Most Significant Address
*/
cld
+
+ subl $52, %esp
pushl %esp
subl $16, %esp
pushl %ebx
pushl %eax
- movl 60(%esp), %eax /* 取出 %cs */
+ movl __current, %eax
+ movl 8(%eax), %eax
+ incl %eax
+ pushl %eax # nested intr: current depth
+
+ movl 116(%esp), %eax /* 取出 %cs */
andl $0x3, %eax /* 判断 RPL */
jz 1f
# 保存用户栈顶指针。这是因为我们允许系统调用内进行上下文切换,而这样一来,我们就失去了用户栈的信息,
# 这样一来,就无法设置信号上下文。这主要是为了实现了pause()而做的准备
- movl (__current), %eax
+ movl __current, %eax
# 保存x87FPU的状态
- movl 92(%eax), %ebx
+ movl 68(%eax), %ebx
fxsave (%ebx)
- movl 68(%esp), %ebx # 取出esp
- movl %ebx, 84(%eax) # 存入__current->ustack_top
+ movl 124(%esp), %ebx # 取出esp
+ movl %ebx, 60(%eax) # 存入__current->ustack_top
1:
movl %esp, %eax
#ifdef __ASM_INTR_DIAGNOSIS
movl %eax, (debug_resv + 8)
- movl 56(%esp), %eax
- movl %eax, (debug_resv + 4)
+ movl 48(%esp), %eax
+ movl 60(%eax), %eax
+ movl %eax, (debug_resv + 4) # eip
#endif
- movl (__current), %eax
- movl 92(%eax), %eax
+ movl __current, %eax
+ movl 68(%eax), %eax
test %eax, %eax # do we have stored x87 context?
jz 1f
fxrstor (%eax)
1:
+ popl %eax # discard isr_param::depth
popl %eax
popl %ebx
popl %ecx
movl 16(%esp), %esp
+ movl %eax, tmp_store
+ movl __current, %eax
+ # nested intr: restore saved context
+ popl 8(%eax) # depth
+ popl 12(%eax) # eax
+ popl 16(%eax) # ebx
+ popl 20(%eax) # ecx
+ popl 24(%eax) # edx
+ popl 28(%eax) # edi
+ popl 32(%eax) # ebp
+ popl 36(%eax) # esi
+ popl 40(%eax) # ds
+ popl 44(%eax) # es
+ popl 48(%eax) # fs
+ popl 52(%eax) # gs
+ popl 56(%eax) # esp
+
addl $8, %esp
- pushl %eax
#ifdef __ASM_INTR_DIAGNOSIS
- movl 4(%esp), %eax
+ movl (%esp), %eax
movl %eax, debug_resv
#endif
# 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
# 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
# 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
- movl 8(%esp), %eax
+ movl 4(%esp), %eax
andl $3, %eax
setnz %al
shll $3, %eax
- addl $16, %eax
+ addl $12, %eax
addl %esp, %eax
movl %eax, (_tss + 4)
- popl %eax
+ movl tmp_store, %eax
iret
.global switch_to
popl %ebx # next
movl __current, %eax
- movl 88(%eax), %ecx # __current->pagetable
- movl 88(%ebx), %eax # next->pagetable
+ movl 64(%eax), %ecx # __current->pagetable
+ movl 64(%ebx), %eax # next->pagetable
cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
jz 1f
pushl $UDATA_SEG # proc_sig->prev_context.proc_regs.ss
pushl %eax # esp
- pushl 64(%ebx) # proc_sig->prev_context.proc_regs.eflags
+ movl 48(%ebx), %ebx
+ pushl 68(%ebx) # proc_sig->prev_context.proc_regs.execp->eflags
pushl $UCODE_SEG # cs
pushl $sig_wrapper # eip for sig wrapper
pushl %eax # Addr to proc_sig structure
pushl 4(%eax) # proc_sig->sig_num ---- 16 bytes aligned
- call (%eax) # invoke signal handler
+ call *(%eax) # invoke signal handler
# invoke the sigreturn syscall to exit the signal wrapper
movl $__SYSCALL_sigreturn, %eax
void
intr_handler(isr_param* param)
{
+ param->execp->saved_prev_ctx = __current->intr_ctx;
__current->intr_ctx = *param;
- isr_param* lparam = &__current->intr_ctx;
+ volatile struct exec_param* execp = __current->intr_ctx.execp;
- if (lparam->vector <= 255) {
- isr_cb subscriber = isrm_get(lparam->vector);
+ if (execp->vector <= 255) {
+ isr_cb subscriber = isrm_get(execp->vector);
subscriber(param);
goto done;
}
kprint_panic("INT %u: (%x) [%p: %p] Unknown",
- lparam->vector,
- lparam->err_code,
- lparam->cs,
- lparam->eip);
+ execp->vector,
+ execp->err_code,
+ execp->cs,
+ execp->eip);
done:
// for all external interrupts except the spurious interrupt
// this is required by Intel Manual Vol.3A, section 10.8.1 & 10.8.5
- if (lparam->vector >= IV_EX && lparam->vector != APIC_SPIV_IV) {
+ if (execp->vector >= IV_EX && execp->vector != APIC_SPIV_IV) {
apic_done_servicing();
}
void
__print_panic_msg(const char* msg, const isr_param* param)
{
+ struct exec_param* execp = param->execp;
kprint_panic(" INT %u: (%x) [%p: %p] %s",
- param->vector,
- param->err_code,
- param->cs,
- param->eip,
+ execp->vector,
+ execp->err_code,
+ execp->cs,
+ execp->eip,
msg);
}
#include <arch/x86/interrupts.h>
#include <lunaix/common.h>
-#include <lunaix/lxsignal.h>
#include <lunaix/mm/mm.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/region.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/sched.h>
+#include <lunaix/signal.h>
#include <lunaix/status.h>
#include <lunaix/syslog.h>
+#include <klibc/string.h>
+
static void
kprintf(const char* fmt, ...)
{
goto segv_term;
}
- if (!SEL_RPL(param->cs)) {
+ if (!SEL_RPL(param->execp->cs)) {
// 如果是内核页错误……
if (do_kernel(&mapping)) {
return;
goto segv_term;
}
- volatile x86_pte_t* pte = &PTE_MOUNTED(PD_REFERENCED, ptr >> 12);
- if ((*pte & PG_PRESENT)) {
+ volatile x86_pte_t* pte = &PTE_MOUNTED(VMS_SELF, ptr >> 12);
+ if (PG_IS_PRESENT(*pte)) {
if ((hit_region->attr & COW_MASK) == COW_MASK) {
// normal page fault, do COW
cpu_invplg(pte);
uintptr_t pa =
(uintptr_t)vmm_dup_page(__current->pid, PG_ENTRY_ADDR(*pte));
pmm_free_page(__current->pid, *pte & ~0xFFF);
- *pte = (*pte & 0xFFF) | pa | PG_WRITE;
+ *pte = (*pte & 0xFFF & ~PG_DIRTY) | pa | PG_WRITE;
goto resolved;
}
// impossible cases or accessing privileged page
goto segv_term;
}
- if (!(*pte)) {
- // Invalid location
+ // an anonymous page and not present
+ // -> a new page need to be alloc
+ if ((hit_region->attr & REGION_ANON)) {
+ if (!PG_IS_PRESENT(*pte)) {
+ cpu_invplg(pte);
+ uintptr_t pa = pmm_alloc_page(__current->pid, 0);
+ if (!pa) {
+ goto oom;
+ }
+
+ *pte = *pte | pa | PG_PRESENT;
+ memset(PG_ALIGN(ptr), 0, PG_SIZE);
+ goto resolved;
+ }
+ // permission denied on anon page (e.g., write on readonly page)
goto segv_term;
}
- uintptr_t loc = *pte & ~0xfff;
+ // if mfile is set (Non-anonymous), then it is a mem map
+ if (hit_region->mfile && !PG_IS_PRESENT(*pte)) {
+ struct v_file* file = hit_region->mfile;
- // a writable page, not present, not cached, pte attr is not null
- // -> a new page need to be alloc
- if ((hit_region->attr & REGION_WRITE) && (*pte & 0xfff) && !loc) {
- cpu_invplg(pte);
+ ptr = PG_ALIGN(ptr);
+
+ u32_t offset = (ptr - hit_region->start) + hit_region->foff;
uintptr_t pa = pmm_alloc_page(__current->pid, 0);
- *pte = *pte | pa | PG_PRESENT;
+
+ if (!pa) {
+ goto oom;
+ }
+
+ cpu_invplg(pte);
+ *pte = (*pte & 0xFFF) | pa | PG_PRESENT;
+
+ memset(ptr, 0, PG_SIZE);
+
+ int errno = 0;
+ if (hit_region->init_page) {
+ errno = hit_region->init_page(hit_region, ptr, offset);
+ } else {
+ errno = file->ops->read_page(file->inode, ptr, PG_SIZE, offset);
+ }
+
+ if (errno < 0) {
+ kprintf(KERROR "fail to populate page (%d)\n", errno);
+ goto segv_term;
+ }
+
+ *pte &= ~PG_DIRTY;
+
goto resolved;
}
- // page not present, bring it from disk or somewhere else
+ // page not present, might be a chance to introduce swap file?
__print_panic_msg("WIP page fault route", param);
while (1)
;
+oom:
+ kprintf(KERROR "out of memory\n");
segv_term:
kprintf(KERROR "(pid: %d) Segmentation fault on %p (%p:%p)\n",
__current->pid,
ptr,
- param->cs,
- param->eip);
+ param->execp->cs,
+ param->execp->eip);
__SIGSET(__current->sig_pending, _SIGSEGV);
schedule();
// should not reach
.long __lxsys_close /* 20 */
.long __lxsys_read
.long __lxsys_write
- .long __lxsys_readdir
+ .long __lxsys_sys_readdir
.long __lxsys_mkdir
.long __lxsys_lseek /* 25 */
.long __lxsys_geterrno
.long __lxsys_getpgid
.long __lxsys_setpgid /* 50 */
.long __lxsys_syslog
+ .long __lxsys_sys_mmap
+ .long __lxsys_munmap
+ .long __lxsys_execve
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
.long 0
.section .text
syscall_hndlr:
pushl %ebp
- movl 8(%esp), %ebp
+ movl 8(%esp), %ebp // isr_param*
- movl (%ebp), %eax /* eax: call code as well as the return value from syscall */
- cmpl $__SYSCALL_MAX, %eax
+ addl $4, %ebp
+ movl (%ebp), %eax /* eax: call code as well as the return value from syscall */
+ cmpl $__SYSCALL_MAX, %eax
jae 2f
shll $2, %eax
popl %ebp
ret
1:
- pushl 24(%ebp) /* esi - #6 arg */
- pushl 20(%ebp) /* ebp - #5 arg */
+ pushl 24(%ebp) /* esi - #5 arg */
pushl 16(%ebp) /* edi - #4 arg */
pushl 12(%ebp) /* edx - #3 arg */
pushl 8(%ebp) /* ecx - #2 arg */
movl %eax, (%ebp) /* save the return value */
- addl $24, %esp /* remove the parameters from stack */
+ addl $20, %esp /* remove the parameters from stack */
popl %ebp
+++ /dev/null
-#include <lunaix/dirent.h>
-#include <lunaix/fctrl.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-
-void
-_readdir_main()
-{
- int fd = open("/dev/./../dev/.", 0);
- if (fd == -1) {
- printf("fail to open (%d)\n", geterrno());
- return;
- }
-
- char path[129];
- int len = realpathat(fd, path, 128);
- if (len < 0) {
- printf("fail to read (%d)\n", geterrno());
- } else {
- path[len] = 0;
- printf("%s\n", path);
- }
-
- struct dirent ent = { .d_offset = 0 };
-
- while (readdir(fd, &ent) == 1) {
- printf("%s\n", ent.d_name);
- }
-
- close(fd);
-
- return;
-}
\ No newline at end of file
+++ /dev/null
-#include <lunaix/fctrl.h>
-#include <lunaix/foptions.h>
-#include <lunaix/input.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-#include <ulibc/stdio.h>
-
-#define STDIN 1
-#define STDOUT 0
-
-void
-input_test()
-{
- int fd = open("/dev/input/i8042-kbd", 0);
-
- if (fd < 0) {
- printf("fail to open (%d)", geterrno());
- return;
- }
-
- struct input_evt_pkt event;
-
- while (read(fd, &event, sizeof(event)) > 0) {
- char* action;
- if (event.pkt_type == PKT_PRESS) {
- action = "pressed";
- } else {
- action = "release";
- }
-
- printf("%u: %s '%c', class=0x%x, scan=%x\n",
- event.timestamp,
- action,
- event.sys_code & 0xff,
- (event.sys_code & 0xff00) >> 8,
- event.scan_code);
- }
- return;
-}
\ No newline at end of file
+++ /dev/null
-#include <lunaix/fctrl.h>
-#include <lunaix/foptions.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-#include <ulibc/stdio.h>
-
-void
-_iotest_main()
-{
- char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
- "There were two regal sisters who ruled together "
- "and created harmony for all the land.";
- char read_out[256];
-
- // 切换工作目录至 /dev
- int errno = chdir("/dev");
- if (errno) {
- write(stdout, "fail to chdir", 15);
- return;
- }
-
- if (getcwd(read_out, sizeof(read_out))) {
- printf("current working dir: %s\n", read_out);
- }
-
- // sda 设备 - 硬盘
- // sda设备属于容积设备(Volumetric Device),
- // Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能)
- int fd = open("./sda", 0);
-
- if (fd < 0) {
- printf("fail to open (%d)\n", geterrno());
- return;
- }
-
- // 移动指针至512字节,在大多数情况下,这是第二个逻辑扇区的起始处
- lseek(fd, 512, FSEEK_SET);
-
- // 总共写入 64 * 136 字节,会产生3个页作为缓存
- for (size_t i = 0; i < 64; i++) {
- write(fd, test_sequence, sizeof(test_sequence));
- }
-
- // 随机读写测试
- lseek(fd, 4 * 4096, FSEEK_SET);
- write(fd, test_sequence, sizeof(test_sequence));
-
- printf("input: ");
- int size = read(stdin, read_out, 256);
-
- printf("your said: %s\n", read_out);
-
- write(fd, read_out, size);
-
- // 读出我们写的内容
- lseek(fd, 512, FSEEK_SET);
- read(fd, read_out, sizeof(read_out));
-
- // 将读出的内容直接写入tty设备
- write(stdout, read_out, sizeof(read_out));
- write(stdout, "\n", 1);
-
- // 关闭文件,这同时会将页缓存中的数据下发到底层驱动
- close(fd);
-}
\ No newline at end of file
+++ /dev/null
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-#include <lunaix/signal.h>
-#include <lunaix/spike.h>
-#include <lunaix/types.h>
-#include <ulibc/stdio.h>
-
-void __USER__
-sigchild_handler(int signum)
-{
- printf("SIGCHLD received\n");
-}
-
-void __USER__
-sigsegv_handler(int signum)
-{
- pid_t pid = getpid();
- printf("SIGSEGV received on process %d\n", pid);
- _exit(signum);
-}
-
-void __USER__
-sigalrm_handler(int signum)
-{
- pid_t pid = getpid();
- printf("I, pid %d, have received an alarm!\n", pid);
-}
-
-void __USER__
-_signal_demo_main()
-{
- signal(_SIGCHLD, sigchild_handler);
- signal(_SIGSEGV, sigsegv_handler);
- signal(_SIGALRM, sigalrm_handler);
-
- alarm(5);
-
- int status;
- pid_t p = 0;
-
- printf("Child sleep 3s, parent pause.\n");
- if (!fork()) {
- sleep(3);
- _exit(0);
- }
-
- pause();
-
- printf("Parent resumed on SIGCHILD\n");
-
- for (int i = 0; i < 5; i++) {
- pid_t pid = 0;
- if (!(pid = fork())) {
- signal(_SIGSEGV, sigsegv_handler);
- sleep(i);
- if (i == 3) {
- i = *(int*)0xdeadc0de; // seg fault!
- }
- printf("%d\n", i);
- _exit(0);
- }
- printf("Forked %d\n", pid);
- }
-
- while ((p = wait(&status)) >= 0) {
- short code = WEXITSTATUS(status);
- if (WIFSIGNALED(status)) {
- printf("Process %d terminated by signal, exit_code: %d\n", p, code);
- } else if (WIFEXITED(status)) {
- printf("Process %d exited with code %d\n", p, code);
- } else {
- printf("Process %d aborted with code %d\n", p, code);
- }
- }
-
- printf("done\n");
-}
\ No newline at end of file
+++ /dev/null
-#include <lunaix/fctrl.h>
-#include <lunaix/foptions.h>
-#include <lunaix/ioctl.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-#include <lunaix/signal.h>
-#include <lunaix/status.h>
-
-#include <klibc/string.h>
-#include <ulibc/stdio.h>
-
-char pwd[512];
-char cat_buf[1024];
-
-/*
- Simple shell - (actually this is not even a shell)
- It just to make the testing more easy.
-*/
-
-void
-parse_cmdline(char* line, char** cmd, char** arg_part)
-{
- strrtrim(line);
- line = strltrim_safe(line);
- int l = 0;
- char c = 0;
- while ((c = line[l])) {
- if (c == ' ') {
- line[l++] = 0;
- break;
- }
- l++;
- }
- *cmd = line;
- *arg_part = strltrim_safe(line + l);
-}
-
-void
-sh_printerr()
-{
- int errno = geterrno();
- switch (errno) {
- case ENOTDIR:
- printf("Error: Not a directory\n");
- break;
- case ENOENT:
- printf("Error: No such file or directory\n");
- break;
- case EINVAL:
- printf("Error: Invalid parameter or operation\n");
- break;
- case ENOTSUP:
- printf("Error: Not supported\n");
- break;
- case EROFS:
- printf("Error: File system is read only\n");
- break;
- case ENOMEM:
- printf("Error: Out of memory\n");
- break;
- case EISDIR:
- printf("Error: This is a directory\n");
- break;
- default:
- printf("Error: (%d)\n", errno);
- break;
- }
-}
-
-void
-sigint_handle(int signum)
-{
- return;
-}
-
-void
-do_cat(const char* file)
-{
- int fd = open(file, 0);
- if (fd < 0) {
- sh_printerr();
- } else {
- int sz;
- while ((sz = read(fd, cat_buf, 1024)) > 0) {
- write(stdout, cat_buf, sz);
- }
- if (sz < 0) {
- sh_printerr();
- }
- close(fd);
- printf("\n");
- }
-}
-
-void
-do_ls(const char* path)
-{
- int fd = open(path, 0);
- if (fd < 0) {
- sh_printerr();
- } else {
- struct dirent ent = { .d_offset = 0 };
- int status;
- while ((status = readdir(fd, &ent)) == 1) {
- if (ent.d_type == DT_DIR) {
- printf(" \033[3m%s\033[39;49m\n", ent.d_name);
- } else {
- printf(" %s\n", ent.d_name);
- }
- }
-
- if (status < 0)
- sh_printerr();
-
- close(fd);
- }
-}
-
-void
-sh_loop()
-{
- char buf[512];
- char *cmd, *argpart;
- pid_t p;
- signal(_SIGINT, sigint_handle);
-
- // set our shell as foreground process
- // (unistd.h:tcsetpgrp is essentially a wrapper of this)
- // stdout (by default, unless user did smth) is the tty we are currently at
- ioctl(stdout, TIOCSPGRP, getpgid());
-
- while (1) {
- getcwd(pwd, 512);
- printf("[\033[2m%s\033[39;49m]$ ", pwd);
- size_t sz = read(stdin, buf, 511);
- if (sz < 0) {
- printf("fail to read user input (%d)\n", geterrno());
- return;
- }
- buf[sz] = '\0';
- parse_cmdline(buf, &cmd, &argpart);
- if (cmd[0] == 0) {
- printf("\n");
- goto cont;
- }
- if (streq(cmd, "cd")) {
- if (chdir(argpart) < 0) {
- sh_printerr();
- }
- goto cont;
- } else if (streq(cmd, "clear")) {
- ioctl(stdout, TIOCCLSBUF);
- goto cont;
- } else if (streq(cmd, "ls")) {
- if (!(p = fork())) {
- do_ls(argpart);
- _exit(0);
- }
- } else if (streq(cmd, "cat")) {
- if (!(p = fork())) {
- do_cat(argpart);
- _exit(0);
- }
- } else {
- printf("unknow command\n");
- goto cont;
- }
- setpgid(p, getpgid());
- waitpid(p, NULL, 0);
- cont:
- printf("\n");
- }
-}
-
-void
-sh_main()
-{
- printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
- if (!fork()) {
- sh_loop();
- _exit(0);
- }
- wait(NULL);
-}
\ No newline at end of file
#include <lunaix/device.h>
-#include <lunaix/dirent.h>
#include <lunaix/fs.h>
#include <lunaix/fs/devfs.h>
#include <lunaix/spike.h>
+#include <sys/dirent_defs.h>
+
extern struct v_inode_ops devfs_inode_ops;
extern struct v_file_ops devfs_file_ops;
#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
static DEFINE_LLIST(root_list);
-#include <lunaix/dirent.h>
#include <lunaix/fs.h>
#include <lunaix/fs/iso9660.h>
#include <lunaix/mm/cake.h>
#include <klibc/string.h>
+#include <sys/dirent_defs.h>
+
extern struct cake_pile* drec_cache_pile;
void
#include <lunaix/mm/valloc.h>
#include <lunaix/process.h>
#include <lunaix/spike.h>
+#include <lunaix/syscall_utils.h>
#include <lunaix/syslog.h>
#include <lunaix/types.h>
#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
#include <lunaix/spike.h>
#include <klibc/string.h>
#include <klibc/stdio.h>
#include <klibc/string.h>
-#define TWIMAP_BUFFER_SIZE 1024
+#define TWIMAP_BUFFER_SIZE 4096
void
__twimap_default_reset(struct twimap* map)
acc_size += rdlen;
}
+ if (acc_size <= len - 1) {
+ // pad zero
+ *(char*)(buffer + acc_size + 1) = 0;
+ }
+
vfree(map->buffer);
return acc_size;
}
char* buf = mapping->buffer + mapping->size_acc;
mapping->size_acc +=
- __ksprintf_internal(buf, fmt, TWIMAP_BUFFER_SIZE, args);
+ __ksprintf_internal(buf, fmt, TWIMAP_BUFFER_SIZE, args) - 1;
va_end(args);
}
struct v_file_ops twimap_file_ops = { .close = default_file_close,
.read = __twimap_file_read,
+ .read_page = __twimap_file_read,
.readdir = default_file_readdir,
.seek = default_file_seek,
.write = default_file_write };
\ No newline at end of file
*/
#include <klibc/string.h>
-#include <lunaix/dirent.h>
#include <lunaix/foptions.h>
#include <lunaix/fs.h>
#include <lunaix/mm/cake.h>
#include <lunaix/process.h>
#include <lunaix/spike.h>
#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
#include <lunaix/fs/twifs.h>
+#include <sys/dirent_defs.h>
+
static struct cake_pile* dnode_pile;
static struct cake_pile* inode_pile;
static struct cake_pile* file_pile;
const int len,
const int dtype)
{
- struct dirent* dent = (struct dirent*)dctx->cb_data;
+ struct lx_dirent* dent = (struct lx_dirent*)dctx->cb_data;
strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
dent->d_nlen = len;
dent->d_type = dtype;
}
-__DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+__DEFINE_LXSYSCALL2(int, sys_readdir, int, fd, struct lx_dirent*, dent)
{
struct v_fd* fd_s;
int errno;
return DO_STATUS(errno);
}
+void
+vfs_ref_file(struct v_file* file)
+{
+ atomic_fetch_add(&file->ref_count, 1);
+}
+
void
vfs_ref_dnode(struct v_dnode* dnode)
{
#include <klibc/string.h>
#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
+
+#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
struct v_xattr_entry*
xattr_new(struct hstr* name)
proc0->intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG,
.es = KDATA_SEG,
.fs = KDATA_SEG,
- .gs = KDATA_SEG },
- .cs = KCODE_SEG,
- .eip = (void*)__proc0,
- .ss = KDATA_SEG,
- .eflags = cpu_reflags() };
+ .gs = KDATA_SEG } };
proc0->parent = proc0;
// 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
// 为内核创建一个专属栈空间。
for (size_t i = 0; i < (KSTACK_SIZE >> PG_SIZE_BITS); i++) {
uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
- vmm_set_mapping(PD_REFERENCED,
+ vmm_set_mapping(VMS_SELF,
KSTACK_START + (i << PG_SIZE_BITS),
pa,
PG_PREM_RW,
VMAP_NULL);
}
- // 手动设置进程上下文:用于第一次调度
- asm volatile("movl %%esp, %%ebx\n"
- "movl %1, %%esp\n"
- "pushf\n"
- "pushl %2\n"
- "pushl %3\n"
- "pushl $0\n"
- "pushl $0\n"
- "movl %%esp, %0\n"
- "movl %%ebx, %%esp\n"
- : "=m"(proc0->intr_ctx.registers.esp)
- : "i"(KSTACK_TOP), "i"(KCODE_SEG), "r"(proc0->intr_ctx.eip)
- : "%ebx", "memory");
+ struct exec_param* execp =
+ (struct exec_param*)(KSTACK_TOP - sizeof(struct exec_param));
+
+ *execp = (struct exec_param){ .cs = KCODE_SEG,
+ .eip = (void*)__proc0,
+ .ss = KDATA_SEG,
+ .eflags = cpu_reflags() };
+ proc0->intr_ctx.execp = execp;
// 加载x87默认配置
asm volatile("fninit\n"
pmm_mark_chunk_occupied(KERNEL_PID, 0, pg_count, PP_FGLOCKED);
for (uintptr_t i = &__usrtext_start; i < &__usrtext_end; i += PG_SIZE) {
- vmm_set_mapping(PD_REFERENCED, i, V2P(i), PG_PREM_UR, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, i, V2P(i), PG_PREM_UR, VMAP_NULL);
}
// reserve higher half
for (size_t i = L1_INDEX(KERNEL_MM_BASE); i < 1023; i++) {
- assert(vmm_set_mapping(PD_REFERENCED, i << 22, 0, 0, VMAP_NOMAP));
+ assert(vmm_set_mapping(VMS_SELF, i << 22, 0, 0, VMAP_NOMAP));
}
}
--- /dev/null
+#include <lunaix/common.h>
+#include <lunaix/elf.h>
+#include <lunaix/fs.h>
+#include <lunaix/ld.h>
+#include <lunaix/mm/mmap.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/spike.h>
+
+int
+__elf_populate_mapped(struct mm_region* region, void* pg, off_t segfoff)
+{
+ size_t segsz = region->flen;
+ size_t segmoff = segfoff - region->foff;
+
+ if (segmoff >= segsz) {
+ return 0;
+ }
+
+ struct v_file* file = region->mfile;
+ size_t rdlen = MIN(segsz - segmoff, PG_SIZE);
+
+ if (rdlen == PG_SIZE) {
+ // This is because we want to exploit any optimization on read_page
+ return file->ops->read_page(file->inode, pg, PG_SIZE, segfoff);
+ } else {
+ // we don't want to over-read the segment!
+ return file->ops->read(file->inode, pg, rdlen, segfoff);
+ }
+}
+
+int
+elf_map_segment(struct ld_param* ldparam,
+ struct v_file* elfile,
+ struct elf32_phdr* phdr)
+{
+ int proct = 0;
+ if ((phdr->p_flags & PF_R)) {
+ proct |= PROT_READ;
+ }
+ if ((phdr->p_flags & PF_W)) {
+ proct |= PROT_WRITE;
+ }
+ if ((phdr->p_flags & PF_X)) {
+ proct |= PROT_EXEC;
+ }
+
+ struct mm_region* seg_reg;
+ struct mmap_param param = { .vms_mnt = ldparam->vms_mnt,
+ .pvms = &ldparam->proc->mm,
+ .proct = proct,
+ .offset = phdr->p_offset,
+ .mlen = ROUNDUP(phdr->p_memsz, PG_SIZE),
+ .flen = phdr->p_filesz,
+ .flags = MAP_FIXED | MAP_PRIVATE,
+ .type = REGION_TYPE_CODE };
+
+ int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdr->p_va), elfile, ¶m);
+
+ if (!status) {
+ seg_reg->init_page = __elf_populate_mapped;
+
+ size_t next_addr = phdr->p_memsz + phdr->p_va;
+ ldparam->info.end = MAX(ldparam->info.end, ROUNDUP(next_addr, PG_SIZE));
+ ldparam->info.mem_sz += phdr->p_memsz;
+ }
+
+ return status;
+}
+
+int
+elf_setup_mapping(struct ld_param* ldparam,
+ struct v_file* elfile,
+ struct elf32_ehdr* ehdr)
+{
+ int status = 0;
+ size_t tbl_sz = ehdr->e_phnum * SIZE_PHDR;
+ struct elf32_phdr* phdrs = valloc(tbl_sz);
+
+ if (!phdrs) {
+ status = ENOMEM;
+ goto done;
+ }
+
+ tbl_sz = 1 << ILOG2(tbl_sz);
+ status = elfile->ops->read(elfile->inode, phdrs, tbl_sz, ehdr->e_phoff);
+
+ if (status < 0) {
+ goto done;
+ }
+
+ if (PG_ALIGN(phdrs[0].p_va) != USER_START) {
+ status = ENOEXEC;
+ goto done;
+ }
+
+ size_t entries = tbl_sz / SIZE_PHDR;
+ for (size_t i = 0; i < entries; i++) {
+ struct elf32_phdr* phdr = &phdrs[i];
+
+ if (phdr->p_type == PT_LOAD) {
+ if (phdr->p_align == PG_SIZE) {
+ status = elf_map_segment(ldparam, elfile, phdr);
+ } else {
+ // surprising alignment!
+ status = ENOEXEC;
+ }
+ }
+ // TODO process other types of segments
+
+ if (status) {
+ // errno in the middle of mapping restructuring, it is impossible
+ // to recover!
+ ldparam->status |= LD_STAT_FKUP;
+ goto done;
+ }
+ }
+
+done:
+ vfree(phdrs);
+ return status;
+}
+
+int
+elf_load(struct ld_param* ldparam, struct v_file* elfile)
+{
+ struct elf32_ehdr* ehdr = valloc(SIZE_EHDR);
+ int status = elfile->ops->read(elfile->inode, ehdr, SIZE_EHDR, 0);
+
+ if (status < 0) {
+ goto done;
+ }
+
+ if (!elf_check_exec(ehdr)) {
+ status = ENOEXEC;
+ goto done;
+ }
+
+ if ((status = elf_setup_mapping(ldparam, elfile, ehdr))) {
+ goto done;
+ }
+
+ ldparam->info.ehdr_out = *ehdr;
+
+done:
+ vfree(ehdr);
+ return status;
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/elf.h>
+#include <lunaix/fs.h>
+#include <lunaix/ld.h>
+#include <lunaix/mm/mmap.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/process.h>
+#include <lunaix/spike.h>
+#include <lunaix/status.h>
+#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
+
+#include <klibc/string.h>
+
+size_t
+exec_str_size(const char** str_arr, size_t* length)
+{
+ if (!str_arr) {
+ *length = 0;
+ return 0;
+ }
+
+ const char* chr = *str_arr;
+ size_t sz = 0, len = 0;
+
+ while (chr) {
+ sz += strlen(chr);
+ len++;
+
+ chr = *(str_arr + sz);
+ }
+
+ *length = len;
+ return sz + 1;
+}
+
+void
+__heap_copied(struct mm_region* region)
+{
+ mm_index((void**)®ion->proc_vms->heap, region);
+}
+
+int
+__exec_remap_heap(struct ld_param* param, struct proc_mm* pvms)
+{
+ if (pvms->heap) {
+ mem_unmap_region(param->vms_mnt, pvms->heap);
+ }
+
+ struct mmap_param map_param = { .pvms = pvms,
+ .vms_mnt = param->vms_mnt,
+ .flags = MAP_ANON | MAP_PRIVATE,
+ .type = REGION_TYPE_HEAP,
+ .proct = PROT_READ | PROT_WRITE,
+ .mlen = PG_SIZE };
+ int status = 0;
+ struct mm_region* heap;
+ if ((status = mem_map(NULL, &heap, param->info.end, NULL, &map_param))) {
+ param->status |= LD_STAT_FKUP;
+ return status;
+ }
+
+ heap->region_copied = __heap_copied;
+ mm_index((void**)&pvms->heap, heap);
+
+ return status;
+}
+
+int
+exec_load(struct ld_param* param,
+ struct v_file* executable,
+ const char** argv,
+ const char** envp)
+{
+ int errno = 0;
+
+ size_t argv_len, envp_len;
+ size_t sz_argv = exec_str_size(argv, &argv_len);
+ size_t sz_envp = exec_str_size(envp, &envp_len);
+ size_t total_sz = ROUNDUP(sz_argv + sz_envp, PG_SIZE);
+
+ if (total_sz / PG_SIZE > MAX_VAR_PAGES) {
+ errno = E2BIG;
+ goto done;
+ }
+
+ if ((errno = elf_load(param, executable))) {
+ goto done;
+ }
+
+ struct proc_mm* pvms = ¶m->proc->mm;
+ struct mmap_param map_vars = { .pvms = pvms,
+ .vms_mnt = param->vms_mnt,
+ .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
+ .type = REGION_TYPE_VARS,
+ .proct = PROT_READ,
+ .mlen = MAX_VAR_PAGES * PG_SIZE };
+
+ void* mapped;
+
+ if ((errno = __exec_remap_heap(param, pvms))) {
+ goto done;
+ }
+
+ if ((errno = mem_map(&mapped, NULL, UMMAP_END, NULL, &map_vars))) {
+ goto done;
+ }
+
+ if (param->vms_mnt == VMS_SELF) {
+ // we are loading executable into current addr space
+
+ // make some handy infos available to user space
+ ptr_t arg_start = mapped + sizeof(struct usr_exec_param);
+ if (argv)
+ memcpy(arg_start, (void*)argv, sz_argv);
+ if (envp)
+ memcpy(arg_start + sz_argv, (void*)envp, sz_envp);
+
+ ptr_t* ustack = (ptr_t*)USTACK_TOP;
+ struct usr_exec_param* exec_param = mapped;
+
+ ustack[-1] = (ptr_t)mapped;
+ param->info.stack_top = &ustack[-1];
+
+ *exec_param = (struct usr_exec_param){ .argc = argv_len,
+ .argv = arg_start,
+ .envc = envp_len,
+ .envp = arg_start + sz_argv,
+ .info = param->info };
+ } else {
+ // TODO need to find a way to inject argv and envp remotely
+ fail("not implemented");
+ }
+
+ param->info.entry = param->info.ehdr_out.e_entry;
+done:
+ return errno;
+}
+
+int
+exec_load_byname(struct ld_param* param,
+ const char* filename,
+ const char** argv,
+ const char** envp)
+{
+ int errno = 0;
+ struct v_dnode* dnode;
+ struct v_file* file;
+
+ if ((errno = vfs_walk_proc(filename, &dnode, NULL, 0))) {
+ goto done;
+ }
+
+ if ((errno = vfs_open(dnode, &file))) {
+ goto done;
+ }
+
+ if ((errno = exec_load(param, file, argv, envp))) {
+ vfs_pclose(file, __current->pid);
+ }
+
+done:
+ return errno;
+}
+
+__DEFINE_LXSYSCALL3(int,
+ execve,
+ const char*,
+ filename,
+ const char*,
+ argv[],
+ const char*,
+ envp[])
+{
+ int errno = 0;
+ struct ld_param ldparam;
+ ld_create_param(&ldparam, __current, VMS_SELF);
+
+ if ((errno = exec_load_byname(&ldparam, filename, argv, envp))) {
+ if ((ldparam.status & LD_STAT_FKUP)) {
+ // we fucked up our address space.
+ terminate_proc(11451);
+ schedule();
+ fail("should not reach");
+ }
+ goto done;
+ }
+
+ volatile struct exec_param* execp = __current->intr_ctx.execp;
+ execp->esp = ldparam.info.stack_top;
+ execp->eip = ldparam.info.entry;
+
+ // we will jump to new entry point (_u_start) upon syscall's
+ // return so execve 'will not return' from the perspective of it's invoker
+
+done:
+ return DO_STATUS(errno);
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/ld.h>
+
+void
+ld_create_param(struct ld_param* param, struct proc_info* proc, ptr_t vms)
+{
+ *param = (struct ld_param){ .proc = proc, .vms_mnt = vms };
+}
\ No newline at end of file
+++ /dev/null
-#include <hal/cpu.h>
-#include <lunaix/clock.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
-#include <lunaix/lxconsole.h>
-#include <lunaix/mm/kalloc.h>
-#include <lunaix/mm/vmm.h>
-#include <lunaix/spike.h>
-#include <lunaix/syslog.h>
-#include <lunaix/timer.h>
-
-extern uint8_t __kernel_start;
-
-LOG_MODULE("INIT")
-
-// #define FORK_BOMB_DEMO
-#define WAIT_DEMO
-#define IN_USER_MODE
-
-void __USER__
-_lxinit_main()
-{
-#ifdef FORK_BOMB_DEMO
- // fork炸弹
- for (;;) {
- pid_t p;
- if ((p = fork())) {
- kprintf(KDEBUG "Pinkie Pie #%d: FUN!\n", p);
- }
- }
-#endif
-
- int status;
-#ifdef WAIT_DEMO
- // 测试wait
- kprintf("I am parent, going to fork my child and wait.\n");
- if (!fork()) {
- kprintf("I am child, going to sleep for 2 seconds\n");
- sleep(2);
- kprintf("I am child, I am about to terminated\n");
- _exit(1);
- }
- wait(&status);
- pid_t child = wait(&status);
- kprintf("I am parent, my child (%d) terminated normally with code: %d.\n",
- child,
- WEXITSTATUS(status));
-#endif
-
- pid_t p = 0;
-
- if (!fork()) {
- kprintf("Test no hang!\n");
- sleep(6);
- _exit(0);
- }
-
- waitpid(-1, &status, WNOHANG);
-
- for (size_t i = 0; i < 5; i++) {
- pid_t pid = 0;
- if (!(pid = fork())) {
- sleep(i);
- if (i == 3) {
- i = *(int*)0xdeadc0de; // seg fault!
- }
- kprintf(KINFO "%d\n", i);
- _exit(0);
- }
- kprintf(KINFO "Forked %d\n", pid);
- }
-
- while ((p = wait(&status)) >= 0) {
- short code = WEXITSTATUS(status);
- if (WIFEXITED(status)) {
- kprintf(KINFO "Process %d exited with code %d\n", p, code);
- } else {
- kprintf(KWARN "Process %d aborted with code %d\n", p, code);
- }
- }
-
- char buf[64];
-
- kprintf(KINFO "Hello processes!\n");
-
- cpu_get_brand(buf);
- kprintf("CPU: %s\n\n", buf);
-
- _exit(0);
-}
\ No newline at end of file
vmm_dup_page(pid_t pid, void* pa)
{
void* new_ppg = pmm_alloc_page(pid, 0);
- vmm_set_mapping(PD_REFERENCED, PG_MOUNT_3, new_ppg, PG_PREM_RW, VMAP_NULL);
- vmm_set_mapping(PD_REFERENCED, PG_MOUNT_4, pa, PG_PREM_RW, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, PG_MOUNT_3, new_ppg, PG_PREM_RW, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, PG_MOUNT_4, pa, PG_PREM_RW, VMAP_NULL);
asm volatile("movl %1, %%edi\n"
"movl %2, %%esi\n"
"r"(PG_MOUNT_4)
: "memory", "%edi", "%esi");
- vmm_del_mapping(PD_REFERENCED, PG_MOUNT_3);
- vmm_del_mapping(PD_REFERENCED, PG_MOUNT_4);
+ vmm_del_mapping(VMS_SELF, PG_MOUNT_3);
+ vmm_del_mapping(VMS_SELF, PG_MOUNT_4);
return new_ppg;
}
\ No newline at end of file
-/**
- * @file dmm.c
- * @author Lunaixsky
- * @brief Dynamic memory manager for heap. This design do not incorporate any\
- * specific implementation of malloc family. The main purpose of this routines
- * is to provide handy method to initialize & grow the heap as needed by
- * upstream implementation.
- *
- * This is designed to be portable, so it can serve as syscalls to malloc/free
- * in the c std lib.
- *
- * @version 0.2
- * @date 2022-03-3
- *
- * @copyright Copyright (c) Lunaixsky 2022
- *
- */
-
-#include <lunaix/mm/dmm.h>
-#include <lunaix/mm/page.h>
-#include <lunaix/mm/vmm.h>
+#include <lunaix/mm/mmap.h>
+#include <lunaix/process.h>
#include <lunaix/status.h>
#include <lunaix/spike.h>
#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
-__DEFINE_LXSYSCALL1(int, sbrk, size_t, size)
-{
- heap_context_t* uheap = &__current->mm.u_heap;
- mutex_lock(&uheap->lock);
- void* r = lxsbrk(uheap, size, PG_ALLOW_USER);
- mutex_unlock(&uheap->lock);
- return r;
-}
-
-__DEFINE_LXSYSCALL1(void*, brk, void*, addr)
-{
- heap_context_t* uheap = &__current->mm.u_heap;
- mutex_lock(&uheap->lock);
- int r = lxbrk(uheap, addr, PG_ALLOW_USER);
- mutex_unlock(&uheap->lock);
- return r;
-}
-
-int
-dmm_init(heap_context_t* heap)
+__DEFINE_LXSYSCALL1(void*, sbrk, ssize_t, incr)
{
- assert((uintptr_t)heap->start % BOUNDARY == 0);
-
- heap->brk = heap->start;
- mutex_init(&heap->lock);
-
- return vmm_set_mapping(PD_REFERENCED,
- heap->brk,
- 0,
- PG_WRITE | PG_ALLOW_USER,
- VMAP_NULL) != NULL;
-}
+ struct proc_mm* pvms = &__current->mm;
+ struct mm_region* heap = pvms->heap;
-int
-lxbrk(heap_context_t* heap, void* addr, int user)
-{
- return -(lxsbrk(heap, addr - heap->brk, user) == (void*)-1);
+ assert(heap);
+ int err = mem_adjust_inplace(&pvms->regions, heap, heap->end + incr);
+ if (err) {
+ return (void*)DO_STATUS(err);
+ }
+ return (void*)heap->end;
}
-void*
-lxsbrk(heap_context_t* heap, size_t size, int user)
+__DEFINE_LXSYSCALL1(int, brk, void*, addr)
{
- if (size == 0) {
- return heap->brk;
- }
-
- void* current_brk = heap->brk;
-
- // The upper bound of our next brk of heap given the size.
- // This will be used to calculate the page we need to allocate.
- void* next = current_brk + ROUNDUP(size, BOUNDARY);
-
- // any invalid situations
- if (next >= heap->max_addr || next < current_brk) {
- __current->k_status = LXINVLDPTR;
- return (void*)-1;
- }
-
- uintptr_t diff = PG_ALIGN(next) - PG_ALIGN(current_brk);
- if (diff) {
- // if next do require new pages to be mapped
- for (size_t i = 0; i < diff; i += PG_SIZE) {
- vmm_set_mapping(PD_REFERENCED,
- PG_ALIGN(current_brk) + PG_SIZE + i,
- 0,
- PG_WRITE | user,
- VMAP_NULL);
- }
- }
+ struct proc_mm* pvms = &__current->mm;
+ struct mm_region* heap = pvms->heap;
- heap->brk += size;
- return current_brk;
+ assert(heap);
+ int err = mem_adjust_inplace(&pvms->regions, heap, (ptr_t)addr);
+ return DO_STATUS(err);
}
\ No newline at end of file
+++ /dev/null
-
-/**** DO NOT USE ****/
-
-/**
- * @file kalloc.c
- * @author Lunaixsky
- * @brief Implicit free list implementation of malloc family, for kernel use.
- *
- * This version of code is however the simplest and yet insecured, thread unsafe
- * it just to demonstrate how the malloc/free works behind the curtain
- * @version 0.1
- * @date 2022-03-05
- *
- * @copyright Copyright (c) 2022
- *
- */
-// #include <lunaix/mm/dmm.h>
-// #include <lunaix/mm/kalloc.h>
-// #include <lunaix/mm/vmm.h>
-
-// #include <lunaix/common.h>
-// #include <lunaix/spike.h>
-
-// #include <klibc/string.h>
-
-// #include <stdint.h>
-
-// extern uint8_t __kernel_heap_start;
-
-// void*
-// lx_malloc_internal(heap_context_t* heap, size_t size);
-
-// void
-// place_chunk(uint8_t* ptr, size_t size);
-
-// void
-// lx_free_internal(void* ptr);
-
-// void*
-// coalesce(uint8_t* chunk_ptr);
-
-// void*
-// lx_grow_heap(heap_context_t* heap, size_t sz);
-
-// /*
-// At the beginning, we allocate an empty page and put our initial marker
-
-// | 4/1 | 0/1 |
-// ^ ^ brk
-// start
-
-// Then, expand the heap further, with HEAP_INIT_SIZE (evaluated to 4096,
-// i.e.,
-// 1 pg size) This will allocate as much pages and override old epilogue
-// marker with a free region hdr and put new epilogue marker. These are
-// handled by lx_grow_heap which is internally used by alloc to expand the
-// heap at many moment when needed.
-
-// | 4/1 | 4096/0 | ....... | 4096/0 | 0/1 |
-// ^ ^ brk_old ^
-// start brk
-
-// Note: the brk always point to the beginning of epilogue.
-// */
-
-// static heap_context_t kheap;
-
-// int
-// kalloc_init()
-// {
-// kheap.start = KHEAP_START;
-// kheap.brk = NULL;
-// kheap.max_addr =
-// (void*)PROC_START; // 在新的布局中,堆结束的地方即为进程表开始的地方
-
-// for (size_t i = 0; i < KHEAP_SIZE_MB >> 2; i++) {
-// vmm_set_mapping(PD_REFERENCED,
-// (uintptr_t)kheap.start + (i << 22),
-// 0,
-// PG_PREM_RW,
-// VMAP_NOMAP);
-// }
-
-// if (!dmm_init(&kheap)) {
-// return 0;
-// }
-
-// SW(kheap.start, PACK(4, M_ALLOCATED));
-// SW(kheap.start + WSIZE, PACK(0, M_ALLOCATED));
-// kheap.brk += WSIZE;
-
-// return lx_grow_heap(&kheap, HEAP_INIT_SIZE) != NULL;
-// }
-
-// void*
-// lxmalloc(size_t size)
-// {
-// mutex_lock(&kheap.lock);
-// void* r = lx_malloc_internal(&kheap, size);
-// mutex_unlock(&kheap.lock);
-
-// return r;
-// }
-
-// void*
-// lxcalloc(size_t n, size_t elem)
-// {
-// size_t pd = n * elem;
-
-// // overflow detection
-// if (pd < elem || pd < n) {
-// return NULL;
-// }
-
-// void* ptr = lxmalloc(pd);
-// if (!ptr) {
-// return NULL;
-// }
-
-// return memset(ptr, 0, pd);
-// }
-
-// void
-// lxfree(void* ptr)
-// {
-// if (!ptr) {
-// return;
-// }
-// mutex_lock(&kheap.lock);
-
-// uint8_t* chunk_ptr = (uint8_t*)ptr - WSIZE;
-// u32_t hdr = LW(chunk_ptr);
-// size_t sz = CHUNK_S(hdr);
-// uint8_t* next_hdr = chunk_ptr + sz;
-
-// // make sure the ptr we are 'bout to free makes sense
-// // the size trick is stolen from glibc's malloc/malloc.c:4437 ;P
-
-// assert_msg(((uintptr_t)ptr < (uintptr_t)(-sz)) && !((uintptr_t)ptr &
-// 0x3),
-// "free(): invalid pointer");
-
-// assert_msg(sz > WSIZE, "free(): invalid size");
-
-// SW(chunk_ptr, hdr & ~M_ALLOCATED);
-// SW(FPTR(chunk_ptr, sz), hdr & ~M_ALLOCATED);
-// SW(next_hdr, LW(next_hdr) | M_PREV_FREE);
-
-// coalesce(chunk_ptr);
-
-// mutex_unlock(&kheap.lock);
-// }
-
-// void*
-// lx_malloc_internal(heap_context_t* heap, size_t size)
-// {
-// // Simplest first fit approach.
-
-// if (!size) {
-// return NULL;
-// }
-
-// uint8_t* ptr = heap->start;
-// // round to largest 4B aligned value
-// // and space for header
-// size = ROUNDUP(size + WSIZE, BOUNDARY);
-// while (ptr < (uint8_t*)heap->brk) {
-// u32_t header = *((u32_t*)ptr);
-// size_t chunk_size = CHUNK_S(header);
-// if (!chunk_size && CHUNK_A(header)) {
-// break;
-// }
-// if (chunk_size >= size && !CHUNK_A(header)) {
-// // found!
-// place_chunk(ptr, size);
-// return BPTR(ptr);
-// }
-// ptr += chunk_size;
-// }
-
-// // if heap is full (seems to be!), then allocate more space (if it's
-// // okay...)
-// if ((ptr = lx_grow_heap(heap, size))) {
-// place_chunk(ptr, size);
-// return BPTR(ptr);
-// }
-
-// // Well, we are officially OOM!
-// return NULL;
-// }
-
-// void
-// place_chunk(uint8_t* ptr, size_t size)
-// {
-// u32_t header = *((u32_t*)ptr);
-// size_t chunk_size = CHUNK_S(header);
-// *((u32_t*)ptr) = PACK(size, CHUNK_PF(header) | M_ALLOCATED);
-// uint8_t* n_hdrptr = (uint8_t*)(ptr + size);
-// u32_t diff = chunk_size - size;
-
-// if (!diff) {
-// // if the current free block is fully occupied
-// u32_t n_hdr = LW(n_hdrptr);
-// // notify the next block about our avaliability
-// SW(n_hdrptr, n_hdr & ~0x2);
-// } else {
-// // if there is remaining free space left
-// u32_t remainder_hdr = PACK(diff, M_NOT_ALLOCATED |
-// M_PREV_ALLOCATED); SW(n_hdrptr, remainder_hdr); SW(FPTR(n_hdrptr,
-// diff), remainder_hdr);
-
-// /*
-// | xxxx | | |
-
-// |
-// v
-
-// | xxxx | |
-// */
-// coalesce(n_hdrptr);
-// }
-// }
-
-// void*
-// coalesce(uint8_t* chunk_ptr)
-// {
-// u32_t hdr = LW(chunk_ptr);
-// u32_t pf = CHUNK_PF(hdr);
-// u32_t sz = CHUNK_S(hdr);
-
-// u32_t n_hdr = LW(chunk_ptr + sz);
-
-// if (CHUNK_A(n_hdr) && pf) {
-// // case 1: prev is free
-// u32_t prev_ftr = LW(chunk_ptr - WSIZE);
-// size_t prev_chunk_sz = CHUNK_S(prev_ftr);
-// u32_t new_hdr = PACK(prev_chunk_sz + sz, CHUNK_PF(prev_ftr));
-// SW(chunk_ptr - prev_chunk_sz, new_hdr);
-// SW(FPTR(chunk_ptr, sz), new_hdr);
-// chunk_ptr -= prev_chunk_sz;
-// } else if (!CHUNK_A(n_hdr) && !pf) {
-// // case 2: next is free
-// size_t next_chunk_sz = CHUNK_S(n_hdr);
-// u32_t new_hdr = PACK(next_chunk_sz + sz, pf);
-// SW(chunk_ptr, new_hdr);
-// SW(FPTR(chunk_ptr, sz + next_chunk_sz), new_hdr);
-// } else if (!CHUNK_A(n_hdr) && pf) {
-// // case 3: both free
-// u32_t prev_ftr = LW(chunk_ptr - WSIZE);
-// size_t next_chunk_sz = CHUNK_S(n_hdr);
-// size_t prev_chunk_sz = CHUNK_S(prev_ftr);
-// u32_t new_hdr =
-// PACK(next_chunk_sz + prev_chunk_sz + sz, CHUNK_PF(prev_ftr));
-// SW(chunk_ptr - prev_chunk_sz, new_hdr);
-// SW(FPTR(chunk_ptr, sz + next_chunk_sz), new_hdr);
-// chunk_ptr -= prev_chunk_sz;
-// }
-
-// // (fall through) case 4: prev and next are not free
-// return chunk_ptr;
-// }
-
-// void*
-// lx_grow_heap(heap_context_t* heap, size_t sz)
-// {
-// void* start;
-
-// // The "+ WSIZE" capture the overhead for epilogue marker
-// if (!(start = lxsbrk(heap, sz + WSIZE, 0))) {
-// return NULL;
-// }
-// sz = ROUNDUP(sz, BOUNDARY);
-
-// // minus the overhead for epilogue, keep the invariant.
-// heap->brk -= WSIZE;
-
-// u32_t old_marker = *((u32_t*)start);
-// u32_t free_hdr = PACK(sz, CHUNK_PF(old_marker));
-// SW(start, free_hdr);
-// SW(FPTR(start, sz), free_hdr);
-// SW(NEXT_CHK(start), PACK(0, M_ALLOCATED | M_PREV_FREE));
-
-// return coalesce(start);
-// }
\ No newline at end of file
--- /dev/null
+#include <lunaix/mm/mmap.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/spike.h>
+
+#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
+
+// any size beyond this is bullshit
+#define BS_SIZE (KERNEL_MM_BASE - UMMAP_START)
+
+int
+mem_has_overlap(vm_regions_t* regions, ptr_t start, ptr_t end)
+{
+ struct mm_region *pos, *n;
+ llist_for_each(pos, n, regions, head)
+ {
+ if (pos->end >= start && pos->start < start) {
+ return 1;
+ }
+
+ if (pos->end <= end && pos->start >= start) {
+ return 1;
+ }
+
+ if (pos->end >= end && pos->start < end) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+mem_adjust_inplace(vm_regions_t* regions,
+ struct mm_region* region,
+ ptr_t newend)
+{
+ ssize_t len = newend - region->start;
+ if (len == 0) {
+ return 0;
+ }
+
+ if (len < 0) {
+ return EINVAL;
+ }
+
+ if (mem_has_overlap(regions, region->start, newend)) {
+ return ENOMEM;
+ }
+
+ region->end = newend;
+
+ return 0;
+}
+
+int
+mem_map(void** addr_out,
+ struct mm_region** created,
+ void* addr,
+ struct v_file* file,
+ struct mmap_param* param)
+{
+ assert_msg(addr, "addr can not be NULL");
+
+ ptr_t last_end = USER_START, found_loc = (ptr_t)addr;
+ struct mm_region *pos, *n;
+
+ vm_regions_t* vm_regions = ¶m->pvms->regions;
+
+ if ((param->flags & MAP_FIXED_NOREPLACE)) {
+ if (mem_has_overlap(vm_regions, found_loc, param->mlen + found_loc)) {
+ return EEXIST;
+ }
+ goto found;
+ }
+
+ if ((param->flags & MAP_FIXED)) {
+ int status =
+ mem_unmap(param->vms_mnt, vm_regions, found_loc, param->mlen);
+ if (status) {
+ return status;
+ }
+ goto found;
+ }
+
+ llist_for_each(pos, n, vm_regions, head)
+ {
+ if (last_end < found_loc) {
+ size_t avail_space = pos->start - found_loc;
+ if (pos->start > found_loc && avail_space > param->mlen) {
+ goto found;
+ }
+ found_loc = pos->end + PG_SIZE;
+ }
+
+ last_end = pos->end;
+ }
+
+ return ENOMEM;
+
+found:
+ if (found_loc >= KERNEL_MM_BASE || found_loc < USER_START) {
+ return ENOMEM;
+ }
+
+ struct mm_region* region = region_create_range(
+ found_loc,
+ param->mlen,
+ ((param->proct | param->flags) & 0x3f) | (param->type & ~0xffff));
+
+ region->mfile = file;
+ region->foff = param->offset;
+ region->flen = param->flen;
+ region->proc_vms = param->pvms;
+
+ region_add(vm_regions, region);
+
+ u32_t attr = PG_ALLOW_USER;
+ if ((param->proct & REGION_WRITE)) {
+ attr |= PG_WRITE;
+ }
+
+ for (u32_t i = 0; i < param->mlen; i += PG_SIZE) {
+ vmm_set_mapping(param->vms_mnt, found_loc + i, 0, attr, 0);
+ }
+
+ if (file) {
+ vfs_ref_file(file);
+ }
+
+ if (addr_out) {
+ *addr_out = found_loc;
+ }
+ if (created) {
+ *created = region;
+ }
+ return 0;
+}
+
+void
+mem_sync_pages(ptr_t mnt,
+ struct mm_region* region,
+ ptr_t start,
+ ptr_t length,
+ int options)
+{
+ if (!region->mfile || !(region->attr & REGION_WSHARED)) {
+ return;
+ }
+
+ v_mapping mapping;
+ for (size_t i = 0; i < length; i += PG_SIZE) {
+ if (!vmm_lookupat(mnt, start + i, &mapping)) {
+ continue;
+ }
+
+ if (PG_IS_DIRTY(*mapping.pte)) {
+ size_t offset = mapping.va - region->start + region->foff;
+ struct v_inode* inode = region->mfile->inode;
+ region->mfile->ops->write_page(inode, mapping.va, PG_SIZE, offset);
+ *mapping.pte &= ~PG_DIRTY;
+ cpu_invplg(mapping.pte);
+ } else if ((options & MS_INVALIDATE)) {
+ goto invalidate;
+ }
+
+ if (options & MS_INVALIDATE_ALL) {
+ goto invalidate;
+ }
+
+ continue;
+
+ invalidate:
+ *mapping.pte &= ~PG_PRESENT;
+ pmm_free_page(KERNEL_PID, mapping.pa);
+ cpu_invplg(mapping.pte);
+ }
+}
+
+int
+mem_msync(ptr_t mnt,
+ vm_regions_t* regions,
+ ptr_t addr,
+ size_t length,
+ int options)
+{
+ struct mm_region* pos = list_entry(regions->next, struct mm_region, head);
+ while (length && (ptr_t)&pos->head != (ptr_t)regions) {
+ if (pos->end >= addr && pos->start <= addr) {
+ size_t l = MIN(length, pos->end - addr);
+ mem_sync_pages(mnt, pos, addr, l, options);
+
+ addr += l;
+ length -= l;
+ }
+ pos = list_entry(pos->head.next, struct mm_region, head);
+ }
+
+ if (length) {
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+void
+mem_unmap_region(ptr_t mnt, struct mm_region* region)
+{
+ size_t len = ROUNDUP(region->end - region->start, PG_SIZE);
+ mem_sync_pages(mnt, region, region->start, len, 0);
+
+ for (size_t i = region->start; i <= region->end; i += PG_SIZE) {
+ ptr_t pa = vmm_del_mapping(mnt, i);
+ if (pa) {
+ pmm_free_page(__current->pid, pa);
+ }
+ }
+ llist_delete(®ion->head);
+ region_release(region);
+}
+
+int
+mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length)
+{
+ length = ROUNDUP(length, PG_SIZE);
+ ptr_t cur_addr = PG_ALIGN(addr);
+ struct mm_region *pos, *n;
+
+ llist_for_each(pos, n, regions, head)
+ {
+ if (pos->start <= cur_addr && pos->end >= cur_addr) {
+ break;
+ }
+ }
+
+ while (&pos->head != regions && cur_addr >= pos->start) {
+ u32_t l = pos->end - cur_addr;
+ pos->end = cur_addr;
+
+ if (l > length) {
+ // unmap cause discontinunity in a memory region - do split
+ struct mm_region* region = valloc(sizeof(struct mm_region));
+ *region = *pos;
+ region->start = cur_addr + length;
+ llist_insert_after(&pos->head, ®ion->head);
+ l = length;
+ }
+
+ mem_sync_pages(mnt, pos, cur_addr, l, 0);
+
+ for (size_t i = 0; i < l; i += PG_SIZE) {
+ ptr_t pa = vmm_del_mapping(mnt, cur_addr + i);
+ if (pa) {
+ pmm_free_page(pos->proc_vms->pid, pa);
+ }
+ }
+
+ n = container_of(pos->head.next, typeof(*pos), head);
+ if (pos->end == pos->start) {
+ llist_delete(&pos->head);
+ region_release(pos);
+ }
+
+ pos = n;
+ length -= l;
+ cur_addr += length;
+ }
+
+ return 0;
+}
+
+__DEFINE_LXSYSCALL3(void*, sys_mmap, void*, addr, size_t, length, va_list, lst)
+{
+ int proct = va_arg(lst, int);
+ int fd = va_arg(lst, u32_t);
+ off_t offset = va_arg(lst, off_t);
+ int options = va_arg(lst, int);
+ int errno = 0;
+ void* result = (void*)-1;
+
+ if (!length || length > BS_SIZE || !PG_ALIGNED(addr)) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ if (!addr) {
+ addr = UMMAP_START;
+ } else if (addr < UMMAP_START || addr + length >= UMMAP_END) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ struct v_fd* vfd;
+ if ((errno = vfs_getfd(fd, &vfd))) {
+ goto done;
+ }
+
+ struct v_file* file = vfd->file;
+
+ if (!(options & MAP_ANON)) {
+ if (!file->ops->read_page) {
+ errno = ENODEV;
+ goto done;
+ }
+ } else {
+ file = NULL;
+ }
+
+ struct mmap_param param = { .flags = options,
+ .mlen = ROUNDUP(length, PG_SIZE),
+ .offset = offset,
+ .type = REGION_TYPE_GENERAL,
+ .proct = proct,
+ .pvms = &__current->mm,
+ .vms_mnt = VMS_SELF };
+
+ errno = mem_map(&result, NULL, addr, file, ¶m);
+
+done:
+ __current->k_status = errno;
+ return result;
+}
+
+__DEFINE_LXSYSCALL2(void, munmap, void*, addr, size_t, length)
+{
+ return mem_unmap(VMS_SELF, &__current->mm.regions, addr, length);
+}
+
+__DEFINE_LXSYSCALL3(int, msync, void*, addr, size_t, length, int, flags)
+{
+ if (!PG_ALIGNED(addr) || ((flags & MS_ASYNC) && (flags & MS_SYNC))) {
+ return DO_STATUS(EINVAL);
+ }
+
+ int status =
+ mem_msync(VMS_SELF, &__current->mm.regions, addr, length, flags);
+
+ return DO_STATUS(status);
+}
\ No newline at end of file
iounmap(uintptr_t vaddr, u32_t size)
{
for (size_t i = 0; i < size; i += PG_SIZE) {
- uintptr_t paddr = vmm_del_mapping(PD_REFERENCED, vaddr + i);
+ uintptr_t paddr = vmm_del_mapping(VMS_SELF, vaddr + i);
pmm_free_page(KERNEL_PID, paddr);
}
}
\ No newline at end of file
+#include <lunaix/mm/page.h>
#include <lunaix/mm/region.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
-void
-region_add(struct mm_region* regions,
- unsigned long start,
- unsigned long end,
- unsigned int attr)
+#include <klibc/string.h>
+
+struct mm_region*
+region_create(ptr_t start, ptr_t end, u32_t attr)
{
+ assert_msg(PG_ALIGNED(start), "not page aligned");
+ assert_msg(PG_ALIGNED(end), "not page aligned");
struct mm_region* region = valloc(sizeof(struct mm_region));
+ *region =
+ (struct mm_region){ .attr = attr, .start = start, .end = end - 1 };
+ return region;
+}
+
+struct mm_region*
+region_create_range(ptr_t start, size_t length, u32_t attr)
+{
+ assert_msg(PG_ALIGNED(start), "not page aligned");
+ assert_msg(PG_ALIGNED(length), "not page aligned");
+ struct mm_region* region = valloc(sizeof(struct mm_region));
+ *region = (struct mm_region){ .attr = attr,
+ .start = start,
+ .end = PG_ALIGN(start + length - 1) };
+ return region;
+}
- *region = (struct mm_region){ .attr = attr, .end = end, .start = start };
+void
+region_add(vm_regions_t* lead, struct mm_region* vmregion)
+{
+ if (llist_empty(lead)) {
+ llist_append(lead, &vmregion->head);
+ return;
+ }
- llist_append(®ions->head, ®ion->head);
+ ptr_t cur_end = 0;
+ struct mm_region *pos = (struct mm_region*)lead,
+ *n = list_entry(lead->next, struct mm_region, head);
+ do {
+ if (vmregion->start > cur_end && vmregion->end < n->start) {
+ break;
+ }
+ cur_end = n->end;
+ pos = n;
+ n = list_entry(n->head.next, struct mm_region, head);
+ } while ((ptr_t)&n->head != (ptr_t)lead);
+
+ // XXX caution. require mm_region::head to be the lead of struct
+ llist_insert_after(&pos->head, &vmregion->head);
}
void
-region_release_all(struct mm_region* regions)
+region_release(struct mm_region* region)
{
- struct mm_region *pos, *n;
+ if (region->destruct_region) {
+ region->destruct_region(region);
+ }
- llist_for_each(pos, n, ®ions->head, head)
- {
- vfree(pos);
+ if (region->mfile) {
+ vfs_pclose(region->mfile, region->proc_vms->pid);
}
+
+ if (region->index) {
+ *region->index = NULL;
+ }
+
+ vfree(region);
}
void
-region_copy(struct mm_region* src, struct mm_region* dest)
+region_release_all(vm_regions_t* lead)
{
- if (!src) {
- return;
+ struct mm_region *pos, *n;
+
+ llist_for_each(pos, n, lead, head)
+ {
+ region_release(pos);
}
+}
- struct mm_region *pos, *n;
+void
+region_copy(struct proc_mm* src, struct proc_mm* dest)
+{
+ struct mm_region *pos, *n, *dup;
- llist_for_each(pos, n, &src->head, head)
+ llist_for_each(pos, n, &src->regions, head)
{
- region_add(dest, pos->start, pos->end, pos->attr);
+ dup = valloc(sizeof(struct mm_region));
+ memcpy(dup, pos, sizeof(*pos));
+
+ dup->proc_vms = dest;
+
+ if (dup->mfile) {
+ vfs_ref_file(dup->mfile);
+ }
+
+ if (dup->region_copied) {
+ dup->region_copied(dup);
+ }
+
+ region_add(&dest->regions, dup);
}
}
struct mm_region*
-region_get(struct mm_region* regions, unsigned long vaddr)
+region_get(vm_regions_t* lead, unsigned long vaddr)
{
- if (!regions) {
+ if (llist_empty(lead)) {
return NULL;
}
struct mm_region *pos, *n;
- llist_for_each(pos, n, ®ions->head, head)
+ vaddr = PG_ALIGN(vaddr);
+
+ llist_for_each(pos, n, lead, head)
{
- if (pos->start <= vaddr && vaddr < pos->end) {
+ if (pos->start <= vaddr && vaddr <= pos->end) {
return pos;
}
}
#include <lunaix/spike.h>
#define VMAP_START PG_MOUNT_BASE + MEM_4MB
-#define VMAP_END PD_REFERENCED
+#define VMAP_END VMS_SELF
static uintptr_t start = VMAP_START;
done:
uintptr_t alloc_begin = current_addr - examed_size;
for (size_t i = 0; i < size; i += PG_SIZE) {
- vmm_set_mapping(
- PD_REFERENCED, alloc_begin + i, paddr + i, PG_PREM_RW, 0);
+ vmm_set_mapping(VMS_SELF, alloc_begin + i, paddr + i, PG_PREM_RW, 0);
pmm_ref_page(KERNEL_PID, paddr + i);
}
start = alloc_begin + size;
}
}
- if (mnt == PD_REFERENCED) {
+ if (mnt == VMS_SELF) {
cpu_invplg(va);
}
int
vmm_lookup(uintptr_t va, v_mapping* mapping)
+{
+ return vmm_lookupat(VMS_SELF, va, mapping);
+}
+
+int
+vmm_lookupat(ptr_t mnt, uintptr_t va, v_mapping* mapping)
{
u32_t l1_index = L1_INDEX(va);
u32_t l2_index = L2_INDEX(va);
- x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
+ x86_page_table* l1pt = (x86_page_table*)(mnt | 1023 << 12);
x86_pte_t l1pte = l1pt->entry[l1_index];
if (l1pte) {
x86_pte_t* l2pte =
- &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index];
+ &((x86_page_table*)(mnt | (l1_index << 12)))->entry[l2_index];
if (l2pte) {
mapping->flags = PG_ENTRY_FLAGS(*l2pte);
mapping->pa = PG_ENTRY_ADDR(*l2pte);
return 0;
}
+void*
+vmm_v2pat(ptr_t mnt, void* va)
+{
+ u32_t l1_index = L1_INDEX(va);
+ u32_t l2_index = L2_INDEX(va);
+
+ x86_page_table* l1pt = (x86_page_table*)(mnt | 1023 << 12);
+ x86_pte_t l1pte = l1pt->entry[l1_index];
+
+ if (l1pte) {
+ x86_pte_t* l2pte =
+ &((x86_page_table*)(mnt | (l1_index << 12)))->entry[l2_index];
+ if (l2pte) {
+ return PG_ENTRY_ADDR(*l2pte) | ((uintptr_t)va & 0xfff);
+ }
+ }
+ return 0;
+}
+
void*
vmm_mount_pd(uintptr_t mnt, void* pde)
{
#include <lunaix/block.h>
#include <lunaix/common.h>
-#include <lunaix/fctrl.h>
#include <lunaix/foptions.h>
#include <lunaix/fs.h>
#include <lunaix/fs/twifs.h>
-#include <lunaix/lunaix.h>
-#include <lunaix/lunistd.h>
+#include <lunaix/ld.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/cake.h>
#include <lunaix/mm/pmm.h>
#include <klibc/string.h>
-#include <ulibc/stdio.h>
-
LOG_MODULE("PROC0")
-extern void
-_lxinit_main(); /* lxinit.c */
-
void
init_platform();
void
__do_reserved_memory(int unlock);
-#define USE_DEMO
-// #define DEMO_SIGNAL
-// #define DEMO_READDIR
-// #define DEMO_IOTEST
-// #define DEMO_INPUT_TEST
-#define DEMO_SIMPLE_SH
-
-extern void
-_pconsole_main();
-
-extern void
-_signal_demo_main();
-
-extern void
-_lxinit_main();
-
-extern void
-_readdir_main();
-
-extern void
-_iotest_main();
-
-extern void
-input_test();
-
-extern void
-sh_main();
-
-void __USER__
-__setup_dir()
+int
+mount_bootmedium()
{
- int errno;
- mkdir("/mnt");
- mkdir("/mnt/lunaix-os");
+ struct v_dnode* dnode;
+ int errno = 0;
+ if ((errno = vfs_walk_proc("/dev/sdb", &dnode, NULL, 0))) {
+ kprintf(KERROR "fail to acquire device. (%d)", errno);
+ return 0;
+ }
- if ((errno = mount("/dev/sdb", "/mnt/lunaix-os", "iso9660", 0))) {
- syslog(2, "fail mounting boot medium. (%d)\n", errno);
+ struct device* dev = (struct device*)dnode->inode->data;
+ if ((errno = vfs_mount("/mnt/lunaix-os", "iso9660", dev, 0))) {
+ kprintf(KERROR "fail to boot medium. (%d)", errno);
+ return 0;
}
+
+ return 1;
}
-void __USER__
-__proc0_usr()
+int
+exec_initd()
{
- // 打开tty设备(控制台),作为标准输入输出。
- // tty设备属于序列设备(Sequential Device),该类型设备的上层读写
- // 无须经过Lunaix的缓存层,而是直接下发到底层驱动。(不受FO_DIRECT的影响)
- int fdstdout = open("/dev/tty", 0);
- int fdstdin = dup2(stdout, 1);
-
- __setup_dir();
-
- pid_t p;
-
- if (!(p = fork())) {
-#ifndef USE_DEMO
- _exit(0);
-#elif defined DEMO_SIGNAL
- _signal_demo_main();
-#elif defined DEMO_READDIR
- _readdir_main();
-#elif defined DEMO_IOTEST
- _iotest_main();
-#elif defined DEMO_INPUT_TEST
- input_test();
-#elif defined DEMO_SIMPLE_SH
- sh_main();
-#else
- _lxinit_main();
-#endif
- printf("==== test end ====\n");
- _exit(0);
- }
+ int errno = 0;
+ struct ld_param param;
+ char filename[] = "/mnt/lunaix-os/usr/init";
- waitpid(p, 0, 0);
+ ld_create_param(¶m, __current, VMS_SELF);
- while (1) {
- yield();
+ if ((errno = exec_load_byname(¶m, filename, NULL, NULL))) {
+ goto fail;
}
+
+ // user space
+ asm volatile("movw %0, %%ax\n"
+ "movw %%ax, %%es\n"
+ "movw %%ax, %%ds\n"
+ "movw %%ax, %%fs\n"
+ "movw %%ax, %%gs\n"
+ "pushl %0\n"
+ "pushl %1\n"
+ "pushl %2\n"
+ "pushl %3\n"
+ "retf" ::"i"(UDATA_SEG),
+ "r"(param.info.stack_top),
+ "i"(UCODE_SEG),
+ "r"(param.info.entry)
+ : "eax", "memory");
+
+ fail("should not reach");
+
+fail:
+ kprintf(KERROR "fail to load initd. (%d)", errno);
+ return 0;
}
/**
init_proc_user_space(__current);
- // user space
- asm volatile("movw %0, %%ax\n"
- "movw %%ax, %%es\n"
- "movw %%ax, %%ds\n"
- "movw %%ax, %%fs\n"
- "movw %%ax, %%gs\n"
- "pushl %0\n"
- "pushl %1\n"
- "pushl %2\n"
- "pushl %3\n"
- "retf" ::"i"(UDATA_SEG),
- "i"(USTACK_TOP & ~0xf),
- "i"(UCODE_SEG),
- "r"(__proc0_usr)
- : "eax", "memory");
+ if (!mount_bootmedium() || !exec_initd()) {
+ while (1) {
+ asm("hlt");
+ }
+ // should not reach
+ }
}
extern uint8_t __kernel_start; /* link/linker.ld */
// clean up
for (size_t i = 0; i < (uintptr_t)(&__init_hhk_end); i += PG_SIZE) {
- vmm_del_mapping(PD_REFERENCED, (void*)i);
+ vmm_del_mapping(VMS_SELF, (void*)i);
pmm_free_page(KERNEL_PID, (void*)i);
}
}
// Don't fuck up our kernel space!
break;
}
- vmm_set_mapping(PD_REFERENCED, _pa, _pa, PG_PREM_R, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, _pa, _pa, PG_PREM_R, VMAP_NULL);
pmm_mark_page_occupied(
KERNEL_PID, _pa >> PG_SIZE_BITS, PP_FGLOCKED);
}
mmap.type);
for (; j < pg_num; j++) {
uintptr_t _pa = pa + (j << PG_SIZE_BITS);
- vmm_del_mapping(PD_REFERENCED, _pa);
+ vmm_del_mapping(VMS_SELF, _pa);
if (mmap.type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE) {
pmm_mark_page_free(_pa >> PG_SIZE_BITS);
}
#include <klibc/string.h>
#include <lunaix/clock.h>
#include <lunaix/common.h>
+#include <lunaix/mm/mmap.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/region.h>
#include <lunaix/mm/valloc.h>
__dup_pagetable(pid_t pid, uintptr_t mount_point)
{
void* ptd_pp = pmm_alloc_page(pid, PP_FGPERSIST);
- vmm_set_mapping(PD_REFERENCED, PG_MOUNT_1, ptd_pp, PG_PREM_RW, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, PG_MOUNT_1, ptd_pp, PG_PREM_RW, VMAP_NULL);
x86_page_table* ptd = PG_MOUNT_1;
x86_page_table* pptd = (x86_page_table*)(mount_point | (0x3FF << 12));
// 复制L2页表
void* pt_pp = pmm_alloc_page(pid, PP_FGPERSIST);
- vmm_set_mapping(
- PD_REFERENCED, PG_MOUNT_2, pt_pp, PG_PREM_RW, VMAP_NULL);
+ vmm_set_mapping(VMS_SELF, PG_MOUNT_2, pt_pp, PG_PREM_RW, VMAP_NULL);
x86_page_table* ppt = (x86_page_table*)(mount_point | (i << 12));
x86_page_table* pt = PG_MOUNT_2;
void*
vmm_dup_vmspace(pid_t pid)
{
- return __dup_pagetable(pid, PD_REFERENCED);
+ return __dup_pagetable(pid, VMS_SELF);
}
__DEFINE_LXSYSCALL(pid_t, fork)
return 0;
}
+void
+__stack_copied(struct mm_region* region)
+{
+ mm_index((void**)®ion->proc_vms->stack, region);
+}
+
void
init_proc_user_space(struct proc_info* pcb)
{
- vmm_mount_pd(PD_MOUNT_1, pcb->page_table);
+ vmm_mount_pd(VMS_MOUNT_1, pcb->page_table);
/*--- 分配用户栈 ---*/
- // 注册用户栈区域
- region_add(
- &pcb->mm.regions, USTACK_END, USTACK_TOP, REGION_RW | REGION_RSHARED);
-
- // 预留地址空间,具体物理页将由Page Fault Handler按需分配。
- for (uintptr_t i = PG_ALIGN(USTACK_END); i < USTACK_TOP; i += PG_SIZE) {
- vmm_set_mapping(PD_MOUNT_1, i, 0, PG_ALLOW_USER | PG_WRITE, VMAP_NULL);
+ struct mm_region* mapped;
+ struct mmap_param param = { .vms_mnt = VMS_MOUNT_1,
+ .pvms = &pcb->mm,
+ .mlen = USTACK_SIZE,
+ .proct = PROT_READ | PROT_WRITE,
+ .flags = MAP_ANON | MAP_PRIVATE | MAP_FIXED,
+ .type = REGION_TYPE_STACK };
+
+ int status = 0;
+ if ((status = mem_map(NULL, &mapped, USTACK_END, NULL, ¶m))) {
+ kprint_panic("fail to alloc user stack: %d", status);
}
+ mapped->region_copied = __stack_copied;
+ mm_index((void**)&pcb->mm.stack, mapped);
+
// TODO other uspace initialization stuff
- vmm_unmount_pd(PD_MOUNT_1);
+ vmm_unmount_pd(VMS_MOUNT_1);
}
void
__mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr)
{
for (size_t i = start_vpn; i <= end_vpn; i++) {
- x86_pte_t* curproc = &PTE_MOUNTED(PD_REFERENCED, i);
- x86_pte_t* newproc = &PTE_MOUNTED(PD_MOUNT_1, i);
+ x86_pte_t* curproc = &PTE_MOUNTED(VMS_SELF, i);
+ x86_pte_t* newproc = &PTE_MOUNTED(VMS_MOUNT_1, i);
cpu_invplg(newproc);
if ((attr & REGION_MODE_MASK) == REGION_RSHARED) {
dup_proc()
{
struct proc_info* pcb = alloc_process();
- pcb->mm.u_heap = __current->mm.u_heap;
pcb->intr_ctx = __current->intr_ctx;
pcb->parent = __current;
}
__copy_fdtable(pcb);
- region_copy(&__current->mm.regions, &pcb->mm.regions);
+ region_copy(&__current->mm, &pcb->mm);
- setup_proc_mem(pcb, PD_REFERENCED);
+ setup_proc_mem(pcb, VMS_SELF);
// 根据 mm_region 进一步配置页表
struct mm_region *pos, *n;
- llist_for_each(pos, n, &pcb->mm.regions.head, head)
+ llist_for_each(pos, n, &pcb->mm.regions, head)
{
// 如果写共享,则不作处理。
if ((pos->attr & REGION_WSHARED)) {
__mark_region(start_vpn, end_vpn, pos->attr);
}
- vmm_unmount_pd(PD_MOUNT_1);
+ vmm_unmount_pd(VMS_MOUNT_1);
// 正如同fork,返回两次。
pcb->intr_ctx.registers.eax = 0;
pid_t pid = proc->pid;
void* pt_copy = __dup_pagetable(pid, usedMnt);
- vmm_mount_pd(PD_MOUNT_1, pt_copy); // 将新进程的页表挂载到挂载点#2
+ vmm_mount_pd(VMS_MOUNT_1, pt_copy); // 将新进程的页表挂载到挂载点#2
// copy the kernel stack
for (size_t i = KSTACK_START >> 12; i <= KSTACK_TOP >> 12; i++) {
- volatile x86_pte_t* ppte = &PTE_MOUNTED(PD_MOUNT_1, i);
+ volatile x86_pte_t* ppte = &PTE_MOUNTED(VMS_MOUNT_1, i);
/*
This is a fucking nightmare, the TLB caching keep the rewrite to PTE
#include <lunaix/fs/taskfs.h>
#include <lunaix/mm/cake.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/mmap.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/syscall.h>
#include <lunaix/syslog.h>
+#include <klibc/string.h>
+
volatile struct proc_info* __current;
static struct proc_info dummy_proc;
extern void my_dummy();
static char dummy_stack[DUMMY_STACK_SIZE] __attribute__((aligned(16)));
- // memset to 0
- dummy_proc = (struct proc_info){};
- dummy_proc.intr_ctx = (isr_param){
- .registers = { .ds = KDATA_SEG,
- .es = KDATA_SEG,
- .fs = KDATA_SEG,
- .gs = KDATA_SEG,
- .esp = (void*)dummy_stack + DUMMY_STACK_SIZE - 20 },
+ struct exec_param* execp =
+ (void*)dummy_stack + DUMMY_STACK_SIZE - sizeof(struct exec_param);
+
+ *execp = (struct exec_param){
.cs = KCODE_SEG,
+ .eflags = cpu_reflags() | 0x0200,
.eip = (void*)my_dummy,
.ss = KDATA_SEG,
- .eflags = cpu_reflags() | 0x0200
};
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 4]) = dummy_proc.intr_ctx.eflags;
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 8]) = KCODE_SEG;
- *(u32_t*)(&dummy_stack[DUMMY_STACK_SIZE - 12]) = dummy_proc.intr_ctx.eip;
+ // memset to 0
+ dummy_proc = (struct proc_info){};
+ dummy_proc.intr_ctx = (isr_param){ .registers = { .ds = KDATA_SEG,
+ .es = KDATA_SEG,
+ .fs = KDATA_SEG,
+ .gs = KDATA_SEG },
+ .execp = execp };
dummy_proc.page_table = cpu_rcr3();
dummy_proc.state = PS_READY;
由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
*/
- tss_update_esp(proc->intr_ctx.registers.esp);
+ tss_update_esp(proc->intr_ctx.esp);
apic_done_servicing();
proc->state = PS_CREATED;
proc->pid = i;
+ proc->mm.pid = i;
proc->created = clock_systime();
proc->pgid = proc->pid;
proc->fdtable = vzalloc(sizeof(struct v_fdtable));
proc->fxstate =
vzalloc_dma(512); // FXSAVE需要十六位对齐地址,使用DMA块(128位对齐)
- llist_init_head(&proc->mm.regions.head);
+ llist_init_head(&proc->mm.regions);
llist_init_head(&proc->tasks);
llist_init_head(&proc->children);
llist_init_head(&proc->grp_member);
vfree(proc->fdtable);
vfree_dma(proc->fxstate);
+ vmm_mount_pd(VMS_MOUNT_1, proc->page_table);
+
struct mm_region *pos, *n;
- llist_for_each(pos, n, &proc->mm.regions.head, head)
+ llist_for_each(pos, n, &proc->mm.regions, head)
{
- vfree(pos);
+ mem_sync_pages(VMS_MOUNT_1, pos, pos->start, pos->end - pos->start, 0);
+ region_release(pos);
}
- vmm_mount_pd(PD_MOUNT_1, proc->page_table);
-
- __del_pagetable(pid, PD_MOUNT_1);
+ __del_pagetable(pid, VMS_MOUNT_1);
- vmm_unmount_pd(PD_MOUNT_1);
+ vmm_unmount_pd(VMS_MOUNT_1);
cake_release(proc_pile, proc);
-#include <klibc/string.h>
-#include <lunaix/lunistd.h>
-#include <lunaix/lxsignal.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/signal.h>
#include <lunaix/status.h>
#include <lunaix/syscall.h>
+#include <klibc/string.h>
+
extern struct scheduler sched_ctx; /* kernel/sched.c */
void __USER__
#include <lunaix/fs/taskfs.h>
+#include <lunaix/process.h>
void
__read_pending_sig(struct twimap* map)
-#include <lunaix/dirent.h>
#include <lunaix/fs/taskfs.h>
#include <lunaix/fs/twimap.h>
#include <lunaix/mm/valloc.h>
#include <klibc/stdio.h>
#include <klibc/string.h>
+#include <sys/dirent_defs.h>
+
#define COUNTER_MASK ((1 << 16) - 1)
static struct hbucket* attr_export_table;
#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/sched.h>
+#include <lunaix/signal.h>
#include <lunaix/tty/console.h>
#include <lunaix/tty/tty.h>
-#include <lunaix/lxsignal.h>
-
static struct console lx_console;
int
}
size_t
-strnlen(const char* str, size_t max_len) {
+strnlen(const char* str, size_t max_len)
+{
size_t len = 0;
while (str[len] && len <= max_len)
len++;
+++ /dev/null
-#include <klibc/stdio.h>
-#include <lunaix/lunistd.h>
-#include <lunaix/spike.h>
-#include <ulibc/stdio.h>
-
-// This is VERY bad implementation as it mixes both kernel and user space
-// code together. It is here however, just for the convenience of our testing
-// program.
-// FIXME Eliminate this when we're able to load program.
-
-void __USER__
-printf(const char* fmt, ...)
-{
- const char buf[512];
- va_list args;
- va_start(args, fmt);
-
- size_t sz = __ksprintf_internal(buf, fmt, 512, args);
-
- write(stdout, buf, sz);
-
- va_end(args);
-}
\ No newline at end of file
include config/make-cc
include config/make-debug-tool
-DEPS := $(CC) $(LD) xorriso grub-mkrescue
-
-INCLUDES := $(patsubst %, -I%, $(INCLUDES_DIR))
-SOURCE_FILES := $(shell find -name "*.[cS]")
-SRC := $(patsubst ./%, $(OBJECT_DIR)/%.o, $(SOURCE_FILES))
+DEPS := $(CC) $(LD) $(AR) xorriso grub-mkrescue
$(DEPS):
@echo -n "checking $@ .... "
@echo -n "checking target i686-elf.... "
@test "`i686-elf-gcc -dumpmachine`" = "i686-elf" && echo ok || (echo "failed" && exit 1)
-check: $(DEPS) check-cc
-
$(OBJECT_DIR):
@mkdir -p $(OBJECT_DIR)
$(BIN_DIR):
@mkdir -p $(BIN_DIR)
+$(USR_DIR):
+ @mkdir -p $(USR_DIR)
+
$(ISO_DIR):
@mkdir -p $(ISO_DIR)
@mkdir -p $(ISO_BOOT_DIR)
@mkdir -p $(ISO_GRUB_DIR)
-$(OBJECT_DIR)/%.S.o: %.S
- @mkdir -p $(@D)
- @echo " CC $<"
- @$(CC) $(INCLUDES) -c $< -o $@
+check: $(DEPS) check-cc GRUB_TEMPLATE
+
+prepare: check $(OBJECT_DIR) $(BIN_DIR) $(ISO_DIR) $(USR_DIR)
+
+usrlib: prepare makefile.usr
+ @make -f makefile.usr usr-runtime
+
+usrlib-debug: prepare makefile.usr
+ @make -f makefile.usr usr-runtime-debug
-$(OBJECT_DIR)/%.c.o: %.c
- @mkdir -p $(@D)
- @echo " CC $<"
- @$(CC) $(INCLUDES) -c $< -o $@ $(CFLAGS)
+usr-prog: prepare usrlib makefile.prog
+ @make -f makefile.prog all
-$(BIN_DIR)/$(OS_BIN): $(OBJECT_DIR) $(BIN_DIR) $(SRC)
- @echo " LD $(BIN_DIR)/$(OS_BIN)"
- @$(CC) -T link/linker.ld -o $(BIN_DIR)/$(OS_BIN) $(SRC) $(LDFLAGS)
+bootable: usr-prog usrlib makefile.ker
+ @make -f makefile.ker all
-$(BUILD_DIR)/$(OS_ISO): check $(ISO_DIR) $(BIN_DIR)/$(OS_BIN) GRUB_TEMPLATE
- @./config-grub.sh ${OS_NAME} $(ISO_GRUB_DIR)/grub.cfg
- @cp $(BIN_DIR)/$(OS_BIN) $(ISO_BOOT_DIR)
- @grub-mkrescue -o $(BUILD_DIR)/$(OS_ISO) $(ISO_DIR)
+bootable-debug: usr-prog usrlib-debug makefile.ker
+ @make -f makefile.ker all-debug
-all: $(BUILD_DIR)/$(OS_ISO)
+all: bootable
instable: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) -D__LUNAIXOS_DEBUG__
instable: all
-all-debug: O := -Og
-all-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) -D__LUNAIXOS_DEBUG__
-all-debug: LDFLAGS := -g -ffreestanding $(O) -nostdlib -lgcc
-all-debug: clean $(BUILD_DIR)/$(OS_ISO)
+all-debug: clean bootable-debug
@echo "Dumping the disassembled kernel code to $(BUILD_DIR)/kdump.txt"
@i686-elf-objdump -S $(BIN_DIR)/$(OS_BIN) > $(BUILD_DIR)/kdump.txt
--- /dev/null
+include config/make-os
+include config/make-cc
+include config/make-debug-tool
+include config/make-locations
+
+SRC_DIRS := kernel \
+ hal \
+ debug \
+ libs \
+ arch \
+
+SRC_FILES := $(foreach f, $(SRC_DIRS), $(shell find $(f) -name "*.[cS]"))
+
+OBJS := $(foreach f, $(SRC_FILES), $(OBJECT_DIR)/$(f).o)
+
+$(OBJECT_DIR)/%.S.o: %.S
+ @mkdir -p $(@D)
+ @echo " CC $<"
+ @$(CC) $(INCLUDES) -c $< -o $@
+
+$(OBJECT_DIR)/%.c.o: %.c
+ @mkdir -p $(@D)
+ @echo " CC $<"
+ @$(CC) $(INCLUDES) -c $< -o $@ $(CFLAGS)
+
+$(BIN_DIR)/$(OS_BIN): $(OBJECT_DIR) $(BIN_DIR) $(OBJS)
+ @echo " LD $(BIN_DIR)/$(OS_BIN)"
+ @$(CC) -T link/linker.ld -o $(BIN_DIR)/$(OS_BIN) $(OBJS) $(BIN_DIR)/$(USR_LIB) $(LDFLAGS)
+
+$(BUILD_DIR)/$(OS_ISO): $(BIN_DIR)/$(OS_BIN)
+ @./config-grub.sh ${OS_NAME} $(ISO_GRUB_DIR)/grub.cfg
+ @cp $(BIN_DIR)/$(OS_BIN) $(ISO_BOOT_DIR)
+ @cp -r $(USR_DIR) $(ISO_DIR)
+ @grub-mkrescue -o $(BUILD_DIR)/$(OS_ISO) $(ISO_DIR)
+
+all: $(BUILD_DIR)/$(OS_ISO)
+
+all-debug: O := -Og
+all-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) -D__LUNAIXOS_DEBUG__
+all-debug: LDFLAGS := -g -ffreestanding $(O) -nostdlib -lgcc
+all-debug: all
\ No newline at end of file
--- /dev/null
+include config/make-locations
+include config/make-os
+include config/make-cc
+
+SRC_FILES := $(wildcard uprog/*.c)
+PROGRAMES := $(patsubst uprog/%.c, $(USR_DIR)/%, $(SRC_FILES))
+
+$(USR_DIR)/%:
+ @echo " BUILD $(*F)"
+ @$(CC) -T usr/link-usr.ld $(INCLUDES) $(CFLAGS) -g $(LDFLAGS) uprog/$(*F).c $(BIN_DIR)/$(USR_LIB) -o $@
+
+all: $(PROGRAMES)
\ No newline at end of file
--- /dev/null
+include config/make-cc
+include config/make-os
+include config/make-locations
+
+SRC_DIRS := usr
+
+SRC_FILES := $(foreach f, $(SRC_DIRS), $(shell find $(f) -name "*.[cS]"))
+
+OBJS := $(foreach f, $(SRC_FILES), $(OBJECT_DIR)/$(f).o)
+
+$(OBJECT_DIR)/%.S.o: %.S
+ @mkdir -p $(@D)
+ @echo " CC $<"
+ @$(CC) $(INCLUDES) -c $< -o $@
+
+$(OBJECT_DIR)/%.c.o: %.c
+ @mkdir -p $(@D)
+ @echo " CC $<"
+ @$(CC) $(INCLUDES) $(CFLAGS) -g -c $< -o $@
+
+$(BIN_DIR)/$(USR_LIB): $(OBJS)
+ @echo " AR $@"
+ @$(AR) rcs $@ $^
+
+usr-runtime: $(BIN_DIR)/$(USR_LIB)
+
+usr-runtime-debug: O := -Og
+usr-runtime-debug: CFLAGS := -g -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) -D__LUNAIXOS_DEBUG__
+usr-runtime-debug: LDFLAGS := -g -ffreestanding $(O) -nostdlib -lgcc
+usr-runtime-debug: usr-runtime
+
+usr-objs: $(OBJS)
\ No newline at end of file
--- /dev/null
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/lunaix.h>
+#include <unistd.h>
+
+int
+main(int argc, const char** argv)
+{
+ int errno = 0;
+
+ if ((errno = open("/dev/tty", 0)) < 0) {
+ syslog(2, "fail to open tty (%d)\n", errno);
+ return 0;
+ }
+
+ if ((errno = dup(errno)) < 0) {
+ syslog(2, "fail to setup tty i/o (%d)\n", errno);
+ return 0;
+ }
+
+ printf("(%p) user space!\n", (void*)main);
+
+ pid_t pid;
+ if (!(pid = fork())) {
+ int err = execve("/mnt/lunaix-os/usr/ls", NULL, NULL);
+ printf("fail to execute (%d)\n", err);
+ _exit(err);
+ }
+
+ waitpid(pid, NULL, 0);
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+
+int
+main(int argc, const char* argv[])
+{
+ char* path = ".";
+ if (argc > 0) {
+ path = argv[0];
+ }
+
+ DIR* dir = opendir(path);
+
+ if (!dir) {
+ return errno;
+ }
+
+ struct dirent* dent;
+
+ while ((dent = readdir(dir))) {
+ if (dent->d_type == DT_DIR) {
+ printf(" \033[3m%s\033[39;49m\n", dent->d_name);
+ } else {
+ printf(" %s\n", dent->d_name);
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/syscall.h>
+#include <sys/lxdirent.h>
+
+__LXSYSCALL2(int, sys_readdir, int, fd, struct lx_dirent*, dent)
--- /dev/null
+#include <lunaix/syscall.h>
+#include <errno.h>
+
+__LXSYSCALL(int, geterrno);
\ No newline at end of file
--- /dev/null
+#include <lunaix/syscall.h>
+#include <fcntl.h>
+
+__LXSYSCALL2(int, open, const char*, path, int, options)
--- /dev/null
+#include <lunaix/syscall.h>
+#include <sys/ioctl.h>
+
+__LXSYSCALL2_VARG(int, ioctl, int, fd, int, req);
\ No newline at end of file
-#ifndef __LUNAIX_LUNAIX_H
-#define __LUNAIX_LUNAIX_H
-
#include <lunaix/syscall.h>
-#include <lunaix/types.h>
+#include <sys/lunaix.h>
__LXSYSCALL(void, yield);
__LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options);
-__LXSYSCALL(int, geterrno);
-
__LXSYSCALL2_VARG(void, syslog, int, level, const char*, fmt);
-#endif /* __LUNAIX_LUNAIX_H */
+__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
--- /dev/null
+#include <lunaix/syscall.h>
+#include <sys/mann.h>
+
+__LXSYSCALL2_VARG(void*, sys_mmap, void*, addr, size_t, length);
+
+void*
+mmap(void* addr, size_t length, int proct, int flags, int fd, off_t offset)
+{
+ return sys_mmap(addr, length, proct, fd, offset, flags);
+}
+
+__LXSYSCALL2(void, munmap, void*, addr, size_t, length)
--- /dev/null
+#include <lunaix/syscall.h>
+#include <sys/mount.h>
+
+__LXSYSCALL4(int,
+ mount,
+ const char*,
+ source,
+ const char*,
+ target,
+ const char*,
+ fstype,
+ int,
+ options)
+
+__LXSYSCALL1(int, unmount, const char*, target)
\ No newline at end of file
--- /dev/null
+#include <lunaix/syscall.h>
+#include <signal.h>
+
+__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler);
+
+__LXSYSCALL1(int, sigpending, sigset_t, *set);
+__LXSYSCALL1(int, sigsuspend, const sigset_t, *mask);
+
+__LXSYSCALL3(int,
+ sigprocmask,
+ int,
+ how,
+ const sigset_t,
+ *set,
+ sigset_t,
+ *oldset);
--- /dev/null
+#include <lunaix/syscall.h>
+#include <unistd.h>
+
+__LXSYSCALL(pid_t, fork)
+
+__LXSYSCALL1(int, brk, void*, addr)
+
+__LXSYSCALL1(void*, sbrk, ssize_t, size)
+
+__LXSYSCALL(pid_t, getpid)
+
+__LXSYSCALL(pid_t, getppid)
+
+__LXSYSCALL(pid_t, getpgid)
+
+__LXSYSCALL2(pid_t, setpgid, pid_t, pid, pid_t, pgid)
+
+__LXSYSCALL1(void, _exit, int, status)
+
+__LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
+
+__LXSYSCALL(int, pause)
+
+__LXSYSCALL2(int, kill, pid_t, pid, int, signum)
+
+__LXSYSCALL1(unsigned int, alarm, unsigned int, seconds)
+
+__LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
+
+__LXSYSCALL1(int, rmdir, const char*, pathname)
+
+__LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
+
+__LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
+
+__LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
+
+__LXSYSCALL3(int, lseek, int, fd, off_t, offset, int, options)
+
+__LXSYSCALL1(int, unlink, const char*, pathname)
+
+__LXSYSCALL1(int, close, int, fd)
+
+__LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+
+__LXSYSCALL1(int, dup, int, oldfd)
+
+__LXSYSCALL1(int, fsync, int, fildes)
+
+__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
+
+__LXSYSCALL1(int, chdir, const char*, path)
+
+__LXSYSCALL1(int, fchdir, int, fd)
+
+__LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
+
+__LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
+
+__LXSYSCALL4(int,
+ getxattr,
+ const char*,
+ path,
+ const char*,
+ name,
+ void*,
+ value,
+ size_t,
+ len)
+
+__LXSYSCALL4(int,
+ setxattr,
+ const char*,
+ path,
+ const char*,
+ name,
+ void*,
+ value,
+ size_t,
+ len)
+
+__LXSYSCALL4(int,
+ fgetxattr,
+ int,
+ fd,
+ const char*,
+ name,
+ void*,
+ value,
+ size_t,
+ len)
+
+__LXSYSCALL4(int,
+ fsetxattr,
+ int,
+ fd,
+ const char*,
+ name,
+ void*,
+ value,
+ size_t,
+ len)
+
+__LXSYSCALL4(int,
+ readlinkat,
+ int,
+ dirfd,
+ const char*,
+ pathname,
+ char*,
+ buf,
+ size_t,
+ size)
+
+__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
+
+__LXSYSCALL1(int, mkdir, const char*, path)
+
+__LXSYSCALL3(int,
+ execve,
+ const char*,
+ filename,
+ const char**,
+ argv,
+ const char**,
+ envp)
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_SYS_DIRENT_H
+#define __LUNAIX_SYS_DIRENT_H
+
+#include <sys/dirent_defs.h>
+
+typedef struct
+{
+ int dirfd;
+ struct lx_dirent _lxd;
+} DIR;
+
+struct dirent
+{
+ unsigned char d_type;
+ char d_name[256];
+};
+
+DIR*
+opendir(const char* dirp);
+
+int
+closedir(DIR* dirp);
+
+struct dirent*
+readdir(DIR* dir);
+
+#endif /* __LUNAIX_DIRENT_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_ERRNO_H
+#define __LUNAIX_SYS_ERRNO_H
+
+#define EINVAL -(6)
+#define EINTR -(7)
+#define EMFILE -8
+#define ENOENT -9
+#define ENAMETOOLONG -10
+#define ENOTDIR -11
+#define EEXIST -12
+#define EBADF -13
+#define ENOTSUP -14
+#define EIO -15
+#define ELOOP -16
+#define ENOTEMPTY -17
+#define EROFS -18
+#define EISDIR -19
+#define EBUSY -20
+#define EXDEV -21
+#define ENODEV -22
+#define ERANGE -23
+#define ENOMEM -(3)
+#define ENOTDEV -24
+#define EOVERFLOW -25
+#define ENOTBLK -26
+#define ENOEXEC -27
+#define E2BIG -28
+
+int
+geterrno();
+
+#define errno (geterrno())
+
+#endif /* __LUNAIX_ERRNO_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_FCNTL_H
+#define __LUNAIX_SYS_FCNTL_H
+
+#include <fcntl_defs.h>
+#include <sys/types.h>
+
+int
+open(const char* path, int flags);
+
+#endif /* __LUNAIX_FCNTL_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_FCNTL_DEFS_H
+#define __LUNAIX_SYS_FCNTL_DEFS_H
+
+#define FO_CREATE 0x1
+#define FO_APPEND 0x2
+#define FO_DIRECT 0x4
+#define FO_WRONLY 0x8
+#define FO_RDONLY 0x10
+#define FO_RDWR 0x20
+
+#define FSEEK_SET 0x1
+#define FSEEK_CUR 0x2
+#define FSEEK_END 0x3
+
+#define O_CREAT FO_CREATE
+#define O_APPEND FO_APPEND
+#define O_DIRECT FO_DIRECT
+#define O_WRONLY FO_WRONLY
+#define O_RDONLY FO_RDONLY
+#define O_RDWR FO_RDWR
+
+#define MNT_RO 0x1
+
+#endif /* __LUNAIX_FNCTL_DEFS_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_SIGNAL_H
+#define __LUNAIX_SYS_SIGNAL_H
+
+#include <signal_defs.h>
+#include <sys/types.h>
+
+int
+signal(int signum, sighandler_t handler);
+
+int
+sigpending(sigset_t* set);
+
+int
+sigsuspend(const sigset_t* mask);
+
+int
+sigprocmask(int how, const sigset_t* set, sigset_t* oldset);
+
+#endif /* __LUNAIX_SIGNAL_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_SIGNAL_DEFS_H
+#define __LUNAIX_SYS_SIGNAL_DEFS_H
+
+#define SIGSEGV 1
+#define SIGALRM 2
+#define SIGCHLD 3
+#define SIGCLD SIGCHLD
+#define SIGINT 4
+#define SIGKILL 5
+#define SIGSTOP 6
+#define SIGCONT 7
+#define SIGTERM 8
+
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+typedef unsigned int sigset_t;
+typedef void (*sighandler_t)(int);
+
+#endif /* __LUNAIX_SIGNAL_DEFS_H */
#define stdout 0
#define stdin 1
-void
+int
printf(const char* fmt, ...);
#endif /* __LUNAIX_USTDIO_H */
--- /dev/null
+#ifndef __LUNAIX_STDLIB_H
+#define __LUNAIX_STDLIB_H
+
+char*
+itoa(int value, char* str, int base);
+
+#endif /* __LUNAIX_STDLIB_H */
--- /dev/null
+#ifndef __LUNAIX_STRING_H
+#define __LUNAIX_STRING_H
+
+#include <stddef.h>
+
+size_t
+strlen(const char* str);
+
+size_t
+strnlen(const char* str, size_t max_len);
+
+char*
+strncpy(char* dest, const char* src, size_t n);
+
+const char*
+strchr(const char* str, int character);
+
+char*
+strcpy(char* dest, const char* src);
+
+#endif /* __LUNAIX_STRING_H */
-#ifndef __LUNAIX_DIRENT_H
-#define __LUNAIX_DIRENT_H
+#ifndef __LUNAIX_SYS_DIRENT_DEFS_H
+#define __LUNAIX_SYS_DIRENT_DEFS_H
#define DIRENT_NAME_MAX_LEN 256
#define DT_SYMLINK 0x2
#define DT_PIPE 0x2
-struct dirent
+struct lx_dirent
{
unsigned int d_type;
unsigned int d_offset;
char d_name[DIRENT_NAME_MAX_LEN];
};
-#endif /* __LUNAIX_DIRENT_H */
+#endif /* __LUNAIX_DIRENT_DEFS_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_IOCTL_H
+#define __LUNAIX_SYS_IOCTL_H
+
+#include <sys/ioctl_defs.h>
+
+int
+ioctl(int fd, int req, ...);
+
+#endif /* __LUNAIX_IOCTL_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_IOCTL_DEFS_H
+#define __LUNAIX_SYS_IOCTL_DEFS_H
+
+#define IOREQ(cmd, arg_num) ((((cmd)&0xffff) << 8) | ((arg_num)&0xff))
+
+#define IOCMD(req) ((req) >> 8)
+
+#define IOARGNUM(req) ((req)&0xff)
+
+#define TIOCGPGRP IOREQ(1, 0)
+#define TIOCSPGRP IOREQ(1, 1)
+#define TIOCCLSBUF IOREQ(2, 0)
+#define TIOCFLUSH IOREQ(3, 0)
+
+#endif /* __LUNAIX_IOCTL_DEFS_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_LUNAIX_H
+#define __LUNAIX_SYS_LUNAIX_H
+
+#include <sys/types.h>
+
+void
+yield();
+
+pid_t
+wait(int* status);
+
+pid_t
+waitpid(pid_t pid, int* status, int flags);
+
+void
+syslog(int level, const char* fmt, ...);
+
+int
+realpathat(int fd, char* buf, size_t size);
+
+#endif /* __LUNAIX_LUNAIX_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_LXDIRENT_H
+#define __LUNAIX_SYS_LXDIRENT_H
+
+#include <sys/dirent_defs.h>
+
+int
+sys_readdir(int fd, struct lx_dirent* dirent);
+
+#endif /* __LUNAIX_DIRENT_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_MANN_H
+#define __LUNAIX_SYS_MANN_H
+
+#include <sys/mann_flags.h>
+#include <sys/types.h>
+
+void*
+mmap(void* addr, size_t length, int proct, int flags, int fd, off_t offset);
+
+void
+munmap(void* addr, size_t length);
+
+#endif /* __LUNAIX_MANN_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_MANN_FLAGS_H
+#define __LUNAIX_SYS_MANN_FLAGS_H
+
+// POSIX compliant.
+
+// identity mapped to region attributes
+#define PROT_READ (1 << 2)
+#define PROT_WRITE (1 << 3)
+#define PROT_EXEC (1 << 4)
+
+// identity mapped to region attributes
+
+#define MAP_WSHARED 0x2
+#define MAP_RSHARED 0x1
+#define MAP_SHARED MAP_WSHARED
+#define MAP_PRIVATE MAP_RSHARED
+#define MAP_EXCLUSIVE 0x0
+#define MAP_ANON (1 << 5)
+#define MAP_STACK 0 // no effect in Lunaix
+
+// other MAP_* goes should beyond 0x20
+
+#define MAP_FIXED 0x40
+#define MAP_FIXED_NOREPLACE 0x80
+
+#define MS_ASYNC 0x1
+#define MS_SYNC 0x2
+#define MS_INVALIDATE 0x4
+#define MS_INVALIDATE_ALL 0x8
+
+#endif /* __LUNAIX_MANN_FLAGS_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_MOUNT_H
+#define __LUNAIX_SYS_MOUNT_H
+
+#include <sys/types.h>
+
+int
+mount(const char* source, const char* target, const char* fstype, int flags);
+
+int
+unmount(const char* target);
+
+static inline int
+umount(const char* target)
+{
+ return unmount(target);
+}
+#endif /* __LUNAIX_MOUNT_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_TYPES_H
+#define __LUNAIX_SYS_TYPES_H
+
+#define NULL (void*)0
+
+#define PEXITTERM 0x100
+#define PEXITSTOP 0x200
+#define PEXITSIG 0x400
+
+#define PEXITNUM(flag, code) (flag | (code & 0xff))
+
+#define WNOHANG 1
+#define WUNTRACED 2
+#define WEXITSTATUS(wstatus) ((wstatus & 0xff))
+#define WIFSTOPPED(wstatus) ((wstatus & PEXITSTOP))
+#define WIFEXITED(wstatus) \
+ ((wstatus & PEXITTERM) && ((char)WEXITSTATUS(wstatus) >= 0))
+
+#define WIFSIGNALED(wstatus) ((wstatus & PEXITSIG))
+
+typedef signed long ssize_t;
+
+typedef int pid_t;
+
+typedef unsigned long size_t;
+
+typedef unsigned long off_t;
+
+#endif /* __LUNAIX_TYPES_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_UNISTD_H
+#define __LUNAIX_SYS_UNISTD_H
+
+#include <sys/types.h>
+
+extern const char** environ;
+
+pid_t
+fork();
+
+pid_t
+getpid();
+
+pid_t
+getppid();
+
+pid_t
+getpgid();
+
+pid_t
+setpgid(pid_t pid, pid_t pgid);
+
+int
+brk(void* addr);
+
+void*
+sbrk(ssize_t size);
+
+void
+_exit(int status);
+
+unsigned int
+sleep(unsigned int);
+
+int
+pause();
+
+int
+kill(pid_t pid, int signum);
+
+unsigned int
+alarm(unsigned int seconds);
+
+int
+link(const char* oldpath, const char* newpath);
+
+int
+rmdir(const char* pathname);
+
+int
+read(int fd, void* buf, size_t size);
+
+int
+write(int fd, void* buf, size_t size);
+
+int
+readlink(const char* path, char* buffer, size_t size);
+
+int
+readlinkat(int dirfd, const char* pathname, char* buffer, size_t size);
+
+int
+lseek(int fd, off_t offset, int mode);
+
+int
+unlink(const char* pathname);
+
+int
+unlinat(int fd, const char* pathname);
+
+int
+mkdir(const char* path);
+
+int
+close(int fd);
+
+int
+dup2(int oldfd, int newfd);
+
+int
+dup(int oldfd);
+
+int
+fsync(int fd);
+
+int
+symlink(const char* pathname, const char* linktarget);
+
+int
+chdir(const char* path);
+
+int
+fchdir(int fd);
+
+char*
+getcwd(char* buf, size_t size);
+
+int
+rename(const char* oldpath, const char* newpath);
+
+int
+getxattr(const char* path, const char* name, void* value, size_t len);
+
+int
+setxattr(const char* path, const char* name, void* value, size_t len);
+
+int
+fgetxattr(int fd, const char* name, void* value, size_t len);
+
+int
+fsetxattr(int fd, const char* name, void* value, size_t len);
+
+int
+execve(const char* filename, const char* argv[], const char* envp[]);
+
+#endif /* __LUNAIX_UNISTD_H */
--- /dev/null
+#ifndef __LUNAIX__MYSTDIO_H
+#define __LUNAIX__MYSTDIO_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+int
+__vprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs);
+
+#endif /* __LUNAIX__MYSTDIO_H */
--- /dev/null
+#include "_mystdio.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NUMBUFSIZ 24
+
+static const char flag_chars[] = "#0- +";
+
+#define FLAG_ALT (1 << 0)
+#define FLAG_ZERO (1 << 1)
+#define FLAG_LEFTJUSTIFY (1 << 2)
+#define FLAG_SPACEPOSITIVE (1 << 3)
+#define FLAG_PLUSPOSITIVE (1 << 4)
+#define FLAG_NUMERIC (1 << 5)
+#define FLAG_SIGNED (1 << 6)
+#define FLAG_NEGATIVE (1 << 7)
+#define FLAG_ALT2 (1 << 8)
+#define FLAG_CAPS (1 << 9)
+
+int
+__vprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
+{
+ // This sprintf just a random implementation I found it on Internet . lol.
+ // Of course, with some modifications for porting to LunaixOS :)
+
+ char numbuf[NUMBUFSIZ];
+ uintptr_t ptr = 0;
+ for (; *fmt; ++fmt) {
+ if (max_len && ptr >= max_len - 1) {
+ break;
+ }
+
+ if (*fmt != '%') {
+ buffer[ptr++] = *fmt;
+ continue;
+ }
+
+ // process flags
+ int flags = 0;
+ for (++fmt; *fmt; ++fmt) {
+ const char* flagc = strchr(flag_chars, *fmt);
+ if (flagc) {
+ flags |= 1 << (flagc - flag_chars);
+ } else {
+ break;
+ }
+ }
+
+ // process width
+ int width = -1;
+ if (*fmt >= '1' && *fmt <= '9') {
+ for (width = 0; *fmt >= '0' && *fmt <= '9';) {
+ width = 10 * width + *fmt++ - '0';
+ }
+ } else if (*fmt == '*') {
+ width = va_arg(vargs, int);
+ ++fmt;
+ }
+
+ // process precision
+ int precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (*fmt >= '0' && *fmt <= '9') {
+ for (precision = 0; *fmt >= '0' && *fmt <= '9';) {
+ precision = 10 * precision + *fmt++ - '0';
+ }
+ } else if (*fmt == '*') {
+ precision = va_arg(vargs, int);
+ ++fmt;
+ }
+ if (precision < 0) {
+ precision = 0;
+ }
+ }
+
+ // process main conversion character
+ int base = 10;
+ unsigned long num = 0;
+ int length = 0;
+ char* data = "";
+ again:
+ switch (*fmt) {
+ case 'l':
+ case 'z':
+ length = 1;
+ ++fmt;
+ goto again;
+ case 'd':
+ case 'i': {
+ long x = length ? va_arg(vargs, long) : va_arg(vargs, int);
+ int negative = x < 0 ? FLAG_NEGATIVE : 0;
+ num = negative ? -x : x;
+ flags |= FLAG_NUMERIC | FLAG_SIGNED | negative;
+ break;
+ }
+ case 'u':
+ format_unsigned:
+ num = length ? va_arg(vargs, unsigned long)
+ : va_arg(vargs, unsigned);
+ flags |= FLAG_NUMERIC;
+ break;
+ case 'b':
+ base = 2;
+ goto format_unsigned;
+ case 'x':
+ base = 16;
+ goto format_unsigned;
+ case 'X':
+ flags = flags | FLAG_CAPS;
+ base = 16;
+ goto format_unsigned;
+ case 'p':
+ num = (uintptr_t)va_arg(vargs, void*);
+ base = 16;
+ flags |= FLAG_ALT | FLAG_ALT2 | FLAG_NUMERIC;
+ break;
+ case 's':
+ data = va_arg(vargs, char*);
+ break;
+ case 'c':
+ data = numbuf;
+ numbuf[0] = va_arg(vargs, int);
+ numbuf[1] = '\0';
+ break;
+ default:
+ data = numbuf;
+ numbuf[0] = (*fmt ? *fmt : '%');
+ numbuf[1] = '\0';
+ if (!*fmt) {
+ fmt--;
+ }
+ break;
+ }
+
+ if (flags & FLAG_NUMERIC) {
+ data = itoa(num, numbuf, base);
+ int i = 0;
+ char c;
+ while ((flags & FLAG_CAPS) && (c = data[i])) {
+ data[i] = c & ~((c & 0x40) >> 1);
+ i++;
+ }
+ }
+
+ const char* prefix = "";
+ if ((flags & FLAG_NUMERIC) && (flags & FLAG_SIGNED)) {
+ if (flags & FLAG_NEGATIVE) {
+ prefix = "-";
+ } else if (flags & FLAG_PLUSPOSITIVE) {
+ prefix = "+";
+ } else if (flags & FLAG_SPACEPOSITIVE) {
+ prefix = " ";
+ }
+ } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ALT) &&
+ (base == 16 || base == -16) &&
+ (num || (flags & FLAG_ALT2))) {
+ prefix = "0x";
+ }
+
+ int len;
+ if (precision >= 0 && !(flags & FLAG_NUMERIC)) {
+ len = strnlen(data, precision);
+ } else {
+ len = strlen(data);
+ }
+ int zeros;
+ if ((flags & FLAG_NUMERIC) && precision >= 0) {
+ zeros = precision > len ? precision - len : 0;
+ } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ZERO) &&
+ !(flags & FLAG_LEFTJUSTIFY) &&
+ len + (int)strlen(prefix) < width) {
+ zeros = width - len - strlen(prefix);
+ } else {
+ zeros = 0;
+ }
+ width -= len + zeros + strlen(prefix);
+ for (; !(flags & FLAG_LEFTJUSTIFY) && width > 0; --width) {
+ buffer[ptr++] = ' ';
+ }
+ for (; *prefix; ++prefix) {
+ buffer[ptr++] = *prefix;
+ }
+ for (; zeros > 0; --zeros) {
+ buffer[ptr++] = '0';
+ }
+ for (; len > 0; ++data, --len) {
+ buffer[ptr++] = *data;
+ }
+ for (; width > 0; --width) {
+ buffer[ptr++] = ' ';
+ }
+ }
+ buffer[ptr++] = '\0';
+
+ return ptr;
+}
--- /dev/null
+#include <stddef.h>
+#include <stdlib.h>
+
+char base_char[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+char*
+__uitoa_internal(unsigned int value, char* str, int base, unsigned int* size)
+{
+ unsigned int ptr = 0;
+ do {
+ str[ptr] = base_char[value % base];
+ value = value / base;
+ ptr++;
+ } while (value);
+
+ for (unsigned int i = 0; i < (ptr >> 1); i++) {
+ char c = str[i];
+ str[i] = str[ptr - i - 1];
+ str[ptr - i - 1] = c;
+ }
+ str[ptr] = '\0';
+ if (size) {
+ *size = ptr;
+ }
+ return str;
+}
+
+char*
+__itoa_internal(int value, char* str, int base, unsigned int* size)
+{
+ if (value < 0 && base == 10) {
+ str[0] = '-';
+ unsigned int _v = (unsigned int)(-value);
+ __uitoa_internal(_v, str + 1, base, size);
+ } else {
+ __uitoa_internal(value, str, base, size);
+ }
+
+ return str;
+}
+
+char*
+itoa(int value, char* str, int base)
+{
+ return __itoa_internal(value, str, base, NULL);
+}
\ No newline at end of file
--- /dev/null
+#include "_mystdio.h"
+#include <stdio.h>
+#include <unistd.h>
+
+int
+printf(const char* fmt, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, fmt);
+ int n = __vprintf_internal(buf, fmt, 1024, args);
+ va_end(args);
+
+ return write(stdout, buf, n);
+}
\ No newline at end of file
--- /dev/null
+#include <dirent.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/lxdirent.h>
+#include <unistd.h>
+
+DIR*
+opendir(const char* dir)
+{
+ static DIR _dir;
+ int fd = open(dir, O_RDONLY);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ _dir = (DIR){ .dirfd = fd };
+ return &_dir;
+}
+
+int
+closedir(DIR* dirp)
+{
+ if (!dirp || dirp->dirfd == -1) {
+ // TODO migrate the status.h
+ return -1;
+ }
+
+ int err = close(dirp->dirfd);
+
+ if (!err) {
+ dirp->dirfd = -1;
+ return 0;
+ }
+
+ return -1;
+}
+
+struct dirent*
+readdir(DIR* dir)
+{
+ static struct dirent _dirent;
+ if (!dir) {
+ return NULL;
+ }
+
+ struct lx_dirent* _lxd = &dir->_lxd;
+
+ int more = sys_readdir(dir->dirfd, _lxd);
+
+ _dirent.d_type = _lxd->d_type;
+ strncpy(_dirent.d_name, _lxd->d_name, 256);
+
+ if (more) {
+ return &_dirent;
+ }
+
+ return NULL;
+}
\ No newline at end of file
--- /dev/null
+#include <string.h>
+
+size_t
+strlen(const char* str)
+{
+ size_t len = 0;
+ while (str[len])
+ len++;
+ return len;
+}
+
+const char*
+strchr(const char* str, int character)
+{
+ char c = (char)character;
+ while ((*str)) {
+ if (*str == c) {
+ return str;
+ }
+ str++;
+ }
+ return c == '\0' ? str : NULL;
+}
+
+size_t
+strnlen(const char* str, size_t max_len)
+{
+ size_t len = 0;
+ while (str[len] && len <= max_len)
+ len++;
+ return len;
+}
+
+char*
+strncpy(char* dest, const char* src, size_t n)
+{
+ char c;
+ unsigned int i = 0;
+ while ((c = src[i]) && i <= n)
+ dest[i++] = c;
+ while (i <= n)
+ dest[i++] = 0;
+ return dest;
+}
+
+char*
+strcpy(char* dest, const char* src)
+{
+ char c;
+ unsigned int i = 0;
+ while ((c = src[i])) {
+ dest[i] = c;
+ i++;
+ }
+ dest[i] = '\0';
+ return dest;
+}
--- /dev/null
+ENTRY(_u_start)
+
+SECTIONS {
+ . = 0x400000;
+}
\ No newline at end of file
--- /dev/null
+#define __USR_WRAPPER__
+#include <lunaix/ld.h>
+
+int
+usr_pre_init(struct usr_exec_param* param)
+{
+ // TODO some inits before executing user program
+
+ extern ptr_t environ;
+ environ = (ptr_t)param->envp;
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+#define __ASM__
+#include <lunaix/syscall.h>
+
+.section .data
+ .global environ
+ environ:
+ .long 0
+
+.section .text
+ .global _u_start
+ _u_start:
+ call usr_pre_init
+ jnz 1f
+
+ popl %eax
+
+ pushl (%eax) // argc
+ pushl 4(%eax) // argv
+
+ xorl %eax, %eax
+ call main
+
+ 1:
+ movl %eax, %ebx
+ movl $__SYSCALL__exit, %eax
+ int $LUNAIX_SYS_CALL
+
+ ud2 // should not reach
\ No newline at end of file