From 9b73964f6d9883318cbfd5834f3d2cd1661a71b7 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 28 May 2009 13:47:20 +0000 Subject: [PATCH] beng work in progress, to be explained in a future commit message :). --- drivers/memory/memory.c | 3 +- drivers/tty/keyboard.c | 18 +- include/minix/com.h | 5 +- include/minix/config.h | 3 - include/minix/debug.h | 13 + include/minix/type.h | 3 - include/sys/vm_i386.h | 6 + kernel/arch/i386/arch_do_vmctl.c | 28 +- kernel/arch/i386/do_sdevio.c | 5 + kernel/arch/i386/exception.c | 55 ++- kernel/arch/i386/klib386.s | 292 ++++++------ kernel/arch/i386/memory.c | 780 ++++++++++++++++++------------- kernel/arch/i386/mpx386.s | 36 +- kernel/arch/i386/proto.h | 3 + kernel/arch/i386/system.c | 64 ++- kernel/arch/i386/vm.h | 18 +- kernel/debug.c | 25 + kernel/debug.h | 31 +- kernel/glo.h | 4 +- kernel/main.c | 11 + kernel/proc.c | 56 +-- kernel/proc.h | 1 + kernel/proto.h | 8 +- kernel/system.c | 15 +- kernel/system.h | 3 - kernel/system/do_exec.c | 2 + kernel/system/do_fork.c | 3 + kernel/system/do_memset.c | 4 +- kernel/system/do_vm_setbuf.c | 4 + kernel/system/do_vmctl.c | 17 +- kernel/table.c | 5 +- kernel/utility.c | 18 +- kernel/vm.h | 6 +- lib/sysutil/Makefile.in | 1 + servers/init/init.c | 4 + servers/mfs/cache.c | 20 +- servers/pm/main.c | 4 + servers/vfs/fs.h | 2 +- servers/vfs/main.c | 5 + servers/vm/exit.c | 2 + servers/vm/fork.c | 12 + servers/vm/i386/pagetable.c | 202 ++++---- servers/vm/i386/pagetable.h | 9 + servers/vm/i386/vm.c | 67 --- servers/vm/main.c | 21 +- servers/vm/pagefaults.c | 11 + servers/vm/proto.h | 1 + servers/vm/region.c | 14 +- servers/vm/sanitycheck.h | 2 +- servers/vm/vm.h | 2 +- 50 files changed, 1093 insertions(+), 831 deletions(-) create mode 100644 include/minix/debug.h diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index 560508744..4b57ade42 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -403,7 +403,8 @@ int safe; #endif /* Try to allocate a piece of memory for the RAM disk. */ - if((mem = mmap(0, ramdev_size, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0)) == MAP_FAILED) { + if((mem = mmap(0, ramdev_size, PROT_READ|PROT_WRITE, + MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) { printf("MEM: failed to get memory for ramdisk\n"); return(ENOMEM); } diff --git a/drivers/tty/keyboard.c b/drivers/tty/keyboard.c index 018ce0118..bdc27770d 100644 --- a/drivers/tty/keyboard.c +++ b/drivers/tty/keyboard.c @@ -766,8 +766,22 @@ int scode; /* scan code of key just struck or released */ return -1; if(ch) return ch; - printf("tty: ignoring unrecognized %s scancode 0x%x\n", - escape ? "escaped" : "straight", scode); + { + static char seen[2][NR_SCAN_CODES]; + int notseen = 0, ei; + ei = escape ? 1 : 0; + if(scode >= 0 && scode < NR_SCAN_CODES) { + notseen = !seen[ei][scode]; + seen[ei][scode] = 1; + } else { + printf("tty: scode %d makes no sense\n", scode); + } + if(notseen) { + printf("tty: ignoring unrecognized %s " + "scancode 0x%x\n", + escape ? "escaped" : "straight", scode); + } + } return -1; } diff --git a/include/minix/com.h b/include/minix/com.h index aecb85733..0c838685a 100755 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -311,7 +311,6 @@ # define SYS_GETINFO (KERNEL_CALL + 26) /* sys_getinfo() */ # define SYS_ABORT (KERNEL_CALL + 27) /* sys_abort() */ # define SYS_IOPENABLE (KERNEL_CALL + 28) /* sys_enable_iop() */ -# define SYS_VM_SETBUF (KERNEL_CALL + 29) /* sys_vm_setbuf() */ # define SYS_SAFECOPYFROM (KERNEL_CALL + 31) /* sys_safecopyfrom() */ # define SYS_SAFECOPYTO (KERNEL_CALL + 32) /* sys_safecopyto() */ # define SYS_VSAFECOPY (KERNEL_CALL + 33) /* sys_vsafecopy() */ @@ -605,9 +604,9 @@ #define VMCTL_NOPAGEZERO 18 #define VMCTL_I386_KERNELLIMIT 19 #define VMCTL_I386_PAGEDIRS 20 -#define VMCTL_I386_PDE 21 -#define VMCTL_I386_PDEVAL 22 #define VMCTL_I386_FREEPDE 23 +#define VMCTL_ENABLE_PAGING 24 +#define VMCTL_I386_INVLPG 25 /*===========================================================================* * Messages for the Reincarnation Server * diff --git a/include/minix/config.h b/include/minix/config.h index c4b3b9690..788a9bce6 100755 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -95,7 +95,4 @@ #define SPROFILE 1 /* statistical profiling */ #define CPROFILE 0 /* call profiling */ -/* Compile kernel so that first page of code and data can be unmapped. */ -#define VM_KERN_NOPAGEZERO 0 - #endif /* _CONFIG_H */ diff --git a/include/minix/debug.h b/include/minix/debug.h new file mode 100644 index 000000000..808d73583 --- /dev/null +++ b/include/minix/debug.h @@ -0,0 +1,13 @@ +#ifndef _MINIX_DEBUG_H +#define _MINIX_DEBUG_H 1 + +/* For reminders of things to be fixed. */ +#define FIXME(str) { static int fixme_warned = 0; \ + if(!fixme_warned) { \ + printf("FIXME: %s:%d: %s\n", __FILE__, __LINE__, str);\ + fixme_warned = 1; \ + } \ +} + +#endif /* _MINIX_DEBUG_H */ + diff --git a/include/minix/type.h b/include/minix/type.h index 7d182348d..a6429c6b5 100755 --- a/include/minix/type.h +++ b/include/minix/type.h @@ -97,9 +97,6 @@ struct kinfo { int nr_tasks; /* number of kernel tasks */ char release[6]; /* kernel release number */ char version[6]; /* kernel version number */ -#if DEBUG_LOCK_CHECK - int relocking; /* interrupt locking depth (should be 0) */ -#endif }; /* Load data accounted every this no. of seconds. */ diff --git a/include/sys/vm_i386.h b/include/sys/vm_i386.h index 1ab6d4c12..02485f83a 100644 --- a/include/sys/vm_i386.h +++ b/include/sys/vm_i386.h @@ -36,6 +36,12 @@ sys/vm_i386.h #define I386_VM_PFA_SHIFT 22 /* Page frame address shift */ /* CR0 bits */ +#define I386_CR0_PE 0x00000001 /* Protected mode */ +#define I386_CR0_MP 0x00000002 /* Monitor Coprocessor */ +#define I386_CR0_EM 0x00000004 /* Emulate */ +#define I386_CR0_TS 0x00000008 /* Task Switched */ +#define I386_CR0_ET 0x00000010 /* Extension Type */ +#define I386_CR0_WP 0x00010000 /* Enable paging */ #define I386_CR0_PG 0x80000000 /* Enable paging */ /* some CR4 bits */ diff --git a/kernel/arch/i386/arch_do_vmctl.c b/kernel/arch/i386/arch_do_vmctl.c index 7ab5aa3ee..71a0469aa 100644 --- a/kernel/arch/i386/arch_do_vmctl.c +++ b/kernel/arch/i386/arch_do_vmctl.c @@ -12,7 +12,6 @@ #include "proto.h" -extern u32_t kernel_cr3; extern u32_t *vm_pagedirs; /*===========================================================================* @@ -22,10 +21,6 @@ PUBLIC int arch_do_vmctl(m_ptr, p) register message *m_ptr; /* pointer to request message */ struct proc *p; { - - static int vmpde = -1; - static u32_t pdeval = -1; - switch(m_ptr->SVMCTL_PARAM) { case VMCTL_I386_GETCR3: /* Get process CR3. */ @@ -37,7 +32,7 @@ struct proc *p; p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE; p->p_misc_flags |= MF_FULLVM; } else { - p->p_seg.p_cr3 = kernel_cr3; + p->p_seg.p_cr3 = 0; p->p_misc_flags &= ~MF_FULLVM; } RTS_LOCK_UNSET(p, VMINHIBIT); @@ -58,6 +53,8 @@ struct proc *p; m_ptr->SVMCTL_PF_WHO = rp->p_endpoint; m_ptr->SVMCTL_PF_I386_CR2 = rp->p_pagefault.pf_virtual; m_ptr->SVMCTL_PF_I386_ERR = rp->p_pagefault.pf_flags; + printf("kernel: returning pagefault for %s / %d\n", + rp->p_name, rp->p_endpoint); return OK; } case VMCTL_I386_KERNELLIMIT: @@ -74,25 +71,14 @@ struct proc *p; kprintf("kernel: pagedirs now 0x%lx\n", vm_pagedirs); return OK; } - case VMCTL_I386_PDE: - { - vmpde = m_ptr->SVMCTL_VALUE; - kprintf("kernel: HACK: vmpde %d\n", vmpde); - return OK; - } - case VMCTL_I386_PDEVAL: + case VMCTL_I386_FREEPDE: { - pdeval = m_ptr->SVMCTL_VALUE; - kprintf("kernel: HACK: vmpde %d, set val 0x%x\n", - vmpde, pdeval); - i386_updatepde(vmpde, pdeval); - kprintf("kernel: HACK: vmpde %d, set val 0x%x done\n", - vmpde, pdeval); + i386_freepde(m_ptr->SVMCTL_VALUE); return OK; } - case VMCTL_I386_FREEPDE: + case VMCTL_I386_INVLPG: { - i386_freepde(m_ptr->SVMCTL_VALUE); + invlpg_range(m_ptr->SVMCTL_VALUE, 1); return OK; } } diff --git a/kernel/arch/i386/do_sdevio.c b/kernel/arch/i386/do_sdevio.c index 5028d9e65..1beefa499 100644 --- a/kernel/arch/i386/do_sdevio.c +++ b/kernel/arch/i386/do_sdevio.c @@ -33,6 +33,10 @@ register message *m_ptr; /* pointer to request message */ struct priv *privp; struct io_range *iorp; + kprintf("kernel: no sdevio\n"); + return EIO; + +#if 0 /* Allow safe copies and accesses to SELF */ if ((m_ptr->DIO_REQUEST & _DIO_SAFEMASK) != _DIO_SAFE && proc_nr_e != SELF) @@ -141,6 +145,7 @@ register message *m_ptr; /* pointer to request message */ return(EINVAL); } return(OK); +#endif } #endif /* USE_SDEVIO */ diff --git a/kernel/arch/i386/exception.c b/kernel/arch/i386/exception.c index 2657482de..0e137755d 100755 --- a/kernel/arch/i386/exception.c +++ b/kernel/arch/i386/exception.c @@ -11,10 +11,11 @@ #include #include "../../proc.h" -extern int vm_copy_in_progress; +extern int vm_copy_in_progress, catch_pagefaults; extern struct proc *vm_copy_from, *vm_copy_to; extern u32_t vm_copy_from_v, vm_copy_to_v; extern u32_t vm_copy_from_p, vm_copy_to_p, vm_copy_cr3; +extern u32_t catchrange_lo, catchrange_hi; u32_t pagefault_cr2, pagefault_count = 0; @@ -24,15 +25,33 @@ void pagefault(struct proc *pr, int trap_errno) vir_bytes ph; u32_t pte; - if(pagefault_count != 1) - minix_panic("recursive pagefault", pagefault_count); + vmassert(pagefault_count == 1); + + if((iskernelp(pr) || k_reenter) && catch_pagefaults + && (pr->p_reg.pc > (vir_bytes) _memcpy_k && + pr->p_reg.pc < (vir_bytes) _memcpy_k_fault) && + pagefault_cr2 >= catchrange_lo && + pagefault_cr2 < catchrange_hi) { + kprintf("handling pagefault during copy\n"); + pr->p_reg.pc = (vir_bytes) _memcpy_k_fault; + pr->p_reg.retreg = pagefault_cr2; + pagefault_count = 0; + return; + } - /* Don't schedule this process until pagefault is handled. */ - if(RTS_ISSET(pr, PAGEFAULT)) - minix_panic("PAGEFAULT set", pr->p_endpoint); - RTS_LOCK_SET(pr, PAGEFAULT); + proc_stacktrace(pr); + + if(catch_pagefaults) { + printf("k_reenter: %d addr: 0x%lx range: 0x%lx-0x%lx\n", + k_reenter, pagefault_cr2, catchrange_lo, catchrange_hi); + } - if(pr->p_endpoint <= INIT_PROC_NR && !(pr->p_misc_flags & MF_FULLVM)) { + /* System processes that don't have their own page table can't + * have page faults. VM does have its own page table but also + * can't have page faults (because VM has to handle them). + */ + if(k_reenter || (pr->p_endpoint <= INIT_PROC_NR && + !(pr->p_misc_flags & MF_FULLVM)) || pr->p_endpoint == VM_PROC_NR) { /* Page fault we can't / don't want to * handle. */ @@ -45,6 +64,11 @@ void pagefault(struct proc *pr, int trap_errno) return; } + /* Don't schedule this process until pagefault is handled. */ + vmassert(pr->p_seg.p_cr3 == read_cr3()); + vmassert(!RTS_ISSET(pr, PAGEFAULT)); + RTS_LOCK_SET(pr, PAGEFAULT); + /* Save pagefault details, suspend process, * add process to pagefault chain, * and tell VM there is a pagefault to be @@ -54,7 +78,7 @@ void pagefault(struct proc *pr, int trap_errno) pr->p_pagefault.pf_flags = trap_errno; pr->p_nextpagefault = pagefaults; pagefaults = pr; - lock_notify(HARDWARE, VM_PROC_NR); + soft_notify(VM_PROC_NR); pagefault_count = 0; @@ -184,17 +208,20 @@ PUBLIC void proc_stacktrace(struct proc *proc) v_bp = proc->p_reg.fp; - kprintf("%8.8s %6d 0x%lx ", + kprintf("%-8.8s %6d 0x%lx ", proc->p_name, proc->p_endpoint, proc->p_reg.pc); while(v_bp) { - if(data_copy(proc->p_endpoint, v_bp, - SYSTEM, (vir_bytes) &v_hbp, sizeof(v_hbp)) != OK) { + +#define PRCOPY(pr, pv, v, n) \ + (iskernelp(pr) ? (memcpy(v, pv, n), OK) : \ + data_copy(pr->p_endpoint, pv, SYSTEM, (vir_bytes) (v), n)) + + if(PRCOPY(proc, v_bp, &v_hbp, sizeof(v_hbp)) != OK) { kprintf("(v_bp 0x%lx ?)", v_bp); break; } - if(data_copy(proc->p_endpoint, v_bp + sizeof(v_pc), - SYSTEM, (vir_bytes) &v_pc, sizeof(v_pc)) != OK) { + if(PRCOPY(proc, v_bp + sizeof(v_pc), &v_pc, sizeof(v_pc)) != OK) { kprintf("(v_pc 0x%lx ?)", v_pc); break; } diff --git a/kernel/arch/i386/klib386.s b/kernel/arch/i386/klib386.s index dfec1dbb9..fda2f3f39 100755 --- a/kernel/arch/i386/klib386.s +++ b/kernel/arch/i386/klib386.s @@ -21,10 +21,10 @@ .define __exit ! dummy for library routines .define ___exit ! dummy for library routines .define ___main ! dummy for GCC -.define _phys_insw ! transfer data from (disk controller) port to memory -.define _phys_insb ! likewise byte by byte -.define _phys_outsw ! transfer data from memory to (disk controller) port -.define _phys_outsb ! likewise byte by byte +!.define _phys_insw ! transfer data from (disk controller) port to memory +!.define _phys_insb ! likewise byte by byte +!.define _phys_outsw ! transfer data from memory to (disk controller) port +!.define _phys_outsb ! likewise byte by byte .define _intr_unmask ! enable an irq at the 8259 controller .define _intr_mask ! disable an irq .define _phys_copy ! copy data from anywhere to anywhere in memory @@ -36,14 +36,16 @@ .define _read_cpu_flags ! read the cpu flags .define _read_cr0 ! read cr0 .define _write_cr3 ! write cr3 +.define _getcr3val .define _last_cr3 .define _write_cr0 ! write a value in cr0 .define _read_cr4 +.define _thecr3 .define _write_cr4 .define _i386_invlpg_addr .define _i386_invlpg_level0 - -.define _kernel_cr3 +.define __memcpy_k +.define __memcpy_k_fault ! The routines only guarantee to preserve the registers the C compiler ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and @@ -158,55 +160,6 @@ csinit: mov eax, DS_SELECTOR ret -!*===========================================================================* -!* cp_mess * -!*===========================================================================* -! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset, -! phys_clicks dst_clicks, vir_bytes dst_offset); -! This routine makes a fast copy of a message from anywhere in the address -! space to anywhere else. It also copies the source address provided as a -! parameter to the call into the first word of the destination message. -! -! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set -! correctly. Changing the definition of message in the type file and not -! changing it here will lead to total disaster. -! -!CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4 -!! es ds edi esi eip proc scl sof dcl dof -! -! .align 16 -!_cp_mess: -! cld -! push esi -! push edi -! push ds -! push es -! -! mov eax, FLAT_DS_SELECTOR -! mov ds, ax -! mov es, ax -! -! mov esi, CM_ARGS+4(esp) ! src clicks -! shl esi, CLICK_SHIFT -! add esi, CM_ARGS+4+4(esp) ! src offset -! mov edi, CM_ARGS+4+4+4(esp) ! dst clicks -! shl edi, CLICK_SHIFT -! add edi, CM_ARGS+4+4+4+4(esp) ! dst offset -! -! mov eax, CM_ARGS(esp) ! process number of sender -! stos ! copy number of sender to dest message -! add esi, 4 ! do not copy first word -! mov ecx, Msize - 1 ! remember, first word does not count -! rep -! movs ! copy the message -! -! pop es -! pop ds -! pop edi -! pop esi -! ret ! that is all folks! -! - !*===========================================================================* !* exit * !*===========================================================================* @@ -230,56 +183,52 @@ ___main: !*===========================================================================* ! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count); ! Input an array from an I/O port. Absolute address version of insw(). - -_phys_insw: - push ebp - mov ebp, esp - cld - push edi - push es - - LOADKERNELCR3 - - mov ecx, FLAT_DS_SELECTOR - mov es, cx - mov edx, 8(ebp) ! port to read from - mov edi, 12(ebp) ! destination addr - mov ecx, 16(ebp) ! byte count - shr ecx, 1 ! word count -rep o16 ins ! input many words - pop es - pop edi - pop ebp - ret - +! +!_phys_insw: +! push ebp +! mov ebp, esp +! cld +! push edi +! push es +! +! mov ecx, FLAT_DS_SELECTOR +! mov es, cx +! mov edx, 8(ebp) ! port to read from +! mov edi, 12(ebp) ! destination addr +! mov ecx, 16(ebp) ! byte count +! shr ecx, 1 ! word count +!rep o16 ins ! input many words +! pop es +! pop edi +! pop ebp +! ret +! !*===========================================================================* !* phys_insb * !*===========================================================================* ! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count); ! Input an array from an I/O port. Absolute address version of insb(). - -_phys_insb: - push ebp - mov ebp, esp - cld - push edi - push es - - LOADKERNELCR3 - - mov ecx, FLAT_DS_SELECTOR - mov es, cx - mov edx, 8(ebp) ! port to read from - mov edi, 12(ebp) ! destination addr - mov ecx, 16(ebp) ! byte count -! shr ecx, 1 ! word count - rep insb ! input many bytes - pop es - pop edi - pop ebp - ret - +! +!_phys_insb: +! push ebp +! mov ebp, esp +! cld +! push edi +! push es +! +! mov ecx, FLAT_DS_SELECTOR +! mov es, cx +! mov edx, 8(ebp) ! port to read from +! mov edi, 12(ebp) ! destination addr +! mov ecx, 16(ebp) ! byte count +!! shr ecx, 1 ! word count +! rep insb ! input many bytes +! pop es +! pop edi +! pop ebp +! ret +! !*===========================================================================* !* phys_outsw * @@ -287,55 +236,51 @@ _phys_insb: ! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count); ! Output an array to an I/O port. Absolute address version of outsw(). - .align 16 -_phys_outsw: - push ebp - mov ebp, esp - cld - push esi - push ds - - LOADKERNELCR3 - - mov ecx, FLAT_DS_SELECTOR - mov ds, cx - mov edx, 8(ebp) ! port to write to - mov esi, 12(ebp) ! source addr - mov ecx, 16(ebp) ! byte count - shr ecx, 1 ! word count -rep o16 outs ! output many words - pop ds - pop esi - pop ebp - ret - +! .align 16 +!_phys_outsw: +! push ebp +! mov ebp, esp +! cld +! push esi +! push ds +! +! mov ecx, FLAT_DS_SELECTOR +! mov ds, cx +! mov edx, 8(ebp) ! port to write to +! mov esi, 12(ebp) ! source addr +! mov ecx, 16(ebp) ! byte count +! shr ecx, 1 ! word count +!rep o16 outs ! output many words +! pop ds +! pop esi +! pop ebp +! ret +! !*===========================================================================* !* phys_outsb * !*===========================================================================* ! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count); ! Output an array to an I/O port. Absolute address version of outsb(). - - .align 16 -_phys_outsb: - push ebp - mov ebp, esp - cld - push esi - push ds - - LOADKERNELCR3 - - mov ecx, FLAT_DS_SELECTOR - mov ds, cx - mov edx, 8(ebp) ! port to write to - mov esi, 12(ebp) ! source addr - mov ecx, 16(ebp) ! byte count - rep outsb ! output many bytes - pop ds - pop esi - pop ebp - ret +! +! .align 16 +!_phys_outsb: +! push ebp +! mov ebp, esp +! cld +! push esi +! push ds +! +! mov ecx, FLAT_DS_SELECTOR +! mov ds, cx +! mov edx, 8(ebp) ! port to write to +! mov esi, 12(ebp) ! source addr +! mov ecx, 16(ebp) ! byte count +! rep outsb ! output many bytes +! pop ds +! pop esi +! pop ebp +! ret !*==========================================================================* @@ -432,8 +377,6 @@ _phys_copy: push edi push es - LOADKERNELCR3 - mov eax, FLAT_DS_SELECTOR mov es, ax @@ -479,8 +422,6 @@ _phys_memset: push ebx push ds - LOADKERNELCR3 - mov esi, 8(ebp) mov eax, 16(ebp) mov ebx, FLAT_DS_SELECTOR @@ -494,7 +435,7 @@ fill_start: jnz fill_start ! Any remaining bytes? mov eax, 16(ebp) - and eax, 3 +! and eax, 3 remain_fill: cmp eax, 0 jz fill_done @@ -642,10 +583,20 @@ _write_cr4: _write_cr3: push ebp mov ebp, esp - LOADCR3WITHEAX(0x22, 8(ebp)) + mov eax, 8(ebp) + mov cr3, eax pop ebp ret +!*===========================================================================* +!* getcr3val * +!*===========================================================================* +! PUBLIC unsigned long getcr3val(void); +_getcr3val: + mov eax, cr3 + mov (_thecr3), eax + ret + !*===========================================================================* !* i386_invlpg * !*===========================================================================* @@ -657,4 +608,47 @@ _i386_invlpg_level0: ret - +!*===========================================================================* +!* _memcpy_k * +!*===========================================================================* +! _memcpy_k() Original Author: Kees J. Bot +! 2 Jan 1994 +! void *_memcpy_k(void *s1, const void *s2, size_t n) +! Copy a chunk of memory that the kernel can use to trap pagefaults. +.define __memcpy_k +.define __memcpy_k_fault + .align 16 +__memcpy_k: + push ebp + mov ebp, esp + push esi + push edi + mov edi, 8(ebp) ! String s1 + mov esi, 12(ebp) ! String s2 + mov ecx, 16(ebp) ! Length + cld ! Clear direction bit: upwards + cmp ecx, 16 + jb upbyte ! Don't bother being smart with short arrays + mov eax, esi + or eax, edi + testb al, 1 + jnz upbyte ! Bit 0 set, use byte copy + testb al, 2 + jnz upword ! Bit 1 set, use word copy +uplword:shrd eax, ecx, 2 ! Save low 2 bits of ecx in eax + shr ecx, 2 + rep + movs ! Copy longwords. + shld ecx, eax, 2 ! Restore excess count +upword: shr ecx, 1 + rep + o16 movs ! Copy words + adc ecx, ecx ! One more byte? +upbyte: rep + movsb ! Copy bytes +done: mov eax, 0 +__memcpy_k_fault: ! Kernel can send us here with pf cr2 in eax + pop edi + pop esi + pop ebp + ret diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index ed5b05169..c747932d6 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -9,6 +9,10 @@ #include #include +#define FREEPDE_SRC 0 +#define FREEPDE_DST 1 +#define FREEPDE_MEMSET 2 + #include #include @@ -17,13 +21,26 @@ #include "../../proto.h" #include "../../debug.h" +PRIVATE int psok = 0; + +#define PROCPDEPTR(pr, pi) ((u32_t *) ((u8_t *) vm_pagedirs +\ + I386_PAGE_SIZE * pr->p_nr + \ + I386_VM_PT_ENT_SIZE * pi)) + +/* Signal to exception handler that pagefaults can happen. */ +int catch_pagefaults = 0; +u32_t catchrange_lo = 0; +u32_t catchrange_hi = 0; + +#if 0 /* VM functions and data. */ -PRIVATE u32_t vm_cr3; PUBLIC u32_t kernel_cr3; +#endif + extern u32_t cswitch; u32_t last_cr3 = 0; -u32_t *vm_pagedirs = NULL; +u8_t *vm_pagedirs = NULL; u32_t i386_invlpg_addr = 0; @@ -32,122 +49,81 @@ PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES]; #define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0) -FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) ); -FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) ); +FORWARD _PROTOTYPE( u32_t phys_get32, (vir_bytes v) ); FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) ); FORWARD _PROTOTYPE( void set_cr3, (void) ); FORWARD _PROTOTYPE( void vm_enable_paging, (void) ); -#if DEBUG_VMASSERT -#define vmassert(t) { \ - if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } } -#else -#define vmassert(t) { } -#endif - /* *** Internal VM Functions *** */ -PUBLIC void vm_init(void) +PUBLIC void vm_init(struct proc *newptproc) { - int o; - phys_bytes p, pt_size; - phys_bytes vm_dir_base, vm_pt_base, phys_mem; - u32_t entry; - unsigned pages; - struct proc* rp; - struct proc *sys = proc_addr(SYSTEM); - static int init_done = 0; - - if (!vm_size) - minix_panic("i386_vm_init: no space for page tables", NO_NUM); - - if(init_done) - return; - - /* Align page directory */ - o= (vm_base % I386_PAGE_SIZE); - if (o != 0) - o= I386_PAGE_SIZE-o; - vm_dir_base= vm_base+o; - - /* Page tables start after the page directory */ - vm_pt_base= vm_dir_base+I386_PAGE_SIZE; - - pt_size= (vm_base+vm_size)-vm_pt_base; - pt_size -= (pt_size % I386_PAGE_SIZE); - - /* Compute the number of pages based on vm_mem_high */ - pages= (vm_mem_high-1)/I386_PAGE_SIZE + 1; - - if (pages * I386_VM_PT_ENT_SIZE > pt_size) - minix_panic("i386_vm_init: page table too small", NO_NUM); - - for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++) - { - phys_mem= p*I386_PAGE_SIZE; - entry= phys_mem | I386_VM_USER | I386_VM_WRITE | - I386_VM_PRESENT; - if (phys_mem >= vm_mem_high) - entry= 0; -#if VM_KERN_NOPAGEZERO - if (phys_mem == (sys->p_memmap[T].mem_phys << CLICK_SHIFT) || - phys_mem == (sys->p_memmap[D].mem_phys << CLICK_SHIFT)) { - entry = 0; - } -#endif - phys_put32(vm_pt_base + p*I386_VM_PT_ENT_SIZE, entry); - } + u32_t newcr3; - for (p= 0; p < I386_VM_DIR_ENTRIES; p++) - { - phys_mem= vm_pt_base + p*I386_PAGE_SIZE; - entry= phys_mem | I386_VM_USER | I386_VM_WRITE | - I386_VM_PRESENT; - if (phys_mem >= vm_pt_base + pt_size) - entry= 0; - phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry); - } + if(vm_running) + minix_panic("vm_init: vm_running", NO_NUM); + ptproc = newptproc; + newcr3 = ptproc->p_seg.p_cr3; + kprintf("vm_init: ptproc: %s / %d, cr3 0x%lx\n", + ptproc->p_name, ptproc->p_endpoint, + ptproc->p_seg.p_cr3); + vmassert(newcr3); - /* Set this cr3 in all currently running processes for - * future context switches. - */ - for (rp=BEG_PROC_ADDR; rpp_seg.p_cr3 = vm_dir_base; - } + kprintf("vm_init thinks cr3 0x%lx is loaded, proc %d, cr3 0x%lx, actual cr3 0x%lx\n", + last_cr3, ptproc->p_endpoint, ptproc->p_seg.p_cr3, read_cr3()); - kernel_cr3 = vm_dir_base; + kprintf("vm_init: writing cr3 0x%lx\n", newcr3); /* Set this cr3 now (not active until paging enabled). */ - vm_set_cr3(vm_dir_base); + vm_set_cr3(newcr3); + kprintf("vm_init: writing cr3 0x%lx done; cr3: 0x%lx\n", + newcr3, read_cr3()); + + kprintf("vm_init: enabling\n"); /* Actually enable paging (activating cr3 load above). */ level0(vm_enable_paging); + kprintf("vm_init: enabled\n"); + /* Don't do this init in the future. */ - init_done = 1; vm_running = 1; + + kprintf("vm_init done\n"); } +#if 0 PRIVATE void phys_put32(addr, value) phys_bytes addr; u32_t value; { phys_copy(vir2phys((vir_bytes)&value), addr, sizeof(value)); } +#endif PRIVATE u32_t phys_get32(addr) phys_bytes addr; { - u32_t value; + u32_t v; + int r; - phys_copy(addr, vir2phys((vir_bytes)&value), sizeof(value)); + if(!vm_running) { + phys_copy(addr, vir2phys(&v), sizeof(v)); + return v; + } + + if((r=lin_lin_copy(NULL, addr, NULL, D, + proc_addr(SYSTEM), &v, &v, D, + sizeof(v))) != OK) { + minix_panic("lin_lin_copy for phys_get32 failed", r); + } - return value; + return v; } +PRIVATE u32_t vm_cr3; /* temp arg to level0() func */ + PRIVATE void vm_set_cr3(value) u32_t value; { @@ -160,10 +136,42 @@ PRIVATE void set_cr3() write_cr3(vm_cr3); } +char *cr0_str(u32_t e) +{ + static char str[80]; + strcpy(str, ""); +#define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); e &= ~v; } } while(0) + FLAG(I386_CR0_PE); + FLAG(I386_CR0_MP); + FLAG(I386_CR0_EM); + FLAG(I386_CR0_TS); + FLAG(I386_CR0_ET); + FLAG(I386_CR0_PG); + FLAG(I386_CR0_WP); + if(e) { strcat(str, " (++)"); } + return str; +} + +char *cr4_str(u32_t e) +{ + static char str[80]; + strcpy(str, ""); + FLAG(I386_CR4_VME); + FLAG(I386_CR4_PVI); + FLAG(I386_CR4_TSD); + FLAG(I386_CR4_DE); + FLAG(I386_CR4_PSE); + FLAG(I386_CR4_PAE); + FLAG(I386_CR4_MCE); + FLAG(I386_CR4_PGE); + if(e) { strcat(str, " (++)"); } + return str; +} + PRIVATE void vm_enable_paging(void) { u32_t cr0, cr4; - int psok, pgeok; + int pgeok; psok = _cpufeature(_CPUF_I386_PSE); pgeok = _cpufeature(_CPUF_I386_PGE); @@ -171,22 +179,41 @@ PRIVATE void vm_enable_paging(void) cr0= read_cr0(); cr4= read_cr4(); + kprintf("vm_enable_paging: cr0: %s cr4: %s; want to disable\n", + cr0_str(cr0), cr4_str(cr4)); + /* First clear PG and PGE flag, as PGE must be enabled after PG. */ write_cr0(cr0 & ~I386_CR0_PG); - write_cr4(cr4 & ~I386_CR4_PGE); + write_cr4(cr4 & ~(I386_CR4_PGE | I386_CR4_PSE)); cr0= read_cr0(); cr4= read_cr4(); + kprintf("vm_enable_paging: cr0: %s cr4: %s after disabling\n", + cr0_str(cr0), cr4_str(cr4)); + + /* Our first page table contains 4MB entries. */ + if(psok) + cr4 |= I386_CR4_PSE; + + write_cr4(cr4); + /* First enable paging, then enable global page flag. */ - write_cr0(cr0 | I386_CR0_PG); + kprintf("vm_enable_paging: write PG\n"); + cr0 |= I386_CR0_PG; + write_cr0(cr0 ); + kprintf("vm_enable_paging: writing WP\n"); + cr0 |= I386_CR0_WP; + write_cr0(cr0); + kprintf("vm_enable_paging: write WP done\n"); /* May we enable these features? */ if(pgeok) cr4 |= I386_CR4_PGE; - if(psok) - cr4 |= I386_CR4_PSE; + kprintf("vm_enable_paging: write cr4 0x%lx\n", cr4); + write_cr4(cr4); + kprintf("vm_enable_paging: write cr4 0x%lx done\n", cr4); write_cr4(cr4); } @@ -322,6 +349,7 @@ vir_bytes bytes; /* # of bytes to be copied */ return phys; } + /*===========================================================================* * vm_lookup * *===========================================================================*/ @@ -330,6 +358,7 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, u32_t *root, *pt; int pde, pte; u32_t pde_v, pte_v; + NOREC_ENTER(vmlookup); vmassert(proc); vmassert(physical); @@ -337,7 +366,7 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, if(!HASPT(proc)) { *physical = virtual; - return OK; + NOREC_RETURN(vmlookup, OK); } /* Retrieve page directory entry. */ @@ -346,6 +375,7 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, pde = I386_VM_PDE(virtual); vmassert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); pde_v = phys_get32((u32_t) (root + pde)); + if(!(pde_v & I386_VM_PRESENT)) { #if 0 kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pde %d not present\n", @@ -353,32 +383,33 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, kprintf("kernel stack: "); util_stacktrace(); #endif - return EFAULT; + NOREC_RETURN(vmlookup, EFAULT); } - /* Retrieve page table entry. */ - pt = (u32_t *) I386_VM_PFA(pde_v); - vmassert(!((u32_t) pt % I386_PAGE_SIZE)); - pte = I386_VM_PTE(virtual); - vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES); - pte_v = phys_get32((u32_t) (pt + pte)); - if(!(pte_v & I386_VM_PRESENT)) { -#if 0 - kprintf("vm_lookup: %d:%s:0x%lx: cr3 %lx: pde %d: pte %d not present\n", - proc->p_endpoint, proc->p_name, virtual, root, pde, pte); - kprintf("kernel stack: "); - util_stacktrace(); -#endif - return EFAULT; - } + /* We don't expect to ever see this. */ + if(pde_v & I386_VM_BIGPAGE) { + *physical = pde_v & I386_VM_ADDR_MASK_4MB; + if(ptent) *ptent = pde_v; + *physical += virtual & I386_VM_OFFSET_MASK_4MB; + } else { + /* Retrieve page table entry. */ + pt = (u32_t *) I386_VM_PFA(pde_v); + vmassert(!((u32_t) pt % I386_PAGE_SIZE)); + pte = I386_VM_PTE(virtual); + vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES); + pte_v = phys_get32((u32_t) (pt + pte)); + if(!(pte_v & I386_VM_PRESENT)) { + NOREC_RETURN(vmlookup, EFAULT); + } - if(ptent) *ptent = pte_v; + if(ptent) *ptent = pte_v; - /* Actual address now known; retrieve it and add page offset. */ - *physical = I386_VM_PFA(pte_v); - *physical += virtual % I386_PAGE_SIZE; + /* Actual address now known; retrieve it and add page offset. */ + *physical = I386_VM_PFA(pte_v); + *physical += virtual % I386_PAGE_SIZE; + } - return OK; + NOREC_RETURN(vmlookup, OK); } /* From virtual address v in process p, @@ -397,54 +428,6 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, return r; \ } } } -/*===========================================================================* - * vm_copy * - *===========================================================================*/ -int vm_copy(vir_bytes src, struct proc *srcproc, - vir_bytes dst, struct proc *dstproc, phys_bytes bytes) -{ -#define WRAPS(v) (ULONG_MAX - (v) <= bytes) - - if(WRAPS(src) || WRAPS(dst)) - minix_panic("vm_copy: linear address wraps", NO_NUM); - - while(bytes > 0) { - u32_t n, flags; - phys_bytes p_src, p_dst; -#define PAGEREMAIN(v) (I386_PAGE_SIZE - ((v) % I386_PAGE_SIZE)) - - /* We can copy this number of bytes without - * crossing a page boundary, but don't copy more - * than asked. - */ - n = MIN(PAGEREMAIN(src), PAGEREMAIN(dst)); - n = MIN(n, bytes); - vmassert(n > 0); - vmassert(n <= I386_PAGE_SIZE); - - /* Convert both virtual addresses to physical and do - * copy. - */ - LOOKUP(p_src, srcproc, src, NULL); - LOOKUP(p_dst, dstproc, dst, &flags); - if(!(flags & I386_VM_WRITE)) { - kprintf("vm_copy: copying to nonwritable page\n"); - kprintf("kernel stack: "); - util_stacktrace(); - return EFAULT; - } - phys_copy(p_src, p_dst, n); - - /* Book number of bytes copied. */ - vmassert(bytes >= n); - bytes -= n; - src += n; - dst += n; - } - - return OK; -} - /*===========================================================================* * vm_contiguous * *===========================================================================*/ @@ -509,6 +492,29 @@ PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes) int vm_checkrange_verbose = 0; +/*===========================================================================* + * vm_suspend * + *===========================================================================*/ +PUBLIC int vm_suspend(struct proc *caller, struct proc *target) +{ + /* This range is not OK for this process. Set parameters + * of the request and notify VM about the pending request. + */ + if(RTS_ISSET(caller, VMREQUEST)) + minix_panic("VMREQUEST already set", caller->p_endpoint); + RTS_LOCK_SET(caller, VMREQUEST); + + /* Set caller in target. */ + target->p_vmrequest.requestor = caller; + + /* Connect caller on vmrequest wait queue. */ + caller->p_vmrequest.nextrequestor = vmrequest; + vmrequest = caller; + if(!caller->p_vmrequest.nextrequestor) { + soft_notify(VM_PROC_NR); + } +} + /*===========================================================================* * vm_checkrange * *===========================================================================*/ @@ -518,8 +524,10 @@ PUBLIC int vm_checkrange(struct proc *caller, struct proc *target, u32_t flags, po, v; int r; + NOREC_ENTER(vmcheckrange); + if(!HASPT(target)) - return OK; + NOREC_RETURN(vmcheckrange, OK); /* If caller has had a reply to this request, return it. */ if(RTS_ISSET(caller, VMREQUEST)) { @@ -531,7 +539,7 @@ PUBLIC int vm_checkrange(struct proc *caller, struct proc *target, kprintf("SYSTEM: vm_checkrange: returning vmresult %d\n", caller->p_vmrequest.vmresult); #endif - return caller->p_vmrequest.vmresult; + NOREC_RETURN(vmcheckrange, caller->p_vmrequest.vmresult); } else { #if 0 kprintf("SYSTEM: vm_checkrange: caller has a request for %d, " @@ -558,97 +566,39 @@ PUBLIC int vm_checkrange(struct proc *caller, struct proc *target, */ if(vm_lookup(target, v, &phys, &flags) == OK && !(wrfl && !(flags & I386_VM_WRITE))) { - if(vm_checkrange_verbose) { -#if 0 - kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, OK\n", - target->p_name, target->p_endpoint, v, wrfl, flags, phys); -#endif - } continue; } - if(vm_checkrange_verbose) { - kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, NOT OK\n", - target->p_name, target->p_endpoint, v, wrfl, flags, phys); - } - - if(checkonly) { - return VMSUSPEND; - } - - /* This range is not OK for this process. Set parameters - * of the request and notify VM about the pending request. - */ - if(RTS_ISSET(caller, VMREQUEST)) - minix_panic("VMREQUEST already set", caller->p_endpoint); - RTS_LOCK_SET(caller, VMREQUEST); - - /* Set parameters in caller. */ - caller->p_vmrequest.writeflag = wrfl; - caller->p_vmrequest.start = vir; - caller->p_vmrequest.length = bytes; - caller->p_vmrequest.who = target->p_endpoint; - - /* Set caller in target. */ - target->p_vmrequest.requestor = caller; - - /* Connect caller on vmrequest wait queue. */ - caller->p_vmrequest.nextrequestor = vmrequest; - vmrequest = caller; - if(!caller->p_vmrequest.nextrequestor) { - int n = 0; - struct proc *vmr; - for(vmr = vmrequest; vmr; vmr = vmr->p_vmrequest.nextrequestor) - n++; - soft_notify(VM_PROC_NR); -#if 0 - kprintf("(%d) ", n); - kprintf("%d/%d ", - caller->p_endpoint, target->p_endpoint); - util_stacktrace(); -#endif - } - -#if 0 - kprintf("SYSTEM: vm_checkrange: range bad for " - "target %s:0x%lx-0x%lx, caller %s\n", - target->p_name, vir, vir+bytes, caller->p_name); - - kprintf("vm_checkrange kernel trace: "); - util_stacktrace(); - kprintf("target trace: "); - proc_stacktrace(target); -#endif - - if(target->p_endpoint == VM_PROC_NR) { - kprintf("caller trace: "); - proc_stacktrace(caller); - kprintf("target trace: "); - proc_stacktrace(target); - minix_panic("VM ranges should be OK", NO_NUM); + if(!checkonly) { + /* Set parameters in caller. */ + vm_suspend(caller, target); + caller->p_vmrequest.writeflag = wrfl; + caller->p_vmrequest.start = vir; + caller->p_vmrequest.length = bytes; + caller->p_vmrequest.who = target->p_endpoint; } - return VMSUSPEND; + /* SYSTEM loop will fill in VMSTYPE_SYS_MESSAGE. */ + NOREC_RETURN(vmcheckrange, VMSUSPEND); } - return OK; + NOREC_RETURN(vmcheckrange, OK); } char *flagstr(u32_t e, int dir) { static char str[80]; strcpy(str, ""); -#define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); } } while(0) FLAG(I386_VM_PRESENT); FLAG(I386_VM_WRITE); FLAG(I386_VM_USER); FLAG(I386_VM_PWT); FLAG(I386_VM_PCD); + FLAG(I386_VM_GLOBAL); if(dir) FLAG(I386_VM_BIGPAGE); /* Page directory entry only */ else FLAG(I386_VM_DIRTY); /* Page table entry only */ - return str; } @@ -665,8 +615,9 @@ void vm_pt_print(u32_t *pagetable, u32_t v) if(!(pte_v & I386_VM_PRESENT)) continue; pfa = I386_VM_PFA(pte_v); - kprintf("%4d:%08lx:%08lx ", - pte, v + I386_PAGE_SIZE*pte, pfa); + kprintf("%4d:%08lx:%08lx %2s ", + pte, v + I386_PAGE_SIZE*pte, pfa, + (pte_v & I386_VM_WRITE) ? "rw":"RO"); col++; if(col == 3) { kprintf("\n"); col = 0; } } @@ -675,105 +626,195 @@ void vm_pt_print(u32_t *pagetable, u32_t v) return; } -/*===========================================================================* - * vm_print * - *===========================================================================*/ void vm_print(u32_t *root) { int pde; vmassert(!((u32_t) root % I386_PAGE_SIZE)); - for(pde = 0; pde < I386_VM_DIR_ENTRIES; pde++) { + printf("page table 0x%lx:\n", root); + + for(pde = 10; pde < I386_VM_DIR_ENTRIES; pde++) { u32_t pde_v; u32_t *pte_a; pde_v = phys_get32((u32_t) (root + pde)); if(!(pde_v & I386_VM_PRESENT)) continue; - pte_a = (u32_t *) I386_VM_PFA(pde_v); - kprintf("%4d: pt %08lx %s\n", - pde, pte_a, flagstr(pde_v, 1)); - vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE); + if(pde_v & I386_VM_BIGPAGE) { + kprintf("%4d: 0x%lx, flags %s\n", + pde, I386_VM_PFA(pde_v), flagstr(pde_v, 1)); + } else { + pte_a = (u32_t *) I386_VM_PFA(pde_v); + kprintf("%4d: pt %08lx %s\n", + pde, pte_a, flagstr(pde_v, 1)); + vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE); + kprintf("\n"); + } } return; } +/*===========================================================================* + * invlpg_range * + *===========================================================================*/ void invlpg_range(u32_t lin, u32_t bytes) { - u32_t o; +/* Remove a range of translated addresses from the TLB. + * Addresses are in linear, i.e., post-segment, pre-pagetable + * form. Parameters are byte values, any offset and any multiple. + */ + u32_t cr3; + u32_t o, limit, addr; + limit = lin + bytes - 1; o = lin % I386_PAGE_SIZE; lin -= o; - bytes += o; - while(bytes >= I386_PAGE_SIZE) { - i386_invlpg_addr = lin; + limit += o; + limit &= I386_VM_PT_ENT_MASK; + FIXME("invlpg_range reloads cr3"); + cr3 = read_cr3(); + vm_set_cr3(cr3); + for(i386_invlpg_addr = lin; i386_invlpg_addr <= limit; + i386_invlpg_addr += I386_PAGE_SIZE) level0(i386_invlpg_level0); - lin += I386_PAGE_SIZE; - bytes -= I386_PAGE_SIZE; - } +} + +u32_t thecr3; + +u32_t read_cr3(void) +{ + level0(getcr3val); + return thecr3; +} + +/* This macro sets up a mapping from within the kernel's address + * space to any other area of memory, either straight physical + * memory (PROC == NULL) or a process view of memory, in 4MB chunks. + * It recognizes PROC having kernel address space as a special case. + * + * It sets PTR to the pointer within kernel address space at the start + * of the 4MB chunk, and OFFSET to the offset within that chunk + * that corresponds to LINADDR. + * + * It needs FREEPDE (available and addressable PDE within kernel + * address space), SEG (hardware segment), VIRT (in-datasegment + * address if known). + * + * TODO: don't re-make a pde that's already there. + */ +#define CREATEPDE(PROC, PTR, LINADDR, OFFSET, FREEPDE, VIRT, SEG, REMAIN, BYTES) { \ + if((PROC) && iskernelp(PROC) && SEG == D) { \ + PTR = VIRT; \ + OFFSET = 0; \ + } else { \ + u32_t pdeval, *pdevalptr, newlin; \ + int pde_index; \ + vmassert(psok); \ + pde_index = I386_VM_PDE(LINADDR); \ + vmassert(!iskernelp(PROC)); \ + if(PROC) { \ + u32_t *pdeptr; \ + vmassert(!iskernelp(PROC)); \ + vmassert(HASPT(PROC)); \ + pdeptr = PROCPDEPTR(PROC, pde_index); \ + pdeval = *pdeptr; \ + if(!(pdeval & I386_VM_PRESENT)) { \ + kprintf("kernel: pde %d 0x%lx for proc %d\n", \ + pde_index, pdeval, PROC->p_endpoint); \ + } \ + if(copyverbose) { kprintf("installing pde val 0x%lx from pde index %d of proc %d into my pde\n", pdeval, pde_index, PROC->p_endpoint); } \ + } else { \ + pdeval = (LINADDR & I386_VM_ADDR_MASK_4MB) | \ + I386_VM_BIGPAGE | I386_VM_PRESENT | \ + I386_VM_WRITE | I386_VM_USER; \ + } \ + *PROCPDEPTR(ptproc, FREEPDE) = pdeval; \ + newlin = I386_BIG_PAGE_SIZE*FREEPDE; \ + PTR = (u8_t *) phys2vir(newlin); \ + OFFSET = LINADDR & I386_VM_OFFSET_MASK_4MB; \ + REMAIN = MIN(REMAIN, I386_BIG_PAGE_SIZE - OFFSET); \ + invlpg_range(newlin + OFFSET, REMAIN); \ + } \ } /*===========================================================================* * lin_lin_copy * *===========================================================================*/ int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc, + int srcseg, struct proc *dstproc, vir_bytes dstlinaddr, u8_t *vdst, - vir_bytes bytes) + int dstseg, + vir_bytes bytes, int copyverbose) { + u32_t addr; + int procslot; + u32_t catchrange_dst; + NOREC_ENTER(linlincopy); + + if(srcproc && dstproc && iskernelp(srcproc) && iskernelp(dstproc)) { + memcpy(vdst, vsrc, bytes); + NOREC_RETURN(linlincopy, OK); + } - if(nfreepdes < 2) - minix_panic("vm: not enough free PDE's", NO_NUM); + FIXME("lin_lin_copy requires big pages"); + vmassert(vm_running); + vmassert(!catch_pagefaults); + vmassert(nfreepdes >= 3); - util_stacktrace(); + vmassert(ptproc); + vmassert(proc_ptr); + vmassert(read_cr3() == ptproc->p_seg.p_cr3); -#define CREATEPDE(PROC, PTR, LINADDR, OFFSET, FREEPDE, VIRT) { \ - if(iskernelp(PROC)) { \ - PTR = VIRT; \ - OFFSET = 0; \ - } else { \ - u32_t *pdevalptr; \ - u32_t myphysaddr; \ - int pde_index; \ - pde_index = I386_VM_PDE(LINADDR); \ - pdevalptr = (u32_t *) ((u8_t *) vm_pagedirs + \ - I386_PAGE_SIZE * PROC->p_nr + \ - I386_VM_PT_ENT_SIZE * pde_index); \ - kprintf("pagedirs: 0x%x p_nr: %d linaddr: 0x%x pde: %d\n", \ - vm_pagedirs, PROC->p_nr, LINADDR, pde_index); \ - kprintf("pde ptr: 0x%x\n", pdevalptr); \ - kprintf("value: 0x%x\n", *pdevalptr); \ - myphysaddr = kernel_cr3 + FREEPDE*I386_VM_PT_ENT_SIZE; \ - phys_put32(myphysaddr, *pdevalptr); \ - PTR = (u8_t *) phys2vir(I386_BIG_PAGE_SIZE*FREEPDE); \ - kprintf("ptr: 0x%x\n", PTR); \ - OFFSET = LINADDR & I386_VM_OFFSET_MASK_4MB; \ - kprintf("offset: 0x%lx & 0x%lx -> 0x%lx\n", LINADDR, \ - I386_VM_OFFSET_MASK_4MB, OFFSET); \ - invlpg_range(LINADDR, bytes + I386_PAGE_SIZE); \ - } \ -} + procslot = ptproc->p_nr; + + vmassert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES); + vmassert(freepdes[FREEPDE_SRC] < freepdes[FREEPDE_DST]); + + catchrange_lo = I386_BIG_PAGE_SIZE*freepdes[FREEPDE_SRC]; + catchrange_dst = I386_BIG_PAGE_SIZE*freepdes[FREEPDE_DST]; + catchrange_hi = I386_BIG_PAGE_SIZE*(freepdes[FREEPDE_DST]+1); while(bytes > 0) { u8_t *srcptr, *dstptr; - vir_bytes srcoffset, dstoffset, chunk, remain; + vir_bytes srcoffset, dstoffset; + vir_bytes chunk = bytes; - /* Set up 4MB ranges. */ - CREATEPDE(srcproc, srcptr, srclinaddr, srcoffset, freepdes[0], vsrc); - CREATEPDE(dstproc, dstptr, dstlinaddr, dstoffset, freepdes[1], vdst); + FIXME("copyverbose"); - remain = I386_BIG_PAGE_SIZE - MAX(srcoffset, dstoffset); - chunk = MIN(bytes, remain); + /* Set up 4MB ranges. */ + CREATEPDE(srcproc, srcptr, srclinaddr, srcoffset, + freepdes[FREEPDE_SRC], vsrc, srcseg, chunk, bytes); + CREATEPDE(dstproc, dstptr, dstlinaddr, dstoffset, + freepdes[FREEPDE_DST], vdst, dstseg, chunk, bytes); /* Copy pages. */ - while(chunk > 0) { - kprintf("copy %d -> %d %d/%d using 0x%lx+0x%lx -> 0x%lx+0x%lx\n", - srcproc->p_endpoint, dstproc->p_endpoint, - chunk, bytes, srcptr, srcoffset, - dstptr, dstoffset); - memcpy(dstptr + dstoffset, srcptr + srcoffset, chunk); - kprintf("done\n"); + vmassert(intr_disabled()); + vmassert(!catch_pagefaults); + catch_pagefaults = 1; + addr=_memcpy_k(dstptr + dstoffset, srcptr + srcoffset, chunk); + vmassert(intr_disabled()); + vmassert(catch_pagefaults); + catch_pagefaults = 0; + + if(addr) { + kprintf("kernel: lin_lin copy: returning EFAULT, addr 0x%lx\n", + addr); + if(addr >= catchrange_lo && addr < catchrange_dst) { + kprintf("src\n"); + NOREC_RETURN(linlincopy, EFAULT_SRC); + } + if(addr >= catchrange_dst && addr < catchrange_hi) { + kprintf("dst\n"); + NOREC_RETURN(linlincopy, EFAULT_DST); + } + minix_panic("lin_lin_copy fault out of range", NO_NUM); + + /* Not reached. */ + NOREC_RETURN(linlincopy, EFAULT); } + + vmassert(memcmp(dstptr + dstoffset, srcptr + srcoffset, chunk) == 0); /* Update counter and addresses for next iteration, if any. */ bytes -= chunk; @@ -783,6 +824,43 @@ int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc, vdst += chunk; } + NOREC_RETURN(linlincopy, OK); +} + +/*===========================================================================* + * lin_memset * + *===========================================================================*/ +int vm_phys_memset(phys_bytes ph, u8_t c, phys_bytes bytes) +{ + char *v; + + if(!vm_running) { + u32_t p; + p = c | (c << 8) | (c << 16) | (c << 24); + phys_memset(ph, p, bytes); + return OK; + } + + vmassert(nfreepdes >= 3); + + /* With VM, we have to map in the physical memory. + * We can do this 4MB at a time. + */ + while(bytes > 0) { + vir_bytes chunk = bytes; + u8_t *ptr; + u32_t offset; + int copyverbose = 0; + CREATEPDE(((struct proc *) NULL), ptr, ph, + offset, freepdes[FREEPDE_MEMSET], 0, 0, chunk, bytes); + /* We can memset as many bytes as we have remaining, + * or as many as remain in the 4MB chunk we mapped in. + */ + memset(ptr + offset, c, chunk); + bytes -= chunk; + ph += chunk; + } + return OK; } @@ -803,6 +881,7 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */ int seg_index; int i, r; struct proc *procs[2]; + NOREC_ENTER(virtualcopy); /* Check copy count. */ if (bytes <= 0) return(EDOM); @@ -828,7 +907,9 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */ switch(type) { case LOCAL_SEG: case LOCAL_VM_SEG: - if(!p) return EDEADSRCDST; + if(!p) { + NOREC_RETURN(virtualcopy, EDEADSRCDST); + } seg_index = vir_addr[i]->segment & SEGMENT_INDEX; if(type == LOCAL_SEG) phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset, @@ -844,7 +925,9 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */ } break; case REMOTE_SEG: - if(!p) return EDEADSRCDST; + if(!p) { + NOREC_RETURN(virtualcopy, EDEADSRCDST); + } seg_index = vir_addr[i]->segment & SEGMENT_INDEX; phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes); break; @@ -861,49 +944,96 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */ break; default: kprintf("virtual_copy: strange type 0x%x\n", type); - return(EINVAL); + NOREC_RETURN(virtualcopy, EINVAL); } /* Check if mapping succeeded. */ if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) { kprintf("virtual_copy EFAULT\n"); - return(EFAULT); + NOREC_RETURN(virtualcopy, EFAULT); } } -#if 0 - /* Special case: vir to vir copy */ - if(vm_pagedirs && procs[_SRC_] && procs[_DST_] && - HASPT(procs[_SRC_]) && HASPT(procs[_DST_]) && - src_addr->segment == D && src_addr->segment == D) { - lin_lin_copy(procs[_SRC_], phys_addr[_SRC_], (u8_t *) src_addr->offset, + if(vm_running) { + int r; + struct proc *target, *caller; + int verbose = 0; + + if(procs[_SRC_] && procs[_DST_] && + procs[_SRC_]->p_endpoint == PM_PROC_NR && + (procs[_DST_]->p_endpoint == INIT_PROC_NR || + procs[_DST_]->p_endpoint == 35549) && + bytes == sizeof(message)) { + verbose = 1; + } + + if((r=lin_lin_copy(procs[_SRC_], phys_addr[_SRC_], + (u8_t *) src_addr->offset, src_addr->segment, procs[_DST_], phys_addr[_DST_], (u8_t *) dst_addr->offset, - bytes); + dst_addr->segment, bytes, verbose)) != OK) { + if(r != EFAULT_SRC && r != EFAULT_DST) + minix_panic("lin_lin_copy failed", r); + if(!vmcheck) { + NOREC_RETURN(virtualcopy, r); + } + + caller = proc_addr(who_p); + + printf("virtual_copy: suspending caller %d / %s\n", + caller->p_endpoint, caller->p_name); + + if(r == EFAULT_SRC) { + caller->p_vmrequest.start = phys_addr[_SRC_]; + target = procs[_SRC_]; + caller->p_vmrequest.writeflag = 0; + } else if(r == EFAULT_DST) { + caller->p_vmrequest.start = phys_addr[_DST_]; + target = procs[_DST_]; + caller->p_vmrequest.writeflag = 1; + } else { + minix_panic("r strange", r); + } + + caller->p_vmrequest.length = bytes; + caller->p_vmrequest.who = target->p_endpoint; + + vm_suspend(caller, target); + + NOREC_RETURN(virtualcopy, VMSUSPEND); + } + + if(verbose) { + static int count = 0; + message *m; + kprintf("lin_lin_copy: PM to %d: %d bytes copy OK\n", + procs[_DST_]->p_endpoint, bytes); + if(count++ < 10) { + vm_print(procs[_SRC_]->p_seg.p_cr3); + vm_print(procs[_DST_]->p_seg.p_cr3); + } + } + + NOREC_RETURN(virtualcopy, OK); } -#endif - if(vmcheck && procs[_SRC_]) - CHECKRANGE_OR_SUSPEND(procs[_SRC_], phys_addr[_SRC_], bytes, 0); - if(vmcheck && procs[_DST_]) - CHECKRANGE_OR_SUSPEND(procs[_DST_], phys_addr[_DST_], bytes, 1); + vmassert(!vm_running); + /* can't copy to/from process with PT without VM */ #define NOPT(p) (!(p) || !HASPT(p)) - /* Now copy bytes between physical addresseses. */ - if(NOPT(procs[_SRC_]) && NOPT(procs[_DST_])) { - /* Without vm, address ranges actually are physical. */ - phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes); - r = OK; - } else { - /* With vm, addresses need further interpretation. */ - r = vm_copy(phys_addr[_SRC_], procs[_SRC_], - phys_addr[_DST_], procs[_DST_], (phys_bytes) bytes); - if(r != OK) { - kprintf("vm_copy: %lx to %lx failed\n", - phys_addr[_SRC_],phys_addr[_DST_]); - } + if(!NOPT(procs[_SRC_])) { + kprintf("ignoring page table src: %s / %d at 0x%lx\n", + procs[_SRC_]->p_name, procs[_SRC_]->p_endpoint, procs[_SRC_]->p_seg.p_cr3); +} + if(!NOPT(procs[_DST_])) { + kprintf("ignoring page table dst: %s / %d at 0x%lx\n", + procs[_DST_]->p_name, procs[_DST_]->p_endpoint, + procs[_DST_]->p_seg.p_cr3); } - return(r); + /* Now copy bytes between physical addresseses. */ + phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes); + + NOREC_RETURN(virtualcopy, OK); } /*===========================================================================* @@ -956,17 +1086,7 @@ PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count, return EINVAL; } -void i386_updatepde(int pde, u32_t val) -{ - u32_t physaddr; - physaddr = kernel_cr3 + pde*I386_VM_PT_ENT_SIZE; - kprintf("kernel: i386_updatepde: cr3 0x%lx; phys addr 0x%lx; pde %d, val 0x%lx\n", - kernel_cr3, physaddr, pde, val); - kprintf("previous entry was: 0x%lx\n", phys_get32(physaddr)); - phys_put32(physaddr, val); - kprintf("entry is now: 0x%lx\n", phys_get32(physaddr)); -} - +/* VM reports page directory slot we're allowed to use freely. */ void i386_freepde(int pde) { if(nfreepdes >= WANT_FREEPDES) diff --git a/kernel/arch/i386/mpx386.s b/kernel/arch/i386/mpx386.s index 066df8573..844d93d87 100755 --- a/kernel/arch/i386/mpx386.s +++ b/kernel/arch/i386/mpx386.s @@ -74,7 +74,6 @@ begbss: .define _restart .define save -.define _kernel_cr3 .define _pagefault_cr2 .define _pagefault_count @@ -218,12 +217,6 @@ csinit: ltr ax push 0 ! set flags to known good state popf ! esp, clear nested task and int enable -#if VM_KERN_NOPAGEZERO - jmp laststep - -.align I386_PAGE_SIZE -laststep: -#endif jmp _main ! main() @@ -239,7 +232,6 @@ laststep: #define hwint_master(irq) \ call save /* save interrupted process state */;\ push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ - LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\ call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ pop ecx ;\ cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ @@ -291,7 +283,6 @@ _hwint07: ! Interrupt routine for irq 7 (printer) #define hwint_slave(irq) \ call save /* save interrupted process state */;\ push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ - LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\ call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ pop ecx ;\ cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ @@ -398,8 +389,6 @@ _p_s_call: push eax ! source / destination push ecx ! call number (ipc primitive to use) -! LOADCR3WITHEAX(0x20, (_kernel_cr3)) - call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map) ! caller is now explicitly in proc_ptr mov AXREG(esi), eax ! sys_call MUST PRESERVE si @@ -420,7 +409,16 @@ _restart: mov (_next_ptr), 0 0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0 lldt P_LDT_SEL(esp) ! enable process' segment descriptors - LOADCR3WITHEAX(0x21, P_CR3(esp)) ! switch to process page table + cmp P_CR3(esp), 0 ! process does not have its own PT + jz noload + mov eax, P_CR3(esp) + mov ebx, cr3 + cmp eax, ebx + jz noload + mov cr3, eax + mov eax, (_proc_ptr) + mov (_ptproc), eax +noload: lea eax, P_STACKTOP(esp) ! arrange for next interrupt mov (_tss+TSS3_S_SP0), eax ! to save state in process table restart1: @@ -535,8 +533,6 @@ exception1: ! Common for all exceptions. mov eax, 8+4(esp) ! old eflags sseg mov (old_eflags), eax - LOADCR3WITHEAX(0x24, (_kernel_cr3)) - pop eax call save push (old_eflags) @@ -556,24 +552,12 @@ _level0_call: call save jmp (_level0_func) -!*===========================================================================* -!* load_kernel_cr3 * -!*===========================================================================* -.align 16 -_load_kernel_cr3: - mov eax, (_kernel_cr3) - mov cr3, eax - ret - !*===========================================================================* !* data * !*===========================================================================* .sect .rom ! Before the string table please .data2 0x526F ! this must be the first data entry (magic #) -#if VM_KERN_NOPAGEZERO -.align I386_PAGE_SIZE -#endif .sect .bss k_stack: diff --git a/kernel/arch/i386/proto.h b/kernel/arch/i386/proto.h index a33153a6c..ccb90ff86 100644 --- a/kernel/arch/i386/proto.h +++ b/kernel/arch/i386/proto.h @@ -51,6 +51,7 @@ _PROTOTYPE( void vir_insw, (u16_t port, struct proc *proc, u32_t vir, size_t cou _PROTOTYPE( void vir_outsw, (u16_t port, struct proc *proc, u32_t vir, size_t count)); _PROTOTYPE( void i386_updatepde, (int pde, u32_t val)); _PROTOTYPE( void i386_freepde, (int pde)); +_PROTOTYPE( void getcr3val, (void)); /* exception.c */ @@ -73,6 +74,8 @@ _PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) ); _PROTOTYPE( void i386_invlpg_level0, (void) ); +_PROTOTYPE( int _memcpy_k, (void *dst, void *src, size_t n) ); +_PROTOTYPE( int _memcpy_k_fault, (void) ); /* protect.c */ _PROTOTYPE( void prot_init, (void) ); diff --git a/kernel/arch/i386/system.c b/kernel/arch/i386/system.c index 6eaef954b..ca3fae394 100644 --- a/kernel/arch/i386/system.c +++ b/kernel/arch/i386/system.c @@ -153,6 +153,60 @@ PRIVATE void ser_debug(int c) do_serial_debug--; } +PRIVATE void printslot(struct proc *pp) +{ + static int level = 0; + struct proc *depproc = NULL; + int dep = NONE; + + if(level >= NR_PROCS) { + kprintf("loop??\n"); + return; + } + + level++; + + kprintf("%*s %d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s ", + level, "", + proc_nr(pp), pp->p_name, pp->p_endpoint, + pp->p_priority, pp->p_max_priority, pp->p_user_time, + pp->p_sys_time, pp->p_seg.p_cr3, rtsflagstr(pp->p_rts_flags)); + + if(pp->p_rts_flags & SENDING) { + dep = pp->p_sendto_e; + kprintf(" to: "); + } else if(pp->p_rts_flags & RECEIVING) { + dep = pp->p_getfrom_e; + kprintf(" from: "); + } + + if(dep != NONE) { + if(dep == ANY) { + kprintf(" ANY\n"); + } else { + int procno; + if(!isokendpt(dep, &procno)) { + kprintf(" ??? %d\n", dep); + } else { + depproc = proc_addr(procno); + if(depproc->p_rts_flags & SLOT_FREE) { + kprintf(" empty slot %d???\n", procno); + depproc = NULL; + } else { + kprintf(" %s\n", depproc->p_name); + } + } + } + } else { + kprintf("\n"); + } + kprintf("%*s ", level, ""); + proc_stacktrace(pp); + if(depproc) + printslot(depproc); + level--; +} + PUBLIC void ser_dump_proc() { struct proc *pp; @@ -165,15 +219,7 @@ PUBLIC void ser_dump_proc() { if (pp->p_rts_flags & SLOT_FREE) continue; - kprintf( - "%d: 0x%02x %s e %d src %d dst %d prio %d/%d time %d/%d EIP 0x%x\n", - proc_nr(pp), - pp->p_rts_flags, pp->p_name, - pp->p_endpoint, pp->p_getfrom_e, pp->p_sendto_e, - pp->p_priority, pp->p_max_priority, - pp->p_user_time, pp->p_sys_time, - pp->p_reg.pc); - proc_stacktrace(pp); + printslot(pp); } if(u) { unlock; } diff --git a/kernel/arch/i386/vm.h b/kernel/arch/i386/vm.h index 1707ac990..21e551d3e 100644 --- a/kernel/arch/i386/vm.h +++ b/kernel/arch/i386/vm.h @@ -1,21 +1,7 @@ -.define _load_kernel_cr3 .define _last_cr3 -#define LOADKERNELCR3 ;\ - inc (_cr3switch) ;\ - mov eax, (_kernel_cr3) ;\ - cmp (_last_cr3), eax ;\ - jz 9f ;\ - push _load_kernel_cr3 ;\ - call _level0 ;\ - pop eax ;\ - mov eax, (_kernel_cr3) ;\ - mov (_last_cr3), eax ;\ - inc (_cr3reload) ;\ -9: - -#define LOADCR3WITHEAX(type, newcr3) ;\ +#define LOADCR3WITHEAX(type, newcr3, ptproc) ;\ sseg inc (_cr3switch) ;\ sseg mov eax, newcr3 ;\ sseg cmp (_last_cr3), eax ;\ @@ -23,5 +9,7 @@ sseg cmp (_last_cr3), eax ;\ mov cr3, eax ;\ sseg inc (_cr3reload) ;\ sseg mov (_last_cr3), eax ;\ +sseg mov eax, (ptproc) ;\ +sseg mov (_ptproc), eax ;\ 8: diff --git a/kernel/debug.c b/kernel/debug.c index 12cd8aa64..13a001dd7 100644 --- a/kernel/debug.c +++ b/kernel/debug.c @@ -103,3 +103,28 @@ check_runqueues_f(char *file, int line) } #endif /* DEBUG_SCHED_CHECK */ + +PUBLIC char * +rtsflagstr(int flags) +{ + static char str[100]; + str[0] = '\0'; + +#define FLAG(n) if(flags & n) { strcat(str, #n " "); } + + FLAG(SLOT_FREE); + FLAG(NO_PRIORITY); + FLAG(SENDING); + FLAG(RECEIVING); + FLAG(SIGNALED); + FLAG(SIG_PENDING); + FLAG(P_STOP); + FLAG(NO_PRIV); + FLAG(NO_ENDPOINT); + FLAG(VMINHIBIT); + FLAG(PAGEFAULT); + FLAG(VMREQUEST); + + return str; +} + diff --git a/kernel/debug.h b/kernel/debug.h index 283b00be2..df6790cb9 100644 --- a/kernel/debug.h +++ b/kernel/debug.h @@ -8,6 +8,7 @@ */ #include +#include #include "config.h" /* Enable prints such as @@ -25,6 +26,34 @@ /* Runtime sanity checking. */ #define DEBUG_VMASSERT 1 -#define DEBUG_SCHED_CHECK 0 +#define DEBUG_SCHED_CHECK 1 + +#define NOREC_ENTER(varname) \ + static int varname = 0; \ + int mustunlock = 0; \ + if(!intr_disabled()) { lock; mustunlock = 1; } \ + if(varname) { \ + minix_panic(#varname " recursive enter", __LINE__); \ + } \ + varname = 1; \ + FIXME(#varname " recursion check enabled"); + +#define NOREC_RETURN(varname, v) do { \ + if(!varname) \ + minix_panic(#varname " flag off", __LINE__); \ + if(!intr_disabled()) \ + minix_panic(#varname " interrupts on", __LINE__); \ + varname = 0; \ + if(mustunlock) { unlock; } \ + return v; \ + } while(0) + + +#if DEBUG_VMASSERT +#define vmassert(t) { \ + if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } } +#else +#define vmassert(t) { } +#endif #endif /* DEBUG_H */ diff --git a/kernel/glo.h b/kernel/glo.h index e3ed5735b..b7c1a19eb 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -89,11 +89,9 @@ EXTERN unsigned long cr3switch; EXTERN unsigned long cr3reload; /* VM */ -EXTERN phys_bytes vm_base; -EXTERN phys_bytes vm_size; -EXTERN phys_bytes vm_mem_high; EXTERN int vm_running; EXTERN int must_notify_vm; +EXTERN struct proc *ptproc; /* Verbose flags (debugging). */ EXTERN int verbose_vm; diff --git a/kernel/main.c b/kernel/main.c index 0c26fe171..18b510d48 100755 --- a/kernel/main.c +++ b/kernel/main.c @@ -17,6 +17,7 @@ #include #include #include "proc.h" +#include "debug.h" /* Prototype declarations for PRIVATE functions. */ FORWARD _PROTOTYPE( void announce, (void)); @@ -185,6 +186,16 @@ PUBLIC void main() */ bill_ptr = proc_addr(IDLE); /* it has to point somewhere */ announce(); /* print MINIX startup banner */ +/* Warnings for sanity checks that take time. These warnings are printed + * so it's a clear warning no full release should be done with them + * enabled. + */ +#if DEBUG_SCHED_CHECK + FIXME("DEBUG_SCHED_CHECK enabled"); +#endif +#if DEBUG_VMASSERT + FIXME("DEBUG_VMASSERT enabled"); +#endif restart(); } diff --git a/kernel/proc.c b/kernel/proc.c index 0b5f43c36..02b1ade1d 100755 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -82,19 +82,12 @@ FORWARD _PROTOTYPE( void pick_proc, (void)); break; \ } -#define CopyMess(s,sp,sm,dp,dm) do { \ - vir_bytes dstlin; \ - endpoint_t e = proc_addr(s)->p_endpoint; \ - struct vir_addr src, dst; \ - int r; \ - if((dstlin = umap_local((dp), D, (vir_bytes) dm, sizeof(message))) == 0){\ - minix_panic("CopyMess: umap_local failed", __LINE__); \ - } \ - \ - if(vm_running && \ - (r=vm_checkrange((dp), (dp), dstlin, sizeof(message), 1, 0)) != OK) { \ - if(r != VMSUSPEND) \ - minix_panic("CopyMess: vm_checkrange error", __LINE__); \ +#define RETRYCOPY(sp, dp, sm, dm) {\ + if(r != EFAULT_DST) { \ + kprintf("error %d\n", r); \ + minix_panic("CopyMess: copy error", __LINE__); \ + } \ + vm_suspend(dp, dp); \ (dp)->p_vmrequest.saved.msgcopy.dst = (dp); \ (dp)->p_vmrequest.saved.msgcopy.dst_v = (vir_bytes) dm; \ if(data_copy((sp)->p_endpoint, \ @@ -105,25 +98,26 @@ FORWARD _PROTOTYPE( void pick_proc, (void)); } \ (dp)->p_vmrequest.saved.msgcopy.msgbuf.m_source = e; \ (dp)->p_vmrequest.type = VMSTYPE_MSGCOPY; \ - } else { \ - src.proc_nr_e = (sp)->p_endpoint; \ - dst.proc_nr_e = (dp)->p_endpoint; \ - src.segment = dst.segment = D; \ - src.offset = (vir_bytes) (sm); \ - dst.offset = (vir_bytes) (dm); \ - if(virtual_copy(&src, &dst, sizeof(message)) != OK) { \ - kprintf("copymess: copy %d:%lx to %d:%lx failed\n",\ - (sp)->p_endpoint, (sm), (dp)->p_endpoint, dm);\ - minix_panic("CopyMess: virtual_copy (1) failed", __LINE__); \ - } \ + } + +#define CopyMess(s,sp,sm,dp,dm) do { \ + endpoint_t e = proc_addr(s)->p_endpoint; \ + struct vir_addr src, dst; \ + int r; \ + src.proc_nr_e = (sp)->p_endpoint; \ + dst.proc_nr_e = (dp)->p_endpoint; \ + src.segment = dst.segment = D; \ + src.offset = (vir_bytes) (sm); \ + dst.offset = (vir_bytes) (dm); \ + if((r=virtual_copy(&src, &dst, sizeof(message))) != OK) { \ + RETRYCOPY(sp, dp, sm, dm) \ + } else { \ src.proc_nr_e = SYSTEM; \ src.offset = (vir_bytes) &e; \ - if(virtual_copy(&src, &dst, sizeof(e)) != OK) { \ - kprintf("copymess: copy %d:%lx to %d:%lx\n", \ - (sp)->p_endpoint, (sm), (dp)->p_endpoint, dm);\ - minix_panic("CopyMess: virtual_copy (2) failed", __LINE__); \ + if((r=virtual_copy(&src, &dst, sizeof(e))) != OK) { \ + RETRYCOPY(sp, dp, sm, dm) \ } \ - } \ + } \ } while(0) /*===========================================================================* @@ -1259,8 +1253,8 @@ PRIVATE void pick_proc() if ( (rp = rdy_head[q]) != NIL_PROC) { next_ptr = rp; /* run process 'rp' next */ #if 0 - if(rp->p_endpoint != 4 && rp->p_endpoint != 5 && rp->p_endpoint != IDLE && rp->p_endpoint != SYSTEM) - kprintf("[run %s]", rp->p_name); + if(!iskernelp(rp)) + kprintf("[run %s/%d]", rp->p_name, rp->p_endpoint); #endif if (priv(rp)->s_flags & BILLABLE) bill_ptr = rp; /* bill for system time */ diff --git a/kernel/proc.h b/kernel/proc.h index df90bfed4..52a4612a8 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -107,6 +107,7 @@ struct proc { #define PMAGIC 0xC0FFEE1 int p_magic; /* check validity of proc pointers */ #endif + int verbose; }; /* Bits for the runtime flags. A process is runnable iff p_rts_flags == 0. */ diff --git a/kernel/proto.h b/kernel/proto.h index a3070efdd..130900ebb 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -33,7 +33,7 @@ _PROTOTYPE( int sys_call, (int call_nr, int src_dst, message *m_ptr, long bit_map) ); _PROTOTYPE( void sys_call_restart, (struct proc *caller) ); _PROTOTYPE( int lock_notify, (int src, int dst) ); -_PROTOTYPE( int soft_notify, (int dst) ); +_PROTOTYPE( int soft_notify, (int dst) ); _PROTOTYPE( int lock_send, (int dst, message *m_ptr) ); _PROTOTYPE( void lock_enqueue, (struct proc *rp) ); _PROTOTYPE( void lock_dequeue, (struct proc *rp) ); @@ -87,6 +87,7 @@ _PROTOTYPE( void cons_seth, (int pos, int n) ); #define CHECK_RUNQUEUES check_runqueues_f(__FILE__, __LINE__) _PROTOTYPE( void check_runqueues_f, (char *file, int line) ); #endif +_PROTOTYPE( char *rtsflagstr, (int flags) ); /* system/do_safecopy.c */ _PROTOTYPE( int verify_grant, (endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes, @@ -113,7 +114,7 @@ _PROTOTYPE( int data_copy, (endpoint_t from, vir_bytes from_addr, #define data_copy_to(d, p, v, n) data_copy(SYSTEM, (d), (p), (v), (n)); #define data_copy_from(d, p, v, n) data_copy((p), (v), SYSTEM, (d), (n)); _PROTOTYPE( void alloc_segments, (struct proc *rp) ); -_PROTOTYPE( void vm_init, (void) ); +_PROTOTYPE( void vm_init, (struct proc *first) ); _PROTOTYPE( void vm_map_range, (u32_t base, u32_t size, u32_t offset) ); _PROTOTYPE( int vm_copy, (vir_bytes src, struct proc *srcproc, vir_bytes dst, struct proc *dstproc, phys_bytes bytes)); @@ -126,7 +127,7 @@ _PROTOTYPE( phys_bytes umap_remote, (struct proc* rp, int seg, _PROTOTYPE( phys_bytes umap_virtual, (struct proc* rp, int seg, vir_bytes vir_addr, vir_bytes bytes) ); _PROTOTYPE( phys_bytes seg2phys, (U16_t) ); -_PROTOTYPE( void phys_memset, (phys_bytes source, unsigned long pattern, +_PROTOTYPE( int vm_phys_memset, (phys_bytes source, u8_t pattern, phys_bytes count) ); _PROTOTYPE( vir_bytes alloc_remote_segment, (u32_t *, segframe_t *, int, phys_bytes, vir_bytes, int)); @@ -160,5 +161,6 @@ _PROTOTYPE( int vm_checkrange, (struct proc *caller, struct proc *target, vir_bytes start, vir_bytes length, int writeflag, int checkonly)); _PROTOTYPE( void proc_stacktrace, (struct proc *proc) ); _PROTOTYPE( int vm_lookup, (struct proc *proc, vir_bytes virtual, vir_bytes *result, u32_t *ptent)); +_PROTOTYPE( int vm_suspend, (struct proc *caller, struct proc *target)); #endif /* PROTO_H */ diff --git a/kernel/system.c b/kernel/system.c index 77642f62b..148459ecc 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -121,8 +121,12 @@ PUBLIC void sys_task() if (curr < limit+extra) { +#if 0 kprintf("SYSTEM: request %d from %d denied.\n", call_nr, m.m_source); +#else + FIXME("privileges bypassed"); +#endif } else if (curr == limit+extra) { kprintf("sys_task: no debug output for a while\n"); @@ -220,7 +224,6 @@ PRIVATE void initialize(void) map(SYS_NEWMAP, do_newmap); /* set up a process memory map */ map(SYS_SEGCTL, do_segctl); /* add segment and get selector */ map(SYS_MEMSET, do_memset); /* write char to memory area */ - map(SYS_VM_SETBUF, do_vm_setbuf); /* PM passes buffer for page tables */ map(SYS_VMCTL, do_vmctl); /* various VM process settings */ /* Copying. */ @@ -424,7 +427,10 @@ register struct proc *rc; /* slot of process to clean up */ if(isemptyp(rc)) minix_panic("clear_proc: empty process", rc->p_endpoint); - if(rc->p_endpoint == PM_PROC_NR || rc->p_endpoint == VFS_PROC_NR) { +#if 0 + if(rc->p_endpoint == PM_PROC_NR || rc->p_endpoint == VFS_PROC_NR) +#endif + { /* This test is great for debugging system processes dying, * but as this happens normally on reboot, not good permanent code. */ @@ -432,7 +438,9 @@ register struct proc *rc; /* slot of process to clean up */ proc_stacktrace(rc); kprintf("kernel trace: "); util_stacktrace(); +#if 0 minix_panic("clear_proc: system process died", rc->p_endpoint); +#endif } /* Make sure that the exiting process is no longer scheduled. */ @@ -619,6 +627,8 @@ PRIVATE struct proc *vmrestart_check(message *m) return NULL; case VMSTYPE_MSGCOPY: /* Do delayed message copy. */ + printf("copying message into %d..\n", + restarting->p_vmrequest.saved.msgcopy.dst->p_endpoint); if((r=data_copy(SYSTEM, (vir_bytes) &restarting->p_vmrequest.saved.msgcopy.msgbuf, restarting->p_vmrequest.saved.msgcopy.dst->p_endpoint, @@ -626,6 +636,7 @@ PRIVATE struct proc *vmrestart_check(message *m) sizeof(message))) != OK) { minix_panic("SYSTEM: delayed msgcopy failed", r); } + printf("OK!\n"); RTS_LOCK_UNSET(restarting, VMREQUEST); /* Handled; restart system loop. */ diff --git a/kernel/system.h b/kernel/system.h index 10b4f4003..6188c66d4 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -91,9 +91,6 @@ _PROTOTYPE( int do_memset, (message *m_ptr) ); #define do_memset do_unused #endif -_PROTOTYPE( int do_vm_setbuf, (message *m_ptr) ); -_PROTOTYPE( int do_vm_map, (message *m_ptr) ); - _PROTOTYPE( int do_abort, (message *m_ptr) ); #if ! USE_ABORT #define do_abort do_unused diff --git a/kernel/system/do_exec.c b/kernel/system/do_exec.c index 1fbdd0b0f..4161bb088 100644 --- a/kernel/system/do_exec.c +++ b/kernel/system/do_exec.c @@ -42,6 +42,8 @@ register message *m_ptr; /* pointer to request message */ /* No reply to EXEC call */ RTS_LOCK_UNSET(rp, RECEIVING); + printf("kernel: exec %d now %s\n", rp->p_endpoint, rp->p_name); + return(OK); } #endif /* USE_EXEC */ diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index a365ab77a..e6e1ef5e5 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -88,6 +88,9 @@ register message *m_ptr; /* pointer to request message */ RTS_LOCK_UNSET(rpc, (SIGNALED | SIG_PENDING | P_STOP)); sigemptyset(&rpc->p_pending); + printf("kernel: %d / %s forked into %d\n", + rpp->p_endpoint, rpp->p_name, rpc->p_endpoint); + return r; } diff --git a/kernel/system/do_memset.c b/kernel/system/do_memset.c index a6f88f606..4c1ecc1c4 100644 --- a/kernel/system/do_memset.c +++ b/kernel/system/do_memset.c @@ -18,10 +18,8 @@ PUBLIC int do_memset(m_ptr) register message *m_ptr; { /* Handle sys_memset(). This writes a pattern into the specified memory. */ - unsigned long p; unsigned char c = m_ptr->MEM_PATTERN; - p = c | (c << 8) | (c << 16) | (c << 24); - phys_memset((phys_bytes) m_ptr->MEM_PTR, p, (phys_bytes) m_ptr->MEM_COUNT); + vm_phys_memset((phys_bytes) m_ptr->MEM_PTR, c, (phys_bytes) m_ptr->MEM_COUNT); return(OK); } diff --git a/kernel/system/do_vm_setbuf.c b/kernel/system/do_vm_setbuf.c index 484c43559..f3146e455 100644 --- a/kernel/system/do_vm_setbuf.c +++ b/kernel/system/do_vm_setbuf.c @@ -8,6 +8,8 @@ */ #include "../system.h" +#if 0 + #define VM_DEBUG 0 /* enable/ disable debug output */ /*===========================================================================* @@ -27,3 +29,5 @@ message *m_ptr; /* pointer to request message */ return OK; } + +#endif diff --git a/kernel/system/do_vmctl.c b/kernel/system/do_vmctl.c index f522a20f8..9fa261827 100644 --- a/kernel/system/do_vmctl.c +++ b/kernel/system/do_vmctl.c @@ -25,8 +25,6 @@ register message *m_ptr; /* pointer to request message */ if(ep == SELF) { ep = m_ptr->m_source; } - vm_init(); - if(!isokendpt(ep, &proc_nr)) { kprintf("do_vmctl: unexpected endpoint %d from VM\n", ep); return EINVAL; @@ -45,6 +43,9 @@ register message *m_ptr; /* pointer to request message */ if(!RTS_ISSET(rp, VMREQUEST)) minix_panic("do_vmctl: no VMREQUEST set", NO_NUM); + printf("kernel: vm request sent by: %s / %d about %d\n", + rp->p_name, rp->p_endpoint, rp->p_vmrequest.who); + /* Reply with request fields. */ m_ptr->SVMCTL_MRG_ADDR = (char *) rp->p_vmrequest.start; m_ptr->SVMCTL_MRG_LEN = rp->p_vmrequest.length; @@ -73,6 +74,7 @@ register message *m_ptr; /* pointer to request message */ rp->p_vmrequest.vmresult); /* Put on restart chain. */ + printf("kernel: vm reply received for %d\n", rp->p_endpoint); rp->p_vmrequest.nextrestart = vmrestart; vmrestart = rp; @@ -93,10 +95,15 @@ kprintf("SYSTEM: request %d:0x%lx-0x%lx, wrflag %d, failed\n", } #endif return OK; -#if VM_KERN_NOPAGEZERO - case VMCTL_NOPAGEZERO: + case VMCTL_ENABLE_PAGING: + if(vm_running) + minix_panic("do_vmctl: paging already enabled", NO_NUM); + vm_init(p); + if(!vm_running) + minix_panic("do_vmctl: paging enabling failed", NO_NUM); + if(newmap(p, m_ptr->SVMCTL_VALUE) != OK) + minix_panic("do_vmctl: newmap failed", NO_NUM); return OK; -#endif } /* Try architecture-specific vmctls. */ diff --git a/kernel/table.c b/kernel/table.c index 408819bef..4a09ced02 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -96,7 +96,8 @@ PRIVATE int drv_c[] = { DRV_C }, tty_c[] = { DRV_C, SYS_PHYSCOPY, SYS_ABORT, SYS_IOPENABLE, SYS_READBIOS }, - mem_c[] = { DRV_C, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_IOPENABLE }; + mem_c[] = { DRV_C, SYS_PHYSCOPY, SYS_PHYSVCOPY, SYS_IOPENABLE }, + usr_c[] = { SYS_SYSCTL }; /* The system image table lists all programs that are part of the boot image. * The order of the entries here MUST agree with the order of the programs @@ -126,7 +127,7 @@ PUBLIC struct boot_image image[] = { {LOG_PROC_NR, 0,SVM_F, 4, 2, 0, SRV_T, SYS_M,c(drv_c),"log" }, {MFS_PROC_NR, 0,SVM_F, 32, 5, 0, SRV_T, SRV_M, c(fs_c),"mfs" }, {VM_PROC_NR, 0,SRV_F, 32, 2, 0, SRV_T, SRV_M, c(vm_c),"vm" }, -{INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, no_c,"init" }, +{INIT_PROC_NR, 0,USR_F, 8, USER_Q, 0, USR_T, USR_M, c(usr_c),"init" }, }; /* Verify the size of the system image table at compile time. Also verify that diff --git a/kernel/utility.c b/kernel/utility.c index b0aa38859..03bc8cfce 100755 --- a/kernel/utility.c +++ b/kernel/utility.c @@ -37,7 +37,7 @@ char *mess; int nr; { /* The system has run aground of a fatal kernel error. Terminate execution. */ - if (minix_panicing ++) return; /* prevent recursive panics */ +if (!minix_panicing++) { if (mess != NULL) { kprintf("kernel panic: %s", mess); @@ -48,6 +48,7 @@ int nr; kprintf("kernel stacktrace: "); util_stacktrace(); +} /* Abort MINIX. */ minix_shutdown(NULL); @@ -80,12 +81,13 @@ int c; /* character to append */ kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE; } else { int p, outprocs[] = OUTPUT_PROCS_ARRAY; - if(do_serial_debug) return; - if(minix_panicing || do_serial_debug) return; - for(p = 0; outprocs[p] != NONE; p++) { - if(isokprocn(outprocs[p]) && !isemptyn(outprocs[p])) { - send_sig(outprocs[p], SIGKMESS); - } - } + if(!(minix_panicing || do_serial_debug)) { + for(p = 0; outprocs[p] != NONE; p++) { + if(isokprocn(outprocs[p]) && !isemptyn(outprocs[p])) { + send_sig(outprocs[p], SIGKMESS); + } + } + } } + return; } diff --git a/kernel/vm.h b/kernel/vm.h index 9e0b615da..e94645eed 100644 --- a/kernel/vm.h +++ b/kernel/vm.h @@ -10,10 +10,10 @@ #define CHECKRANGE(pr, start, length, wr) \ vm_checkrange(proc_addr(who_p), pr, start, length, wr, 1) -/* Pseudo error code indicating a process request has to be - * restarted after an OK from VM. - */ +/* Pseudo error codes */ #define VMSUSPEND -996 +#define EFAULT_SRC -995 +#define EFAULT_DST -994 #endif diff --git a/lib/sysutil/Makefile.in b/lib/sysutil/Makefile.in index cd9f53252..a44addf98 100644 --- a/lib/sysutil/Makefile.in +++ b/lib/sysutil/Makefile.in @@ -6,6 +6,7 @@ LIBRARIES=libsys libsys_FILES=" \ asynsend.c \ + kmalloc.c \ kprintf.c \ kputc.c \ tickdelay.c \ diff --git a/servers/init/init.c b/servers/init/init.c index 5fd15fd3e..5e5cb5832 100644 --- a/servers/init/init.c +++ b/servers/init/init.c @@ -99,6 +99,7 @@ int main(void) /* Execute the /etc/rc file. */ if ((pid = fork()) != 0) { + printf("init: parent (%d)\n", getpid()); /* Parent just waits. */ while (wait(NULL) != pid) { if (gotabrt) reboot(RBT_HALT); @@ -111,6 +112,7 @@ int main(void) static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL, NULL }; char **rcp = rc_command + 2; + printf("init: child (%d)\n", getpid()); /* Get the boot options from the boot environment. */ sysgetenv.key = "bootopts"; sysgetenv.keylen = 8+1; @@ -119,7 +121,9 @@ int main(void) if (svrctl(MMGETPARAM, &sysgetenv) == 0) *rcp++ = bootopts; *rcp = "start"; + printf("init: %d: exec /etc/rc..\n", getpid()); execute(rc_command); + printf("init: %d: exec /etc/rc fail..\n", getpid()); report(2, "sh /etc/rc"); _exit(1); /* impossible, we hope */ } diff --git a/servers/mfs/cache.c b/servers/mfs/cache.c index c75f2321a..53a8cc6a7 100644 --- a/servers/mfs/cache.c +++ b/servers/mfs/cache.c @@ -17,6 +17,7 @@ #include "fs.h" #include #include +#include #include "buf.h" #include "super.h" #include "inode.h" @@ -24,6 +25,9 @@ FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) ); FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) ); +char saved[100]; +char *savedptr; + /*===========================================================================* * get_block * *===========================================================================*/ @@ -48,10 +52,19 @@ int only_search; /* if NO_READ, don't read, else act normal */ */ int b; - register struct buf *bp, *prev_ptr; + static struct buf *bp, *prev_ptr; + + savedptr = (vir_bytes) &b + sizeof(b); + memcpy(saved, savedptr, sizeof(saved)); + +#define CHECK \ + if(memcmp(saved, savedptr, sizeof(saved))) \ + panic(__FILE__,"memory corruption", __LINE__); ASSERT(fs_block_size > 0); + CHECK; + /* Search the hash chain for (dev, block). Do_read() can use * get_block(NO_DEV ...) to get an unnamed block to fill with zeros when * someone wants to read from a hole in a file, in which case this search @@ -60,8 +73,11 @@ int only_search; /* if NO_READ, don't read, else act normal */ if (dev != NO_DEV) { b = BUFHASH(block); bp = buf_hash[b]; + CHECK; while (bp != NIL_BUF) { + CHECK; if (bp->b_blocknr == block && bp->b_dev == dev) { + CHECK; /* Block needed has been found. */ if (bp->b_count == 0) rm_lru(bp); bp->b_count++; /* record that block is in use */ @@ -69,6 +85,7 @@ int only_search; /* if NO_READ, don't read, else act normal */ ASSERT(bp->b_dev == dev); ASSERT(bp->b_dev != NO_DEV); ASSERT(bp->bp); + CHECK; return(bp); } else { /* This block is not the one sought. */ @@ -137,6 +154,7 @@ int only_search; /* if NO_READ, don't read, else act normal */ ASSERT(bp->bp); + CHECK; return(bp); /* return the newly acquired block */ } diff --git a/servers/pm/main.c b/servers/pm/main.c index 6ed92614e..b57e87626 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -452,9 +452,13 @@ PRIVATE void send_work() rmp->mp_fs_call= PM_IDLE; /* Wakeup the newly created process */ + printf("PM: replying fork OK to child %d\n", + rmp->mp_endpoint); setreply(rmp-mproc, OK); /* Wakeup the parent */ + printf("PM: replying fork %d to parent %d\n", + rmp->mp_pid, parent_mp->mp_endpoint); setreply(parent_mp-mproc, rmp->mp_pid); break; } diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h index 9bd2058ac..40a22b472 100644 --- a/servers/vfs/fs.h +++ b/servers/vfs/fs.h @@ -5,7 +5,7 @@ #define _MINIX 1 /* tell headers to include MINIX stuff */ #define _SYSTEM 1 /* tell headers that this is the kernel */ -#define DO_SANITYCHECKS 0 +#define DO_SANITYCHECKS 1 #if DO_SANITYCHECKS #define SANITYCHECK do { \ diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 43912b6cc..0d9161792 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "file.h" #include "fproc.h" #include "param.h" @@ -59,6 +60,10 @@ PUBLIC int main() SANITYCHECK; +#if DO_SANITYCHECKS + FIXME("VFS: DO_SANITYCHECKS is on"); +#endif + /* This is the main loop that gets work, processes it, and sends replies. */ while (TRUE) { SANITYCHECK; diff --git a/servers/vm/exit.c b/servers/vm/exit.c index c311e17e0..99151c087 100644 --- a/servers/vm/exit.c +++ b/servers/vm/exit.c @@ -55,6 +55,8 @@ PUBLIC int do_exit(message *msg) SANITYCHECK(SCL_FUNCTIONS); + printf("VM: %d exiting\n", msg->VME_ENDPOINT); + if(vm_isokendpt(msg->VME_ENDPOINT, &proc) != OK) { printf("VM: bogus endpoint VM_EXIT %d\n", msg->VME_ENDPOINT); return EINVAL; diff --git a/servers/vm/fork.c b/servers/vm/fork.c index 8a5aa6ae7..caef81c36 100644 --- a/servers/vm/fork.c +++ b/servers/vm/fork.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ PUBLIC int do_fork(message *msg) { int r, proc, s, childproc, fullvm; struct vmproc *vmp, *vmc; + pt_t origpt; SANITYCHECK(SCL_FUNCTIONS); @@ -49,6 +51,7 @@ PUBLIC int do_fork(message *msg) vmp = &vmproc[proc]; /* parent */ vmc = &vmproc[childproc]; /* child */ + vm_assert(vmc->vm_slot == childproc); if(vmp->vm_flags & VMF_HAS_DMA) { printf("VM: %d has DMA memory and may not fork\n", msg->VMF_ENDPOINT); @@ -58,14 +61,20 @@ PUBLIC int do_fork(message *msg) fullvm = vmp->vm_flags & VMF_HASPT; /* The child is basically a copy of the parent. */ + origpt = vmc->vm_pt; *vmc = *vmp; + vmc->vm_slot = childproc; vmc->vm_regions = NULL; vmc->vm_endpoint = NONE; /* In case someone tries to use it. */ + vmc->vm_pt = origpt; + vmc->vm_flags &= ~VMF_HASPT; #if VMSTATS vmc->vm_bytecopies = 0; #endif + SANITYCHECK(SCL_DETAIL); + if(fullvm) { SANITYCHECK(SCL_DETAIL); @@ -74,6 +83,8 @@ PUBLIC int do_fork(message *msg) return ENOMEM; } + vmc->vm_flags |= VMF_HASPT; + SANITYCHECK(SCL_DETAIL); if(map_proc_copy(vmc, vmp) != OK) { @@ -108,6 +119,7 @@ PUBLIC int do_fork(message *msg) /* Create a copy of the parent's core image for the child. */ child_abs = (phys_bytes) child_base << CLICK_SHIFT; parent_abs = (phys_bytes) vmp->vm_arch.vm_seg[D].mem_phys << CLICK_SHIFT; + FIXME("VM uses kernel for abscopy"); s = sys_abscopy(parent_abs, child_abs, prog_bytes); if (s < 0) vm_panic("do_fork can't copy", s); diff --git a/servers/vm/i386/pagetable.c b/servers/vm/i386/pagetable.c index 27e07d8a6..cc0e6b9de 100644 --- a/servers/vm/i386/pagetable.c +++ b/servers/vm/i386/pagetable.c @@ -44,6 +44,8 @@ PRIVATE u32_t varmap_loc; /* Our page table. */ PRIVATE int kernel_pde = -1, pagedir_pde = -1; PRIVATE u32_t kern_pde_val = 0, global_bit = 0, pagedir_pde_val; +PRIVATE int proc_pde = 0; + /* 4MB page size available in hardware? */ PRIVATE int bigpage_ok = 0; @@ -82,7 +84,6 @@ PRIVATE struct { u32_t page_directories_phys, *page_directories = NULL; #if SANITYCHECKS -#define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); SANITYCHECK(SCL_DETAIL); } /*===========================================================================* * pt_sanitycheck * *===========================================================================*/ @@ -90,21 +91,33 @@ PUBLIC void pt_sanitycheck(pt_t *pt, char *file, int line) { /* Basic pt sanity check. */ int i; + int slot; MYASSERT(pt); MYASSERT(pt->pt_dir); MYASSERT(pt->pt_dir_phys); - for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { + for(slot = 0; slot < ELEMENTS(vmproc); slot++) { + if(pt == &vmproc[slot].vm_pt) + break; + } + + if(slot >= ELEMENTS(vmproc)) { + vm_panic("pt_sanitycheck: passed pt not in any proc", NO_NUM); + } + + for(i = proc_pde; i < I386_VM_DIR_ENTRIES; i++) { if(pt->pt_pt[i]) { + if(!(pt->pt_dir[i] & I386_VM_PRESENT)) { + printf("slot %d: pt->pt_pt[%d] = 0x%lx, but pt_dir entry 0x%lx\n", + slot, i, pt->pt_pt[i], pt->pt_dir[i]); + } MYASSERT(pt->pt_dir[i] & I386_VM_PRESENT); } else { MYASSERT(!(pt->pt_dir[i] & I386_VM_PRESENT)); } } } -#else -#define PT_SANE(p) #endif /*===========================================================================* @@ -348,7 +361,7 @@ PRIVATE int pt_ptalloc(pt_t *pt, int pde, u32_t flags) /* Argument must make sense. */ vm_assert(pde >= 0 && pde < I386_VM_DIR_ENTRIES); - vm_assert(!(flags & ~(PTF_ALLFLAGS | PTF_MAPALLOC))); + vm_assert(!(flags & ~(PTF_ALLFLAGS))); /* We don't expect to overwrite page directory entry, nor * storage for the page table. @@ -386,10 +399,9 @@ PUBLIC int pt_writemap(pt_t *pt, vir_bytes v, phys_bytes physaddr, /* Page directory and table entries for this virtual address. */ int p, pages, pde; int finalpde; - SANITYCHECK(SCL_FUNCTIONS); vm_assert(!(bytes % I386_PAGE_SIZE)); - vm_assert(!(flags & ~(PTF_ALLFLAGS | PTF_MAPALLOC))); + vm_assert(!(flags & ~(PTF_ALLFLAGS))); pages = bytes / I386_PAGE_SIZE; @@ -471,7 +483,7 @@ PUBLIC int pt_writemap(pt_t *pt, vir_bytes v, phys_bytes physaddr, v += I386_PAGE_SIZE; PT_SANE(pt); } - SANITYCHECK(SCL_FUNCTIONS); + PT_SANE(pt); return OK; @@ -489,7 +501,14 @@ PUBLIC int pt_new(pt_t *pt) */ int i; - if(!(pt->pt_dir = vm_allocpages(&pt->pt_dir_phys, 1, VMP_PAGEDIR))) { + /* Don't ever re-allocate/re-move a certain process slot's + * page directory once it's been created. This is a fraction + * faster, but also avoids having to invalidate the page + * mappings from in-kernel page tables pointing to + * the page directories (the page_directories data). + */ + if(!pt->pt_dir && + !(pt->pt_dir = vm_allocpages(&pt->pt_dir_phys, 1, VMP_PAGEDIR))) { return ENOMEM; } @@ -501,10 +520,14 @@ PUBLIC int pt_new(pt_t *pt) /* Where to start looking for free virtual address space? */ pt->pt_virtop = 0; + PT_SANE(pt); + /* Map in kernel. */ if(pt_mapkernel(pt) != OK) vm_panic("pt_new: pt_mapkernel failed", NO_NUM); + PT_SANE(pt); + return OK; } @@ -565,17 +588,15 @@ PUBLIC void pt_init(void) */ kern_pde_val = (KERNEL_TEXT & I386_VM_ADDR_MASK_4MB) | I386_VM_BIGPAGE| + I386_VM_USER| I386_VM_PRESENT|I386_VM_WRITE|global_bit; kernel_pde = pde1; vm_assert(kernel_pde >= 0); free_pde = kernel_pde+1; } - - /* Make new page table for ourselves, partly copied - * from the current one. - */ - if(pt_new(newpt) != OK) - vm_panic("pt_init: pt_new failed", NO_NUM); + + /* First unused pde. */ + proc_pde = free_pde; /* Initial (current) range of our virtual address space. */ lo = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys); @@ -591,6 +612,12 @@ PUBLIC void pt_init(void) vm_assert(!(lo % I386_PAGE_SIZE)); vm_assert(!(moveup % I386_PAGE_SIZE)); } + + /* Make new page table for ourselves, partly copied + * from the current one. + */ + if(pt_new(newpt) != OK) + vm_panic("pt_init: pt_new failed", NO_NUM); /* Set up mappings for VM process. */ for(v = lo; v < hi; v += I386_PAGE_SIZE) { @@ -620,11 +647,10 @@ PUBLIC void pt_init(void) 1, VMP_PAGETABLE))) vm_panic("no virt addr for vm mappings", NO_NUM); + printf("VM: pt made\n"); + memset(page_directories, 0, I386_PAGE_SIZE); - /* Give our process the new, copied, private page table. */ - pt_bind(newpt, vmp); - /* Increase our hardware data segment to create virtual address * space above our stack. We want to increase it to VM_DATATOP, * like regular processes have. @@ -639,19 +665,6 @@ PUBLIC void pt_init(void) (vmp->vm_arch.vm_seg[S].mem_vir + vmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; - if((s=sys_newmap(VM_PROC_NR, vmp->vm_arch.vm_seg)) != OK) - vm_panic("VM: pt_init: sys_newmap failed", s); - - /* Back to reality - this is where the stack actually is. */ - vmp->vm_arch.vm_seg[S].mem_len -= extra_clicks; - - /* Wipe old mappings from VM. */ - for(v = lo; v < hi; v += I386_PAGE_SIZE) { - if(pt_writemap(newpt, v, MAP_NONE, I386_PAGE_SIZE, - 0, WMF_OVERWRITE) != OK) - vm_panic("pt_init: pt_writemap failed", NO_NUM); - } - /* Where our free virtual address space starts. * This is only a hint to the VM system. */ @@ -671,36 +684,25 @@ PUBLIC void pt_init(void) } varmap = (unsigned char *) arch_map2vir(vmp, varmap_loc); + printf("VM: setting pagedir_pde\n"); + /* Find a PDE below processes available for mapping in the * page directories (readonly). */ pagedir_pde = free_pde++; pagedir_pde_val = (page_directories_phys & I386_VM_ADDR_MASK) | - I386_VM_PRESENT | I386_VM_USER; - - printf("VM: HACK: pagedir pde val is 0x%x (phys 0x%x)\n", - pagedir_pde_val, page_directories_phys); - - /* Temporary hack while kernel still maintains own pagetable */ - if((r=sys_vmctl(SELF, VMCTL_I386_PDE, pagedir_pde)) != OK) { - vm_panic("VMCTL_I386_PDE failed", r); - } - - printf("VM: HACK: pagedir pde val is 0x%x\n", pagedir_pde_val); - - /* Temporary hack while kernel still maintains own pagetable */ - if((r=sys_vmctl(SELF, VMCTL_I386_PDEVAL, pagedir_pde_val)) != OK) { - vm_panic("VMCTL_I386_PDEVAL failed", r); - } + I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE; /* Tell kernel about free pde's. */ while(free_pde*I386_BIG_PAGE_SIZE < VM_PROCSTART) { - printf("VM: telling kernel about free pde %d\n", free_pde); if((r=sys_vmctl(SELF, VMCTL_I386_FREEPDE, free_pde++)) != OK) { vm_panic("VMCTL_I386_FREEPDE failed", r); } } + /* first pde in use by process. */ + proc_pde = free_pde; + kernlimit = free_pde*I386_BIG_PAGE_SIZE; printf("VM: set limit to 0x%x\n", kernlimit); @@ -719,6 +721,33 @@ PUBLIC void pt_init(void) if((r=sys_vmctl(SELF, VMCTL_I386_PAGEDIRS, kpagedir)) != OK) { vm_panic("VMCTL_I386_KERNELLIMIT failed", r); } + + /* Give our process the new, copied, private page table. */ + printf("VM: pt_bind for VM\n"); + pt_mapkernel(newpt); /* didn't know about vm_dir pages earlier */ + pt_bind(newpt, vmp); + + printf("VM: enable paging\n"); + + /* Now actually enable paging. */ + if((r=sys_vmctl(SELF, VMCTL_ENABLE_PAGING, + vmp->vm_arch.vm_seg)) != OK) { + vm_panic("VMCTL_ENABLE_PAGING failed", r); + } + + printf("VM: enable paging done\n"); + + /* Back to reality - this is where the stack actually is. */ + vmp->vm_arch.vm_seg[S].mem_len -= extra_clicks; + + /* Wipe old mappings from VM. */ + for(v = lo; v < hi; v += I386_PAGE_SIZE) { + if(pt_writemap(newpt, v, MAP_NONE, I386_PAGE_SIZE, + 0, WMF_OVERWRITE) != OK) + vm_panic("pt_init: pt_writemap failed", NO_NUM); + } + + printf("VM: pt_init done\n"); /* All OK. */ return; @@ -750,6 +779,10 @@ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who) /* Update "page directory pagetable." */ page_directories[slot] = phys | I386_VM_PRESENT|I386_VM_WRITE; +#if 0 + printf("VM: slot %d has pde val 0x%lx\n", slot, page_directories[slot]); +#endif + /* Tell kernel about new page table root. */ return sys_vmctl(who->vm_endpoint, VMCTL_I386_SETCR3, pt ? pt->pt_dir_phys : 0); @@ -765,22 +798,14 @@ PUBLIC void pt_free(pt_t *pt) PT_SANE(pt); - for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { - int p; - if(pt->pt_pt[i]) { - for(p = 0; p < I386_VM_PT_ENTRIES; p++) { - if((pt->pt_pt[i][p] & (PTF_MAPALLOC | I386_VM_PRESENT)) - == (PTF_MAPALLOC | I386_VM_PRESENT)) { - u32_t pa = I386_VM_PFA(pt->pt_pt[i][p]); - FREE_MEM(ABS2CLICK(pa), CLICKSPERPAGE); - } - } - vm_freepages((vir_bytes) pt->pt_pt[i], - I386_VM_PFA(pt->pt_dir[i]), 1, VMP_PAGETABLE); - } - } + for(i = 0; i < I386_VM_DIR_ENTRIES; i++) + if(pt->pt_pt[i]) + vm_freepages((vir_bytes) pt->pt_pt[i], + I386_VM_PFA(pt->pt_dir[i]), 1, VMP_PAGETABLE); +#if 0 vm_freepages((vir_bytes) pt->pt_dir, pt->pt_dir_phys, 1, VMP_PAGEDIR); +#endif return; } @@ -797,8 +822,13 @@ PUBLIC int pt_mapkernel(pt_t *pt) vm_assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE); if(bigpage_ok) { - pt->pt_dir[kernel_pde] = kern_pde_val; + if(kernel_pde >= 0) { + pt->pt_dir[kernel_pde] = kern_pde_val; + } else + vm_panic("VM: pt_mapkernel: no kernel pde", NO_NUM); } else { + vm_panic("VM: pt_mapkernel: no bigpage", NO_NUM); + /* Map in text. flags: don't write, supervisor only */ if((r=pt_writemap(pt, KERNEL_TEXT, KERNEL_TEXT, KERNEL_TEXT_LEN, I386_VM_PRESENT|global_bit, 0)) != OK) @@ -810,40 +840,14 @@ PUBLIC int pt_mapkernel(pt_t *pt) return r; } - /* Kernel also wants to know about all page directories. */ - pt->pt_dir[pagedir_pde] = pagedir_pde_val; - - return OK; -} - -/*===========================================================================* - * pt_freerange * - *===========================================================================*/ -PUBLIC void pt_freerange(pt_t *pt, vir_bytes low, vir_bytes high) -{ -/* Free memory allocated by pagetable functions in this range. */ - int pde; - u32_t v; - - PT_SANE(pt); - - for(v = low; v < high; v += I386_PAGE_SIZE) { - int pte; - pde = I386_VM_PDE(v); - pte = I386_VM_PTE(v); - if(!(pt->pt_dir[pde] & I386_VM_PRESENT)) - continue; - if((pt->pt_pt[pde][pte] & (PTF_MAPALLOC | I386_VM_PRESENT)) - == (PTF_MAPALLOC | I386_VM_PRESENT)) { - u32_t pa = I386_VM_PFA(pt->pt_pt[pde][pte]); - FREE_MEM(ABS2CLICK(pa), CLICKSPERPAGE); - pt->pt_pt[pde][pte] = 0; - } + if(pagedir_pde >= 0) { + /* Kernel also wants to know about all page directories. */ + pt->pt_dir[pagedir_pde] = pagedir_pde_val; + } else { + printf("VM: pagedir pde not set\n"); } - PT_SANE(pt); - - return; + return OK; } /*===========================================================================* @@ -881,8 +885,10 @@ static u32_t ismapped = MAP_NONE; if(r != OK) \ vm_panic("PHYS_MAP: pt_writemap", NO_NUM); \ ismapped = wantmapped; \ - /* pt_bind() flushes TLB. */ \ - pt_bind(&vmp->vm_pt, vmp); \ + /* Invalidate TLB for this page. */ \ + if((r=sys_vmctl(SELF, VMCTL_I386_INVLPG, varmap_loc)) != OK) { \ + vm_panic("VM: vmctl failed", r); \ + } \ } \ } @@ -891,7 +897,7 @@ static u32_t ismapped = MAP_NONE; #if SANITYCHECKS #define PHYS_UNMAP if(OK != pt_writemap(&vmp->vm_pt, varmap_loc, MAP_NONE,\ I386_PAGE_SIZE, 0, WMF_OVERWRITE)) { \ - vm_panic("PHYS_UNMAP: pt_writemap failed", NO_NUM); } + vm_panic("PHYS_UNMAP: pt_writemap failed", NO_NUM); } \ ismapped = MAP_NONE; #endif diff --git a/servers/vm/i386/pagetable.h b/servers/vm/i386/pagetable.h index b26ac9cd3..42fb7d7e6 100644 --- a/servers/vm/i386/pagetable.h +++ b/servers/vm/i386/pagetable.h @@ -5,6 +5,8 @@ #include #include +#include "../vm.h" + /* An i386 pagetable. */ typedef struct { /* Directory entries in VM addr space - root of page table. */ @@ -34,5 +36,12 @@ typedef struct { */ #define PTF_ALLFLAGS (PTF_WRITE|PTF_PRESENT|PTF_USER|PTF_GLOBAL) +#if SANITYCHECKS +#define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); } +#else +#define PT_SANE(p) +#endif + #endif + diff --git a/servers/vm/i386/vm.c b/servers/vm/i386/vm.c index 1f55874cf..43d6db1c3 100644 --- a/servers/vm/i386/vm.c +++ b/servers/vm/i386/vm.c @@ -25,73 +25,6 @@ #include "memory.h" -#define PAGE_SIZE 4096 -#define PAGE_DIR_SIZE (1024*PAGE_SIZE) -#define PAGE_TABLE_COVER (1024*PAGE_SIZE) -/*=========================================================================* - * arch_init_vm * - *=========================================================================*/ -PUBLIC void arch_init_vm(mem_chunks) -struct memory mem_chunks[NR_MEMS]; -{ - phys_bytes high, bytes; - phys_clicks clicks, base_click; - unsigned pages; - int i, r; - - /* Compute the highest memory location */ - high= 0; - for (i= 0; i high) - high= mem_chunks[i].base + mem_chunks[i].size; - } - - high <<= CLICK_SHIFT; -#if VERBOSE_VM - printf("do_x86_vm: found high 0x%x\n", high); -#endif - - /* Rounding up */ - high= (high-1+PAGE_DIR_SIZE) & ~(PAGE_DIR_SIZE-1); - - /* The number of pages we need is one for the page directory, enough - * page tables to cover the memory, and one page for alignement. - */ - pages= 1 + (high + PAGE_TABLE_COVER-1)/PAGE_TABLE_COVER + 1; - bytes= pages*PAGE_SIZE; - clicks= (bytes + CLICK_SIZE-1) >> CLICK_SHIFT; - -#if VERBOSE_VM - printf("do_x86_vm: need %d pages\n", pages); - printf("do_x86_vm: need %d bytes\n", bytes); - printf("do_x86_vm: need %d clicks\n", clicks); -#endif - - for (i= 0; i= NR_MEMS) - panic("VM", "not enough memory for VM page tables?", NO_NUM); - base_click= mem_chunks[i].base; - mem_chunks[i].base += clicks; - mem_chunks[i].size -= clicks; - -#if VERBOSE_VM - printf("do_x86_vm: using 0x%x clicks @ 0x%x\n", clicks, base_click); -#endif - r= sys_vm_setbuf(base_click << CLICK_SHIFT, clicks << CLICK_SHIFT, - high); - if (r != 0) - printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r); - -} - /*===========================================================================* * arch_map2vir * *===========================================================================*/ diff --git a/servers/vm/main.c b/servers/vm/main.c index 31f870aa2..8cfff5c2c 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -77,6 +77,7 @@ PUBLIC int main(void) #if SANITYCHECKS nocheck = 0; + FIXME("VM SANITYCHECKS are on"); memcpy(data1, CHECKADDR, sizeof(data1)); #endif SANITYCHECK(SCL_TOP); @@ -114,21 +115,16 @@ PUBLIC int main(void) switch(msg.m_source) { case SYSTEM: /* Kernel wants to have memory ranges - * verified. + * verified, and/or pagefaults handled. */ do_memory(); + do_pagefaults(); break; case PM_PROC_NR: /* PM sends a notify() on shutdown, which * is OK and we ignore. */ break; - case HARDWARE: - /* This indicates a page fault has happened, - * which we have to handle. - */ - do_pagefaults(); - break; default: /* No-one else should send us notifies. */ printf("VM: ignoring notify() from %d\n", @@ -242,10 +238,6 @@ PRIVATE void vm_init(void) vmp->vm_flags |= VMF_SEPARATE; } - - /* Let architecture-dependent VM initialization use some memory. */ - arch_init_vm(mem_chunks); - /* Architecture-dependent initialization. */ pt_init(); @@ -316,13 +308,6 @@ PRIVATE void vm_init(void) VM_STACKTOP); } - /* Temporary hack; throw away all lower memory. */ - while((click=ALLOC_MEM(1, 0)) <= ABS2CLICK(VM_PROCSTART)) { - clicksforgotten++; - } - - printf("VM: HACK: clicks forgotten: %d last one: 0x%x\n", clicksforgotten, click); - /* Set up table of calls. */ #define CALLMAP(code, func, thecaller) { int i; \ if((i=CALLNUMBER(code)) < 0) { vm_panic(#code " invalid", (code)); } \ diff --git a/servers/vm/pagefaults.c b/servers/vm/pagefaults.c index 3790df238..fcf84c558 100644 --- a/servers/vm/pagefaults.c +++ b/servers/vm/pagefaults.c @@ -106,9 +106,13 @@ PUBLIC void do_pagefaults(void) } + printf("VM: handling pagefault OK: %d addr 0x%lx %s\n", + ep, arch_map2vir(vmp, addr), pf_errstr(err)); + /* Pagefault is handled, so now reactivate the process. */ if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, r)) != OK) vm_panic("do_pagefaults: sys_vmctl failed", ep); + } return; @@ -135,6 +139,9 @@ PUBLIC void do_memory(void) vm_panic("do_memory: endpoint wrong", who); vmp = &vmproc[p]; + printf("VM: handling memory request: %d, 0x%lx-0x%lx, wr %d\n", + who, mem, mem+len, wrflag); + /* Page-align memory and length. */ o = mem % VM_PAGE_SIZE; mem -= o; @@ -167,8 +174,12 @@ PUBLIC void do_memory(void) vmp->vm_endpoint); } + if(sys_vmctl(who, VMCTL_MEMREQ_REPLY, r) != OK) vm_panic("do_memory: sys_vmctl failed", r); + + printf("VM: handling memory request %d done OK\n", + who); } } diff --git a/servers/vm/proto.h b/servers/vm/proto.h index 3e7158a0d..f4e860834 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -135,6 +135,7 @@ _PROTOTYPE(int map_pf,(struct vmproc *vmp, struct vir_region *region, vir_bytes offset, int write)); _PROTOTYPE(int map_handle_memory,(struct vmproc *vmp, struct vir_region *region, vir_bytes offset, vir_bytes len, int write)); +_PROTOTYPE(void map_printmap, (struct vmproc *vmp)); _PROTOTYPE(struct vir_region * map_region_lookup_tag, (struct vmproc *vmp, u32_t tag)); _PROTOTYPE(void map_region_set_tag, (struct vir_region *vr, u32_t tag)); diff --git a/servers/vm/region.c b/servers/vm/region.c index e327c455a..ac25ced45 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -32,8 +32,6 @@ FORWARD _PROTOTYPE(int map_new_physblock, (struct vmproc *vmp, FORWARD _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp, struct vir_region *region, struct phys_region *ph)); FORWARD _PROTOTYPE(struct vir_region *map_copy_region, (struct vir_region *)); -FORWARD _PROTOTYPE(void map_printmap, (struct vmproc *vmp)); - PRIVATE char *map_name(struct vir_region *vr) { int type = vr->flags & (VR_ANON|VR_DIRECT); @@ -52,7 +50,7 @@ PRIVATE char *map_name(struct vir_region *vr) /*===========================================================================* * map_printmap * *===========================================================================*/ -PRIVATE void map_printmap(vmp) +PUBLIC void map_printmap(vmp) struct vmproc *vmp; { struct vir_region *vr; @@ -60,9 +58,10 @@ struct vmproc *vmp; for(vr = vmp->vm_regions; vr; vr = vr->next) { struct phys_region *ph; int nph = 0; + printf("map_printmap: map_name: %s\n", map_name(vr)); printf("\t0x%lx - 0x%lx (len 0x%lx), %s\n", vr->vaddr, vr->vaddr + vr->length, vr->length, - vr->vaddr + vr->length, map_name(vr)); + map_name(vr)); printf("\t\tphysical: "); for(ph = vr->first; ph; ph = ph->next) { printf("0x%lx-0x%lx (refs %d): phys 0x%lx ", @@ -912,6 +911,9 @@ struct vmproc *src; dst->vm_regions = NULL; SANITYCHECK(SCL_FUNCTIONS); + + PT_SANE(&src->vm_pt); + for(vr = src->vm_regions; vr; vr = vr->next) { struct vir_region *newvr; struct phys_region *orig_ph, *new_ph; @@ -958,8 +960,12 @@ struct vmproc *src; } SANITYCHECK(SCL_DETAIL); + PT_SANE(&src->vm_pt); + map_writept(src); + PT_SANE(&src->vm_pt); map_writept(dst); + PT_SANE(&dst->vm_pt); SANITYCHECK(SCL_FUNCTIONS); return OK; diff --git a/servers/vm/sanitycheck.h b/servers/vm/sanitycheck.h index dac7b83e7..96f1fd046 100644 --- a/servers/vm/sanitycheck.h +++ b/servers/vm/sanitycheck.h @@ -34,7 +34,7 @@ for(vmp = vmproc; vmp <= &vmproc[_NR_PROCS]; vmp++) { \ if((vmp->vm_flags & (VMF_INUSE | VMF_HASPT)) == \ (VMF_INUSE | VMF_HASPT)) { \ - pt_sanitycheck(&vmp->vm_pt, __FILE__, __LINE__); \ + PT_SANE(&vmp->vm_pt); \ } \ } \ map_sanitycheck(__FILE__, __LINE__); \ diff --git a/servers/vm/vm.h b/servers/vm/vm.h index 0f4040db7..fb3b14c8e 100644 --- a/servers/vm/vm.h +++ b/servers/vm/vm.h @@ -13,7 +13,7 @@ #define ABS2CLICK(a) ((a) >> CLICK_SHIFT) /* Compile in asserts and custom sanity checks at all? */ -#define SANITYCHECKS 0 +#define SANITYCHECKS 1 #define VMSTATS 1 /* If so, this level: */ -- 2.44.0