#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);
}
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;
}
# 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() */
#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 *
#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 */
--- /dev/null
+#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 */
+
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. */
#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 */
#include "proto.h"
-extern u32_t kernel_cr3;
extern u32_t *vm_pagedirs;
/*===========================================================================*
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. */
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);
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:
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;
}
}
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)
return(EINVAL);
}
return(OK);
+#endif
}
#endif /* USE_SDEVIO */
#include <minix/sysutil.h>
#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;
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.
*/
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
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;
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;
}
.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
.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
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 *
!*===========================================================================*
!*===========================================================================*
! 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 *
! 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
!*==========================================================================*
push edi
push es
- LOADKERNELCR3
-
mov eax, FLAT_DS_SELECTOR
mov es, ax
push ebx
push ds
- LOADKERNELCR3
-
mov esi, 8(ebp)
mov eax, 16(ebp)
mov ebx, FLAT_DS_SELECTOR
jnz fill_start
! Any remaining bytes?
mov eax, 16(ebp)
- and eax, 3
+! and eax, 3
remain_fill:
cmp eax, 0
jz fill_done
_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 *
!*===========================================================================*
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
#include <minix/cpufeature.h>
#include <string.h>
+#define FREEPDE_SRC 0
+#define FREEPDE_DST 1
+#define FREEPDE_MEMSET 2
+
#include <sys/vm_i386.h>
#include <minix/portio.h>
#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;
#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; rp<END_PROC_ADDR; rp++) {
- u32_t mycr3;
- if(isemptyp(rp)) continue;
- rp->p_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;
{
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);
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);
}
return phys;
}
+
/*===========================================================================*
* vm_lookup *
*===========================================================================*/
u32_t *root, *pt;
int pde, pte;
u32_t pde_v, pte_v;
+ NOREC_ENTER(vmlookup);
vmassert(proc);
vmassert(physical);
if(!HASPT(proc)) {
*physical = virtual;
- return OK;
+ NOREC_RETURN(vmlookup, OK);
}
/* Retrieve page directory entry. */
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",
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,
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 *
*===========================================================================*/
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 *
*===========================================================================*/
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)) {
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, "
*/
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;
}
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; }
}
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;
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;
}
int seg_index;
int i, r;
struct proc *procs[2];
+ NOREC_ENTER(virtualcopy);
/* Check copy count. */
if (bytes <= 0) return(EDOM);
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,
}
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;
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);
}
/*===========================================================================*
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)
.define _restart
.define save
-.define _kernel_cr3
.define _pagefault_cr2
.define _pagefault_count
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()
#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? */;\
#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? */;\
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
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:
mov eax, 8+4(esp) ! old eflags
sseg mov (old_eflags), eax
- LOADCR3WITHEAX(0x24, (_kernel_cr3))
-
pop eax
call save
push (old_eflags)
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:
_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 */
_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) );
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;
{
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; }
-.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 ;\
mov cr3, eax ;\
sseg inc (_cr3reload) ;\
sseg mov (_last_cr3), eax ;\
+sseg mov eax, (ptproc) ;\
+sseg mov (_ptproc), eax ;\
8:
}
#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;
+}
+
*/
#include <ansi.h>
+#include <minix/debug.h>
#include "config.h"
/* Enable prints such as
/* 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 */
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;
#include <minix/com.h>
#include <minix/endpoint.h>
#include "proc.h"
+#include "debug.h"
/* Prototype declarations for PRIVATE functions. */
FORWARD _PROTOTYPE( void announce, (void));
*/
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();
}
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, \
} \
(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)
/*===========================================================================*
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 */
#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. */
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) );
#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,
#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));
_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));
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 */
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");
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. */
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.
*/
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. */
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,
sizeof(message))) != OK) {
minix_panic("SYSTEM: delayed msgcopy failed", r);
}
+ printf("OK!\n");
RTS_LOCK_UNSET(restarting, VMREQUEST);
/* Handled; restart system loop. */
#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
/* 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 */
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;
}
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);
}
*/
#include "../system.h"
+#if 0
+
#define VM_DEBUG 0 /* enable/ disable debug output */
/*===========================================================================*
return OK;
}
+
+#endif
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;
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;
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;
}
#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. */
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
{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
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);
kprintf("kernel stacktrace: ");
util_stacktrace();
+}
/* Abort MINIX. */
minix_shutdown(NULL);
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;
}
#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
libsys_FILES=" \
asynsend.c \
+ kmalloc.c \
kprintf.c \
kputc.c \
tickdelay.c \
/* 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);
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;
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 */
}
#include "fs.h"
#include <minix/com.h>
#include <minix/u64.h>
+#include <string.h>
#include "buf.h"
#include "super.h"
#include "inode.h"
FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) );
FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) );
+char saved[100];
+char *savedptr;
+
/*===========================================================================*
* get_block *
*===========================================================================*/
*/
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
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 */
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. */
ASSERT(bp->bp);
+ CHECK;
return(bp); /* return the newly acquired block */
}
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;
}
#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 { \
#include <minix/const.h>
#include <minix/endpoint.h>
#include <minix/safecopies.h>
+#include <minix/debug.h>
#include "file.h"
#include "fproc.h"
#include "param.h"
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;
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;
#include <minix/ipc.h>
#include <minix/sysutil.h>
#include <minix/syslib.h>
+#include <minix/debug.h>
#include <errno.h>
#include <env.h>
{
int r, proc, s, childproc, fullvm;
struct vmproc *vmp, *vmc;
+ pt_t origpt;
SANITYCHECK(SCL_FUNCTIONS);
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);
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);
return ENOMEM;
}
+ vmc->vm_flags |= VMF_HASPT;
+
SANITYCHECK(SCL_DETAIL);
if(map_proc_copy(vmc, vmp) != OK) {
/* 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);
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;
u32_t page_directories_phys, *page_directories = NULL;
#if SANITYCHECKS
-#define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); SANITYCHECK(SCL_DETAIL); }
/*===========================================================================*
* pt_sanitycheck *
*===========================================================================*/
{
/* 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
/*===========================================================================*
/* 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.
/* 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;
v += I386_PAGE_SIZE;
PT_SANE(pt);
}
- SANITYCHECK(SCL_FUNCTIONS);
+
PT_SANE(pt);
return OK;
*/
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;
}
/* 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;
}
*/
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);
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) {
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.
(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.
*/
}
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);
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;
/* 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);
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;
}
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)
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;
}
/*===========================================================================*
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); \
+ } \
} \
}
#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
#include <stdint.h>
#include <sys/vm_i386.h>
+#include "../vm.h"
+
/* An i386 pagetable. */
typedef struct {
/* Directory entries in VM addr space - root of page table. */
*/
#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
+
#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<NR_MEMS; i++)
- {
- if (mem_chunks[i].size == 0)
- continue;
- if (mem_chunks[i].base + mem_chunks[i].size > 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; i++)
- {
- if (mem_chunks[i].size <= clicks)
- continue;
- break;
- }
- if (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 *
*===========================================================================*/
#if SANITYCHECKS
nocheck = 0;
+ FIXME("VM SANITYCHECKS are on");
memcpy(data1, CHECKADDR, sizeof(data1));
#endif
SANITYCHECK(SCL_TOP);
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",
vmp->vm_flags |= VMF_SEPARATE;
}
-
- /* Let architecture-dependent VM initialization use some memory. */
- arch_init_vm(mem_chunks);
-
/* Architecture-dependent initialization. */
pt_init();
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)); } \
}
+ 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;
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;
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);
}
}
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));
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);
/*===========================================================================*
* map_printmap *
*===========================================================================*/
-PRIVATE void map_printmap(vmp)
+PUBLIC void map_printmap(vmp)
struct vmproc *vmp;
{
struct vir_region *vr;
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 ",
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;
}
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;
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__); \
#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: */