fix: (vm_region) ensure the ordering of regions.
fix: (hal/rnd) correct the clobbered register name.
+ 内存管理与按需分页(Demand Paging)
+ 键盘输入
+ 多进程
-+ 47个常见的Linux/POSIX系统调用([附录1](#appendix1))
++ 49个常见的Linux/POSIX系统调用([附录1](#appendix1))
+ 用户模式
+ 信号机制
+ PCI 3.0
2. `ioctl(2)`
2. `getpgid(2)`
2. `setpgid(2)`
+2. `mmap(2)`※
+2. `munmap(2)`※
**LunaixOS自有**
"subl $4, %1\n"
"jnz 1b" ::"r"((ptr_t)data),
"r"((len & ~0x3))
- : "%al");
+ : "%eax");
}
int
__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)
{
#include <lunaix/ds/llist.h>
#include <lunaix/ds/mutex.h>
+#include <lunaix/fs.h>
+#include <lunaix/types.h>
typedef struct
{
struct mm_region
{
struct llist_header head;
- unsigned long start;
- unsigned long end;
- unsigned int attr;
+ struct v_file* mfile;
+ u32_t offset;
+ ptr_t start;
+ ptr_t end;
+ u32_t attr;
};
#endif /* __LUNAIX_MM_H */
--- /dev/null
+#ifndef __LUNAIX_MMAP_H
+#define __LUNAIX_MMAP_H
+
+#include <lunaix/fs.h>
+#include <lunaix/types.h>
+
+void*
+mem_map(ptr_t pd_ref,
+ struct llist_header* regions,
+ void* addr,
+ struct v_file* file,
+ u32_t offset,
+ size_t length,
+ u32_t attrs);
+
+void*
+mem_unmap(ptr_t mnt, struct llist_header* regions, void* addr, size_t length);
+
+#endif /* __LUNAIX_MMAP_H */
#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
#include <lunaix/mm/mm.h>
-void
-region_add(struct mm_region* proc,
- unsigned long start,
- unsigned long end,
- unsigned int attr);
+struct mm_region*
+region_add(struct llist_header* lead, ptr_t start, ptr_t end, u32_t attr);
void
-region_release_all(struct mm_region* proc);
+region_release_all(struct llist_header* lead);
struct mm_region*
-region_get(struct mm_region* proc, unsigned long vaddr);
+region_get(struct llist_header* lead, unsigned long vaddr);
void
-region_copy(struct mm_region* src, struct mm_region* dest);
+region_copy(struct llist_header* src, struct llist_header* dest);
#endif /* __LUNAIX_REGION_H */
struct proc_mm
{
heap_context_t u_heap;
- struct mm_region regions;
+ struct llist_header regions;
};
struct proc_sigstate
// 除法 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 __SYSCALL_syslog 51
+#define __SYSCALL_mmap 52
+#define __SYSCALL_munmap 53
+
#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 }; \
___DOINT33(__SYSCALL_##name, rettype) \
}
+#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"); \
+ ___DOINT33(__SYSCALL_##name, rettype) \
+ }
+
#define __LXSYSCALL2_VARG(rettype, name, t1, p1, t2, p2) \
__attribute__((noinline)) static rettype name( \
__PARAM_MAP2(t1, p1, t2, p2), ...) \
goto segv_term;
}
- if (!(*pte)) {
- // Invalid location
- goto segv_term;
- }
+ // if (!(*pte)) {
+ // // Invalid location
+ // goto segv_term;
+ // }
uintptr_t loc = *pte & ~0xfff;
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;
+ }
+
+ *pte = *pte | pa | PG_PRESENT;
+ goto resolved;
+ }
+
+ // if mfile is set, then it is a mem map
+ if (hit_region->mfile) {
+ struct v_file* file = hit_region->mfile;
+ u32_t offset =
+ (ptr - hit_region->start) & (PG_SIZE - 1) + hit_region->offset;
+ uintptr_t pa = pmm_alloc_page(__current->pid, 0);
+
+ if (!pa) {
+ goto oom;
+ }
+
+ cpu_invplg(pte);
*pte = *pte | pa | PG_PRESENT;
+ int errno = file->ops->read_page(
+ file->inode, ptr & (PG_SIZE - 1), PG_SIZE, offset);
+ if (errno < 0) {
+ kprintf(KERROR "fail to read page (%d)\n", errno);
+ goto segv_term;
+ }
goto resolved;
}
while (1)
;
+oom:
+ kprintf(KERROR "out of memory\n");
segv_term:
kprintf(KERROR "(pid: %d) Segmentation fault on %p (%p:%p)\n",
__current->pid,
.long __lxsys_getpgid
.long __lxsys_setpgid /* 50 */
.long __lxsys_syslog
+ .long __lxsys_mmap
+ .long __lxsys_munmap
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
.long 0
--- /dev/null
+#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>
+
+#include <lunaix/syscall.h>
+
+void*
+mem_map(ptr_t mnt,
+ struct llist_header* regions,
+ void* addr,
+ struct v_file* file,
+ u32_t offset,
+ size_t length,
+ u32_t proct)
+{
+ if (!length || (length & (PG_SIZE - 1)) || (offset & (PG_SIZE - 1))) {
+ __current->k_status = EINVAL;
+ return (void*)-1;
+ }
+
+ // read_page is not supported
+ if (!file->ops->read_page) {
+ __current->k_status = ENODEV;
+ return (void*)-1;
+ }
+
+ ptr_t last_end = USER_START;
+ struct mm_region *pos, *n;
+ llist_for_each(pos, n, regions, head)
+ {
+ if (pos->start - last_end >= length && last_end >= addr) {
+ goto found;
+ }
+ last_end = pos->end;
+ }
+
+ __current->k_status = ENOMEM;
+ return (void*)-1;
+
+found:
+ addr = last_end;
+ ptr_t end = addr + length;
+
+ struct mm_region* region = region_add(regions, addr, end, proct);
+ region->mfile = file;
+ region->offset = offset;
+
+ u32_t attr = PG_ALLOW_USER;
+ if ((proct & REGION_WRITE)) {
+ attr |= PG_WRITE;
+ }
+
+ for (u32_t i = 0; i < length; i += PG_SIZE) {
+ vmm_set_mapping(mnt, addr + i, 0, attr, 0);
+ }
+
+ return addr;
+}
+
+void*
+mem_unmap(ptr_t mnt, struct llist_header* regions, void* addr, size_t length)
+{
+ length = ROUNDUP(length, PG_SIZE);
+ ptr_t cur_addr = ROUNDDOWN((ptr_t)addr, PG_SIZE);
+ struct mm_region *pos, *n;
+
+ llist_for_each(pos, n, regions, head)
+ {
+ if (pos->start >= 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;
+ }
+
+ 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(__current->pid, pa);
+ }
+ }
+
+ n = container_of(pos->head.next, typeof(*pos), head);
+ if (pos->end == pos->start) {
+ llist_delete(&pos->head);
+ vfree(pos);
+ }
+
+ pos = n;
+ length -= l;
+ cur_addr += length;
+ }
+}
+
+__DEFINE_LXSYSCALL5(void*,
+ mmap,
+ void*,
+ addr,
+ size_t,
+ length,
+ int,
+ proct,
+ int,
+ fd,
+ size_t,
+ offset)
+{
+ int errno = 0;
+ struct v_fd* vfd;
+ if ((errno = vfs_getfd(fd, &vfd))) {
+ __current->k_status = errno;
+ return (void*)-1;
+ }
+
+ return mem_map(PD_REFERENCED,
+ &__current->mm.regions,
+ addr,
+ vfd->file,
+ offset,
+ length,
+ proct);
+}
+
+__DEFINE_LXSYSCALL2(void, munmap, void*, addr, size_t, length)
+{
+ return mem_unmap(PD_REFERENCED, &__current->mm.regions, addr, length);
+}
\ No newline at end of file
#include <lunaix/mm/region.h>
#include <lunaix/mm/valloc.h>
-void
-region_add(struct mm_region* regions,
+struct mm_region*
+region_add(struct llist_header* lead,
unsigned long start,
unsigned long end,
unsigned int attr)
*region = (struct mm_region){ .attr = attr, .end = end, .start = start };
- llist_append(®ions->head, ®ion->head);
+ if (llist_empty(lead)) {
+ llist_append(lead, ®ion->head);
+ return region;
+ }
+
+ struct mm_region *pos, *n;
+ llist_for_each(pos, n, lead, head)
+ {
+ if (start >= pos->end && end <= n->start) {
+ break;
+ }
+ }
+
+ llist_insert_after(&pos->head, ®ion->head);
+ return region;
}
void
-region_release_all(struct mm_region* regions)
+region_release_all(struct llist_header* lead)
{
struct mm_region *pos, *n;
- llist_for_each(pos, n, ®ions->head, head)
+ llist_for_each(pos, n, lead, head)
{
vfree(pos);
}
}
void
-region_copy(struct mm_region* src, struct mm_region* dest)
+region_copy(struct llist_header* src, struct llist_header* dest)
{
if (!src) {
return;
struct mm_region *pos, *n;
- llist_for_each(pos, n, &src->head, head)
+ llist_for_each(pos, n, src, head)
{
region_add(dest, pos->start, pos->end, pos->attr);
}
}
struct mm_region*
-region_get(struct mm_region* regions, unsigned long vaddr)
+region_get(struct llist_header* 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)
+ llist_for_each(pos, n, lead, head)
{
if (pos->start <= vaddr && vaddr < pos->end) {
return pos;
// 根据 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)) {
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_dma(proc->fxstate);
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);
}