fix: replace %ebp register to %esi for passing 5-th arg when switching to syscall dispatcher.
feat: support for anonymous mapping
refactor: mm_region interfaces
refactor: page fault handler clean up.
refactor: resolve cyclic dependencies between mm.h and fs.h
refactor: rename readdir to sys_readdir to distinguish readdir(3)
wip refactor: separating syscall definitions to userspace.
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
__LXSYSCALL1(int, mkdir, const char*, path)
__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
-__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+__LXSYSCALL2(int, sys_readdir, int, fd, struct dirent*, dent)
__LXSYSCALL4(int,
readlinkat,
#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) \
#include <lunaix/fs.h>
#include <lunaix/types.h>
+#include <usr/sys/mann_flags.h>
+
typedef struct
{
void* start;
* @brief 私有区域,该区域中的页无法进行任何形式的共享。
*
*/
-#define REGION_PRIVATE 0x0
+#define REGION_PRIVATE MAP_PRIVATE
/**
* @brief
* 读共享区域,该区域中的页可以被两个进程之间读共享,但任何写操作须应用Copy-On-Write
*
*/
-#define REGION_RSHARED 0x1
+#define REGION_RSHARED MAP_RSHARED
/**
* @brief
* 写共享区域,该区域中的页可以被两个进程之间读共享,任何的写操作无需执行Copy-On-Write
*
*/
-#define REGION_WSHARED 0x2
+#define REGION_WSHARED MAP_WSHARED
#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);
struct mm_region
{
- struct llist_header head;
+ struct llist_header head; // must be first field!
struct v_file* mfile;
u32_t offset;
ptr_t start;
#define __LUNAIX_MMAP_H
#include <lunaix/fs.h>
+#include <lunaix/mm/region.h>
#include <lunaix/types.h>
void*
mem_map(ptr_t pd_ref,
- struct llist_header* regions,
+ vm_regions_t* regions,
void* addr,
struct v_file* file,
- u32_t offset,
+ off_t offset,
size_t length,
- u32_t attrs);
+ u32_t attrs,
+ u32_t options);
void*
-mem_unmap(ptr_t mnt, struct llist_header* regions, void* addr, size_t length);
+mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length);
#endif /* __LUNAIX_MMAP_H */
#define PG_DIRTY(pte) ((pte & (1 << 6)) >> 6)
#define PG_ACCESSED(pte) ((pte & (1 << 5)) >> 5)
+#define PG_PRESENTED(pte) ((pte)&PG_PRESENT)
#define IS_CACHED(entry) ((entry & 0x1))
#include <lunaix/mm/mm.h>
+typedef struct llist_header vm_regions_t;
+
struct mm_region*
-region_add(struct llist_header* lead, ptr_t start, ptr_t end, u32_t attr);
+region_create(ptr_t start, ptr_t end, u32_t attr);
+
+void
+region_add(vm_regions_t* lead, struct mm_region* vmregion);
void
-region_release_all(struct llist_header* lead);
+region_release_all(vm_regions_t* lead);
struct mm_region*
-region_get(struct llist_header* lead, unsigned long vaddr);
+region_get(vm_regions_t* lead, unsigned long vaddr);
void
-region_copy(struct llist_header* src, struct llist_header* dest);
+region_copy(vm_regions_t* src, vm_regions_t* dest);
#endif /* __LUNAIX_REGION_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>
struct proc_mm
{
heap_context_t u_heap;
- struct llist_header regions;
+ vm_regions_t regions;
};
struct proc_sigstate
#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_mmap 52
+#define __SYSCALL_sys_mmap 52
#define __SYSCALL_munmap 53
#define __SYSCALL_MAX 0x100
#define __LXSYSCALL5(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \
static rettype name(__PARAM_MAP5(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5)) \
{ \
- asm("movl %0, %%ebp\n" ::"r"(p5), "b"(p1), "c"(p2), "d"(p3), "D"(p4) \
- : "%ebp"); \
+ asm("" ::"r"(p5), "b"(p1), "c"(p2), "d"(p3), "D"(p4), "S"(p5)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
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>
+#include <usr/sys/types.h>
#define PEXITTERM 0x100
#define PEXITSTOP 0x200
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 */
--- /dev/null
+#ifndef __LUNAIX_SYS_MANN_H
+#define __LUNAIX_SYS_MANN_H
+
+#include <usr/sys/mann_flags.h>
+#include <usr/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 | MAP_RSHARED)
+#define MAP_PRIVATE 0x0
+#define MAP_ANON (1 << 5)
+#define MAP_STACK 0 // no effect in Lunaix
+// other MAP_* goes should beyond 0x20
+
+#define MS_ASYNC 0x1
+#define MS_SYNC 0x2
+#define MS_INVALIDATE 0x4
+
+#endif /* __LUNAIX_MANN_FLAGS_H */
--- /dev/null
+#ifndef __LUNAIX_SYS_TYPES_H
+#define __LUNAIX_SYS_TYPES_H
+
+typedef signed long ssize_t;
+
+typedef int pid_t;
+
+typedef unsigned long size_t;
+
+typedef unsigned long off_t;
+
+#endif /* __LUNAIX_TYPES_H */
#include <lunaix/status.h>
#include <lunaix/syslog.h>
+#include <klibc/string.h>
+
static void
kprintf(const char* fmt, ...)
{
}
volatile x86_pte_t* pte = &PTE_MOUNTED(PD_REFERENCED, ptr >> 12);
- if ((*pte & PG_PRESENT)) {
+ if (PG_PRESENTED(*pte)) {
if ((hit_region->attr & COW_MASK) == COW_MASK) {
// normal page fault, do COW
cpu_invplg(pte);
goto segv_term;
}
- // if (!(*pte)) {
- // // Invalid location
- // goto segv_term;
- // }
-
- uintptr_t loc = *pte & ~0xfff;
-
- // a writable page, not present, not cached, pte attr is not null
+ // an anonymous page and not present
// -> a new page need to be alloc
- if ((hit_region->attr & REGION_WRITE) && (*pte & 0xfff) && !loc) {
- cpu_invplg(pte);
- uintptr_t pa = pmm_alloc_page(__current->pid, 0);
- if (!pa) {
- goto oom;
- }
+ if ((hit_region->attr & REGION_ANON)) {
+ if (!PG_PRESENTED(*pte)) {
+ cpu_invplg(pte);
+ uintptr_t pa = pmm_alloc_page(__current->pid, 0);
+ if (!pa) {
+ goto oom;
+ }
- *pte = *pte | pa | PG_PRESENT;
- goto resolved;
+ *pte = *pte | pa | PG_PRESENT;
+ goto resolved;
+ }
+ // permission denied on anon page
+ goto segv_term;
}
- // if mfile is set, then it is a mem map
- if (hit_region->mfile) {
+ // if mfile is set (Non-anonymous), then it is a mem map
+ if (hit_region->mfile && !PG_PRESENTED(*pte)) {
struct v_file* file = hit_region->mfile;
u32_t offset =
(ptr - hit_region->start) & (PG_SIZE - 1) + hit_region->offset;
}
cpu_invplg(pte);
- *pte = *pte | pa | PG_PRESENT;
- int errno = file->ops->read_page(
- file->inode, ptr & (PG_SIZE - 1), PG_SIZE, offset);
+ *pte = (*pte & 0xFFF) | pa | PG_PRESENT;
+
+ ptr = ptr & ~(PG_SIZE - 1);
+ memset(ptr, 0, PG_SIZE);
+
+ int errno = file->ops->read_page(file->inode, ptr, PG_SIZE, offset);
if (errno < 0) {
kprintf(KERROR "fail to read page (%d)\n", errno);
goto segv_term;
}
+
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)
;
.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_mmap
+ .long __lxsys_sys_mmap
.long __lxsys_munmap
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
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
struct dirent ent = { .d_offset = 0 };
- while (readdir(fd, &ent) == 1) {
+ while (sys_readdir(fd, &ent) == 1) {
printf("%s\n", ent.d_name);
}
#include <lunaix/signal.h>
#include <lunaix/status.h>
+#include <usr/sys/mann.h>
+
#include <klibc/string.h>
#include <ulibc/stdio.h>
} else {
struct dirent ent = { .d_offset = 0 };
int status;
- while ((status = readdir(fd, &ent)) == 1) {
+ while ((status = sys_readdir(fd, &ent)) == 1) {
if (ent.d_type == DT_DIR) {
printf(" \033[3m%s\033[39;49m\n", ent.d_name);
} else {
}
}
+void
+do_mcat(const char* file)
+{
+ int fd = open(file, 0);
+ if (fd < 0) {
+ sh_printerr();
+ } else {
+ ptr_t p = mmap(NULL, 2048, 0, 0, fd, 0);
+ if ((int)p < 0) {
+ sh_printerr();
+ } else {
+ printf("%s\n", p);
+ }
+ munmap(p, 1);
+ close(fd);
+ printf("\n");
+ }
+}
+
void
sh_loop()
{
do_cat(argpart);
_exit(0);
}
+ } else if (streq(cmd, "mcat")) {
+ if (!(p = fork())) {
+ do_mcat(argpart);
+ _exit(0);
+ }
} else {
printf("unknow command\n");
goto cont;
#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/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 <lunaix/process.h>
#include <lunaix/spike.h>
#include <lunaix/syscall.h>
+#include <lunaix/syscall_utils.h>
#include <lunaix/fs/twifs.h>
dent->d_type = dtype;
}
-__DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+__DEFINE_LXSYSCALL2(int, sys_readdir, int, fd, struct dirent*, dent)
{
struct v_fd* fd_s;
int errno;
#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)
#include <lunaix/mm/mmap.h>
#include <lunaix/mm/pmm.h>
-#include <lunaix/mm/region.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/spike.h>
void*
mem_map(ptr_t mnt,
- struct llist_header* regions,
+ vm_regions_t* regions,
void* addr,
struct v_file* file,
- u32_t offset,
+ off_t offset,
size_t length,
- u32_t proct)
+ u32_t proct,
+ u32_t options)
{
if (!length || (length & (PG_SIZE - 1)) || (offset & (PG_SIZE - 1))) {
__current->k_status = EINVAL;
addr = last_end;
ptr_t end = addr + length;
- struct mm_region* region = region_add(regions, addr, end, proct);
+ struct mm_region* region =
+ region_create(addr, end, proct | (options & 0x1f));
region->mfile = file;
region->offset = offset;
+ region_add(regions, region);
+
u32_t attr = PG_ALLOW_USER;
if ((proct & REGION_WRITE)) {
attr |= PG_WRITE;
}
void*
-mem_unmap(ptr_t mnt, struct llist_header* regions, void* addr, size_t length)
+mem_unmap(ptr_t mnt, vm_regions_t* regions, void* addr, size_t length)
{
length = ROUNDUP(length, PG_SIZE);
ptr_t cur_addr = ROUNDDOWN((ptr_t)addr, PG_SIZE);
llist_for_each(pos, n, regions, head)
{
- if (pos->start >= cur_addr) {
+ if (pos->start <= cur_addr) {
break;
}
}
l = length;
}
+ // TODO for shared mappings, sync page content if modified. (also
+ // implement msync)
+
for (size_t i = 0; i < l; i += PG_SIZE) {
ptr_t pa = vmm_del_mapping(mnt, cur_addr + i);
if (pa) {
}
}
-__DEFINE_LXSYSCALL5(void*,
- mmap,
- void*,
- addr,
- size_t,
- length,
- int,
- proct,
- int,
- fd,
- size_t,
- offset)
+__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;
struct v_fd* vfd;
if ((errno = vfs_getfd(fd, &vfd))) {
return (void*)-1;
}
+ length = ROUNDUP(length, PG_SIZE);
+
return mem_map(PD_REFERENCED,
&__current->mm.regions,
addr,
vfd->file,
offset,
length,
- proct);
+ proct,
+ options);
}
__DEFINE_LXSYSCALL2(void, munmap, void*, addr, size_t, length)
#include <lunaix/mm/region.h>
#include <lunaix/mm/valloc.h>
+#include <klibc/string.h>
+
struct mm_region*
-region_add(struct llist_header* lead,
- unsigned long start,
- unsigned long end,
- unsigned int attr)
+region_create(ptr_t start, ptr_t end, u32_t attr)
{
- struct mm_region* region = valloc(sizeof(struct mm_region));
-
- *region = (struct mm_region){ .attr = attr, .end = end, .start = start };
+ return valloc(sizeof(struct mm_region));
+}
+void
+region_add(vm_regions_t* lead, struct mm_region* vmregion)
+{
if (llist_empty(lead)) {
- llist_append(lead, ®ion->head);
- return region;
+ llist_append(lead, &vmregion->head);
+ return vmregion;
}
- struct mm_region *pos, *n;
- llist_for_each(pos, n, lead, head)
- {
- if (start >= pos->end && end <= n->start) {
+ 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)&pos->head != (ptr_t)lead);
- llist_insert_after(&pos->head, ®ion->head);
- return region;
+ // XXX caution. require mm_region::head to be the lead of struct
+ llist_insert_after(&pos->head, &vmregion->head);
}
void
-region_release_all(struct llist_header* lead)
+region_release_all(vm_regions_t* lead)
{
struct mm_region *pos, *n;
}
void
-region_copy(struct llist_header* src, struct llist_header* dest)
+region_copy(vm_regions_t* src, vm_regions_t* dest)
{
if (!src) {
return;
}
- struct mm_region *pos, *n;
+ struct mm_region *pos, *n, *dup;
llist_for_each(pos, n, src, head)
{
- region_add(dest, pos->start, pos->end, pos->attr);
+ dup = valloc(sizeof(struct mm_region));
+ memcpy(dup, pos, sizeof(*pos));
+ region_add(dest, dup);
}
}
struct mm_region*
-region_get(struct llist_header* lead, unsigned long vaddr)
+region_get(vm_regions_t* lead, unsigned long vaddr)
{
if (llist_empty(lead)) {
return NULL;
/*--- 分配用户栈 ---*/
+ struct mm_region* stack_vm;
+
+ stack_vm = region_create(
+ USTACK_END, USTACK_TOP, REGION_RW | REGION_RSHARED | REGION_ANON);
// 注册用户栈区域
- region_add(
- &pcb->mm.regions, USTACK_END, USTACK_TOP, REGION_RW | REGION_RSHARED);
+ region_add(&pcb->mm.regions, stack_vm);
// 预留地址空间,具体物理页将由Page Fault Handler按需分配。
for (uintptr_t i = PG_ALIGN(USTACK_END); i < USTACK_TOP; i += PG_SIZE) {
vfree(proc->fdtable);
vfree_dma(proc->fxstate);
+ // TODO unmap all regions
struct mm_region *pos, *n;
llist_for_each(pos, n, &proc->mm.regions, head)
{
#include <lunaix/fs/taskfs.h>
+#include <lunaix/process.h>
void
__read_pending_sig(struct twimap* map)
--- /dev/null
+#include <lunaix/syscall.h>
+#include <usr/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)