* and sys_fork
*/
#define PR_FORK_FLAGS m1_i3
+#define PR_FORK_MSGADDR m1_p1
/* Field names for SYS_INT86 */
#define INT86_REG86 m1_p1 /* pointer to registers */
_PROTOTYPE( int sys_exec, (endpoint_t proc, char *ptr,
char *aout, vir_bytes initpc));
_PROTOTYPE( int sys_fork, (endpoint_t parent, endpoint_t child, int *,
- struct mem_map *ptr, u32_t vm));
+ struct mem_map *ptr, u32_t vm, vir_bytes *));
_PROTOTYPE( int sys_newmap, (endpoint_t proc, struct mem_map *ptr));
_PROTOTYPE( int sys_exit, (endpoint_t proc));
_PROTOTYPE( int sys_trace, (int req, endpoint_t proc, long addr, long *data_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:
{
+ int r;
/* VM wants kernel to increase its segment. */
- kprintf("kernel: increase limit to 0x%x\n",
- m_ptr->SVMCTL_VALUE);
- return prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
+ r = prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
+ return r;
}
case VMCTL_I386_PAGEDIRS:
{
int pde;
vm_pagedirs = (u32_t *) m_ptr->SVMCTL_VALUE;
- kprintf("kernel: pagedirs now 0x%lx\n", vm_pagedirs);
return OK;
}
case VMCTL_I386_FREEPDE:
}
}
+
+
kprintf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
return EINVAL;
}
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)
(vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
return(EFAULT);
}
+ /* current process must be target for phys_* to be OK */
+ if(proc_addr(proc_nr) != ptproc) {
+ kprintf("do_sdevio: wrong process\n");
+ return EIO;
+ }
switch (io_type)
{
return(EINVAL);
}
return(OK);
-#endif
}
#endif /* USE_SDEVIO */
#include <string.h>
#include <minix/sysutil.h>
#include "../../proc.h"
+#include "../../proto.h"
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 *old_eip_ptr = NULL, *old_eax_ptr = NULL;
vir_bytes ph;
u32_t pte;
int procok = 0, pcok = 0, rangeok = 0;
+ int in_memcpy = 0, in_physcopy = 0;
vmassert(old_eip_ptr);
vmassert(old_eax_ptr);
vmassert(pagefault_count == 1);
- if(catch_pagefaults &&
- (rangeok = (pagefault_cr2 >= catchrange_lo &&
- pagefault_cr2 < catchrange_hi))) {
+ if(catch_pagefaults) {
vir_bytes test_eip;
test_eip = k_reenter ? old_eip : pr->p_reg.pc;
- if((pcok = ((test_eip > (vir_bytes) _memcpy_k) &&
- (test_eip < (vir_bytes) _memcpy_k_fault)))) {
- kprintf("handling pagefault during copy\n");
+ in_memcpy = (test_eip > (vir_bytes) _memcpy_k) &&
+ (test_eip < (vir_bytes) _memcpy_k_fault);
+ in_physcopy = (test_eip > (vir_bytes) phys_copy) &&
+ (test_eip < (vir_bytes) phys_copy_fault);
+ if((pcok = in_memcpy || in_physcopy)) {
pagefault_count = 0;
- *old_eip_ptr = _memcpy_k_fault;
+ if(in_memcpy) {
+ vmassert(!in_physcopy);
+ *old_eip_ptr = _memcpy_k_fault;
+ }
+ if(in_physcopy) {
+ vmassert(!in_memcpy);
+ *old_eip_ptr = phys_copy_fault;
+ }
*old_eax_ptr = pagefault_cr2;
return;
}
}
- kprintf("kernel stacktrace in pagefault: ");
- util_stacktrace();
-
- if(catch_pagefaults) {
- kprintf("procok: %d pcok: %d rangeok: %d\n",
- procok, pcok, rangeok);
- printf("k_reenter: %d addr: 0x%lx range: 0x%lx-0x%lx pc: 0x%lx\n",
- k_reenter, pagefault_cr2, catchrange_lo, catchrange_hi, pr->p_reg.pc);
- }
-
/* 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).
pr->p_pagefault.pf_flags = trap_errno;
pr->p_nextpagefault = pagefaults;
pagefaults = pr;
- soft_notify(VM_PROC_NR);
+
+ lock_notify(SYSTEM, VM_PROC_NR);
pagefault_count = 0;
-#if 0
- kprintf("pagefault for process %d ('%s'), pc = 0x%x\n",
- pr->p_endpoint, pr->p_name, pr->p_reg.pc);
- proc_stacktrace(pr);
-#endif
-
return;
}
register struct ex_s *ep;
struct proc *saved_proc;
-#if DEBUG_SCHED_CHECK
- for (t = BEG_PROC_ADDR; t < END_PROC_ADDR; ++t) {
- if(t->p_magic != PMAGIC)
- kprintf("entry %d broken\n", t->p_nr);
- }
-#endif
-
/* Save proc_ptr, because it may be changed by debug statements. */
saved_proc = proc_ptr;
#include <ibm/interrupt.h>
#include <archconst.h>
#include "../../const.h"
-#include "vm.h"
#include "sconst.h"
! This file contains a number of assembly code utility routines needed by the
.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 _phys_copy_fault! phys_copy pagefault
.define _phys_memset ! write pattern anywhere in memory
.define _mem_rdw ! copy one word from [segment:offset]
.define _reset ! reset the system
.define _level0 ! call a function at level 0
.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 _i386_invlpg_level0
.define __memcpy_k
.define __memcpy_k_fault
+.define _catch_pagefaults
! The routines only guarantee to preserve the registers the C compiler
! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
!*===========================================================================*
! 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
-!
-! 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
-!
-! 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
-!
-! 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
-!
-! 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
!*==========================================================================*
!*===========================================================================*
!* phys_copy *
!*===========================================================================*
-! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
+! PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination,
! phys_bytes bytecount);
! Copy a block of physical memory.
mov edi, PC_ARGS+4(esp)
mov eax, PC_ARGS+4+4(esp)
+ mov (_catch_pagefaults), 1
+
cmp eax, 10 ! avoid align overhead for small counts
jb pc_small
mov ecx, esi ! align source, hope target is too
pop es
pop edi
pop esi
+ mov eax, 0 ! 0 means: no fault
+_phys_copy_fault: ! kernel can send us here
+ mov (_catch_pagefaults), 0
ret
!*===========================================================================*
pop ebp
ret
-!*===========================================================================*
-!* write_cr3 *
-!*===========================================================================*
-! PUBLIC void write_cr3(unsigned long value);
-_write_cr3:
- push ebp
- mov ebp, esp
- mov eax, 8(ebp)
- mov cr3, eax
- pop ebp
- ret
!*===========================================================================*
!* getcr3val *
!*===========================================================================*
! PUBLIC void i386_invlpg(void);
_i386_invlpg_level0:
- push ebp
- invlpg (_i386_invlpg_addr)
- pop ebp
+ mov eax, (_i386_invlpg_addr)
+ invlpg (eax)
ret
PRIVATE int psok = 0;
+extern u32_t createpde, linlincopies, physzero;
+
#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. */
-PUBLIC u32_t kernel_cr3;
-#endif
-
-extern u32_t cswitch;
-u32_t last_cr3 = 0;
u8_t *vm_pagedirs = NULL;
ptproc->p_seg.p_cr3);
vmassert(newcr3);
- 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());
-
- kprintf("vm_init: writing cr3 0x%lx\n", newcr3);
-
/* Set this cr3 now (not active until paging enabled). */
vm_set_cr3(newcr3);
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;
{
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 | 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. */
- 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;
- 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);
}
/* Connect caller on vmrequest wait queue. */
caller->p_vmrequest.nextrequestor = vmrequest;
vmrequest = caller;
- if(!caller->p_vmrequest.nextrequestor) {
- soft_notify(VM_PROC_NR);
- }
+ if(!caller->p_vmrequest.nextrequestor)
+ lock_notify(SYSTEM, VM_PROC_NR);
}
/*===========================================================================*
limit = lin + bytes - 1;
o = lin % I386_PAGE_SIZE;
lin -= o;
- limit += o;
- limit &= I386_VM_PT_ENT_MASK;
- FIXME("invlpg_range reloads cr3");
- cr3 = read_cr3();
- vm_set_cr3(cr3);
+ limit = (limit + o) & I386_VM_ADDR_MASK;
for(i386_invlpg_addr = lin; i386_invlpg_addr <= limit;
i386_invlpg_addr += I386_PAGE_SIZE)
level0(i386_invlpg_level0);
* 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) { \
+ FIXME("CREATEPDE: check if invlpg is necessary"); \
+ if(PROC == ptproc) { \
+ FIXME("CREATEPDE: use in-memory process"); \
+ } \
if((PROC) && iskernelp(PROC) && SEG == D) { \
PTR = VIRT; \
OFFSET = 0; \
vmassert(psok); \
pde_index = I386_VM_PDE(LINADDR); \
vmassert(!iskernelp(PROC)); \
+ createpde++; \
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); \
- } \
} else { \
pdeval = (LINADDR & I386_VM_ADDR_MASK_4MB) | \
I386_VM_BIGPAGE | I386_VM_PRESENT | \
} \
}
+
+/*===========================================================================*
+ * arch_switch_copymsg *
+ *===========================================================================*/
+phys_bytes arch_switch_copymsg(struct proc *rp, message *m, phys_bytes lin)
+{
+ phys_bytes r;
+ if(rp->p_seg.p_cr3) {
+ vm_set_cr3(rp->p_seg.p_cr3);
+ ptproc = rp;
+ }
+ r = phys_copy(vir2phys(m), lin, sizeof(message));
+}
+
/*===========================================================================*
* lin_lin_copy *
*===========================================================================*/
{
u32_t addr;
int procslot;
- u32_t catchrange_dst;
+ u32_t catchrange_dst, catchrange_lo, catchrange_hi;
NOREC_ENTER(linlincopy);
+ linlincopies++;
+
if(srcproc && dstproc && iskernelp(srcproc) && iskernelp(dstproc)) {
memcpy(vdst, vsrc, bytes);
NOREC_RETURN(linlincopy, OK);
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);
{
char *v;
+ physzero++;
+
if(!vm_running) {
u32_t p;
p = c | (c << 8) | (c << 16) | (c << 24);
ph += chunk;
}
+
return OK;
}
caller = proc_addr(who_p);
- printf("virtual_copy: suspending caller %d / %s\n",
- caller->p_endpoint, caller->p_name);
+ vmassert(procs[_SRC_] && procs[_DST_]);
if(r == EFAULT_SRC) {
caller->p_vmrequest.start = phys_addr[_SRC_];
minix_panic("r strange", r);
}
+#if 0
+ printf("virtual_copy: suspending caller %d / %s, target %d / %s\n",
+ caller->p_endpoint, caller->p_name,
+ target->p_endpoint, target->p_name);
+#endif
+
caller->p_vmrequest.length = bytes;
caller->p_vmrequest.who = target->p_endpoint;
if(nfreepdes >= WANT_FREEPDES)
return;
freepdes[nfreepdes++] = pde;
- printf("kernel: free pde: %d\n", pde);
}
#include <ibm/interrupt.h>
#include <archconst.h>
#include "../../const.h"
-#include "vm.h"
#include "sconst.h"
/* Selected 386 tss offsets. */
.define _pagefault_count
.define _old_eip_ptr
.define _old_eax_ptr
+.define _cr3_test
+.define _cr3_reload
+.define _write_cr3 ! write cr3
.define errexception
.define exception1
mov (_next_ptr), 0
0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
lldt P_LDT_SEL(esp) ! enable process' segment descriptors
+ inc (_cr3_test)
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
+ cmp eax, (loadedcr3)
jz noload
+ inc (_cr3_reload)
mov cr3, eax
+ mov (loadedcr3), eax
mov eax, (_proc_ptr)
mov (_ptproc), eax
noload:
add esp, 5*4
ret
+
+!*===========================================================================*
+!* write_cr3 *
+!*===========================================================================*
+! PUBLIC void write_cr3(unsigned long value);
+_write_cr3:
+ push ebp
+ mov ebp, esp
+ mov eax, 8(ebp)
+ mov cr3, eax
+ mov (loadedcr3), eax
+ pop ebp
+ ret
+
!*===========================================================================*
!* level0_call *
!*===========================================================================*
.comm old_eip, 4
.comm old_cs, 4
.comm old_eflags, 4
+ .comm loadedcr3, 4
int orig_click;
int incr_clicks;
- kprintf("prot_set_kern_seg_limit: limit 0x%lx\n", limit);
-
if(limit <= kinfo.data_base) {
kprintf("prot_set_kern_seg_limit: limit bogus\n");
return EINVAL;
}
- kprintf("size: 0x%lx -> ", kinfo.data_size);
-
/* Do actual increase. */
orig_click = kinfo.data_size / CLICK_SIZE;
kinfo.data_size = limit - kinfo.data_base;
incr_clicks = kinfo.data_size / CLICK_SIZE - orig_click;
- kprintf("0x%lx\n", kinfo.data_size);
-
- kprintf("prot_set_kern_seg_limit: prot_init\n");
-
prot_init();
- kprintf("prot_set_kern_seg_limit: prot_init done\n");
-
/* Increase kernel processes too. */
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
if (RTS_ISSET(rp, SLOT_FREE) || !iskernelp(rp))
continue;
- kprintf("prot_set_kern_seg_limit: increase %d 0x%x ->\n",
- rp->p_endpoint, rp->p_memmap[S].mem_len);
rp->p_memmap[S].mem_len += incr_clicks;
alloc_segments(rp);
- kprintf("prot_set_kern_seg_limit: increase %d done -> 0x%x\n",
- rp->p_endpoint, rp->p_memmap[S].mem_len);
}
- kprintf("prot_set_kern_seg_limit: done\n");
return OK;
}
level++;
- kprintf("%*s %d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s ",
+ kprintf("%*s %d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s misc %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));
+ pp->p_sys_time, pp->p_seg.p_cr3,
+ rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags));
if(pp->p_rts_flags & SENDING) {
dep = pp->p_sendto_e;
minix_panic("check_runqueues called with interrupts enabled", NO_NUM);
}
+ FIXME("check_runqueues being done");
+
#define MYPANIC(msg) { \
kprintf("check_runqueues:%s:%d: %s\n", file, line, msg); \
minix_panic("check_runqueues failed", NO_NUM); \
return str;
}
+PUBLIC char *
+miscflagstr(int flags)
+{
+ static char str[100];
+ str[0] = '\0';
+
+ FLAG(MF_REPLY_PEND);
+ FLAG(MF_ASYNMSG);
+ FLAG(MF_FULLVM);
+ FLAG(MF_DELIVERMSG);
+
+ return str;
+}
+
#define DEBUG_TIME_LOCKS 1
/* Runtime sanity checking. */
-#define DEBUG_VMASSERT 1
-#define DEBUG_SCHED_CHECK 1
+#define DEBUG_VMASSERT 0
+#define DEBUG_SCHED_CHECK 0
#define NOREC_ENTER(varname) \
static int varname = 0; \
return v; \
} while(0)
-
#if DEBUG_VMASSERT
#define vmassert(t) { \
+ FIXME("vmassert on"); \
if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } }
#else
#define vmassert(t) { }
EXTERN struct proc *vmrestart; /* first process on vmrestart queue */
EXTERN struct proc *vmrequest; /* first process on vmrequest queue */
EXTERN struct proc *pagefaults; /* first process on pagefault queue */
-EXTERN struct proc *softnotify; /* first process on softnotify queue */
EXTERN char k_reenter; /* kernel reentry count (entry count less 1) */
EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */
#endif
#if DEBUG_VMASSERT
FIXME("DEBUG_VMASSERT enabled");
+#endif
+#if DEBUG_PROC_CHECK
+ FIXME("PROC check enabled");
#endif
restart();
}
FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front));
FORWARD _PROTOTYPE( void pick_proc, (void));
-#define BuildMess(m_ptr, src, dst_ptr) \
- (m_ptr)->m_source = proc_addr(src)->p_endpoint; \
+#define BuildNotifyMessage(m_ptr, src, dst_ptr) \
(m_ptr)->m_type = NOTIFY_FROM(src); \
(m_ptr)->NOTIFY_TIMESTAMP = get_uptime(); \
switch (src) { \
break; \
}
-#define RETRYCOPY(sp, dp, sm, dm) {\
- if(r != EFAULT_DST) { \
- kprintf("error %d\n", r); \
- minix_panic("CopyMess: copy error", __LINE__); \
- } \
- minix_panic("parameters unknown", NO_NUM); \
- (dp)->p_vmrequest.saved.msgcopy.dst = (dp); \
- (dp)->p_vmrequest.saved.msgcopy.dst_v = (vir_bytes) dm; \
- (dp)->p_vmrequest.saved.msgcopy.msgbuf.m_source = e; \
- (dp)->p_vmrequest.type = VMSTYPE_MSGCOPY; \
- if(data_copy((sp)->p_endpoint, \
- (vir_bytes) (sm), SYSTEM, \
- (vir_bytes) &(dp)->p_vmrequest.saved.msgcopy.msgbuf, \
- sizeof(message)) != OK) { \
- minix_panic("CopyMess: data_copy failed", __LINE__);\
- } \
+#define Deliver(rp) do { \
+ vmassert(rp->p_misc_flags & MF_DELIVERMSG); \
+ vmassert(rp->p_delivermsg_lin); \
+ if(arch_switch_copymsg(rp, &rp->p_delivermsg, \
+ rp->p_delivermsg_lin)) { \
+ minix_panic("MF_DELIVERMSG copy failed", NO_NUM); \
+ } \
+ rp->p_delivermsg.m_source = NONE; \
+ rp->p_delivermsg_lin = 0; \
+ rp->p_misc_flags &= ~MF_DELIVERMSG; \
+ } while(0)
+
+/*===========================================================================*
+ * QueueMess *
+ *===========================================================================*/
+PRIVATE int QueueMess(endpoint_t ep, vir_bytes msg_lin, struct proc *dst)
+{
+ /* Queue a message from the src process (in memory) to the dst
+ * process (using dst process table entry). Do actual copy here;
+ * it's an error if the copy fails.
+ */
+ vmassert(!(dst->p_misc_flags & MF_DELIVERMSG));
+ vmassert(dst->p_delivermsg_lin);
+ if(phys_copy(msg_lin, vir2phys(&dst->p_delivermsg),
+ sizeof(message))) {
+ return EFAULT;
+ }
+ dst->p_delivermsg.m_source = ep;
+ dst->p_misc_flags |= MF_DELIVERMSG;
+ if(iskernelp(dst) || ptproc == dst) {
+ Deliver(dst);
}
-#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((r=virtual_copy(&src, &dst, sizeof(e))) != OK) { \
- RETRYCOPY(sp, dp, sm, dm) \
- } \
- } \
-} while(0)
+ return OK;
+}
/*===========================================================================*
* sys_call *
int result; /* the system call's result */
int src_dst_p; /* Process slot number */
size_t msg_size;
+ phys_bytes linaddr = 0;
+
+#if DEBUG_SCHED_CHECK
+ if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
+ kprintf("sys_call: MF_DELIVERMSG on for %s / %d\n",
+ caller_ptr->p_name, caller_ptr->p_endpoint);
+ minix_panic("MF_DELIVERMSG on", NO_NUM);
+ }
+#endif
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.total= add64u(ipc_stats.total, 1);
}
#endif
-#if 1
+#if DEBUG_SCHED_CHECK
if (RTS_ISSET(caller_ptr, SLOT_FREE))
{
kprintf("called by the dead?!?\n");
#if DEBUG_ENABLE_IPC_WARNINGS
kprintf(
"sys_call: ipc mask denied trap %d from %d to %d\n",
- call_nr, proc_nr(caller_ptr), src_dst_p);
+ call_nr, caller_ptr->p_endpoint, src_dst_e);
#endif
if (caller_ptr->p_endpoint == ipc_stats_target)
ipc_stats.dst_not_allowed++;
msg_size = sizeof(*m_ptr);
}
- /* If the call involves a message buffer, i.e., for SEND, SENDREC,
- * or RECEIVE, check the message pointer. This check allows a message to be
- * anywhere in data or stack or gap. It will have to be made more elaborate
- * for machines which don't have the gap mapped.
- *
- * We use msg_size decided above.
- */
- if (call_nr == SEND || call_nr == SENDREC ||
- call_nr == RECEIVE || call_nr == SENDA || call_nr == SENDNB) {
- int r;
- phys_bytes lin;
-
- /* Map to linear address. */
- if(msg_size > 0 &&
- (lin = umap_local(caller_ptr, D, (vir_bytes) m_ptr, msg_size)) == 0) {
- kprintf("umap_local failed for %s / %d on 0x%lx size %d\n",
- caller_ptr->p_name, caller_ptr->p_endpoint,
- m_ptr, msg_size);
- return EFAULT;
- }
-
- /* Check if message pages in calling process are mapped.
- * We don't have to check the recipient if this is a send,
- * because this code will do that before its receive() starts.
- *
- * It is important the range is verified as _writable_, because
- * the kernel will want to write to the SENDA buffer in the future,
- * and those pages may not be shared between processes.
- */
-
- if(vm_running && msg_size > 0 &&
- (r=vm_checkrange(caller_ptr, caller_ptr, lin, msg_size, 1, 0)) != OK) {
- if(r != VMSUSPEND) {
- kprintf("SYSTEM:sys_call:vm_checkrange: err %d\n", r);
- return r;
- }
-
- /* We can't go ahead with this call. Caller is suspended
- * and we have to save the state in its process struct.
- */
- caller_ptr->p_vmrequest.saved.sys_call.call_nr = call_nr;
- caller_ptr->p_vmrequest.saved.sys_call.m_ptr = m_ptr;
- caller_ptr->p_vmrequest.saved.sys_call.src_dst_e = src_dst_e;
- caller_ptr->p_vmrequest.saved.sys_call.bit_map = bit_map;
- caller_ptr->p_vmrequest.type = VMSTYPE_SYS_CALL;
-
- kprintf("SYSTEM: %s:%d: suspending call 0x%lx on ipc buffer 0x%lx length 0x%lx\n",
- caller_ptr->p_name, caller_ptr->p_endpoint, call_nr, m_ptr, msg_size);
-
- /* vm_checkrange() will have suspended caller with VMREQUEST. */
- return OK;
- }
-
- }
-
/* Check for a possible deadlock for blocking SEND(REC) and RECEIVE. */
if (call_nr == SEND || call_nr == SENDREC || call_nr == RECEIVE) {
if (group_size = deadlock(call_nr, caller_ptr, src_dst_p)) {
switch(call_nr) {
case SENDREC:
/* A flag is set so that notifications cannot interrupt SENDREC. */
- caller_ptr->p_misc_flags |= REPLY_PENDING;
+ caller_ptr->p_misc_flags |= MF_REPLY_PEND;
/* fall through */
case SEND:
result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
/* fall through for SENDREC */
case RECEIVE:
if (call_nr == RECEIVE)
- caller_ptr->p_misc_flags &= ~REPLY_PENDING;
+ caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
break;
case NOTIFY:
return(0); /* not a deadlock */
}
-/*===========================================================================*
- * sys_call_restart *
- *===========================================================================*/
-PUBLIC void sys_call_restart(caller)
-struct proc *caller;
-{
- int r;
- kprintf("restarting sys_call code 0x%lx, "
- "m_ptr 0x%lx, srcdst %d, bitmap 0x%lx, but not really\n",
- caller->p_vmrequest.saved.sys_call.call_nr,
- caller->p_vmrequest.saved.sys_call.m_ptr,
- caller->p_vmrequest.saved.sys_call.src_dst_e,
- caller->p_vmrequest.saved.sys_call.bit_map);
- caller->p_reg.retreg = r;
-}
-
/*===========================================================================*
* mini_send *
*===========================================================================*/
register struct proc *dst_ptr;
register struct proc **xpp;
int dst_p;
+ phys_bytes linaddr;
+ int r;
+ if(!(linaddr = umap_local(caller_ptr, D, (vir_bytes) m_ptr,
+ sizeof(message)))) {
+ return EFAULT;
+ }
dst_p = _ENDPOINT_P(dst_e);
dst_ptr = proc_addr(dst_p);
*/
if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) {
/* Destination is indeed waiting for this message. */
- CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
- dst_ptr->p_messbuf);
+ vmassert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));
+ if((r=QueueMess(caller_ptr->p_endpoint, linaddr, dst_ptr)) != OK)
+ return r;
RTS_UNSET(dst_ptr, RECEIVING);
} else {
if(flags & NON_BLOCKING) {
}
/* Destination is not waiting. Block and dequeue caller. */
- caller_ptr->p_messbuf = m_ptr;
+ if(phys_copy(linaddr, vir2phys(&caller_ptr->p_sendmsg), sizeof(message))) {
+ return EFAULT;
+ }
RTS_SET(caller_ptr, SENDING);
caller_ptr->p_sendto_e = dst_e;
sys_map_t *map;
bitchunk_t *chunk;
int i, r, src_id, src_proc_nr, src_p;
+ phys_bytes linaddr;
+
+ vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
+
+ if(!(linaddr = umap_local(caller_ptr, D, (vir_bytes) m_ptr,
+ sizeof(message)))) {
+ return EFAULT;
+ }
+
+ /* This is where we want our message. */
+ caller_ptr->p_delivermsg_lin = linaddr;
if(src_e == ANY) src_p = ANY;
else
if (!RTS_ISSET(caller_ptr, SENDING)) {
/* Check if there are pending notifications, except for SENDREC. */
- if (! (caller_ptr->p_misc_flags & REPLY_PENDING)) {
+ if (! (caller_ptr->p_misc_flags & MF_REPLY_PEND)) {
map = &priv(caller_ptr)->s_notify_pending;
for (chunk=&map->chunk[0]; chunk<&map->chunk[NR_SYS_CHUNKS]; chunk++) {
*chunk &= ~(1 << i); /* no longer pending */
/* Found a suitable source, deliver the notification message. */
- BuildMess(&m, src_proc_nr, caller_ptr); /* assemble message */
- CopyMess(src_proc_nr, proc_addr(HARDWARE), &m, caller_ptr, m_ptr);
+ BuildNotifyMessage(&m, src_proc_nr, caller_ptr); /* assemble message */
+ vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
+ if((r=QueueMess(src_proc_nr, vir2phys(&m), caller_ptr)) != OK) {
+ minix_panic("mini_receive: local QueueMess failed", NO_NUM);
+ }
return(OK); /* report success */
}
}
xpp = &caller_ptr->p_caller_q;
while (*xpp != NIL_PROC) {
if (src_e == ANY || src_p == proc_nr(*xpp)) {
-#if 1
+#if DEBUG_SCHED_CHECK
if (RTS_ISSET(*xpp, SLOT_FREE) || RTS_ISSET(*xpp, NO_ENDPOINT))
{
kprintf("%d: receive from %d; found dead %d (%s)?\n",
#endif
/* Found acceptable message. Copy it and update status. */
- CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);
+ FIXME("message copied twice here");
+ vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
+ QueueMess((*xpp)->p_endpoint,
+ vir2phys(&(*xpp)->p_sendmsg), caller_ptr);
RTS_UNSET(*xpp, SENDING);
*xpp = (*xpp)->p_q_link; /* remove from queue */
return(OK); /* report success */
}
else
{
- caller_ptr->p_messbuf = m_ptr;
r= try_async(caller_ptr);
}
if (r == OK)
*/
if ( ! (flags & NON_BLOCKING)) {
caller_ptr->p_getfrom_e = src_e;
- caller_ptr->p_messbuf = m_ptr;
RTS_SET(caller_ptr, RECEIVING);
return(OK);
} else {
register struct proc *dst_ptr = proc_addr(dst);
int src_id; /* source id for late delivery */
message m; /* the notification message */
+ int r;
/* Check to see if target is blocked waiting for this message. A process
* can be both sending and receiving during a SENDREC system call.
*/
if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint) &&
- ! (dst_ptr->p_misc_flags & REPLY_PENDING)) {
+ ! (dst_ptr->p_misc_flags & MF_REPLY_PEND)) {
/* Destination is indeed waiting for a message. Assemble a notification
* message and deliver it. Copy from pseudo-source HARDWARE, since the
* message is in the kernel's address space.
*/
- BuildMess(&m, proc_nr(caller_ptr), dst_ptr);
- CopyMess(proc_nr(caller_ptr), proc_addr(HARDWARE), &m,
- dst_ptr, dst_ptr->p_messbuf);
+ BuildNotifyMessage(&m, proc_nr(caller_ptr), dst_ptr);
+ vmassert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));
+ if((r=QueueMess(caller_ptr->p_endpoint, vir2phys(&m), dst_ptr)) != OK) {
+ minix_panic("mini_notify: local QueueMess failed", NO_NUM);
+ }
RTS_UNSET(dst_ptr, RECEIVING);
return(OK);
}
asynmsg_t *table;
size_t size;
{
- int i, dst_p, done, do_notify;
+ int i, dst_p, done, do_notify, r;
unsigned flags;
struct proc *dst_ptr;
struct priv *privp;
message *m_ptr;
asynmsg_t tabent;
vir_bytes table_v = (vir_bytes) table;
+ vir_bytes linaddr;
+
+ if(!(linaddr = umap_local(caller_ptr, D, (vir_bytes) table,
+ size * sizeof(*table)))) {
+ return EFAULT;
+ }
privp= priv(caller_ptr);
if (!(privp->s_flags & SYS_PROC))
continue;
}
-#if 0
- kprintf("mini_senda: entry[%d]: flags 0x%x dst %d/%d\n",
- i, tabent.flags, tabent.dst, dst_p);
-#endif
-
dst_ptr = proc_addr(dst_p);
/* NO_ENDPOINT should be removed */
m_ptr= &table[i].msg; /* Note: pointer in the
* caller's address space.
*/
- CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
- dst_ptr->p_messbuf);
+ /* Copy message from sender. */
+ tabent.result= QueueMess(caller_ptr->p_endpoint,
+ linaddr + (vir_bytes) &table[i].msg -
+ (vir_bytes) table, dst_ptr);
+ if(tabent.result == OK)
+ RTS_UNSET(dst_ptr, RECEIVING);
- RTS_UNSET(dst_ptr, RECEIVING);
-
- tabent.result= OK;
A_INSERT(i, result);
tabent.flags= flags | AMF_DONE;
A_INSERT(i, flags);
{
privp->s_asyntab= (vir_bytes)table;
privp->s_asynsize= size;
-#if 0
- if(caller_ptr->p_endpoint > INIT_PROC_NR) {
- kprintf("kernel: %s (%d) asynsend table at 0x%lx, %d\n",
- caller_ptr->p_name, caller_ptr->p_endpoint,
- table, size);
- }
-#endif
}
return OK;
}
int r;
struct priv *privp;
struct proc *src_ptr;
-
+
/* Try all privilege structures */
for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; ++privp)
{
continue;
if (privp->s_asynsize == 0)
continue;
-#if 0
- kprintf("try_async: found asyntable for proc %d\n",
- privp->s_proc_nr);
-#endif
src_ptr= proc_addr(privp->s_proc_nr);
+ vmassert(!(caller_ptr->p_misc_flags & MF_DELIVERMSG));
r= try_one(src_ptr, caller_ptr);
if (r == OK)
return r;
asynmsg_t tabent;
vir_bytes table_v;
struct proc *caller_ptr;
+ int r;
privp= priv(src_ptr);
size= privp->s_asynsize;
m_ptr= &table_ptr[i].msg; /* Note: pointer in the
* caller's address space.
*/
- CopyMess(src_ptr->p_nr, src_ptr, m_ptr, dst_ptr,
- dst_ptr->p_messbuf);
+ A_RETRIEVE(i, msg);
+ r = QueueMess(src_ptr->p_endpoint, vir2phys(&tabent.msg),
+ dst_ptr);
- tabent.result= OK;
+ tabent.result= r;
A_INSERT(i, result);
tabent.flags= flags | AMF_DONE;
A_INSERT(i, flags);
return(result);
}
-/*===========================================================================*
- * soft_notify *
- *===========================================================================*/
-PUBLIC int soft_notify(dst_e)
-int dst_e; /* (endpoint) who is to be notified */
-{
- int dst, u = 0;
- struct proc *dstp, *sys = proc_addr(SYSTEM);
-
-/* Delayed interface to notify() from SYSTEM that is safe/easy to call
- * from more places than notify().
- */
- if(!intr_disabled()) { lock; u = 1; }
-
- {
- if(!isokendpt(dst_e, &dst))
- minix_panic("soft_notify to dead ep", dst_e);
-
- dstp = proc_addr(dst);
-
- if(!dstp->p_softnotified) {
- dstp->next_soft_notify = softnotify;
- softnotify = dstp;
- dstp->p_softnotified = 1;
-
- if (RTS_ISSET(sys, RECEIVING)) {
- sys->p_messbuf->m_source = SYSTEM;
- RTS_UNSET(sys, RECEIVING);
- }
- }
- }
-
- if(u) { unlock; }
-
- return OK;
-}
-
/*===========================================================================*
* enqueue *
*===========================================================================*/
*/
for (q=0; q < NR_SCHED_QUEUES; q++) {
if ( (rp = rdy_head[q]) != NIL_PROC) {
+ if(rp->p_misc_flags & MF_DELIVERMSG) {
+ /* Want to schedule process, but have to copy a message
+ * first.
+ */
+ FIXME("MF_DELIVERMSG no callback");
+ Deliver(rp);
+ }
next_ptr = rp; /* run process 'rp' next */
#if 0
if(!iskernelp(rp))
unlock;
}
}
-#if DEBUG
- kprintf("ticks_added: %d\n", ticks_added);
-#endif
/* Now schedule a new watchdog timer to balance the queues again. The
* period depends on the total amount of quantum ticks added.
*p = _ENDPOINT_P(e);
if(!isokprocn(*p)) {
#if DEBUG_ENABLE_IPC_WARNINGS
-#if 0
kprintf("kernel:%s:%d: bad endpoint %d: proc %d out of range\n",
file, line, e, *p);
-#endif
#endif
} else if(isemptyn(*p)) {
#if DEBUG_ENABLE_IPC_WARNINGS
-#if 0
kprintf("kernel:%s:%d: bad endpoint %d: proc %d empty\n", file, line, e, *p);
-#endif
#endif
} else if(proc_addr(*p)->p_endpoint != e) {
#if DEBUG_ENABLE_IPC_WARNINGS
-#if 0
kprintf("kernel:%s:%d: bad endpoint %d: proc %d has ept %d (generation %d vs. %d)\n", file, line,
e, *p, proc_addr(*p)->p_endpoint,
_ENDPOINT_G(e), _ENDPOINT_G(proc_addr(*p)->p_endpoint));
-#endif
#endif
} else ok = 1;
if(!ok && fatalflag) {
struct proc *p_nextready; /* pointer to next ready process */
struct proc *p_caller_q; /* head of list of procs wishing to send */
struct proc *p_q_link; /* link to next proc wishing to send */
- message *p_messbuf; /* pointer to passed message buffer */
int p_getfrom_e; /* from whom does process want to receive? */
int p_sendto_e; /* to whom does process want to send? */
endpoint_t p_endpoint; /* endpoint number, generation-aware */
+ message p_sendmsg; /* Message from this process if SENDING */
+ message p_delivermsg; /* Message for this process if MF_DELIVERMSG */
+ vir_bytes p_delivermsg_lin; /* Linear addr this proc wants message at */
+
/* If handler functions detect a process wants to do something with
* memory that isn't present, VM has to fix it. Until it has asked
* what needs to be done and fixed it, save necessary state here.
struct proc *nextrequestor; /* next in vmrequest chain */
#define VMSTYPE_SYS_NONE 0
#define VMSTYPE_SYS_MESSAGE 1
-#define VMSTYPE_SYS_CALL 2
-#define VMSTYPE_MSGCOPY 3
int type; /* suspended operation */
union {
/* VMSTYPE_SYS_MESSAGE */
message reqmsg; /* suspended request message */
-
- /* VMSTYPE_SYS_CALL */
- struct {
- int call_nr;
- message *m_ptr;
- int src_dst_e;
- long bit_map;
- } sys_call;
-
- /* VMSTYPE_MSGCOPY */
- struct {
- struct proc *dst;
- vir_bytes dst_v;
- message msgbuf;
- } msgcopy;
} saved;
/* Parameters of request to VM */
#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. */
} while(0)
/* Misc flags */
-#define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */
-#define MF_VM 0x08 /* process uses VM */
+#define MF_REPLY_PEND 0x01 /* reply to IPC_REQUEST is pending */
#define MF_ASYNMSG 0x10 /* Asynchrous message pending */
#define MF_FULLVM 0x20
+#define MF_DELIVERMSG 0x40 /* Copy message for him before running */
/* Scheduling priorities for p_priority. Values must start at zero (highest
* priority) and increment. Priorities of the processes in the boot image
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 lock_send, (int dst, message *m_ptr) );
_PROTOTYPE( void lock_enqueue, (struct proc *rp) );
_PROTOTYPE( void lock_dequeue, (struct proc *rp) );
_PROTOTYPE( void check_runqueues_f, (char *file, int line) );
#endif
_PROTOTYPE( char *rtsflagstr, (int flags) );
+_PROTOTYPE( char *miscflagstr, (int flags) );
/* system/do_safecopy.c */
_PROTOTYPE( int verify_grant, (endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes,
#endif
/* functions defined in architecture-dependent files. */
-_PROTOTYPE( void phys_copy, (phys_bytes source, phys_bytes dest,
+_PROTOTYPE( phys_bytes phys_copy, (phys_bytes source, phys_bytes dest,
phys_bytes count) );
+_PROTOTYPE( void phys_copy_fault, (void));
#define virtual_copy(src, dst, bytes) virtual_copy_f(src, dst, bytes, 0)
#define virtual_copy_vmcheck(src, dst, bytes) virtual_copy_f(src, dst, bytes, 1)
_PROTOTYPE( int virtual_copy_f, (struct vir_addr *src, struct vir_addr *dst,
_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));
+_PROTOTYPE( phys_bytes arch_switch_copymsg, (struct proc *rp, message *m,
+ phys_bytes lin));
#endif /* PROTO_H */
call_vec[(call_nr-KERNEL_CALL)] = (handler)
FORWARD _PROTOTYPE( void initialize, (void));
-FORWARD _PROTOTYPE( void softnotify_check, (void));
FORWARD _PROTOTYPE( struct proc *vmrestart_check, (message *));
+u32_t cr3_test, cr3_reload, createpde, linlincopies, physzero;
+
/*===========================================================================*
* sys_task *
*===========================================================================*/
/* Initialize the system task. */
initialize();
+
while (TRUE) {
struct proc *restarting;
restarting = vmrestart_check(&m);
- softnotify_check();
- if(softnotify)
- minix_panic("softnotify non-NULL before receive (1)", NO_NUM);
if(!restarting) {
int r;
/* Get work. Block and wait until a request message arrives. */
- if(softnotify)
- minix_panic("softnotify non-NULL before receive (2)", NO_NUM);
if((r=receive(ANY, &m)) != OK)
minix_panic("receive() failed", r);
- if(m.m_source == SYSTEM)
- continue;
- if(softnotify)
- minix_panic("softnotify non-NULL after receive", NO_NUM);
}
+#if 1
+ {
+ static int prevu;
+ int u;
+ u = get_uptime();
+ if(u/system_hz != prevu/system_hz) {
+ printf("cr3 tests: %5lu reloads: %5lu createpde: %5lu linlincopies: %5lu physzero: %5lu\n",
+ cr3_test, cr3_reload, createpde, linlincopies, physzero);
+ cr3_test = 1;
+ cr3_reload = 0;
+ createpde = linlincopies = physzero = 0;
+ }
+ prevu = u;
+ }
+#endif
+
sys_call_code = (unsigned) m.m_type;
call_nr = sys_call_code - KERNEL_CALL;
who_e = m.m_source;
rp = proc_addr(proc_nr);
sigaddset(&priv(rp)->s_sig_pending, sig_nr);
- soft_notify(rp->p_endpoint);
+ lock_notify(SYSTEM, rp->p_endpoint);
}
/*===========================================================================*
#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
}
+#endif
/* Make sure that the exiting process is no longer scheduled. */
RTS_LOCK_SET(rc, NO_ENDPOINT);
#endif
}
}
-
- /* No pending soft notifies. */
- for(np = softnotify; np; np = np->next_soft_notify) {
- if(np == rc) {
- minix_panic("dying proc was on next_soft_notify", np->p_endpoint);
- }
- }
}
/*===========================================================================*
return umap_virtual(proc_addr(proc_nr), D, v_offset, bytes);
}
-/*===========================================================================*
- * softnotify_check *
- *===========================================================================*/
-PRIVATE void softnotify_check(void)
-{
- struct proc *np, *nextnp;
-
- if(!softnotify)
- return;
-
- for(np = softnotify; np; np = nextnp) {
- if(!np->p_softnotified)
- minix_panic("softnotify but no p_softnotified", NO_NUM);
- lock_notify(SYSTEM, np->p_endpoint);
- nextnp = np->next_soft_notify;
- np->next_soft_notify = NULL;
- np->p_softnotified = 0;
- }
-
- softnotify = NULL;
-}
-
/*===========================================================================*
* vmrestart_check *
*===========================================================================*/
}
}
return restarting;
- case VMSTYPE_SYS_CALL:
- kprintf("SYSTEM: restart sys_call\n");
- /* Restarting a kernel trap. */
- sys_call_restart(restarting);
-
- /* Handled; restart system loop. */
- 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,
- (vir_bytes) restarting->p_vmrequest.saved.msgcopy.dst_v,
- sizeof(message))) != OK) {
- minix_panic("SYSTEM: delayed msgcopy failed", r);
- }
- printf("OK!\n");
- RTS_LOCK_UNSET(restarting, VMREQUEST);
-
- /* Handled; restart system loop. */
- return NULL;
default:
minix_panic("strange restart type", type);
}
rp = proc_addr(proc);
+ if(rp->p_misc_flags & MF_DELIVERMSG) {
+ printf("%s / %d has MF_DELIVERMSG on during exec - clearing.\n",
+ rp->p_name, rp->p_endpoint);
+#if 1
+ rp->p_misc_flags &= ~MF_DELIVERMSG;
+ rp->p_delivermsg_lin = 0;
+#endif
+ }
+
/* Save command name for debugging, ps(1) output, etc. */
if(data_copy(who_e, (vir_bytes) m_ptr->PR_NAME_PTR,
SYSTEM, (vir_bytes) rp->p_name, (phys_bytes) P_NAME_LEN - 1) != OK)
/* 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 */
if(!isokendpt(m_ptr->PR_ENDPT, &p_proc))
return EINVAL;
+
rpp = proc_addr(p_proc);
rpc = proc_addr(m_ptr->PR_SLOT);
if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL);
+ vmassert(!(rpp->p_misc_flags & MF_DELIVERMSG));
+
+ /* needs to be receiving so we know where the message buffer is */
+ if(!RTS_ISSET(rpp, RECEIVING)) {
+ printf("kernel: fork not done synchronously?\n");
+ return EINVAL;
+ }
+
+ /* memory becomes readonly */
+ if (priv(rpp)->s_asynsize > 0) {
+ printf("kernel: process with waiting asynsend table can't fork\n");
+ return EINVAL;
+ }
+
map_ptr= (struct mem_map *) m_ptr->PR_MEM_PTR;
/* Copy parent 'proc' struct to child. And reinitialize some fields. */
/* Calculate endpoint identifier, so caller knows what it is. */
m_ptr->PR_ENDPT = rpc->p_endpoint;
+ m_ptr->PR_FORK_MSGADDR = (char *) rpp->p_delivermsg_lin;
/* Install new map */
r = newmap(rpc, map_ptr);
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;
}
if(!RTS_ISSET(rp, VMREQUEST))
minix_panic("do_vmctl: no VMREQUEST set", NO_NUM);
+#if 0
printf("kernel: vm request sent by: %s / %d about %d; 0x%lx-0x%lx, wr %d\n",
rp->p_name, rp->p_endpoint, rp->p_vmrequest.who,
rp->p_vmrequest.start,
rp->p_vmrequest.start + rp->p_vmrequest.length,
rp->p_vmrequest.writeflag);
+#endif
/* Reply with request fields. */
m_ptr->SVMCTL_MRG_ADDR = (char *) rp->p_vmrequest.start;
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;
rp->p_vmrequest.writeflag);
minix_panic("SYSTEM: fail but VM said OK", NO_NUM);
- }
+ }
}
#endif
return OK;
kprintf("\n");
}
+ kprintf("proc_ptr %s / %d\n", proc_ptr->p_name, proc_ptr->p_endpoint);
kprintf("kernel stacktrace: ");
util_stacktrace();
}
#define _VM_H 1
#define CHECKRANGE_OR_SUSPEND(pr, start, length, wr) { int mr; \
+ FIXME("CHECKRANGE_OR_SUSPEND exists"); \
if(vm_running && (mr=vm_checkrange(proc_addr(who_p), pr, start, length, wr, 0)) != OK) { \
return mr; \
} }
#include "syslib.h"
-PUBLIC int sys_fork(parent, child, child_endpoint, map_ptr, flags)
+PUBLIC int sys_fork(parent, child, child_endpoint, map_ptr, flags, msgaddr)
endpoint_t parent; /* process doing the fork */
endpoint_t child; /* which proc has been created by the fork */
int *child_endpoint;
struct mem_map *map_ptr;
u32_t flags;
+vir_bytes *msgaddr;
{
/* A process has forked. Tell the kernel. */
m.PR_FORK_FLAGS = flags;
r = _taskcall(SYSTASK, SYS_FORK, &m);
*child_endpoint = m.PR_ENDPT;
+ *msgaddr = m.PR_FORK_MSGADDR;
return r;
}
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 */
}
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 1
+#define DO_SANITYCHECKS 0
#if DO_SANITYCHECKS
#define SANITYCHECK do { \
if(who_p >= 0 && fproc[who_p].fp_endpoint != who_e) {
printf("FS: receive endpoint inconsistent (%d, %d, %d).\n",
who_e, fproc[who_p].fp_endpoint, who_e);
+#if 0
panic(__FILE__, "FS: inconsistent endpoint ", NO_NUM);
+#endif
continue;
}
call_nr = m_in.m_type;
#include <minix/const.h>
#include <minix/sysutil.h>
#include <minix/syslib.h>
+#include <minix/debug.h>
#include <sys/mman.h>
}
CHECKHOLES;
+
+ FIXME("below 16MB allocation not done");
}
/*===========================================================================*
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;
int r, proc, s, childproc, fullvm;
struct vmproc *vmp, *vmc;
pt_t origpt;
+ vir_bytes msgaddr;
SANITYCHECK(SCL_FUNCTIONS);
/* Tell kernel about the (now successful) FORK. */
if((r=sys_fork(vmp->vm_endpoint, childproc,
&vmc->vm_endpoint, vmc->vm_arch.vm_seg,
- fullvm ? PFF_VMINHIBIT : 0)) != OK) {
+ fullvm ? PFF_VMINHIBIT : 0, &msgaddr)) != OK) {
vm_panic("do_fork can't sys_fork", r);
}
if(fullvm) {
+ if(handle_memory(vmc, msgaddr, sizeof(message), 1) != OK)
+ vm_panic("can't make message writable (child)", NO_NUM);
+ if(handle_memory(vmp, msgaddr, sizeof(message), 1) != OK)
+ vm_panic("can't make message writable (parent)", NO_NUM);
if((r=pt_bind(&vmc->vm_pt, vmc)) != OK)
vm_panic("fork can't pt_bind", r);
}
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);
/* Increase our hardware data segment to create virtual address
}
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).
*/
kernlimit = free_pde*I386_BIG_PAGE_SIZE;
- printf("VM: set limit to 0x%x\n", kernlimit);
-
/* Increase kernel segment to address this memory. */
if((r=sys_vmctl(SELF, VMCTL_I386_KERNELLIMIT, kernlimit)) != OK) {
vm_panic("VMCTL_I386_KERNELLIMIT failed", r);
kpagedir = arch_map2vir(&vmproc[VMP_SYSTEM],
pagedir_pde*I386_BIG_PAGE_SIZE);
- printf("VM: pagedir linear 0x%x, in kernel 0x%x\n",
- pagedir_pde*I386_BIG_PAGE_SIZE, kpagedir);
/* Tell kernel how to get at the page directories. */
if((r=sys_vmctl(SELF, VMCTL_I386_PAGEDIRS, kpagedir)) != OK) {
}
/* 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;
vm_panic("pt_init: pt_writemap failed", NO_NUM);
}
- printf("VM: pt_init done\n");
-
/* All OK. */
return;
}
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");
}
return OK;
}
+#if 0
printf("VM: handling pagefault OK: %d addr 0x%lx %s\n",
ep, arch_map2vir(vmp, addr), pf_errstr(err));
+#endif
/* Pagefault is handled, so now reactivate the process. */
if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, r)) != OK)
while((r=sys_vmctl_get_memreq(&who, &mem, &len, &wrflag)) == OK) {
int p, r = OK;
- struct vir_region *region;
struct vmproc *vmp;
- vir_bytes o;
if(vm_isokendpt(who, &p) != OK)
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;
- len += o;
- o = len % VM_PAGE_SIZE;
- if(o > 0) len += VM_PAGE_SIZE - o;
-
- if(!(region = map_lookup(vmp, mem))) {
- printf("VM: do_memory: memory doesn't exist\n");
- r = EFAULT;
- } else if(mem + len > region->vaddr + region->length) {
- vm_assert(region->vaddr <= mem);
- vm_panic("do_memory: not contained", NO_NUM);
- } else if(!(region->flags & VR_WRITABLE) && wrflag) {
- printf("VM: do_memory: write to unwritable map\n");
- r = EFAULT;
- } else {
- vir_bytes offset;
- vm_assert(region->vaddr <= mem);
- vm_assert(!(region->flags & VR_NOPF));
- vm_assert(!(region->vaddr % VM_PAGE_SIZE));
- offset = mem - region->vaddr;
-
- r = map_handle_memory(vmp, region, offset, len, wrflag);
- }
-
- if(r != OK) {
- printf("VM: memory range 0x%lx-0x%lx not available in %d\n",
- arch_map2vir(vmp, mem), arch_map2vir(vmp, mem+len),
- vmp->vm_endpoint);
- }
-
+ r = handle_memory(vmp, mem, len, wrflag);
if(sys_vmctl(who, VMCTL_MEMREQ_REPLY, r) != OK)
vm_panic("do_memory: sys_vmctl failed", r);
+#if 0
printf("VM: handling memory request %d done OK\n",
who);
+#endif
}
}
+int handle_memory(struct vmproc *vmp, vir_bytes mem, vir_bytes len, int wrflag)
+{
+ struct vir_region *region;
+ vir_bytes o;
+ int r;
+
+#if 0
+ printf("VM: handling memory request: %d, 0x%lx-0x%lx, wr %d\n",
+ vmp->vm_endpoint, mem, mem+len, wrflag);
+#endif
+
+ /* Page-align memory and length. */
+ o = mem % VM_PAGE_SIZE;
+ mem -= o;
+ len += o;
+ o = len % VM_PAGE_SIZE;
+ if(o > 0) len += VM_PAGE_SIZE - o;
+
+ if(!(region = map_lookup(vmp, mem))) {
+ printf("VM: do_memory: memory doesn't exist\n");
+ r = EFAULT;
+ } else if(mem + len > region->vaddr + region->length) {
+ vm_assert(region->vaddr <= mem);
+ vm_panic("do_memory: not contained", NO_NUM);
+ } else if(!(region->flags & VR_WRITABLE) && wrflag) {
+ printf("VM: do_memory: write to unwritable map\n");
+ r = EFAULT;
+ } else {
+ vir_bytes offset;
+ vm_assert(region->vaddr <= mem);
+ vm_assert(!(region->flags & VR_NOPF));
+ vm_assert(!(region->vaddr % VM_PAGE_SIZE));
+ offset = mem - region->vaddr;
+
+ r = map_handle_memory(vmp, region, offset, len, wrflag);
+ }
+
+ if(r != OK) {
+ printf("VM: memory range 0x%lx-0x%lx not available in %d\n",
+ arch_map2vir(vmp, mem), arch_map2vir(vmp, mem+len),
+ vmp->vm_endpoint);
+ }
+}
_PROTOTYPE( void do_pagefaults, (void) );
_PROTOTYPE( void do_memory, (void) );
_PROTOTYPE( char *pf_errstr, (u32_t err));
+_PROTOTYPE( int handle_memory, (struct vmproc *vmp, vir_bytes mem,
+ vir_bytes len, int wrflag));
/* $(ARCH)/pagetable.c */
_PROTOTYPE( void pt_init, (void) );
if(ph->ph->refcount == 1)
r = map_ph_writept(vmp, region, ph->ph, NULL, NULL);
- else
+ else {
r = map_copy_ph_block(vmp, region, ph);
+ }
} else {
/* Pagefault in non-existing block. Map in new block. */
#if 0
#define ABS2CLICK(a) ((a) >> CLICK_SHIFT)
/* Compile in asserts and custom sanity checks at all? */
-#define SANITYCHECKS 1
-#define VMSTATS 1
+#define SANITYCHECKS 0
+#define VMSTATS 0
/* If so, this level: */
#define SCL_NONE 0 /* No sanity checks - vm_assert()s only. */