The biggie: Get rid of the UPAGES from the top of the per-process address

space. (!)

Have each process use the kernel stack and pcb in the kvm space.  Since
the stacks are at a different address, we cannot copy the stack at fork()
and allow the child to return up through the function call tree to return
to user mode - create a new execution context and have the new process
begin executing from cpu_switch() and go to user mode directly.
In theory this should speed up fork a bit.

Context switch the tss_esp0 pointer in the common tss.  This is a lot
simpler since than swithching the gdt[GPROC0_SEL].sd.sd_base pointer
to each process's tss since the esp0 pointer is a 32 bit pointer, and the
sd_base setting is split into three different bit sections at non-aligned
boundaries and requires a lot of twiddling to reset.

The 8K of memory at the top of the process space is now empty, and unmapped
(and unmappable, it's higher than VM_MAXUSER_ADDRESS).

Simplity the pmap code to manage process contexts, we no longer have to
double map the UPAGES, this simplifies and should measuably speed up fork().

The following parts came from John Dyson:

Set PG_G on the UPAGES that are now in kernel context, and invalidate
them when swapping them out.

Move the upages object (upobj) from the vmspace to the proc structure.

Now that the UPAGES (pcb and kernel stack) are out of user space, make
rfork(..RFMEM..) do what was intended by sharing the vmspace
entirely via reference counting rather than simply inheriting the mappings.
This commit is contained in:
Peter Wemm 1997-04-07 07:16:06 +00:00
parent 271b264e4c
commit a2a1c95c10
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=24691
31 changed files with 533 additions and 342 deletions

View File

@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: swtch.s,v 1.43 1997/02/22 09:32:51 peter Exp $
*/
#include "apm.h"
@ -234,6 +234,19 @@ _idle:
movl $tmpstk,%esp
movl _IdlePTD,%ecx
movl %ecx,%cr3
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %esp, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
sti
/*
@ -406,6 +419,34 @@ swtch_com:
/* switch address space */
movl %ebx,%cr3
#ifdef HOW_TO_SWITCH_TSS /* example only */
/* Fix up tss pointer to floating pcb/stack structure */
/* XXX probably lots faster to store the 64 bits of tss entry
* in the pcb somewhere and copy them on activation.
*/
movl _tssptr, %ebx
movl %edx, %eax /* edx = pcb/tss */
movw %ax, 2(%ebx) /* store bits 0->15 */
roll $16, %eax /* swap upper and lower */
movb %al, 4(%ebx) /* store bits 16->23 */
movb %ah, 7(%ebx) /* store bits 24->31 */
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
#endif
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %edx, %ebx /* pcb */
addl $(UPAGES * PAGE_SIZE), %ebx
movl %ebx, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
/* restore context */
movl PCB_EBX(%edx),%ebx
movl PCB_ESP(%edx),%esp

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: exception.s,v 1.21 1997/02/22 09:32:16 peter Exp $
*/
#include "npx.h" /* NNPX */
@ -250,6 +250,20 @@ IDTVEC(int0x80_syscall)
MEXITCOUNT
jmp _doreti
ENTRY(fork_trampoline)
pushl %ebx /* arg1 */
call %esi /* function */
addl $4,%esp
/* cut from syscall */
/*
* Return via _doreti to handle ASTs.
*/
pushl $0 /* cpl to restore */
subl $4,%esp
movb $1,_intr_nesting_level
MEXITCOUNT
jmp _doreti
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: exception.s,v 1.21 1997/02/22 09:32:16 peter Exp $
*/
#include "npx.h" /* NNPX */
@ -250,6 +250,20 @@ IDTVEC(int0x80_syscall)
MEXITCOUNT
jmp _doreti
ENTRY(fork_trampoline)
pushl %ebx /* arg1 */
call %esi /* function */
addl $4,%esp
/* cut from syscall */
/*
* Return via _doreti to handle ASTs.
*/
pushl $0 /* cpl to restore */
subl $4,%esp
movb $1,_intr_nesting_level
MEXITCOUNT
jmp _doreti
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)genassym.c 5.11 (Berkeley) 5/10/91
* $Id: genassym.c,v 1.42 1997/02/22 09:32:18 peter Exp $
* $Id: genassym.c,v 1.43 1997/04/07 06:45:11 peter Exp $
*/
#include <stdio.h>
@ -57,6 +57,7 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/bootinfo.h>
#include <machine/tss.h>
#include <sys/syscall.h>
#include <sys/vmmeter.h>
#include <vm/vm.h>
@ -84,6 +85,7 @@ main()
struct uprof *uprof = (struct uprof *)0;
struct vmspace *vms = (struct vmspace *)0;
struct pcb *pcb = (struct pcb *)0;
struct i386tss *tss = (struct i386tss *)0;
struct trapframe *tf = (struct trapframe *)0;
struct sigframe *sigf = (struct sigframe *)0;
struct bootinfo *bootinfo = (struct bootinfo *)0;
@ -127,6 +129,7 @@ main()
printf("#define\tPCB_ESP %p\n", &pcb->pcb_esp);
printf("#define\tPCB_EBX %p\n", &pcb->pcb_ebx);
printf("#define\tPCB_EIP %p\n", &pcb->pcb_eip);
printf("#define\tTSS_ESP0 %p\n", &tss->tss_esp0);
printf("#define\tPCB_USERLDT %p\n", &pcb->pcb_ldt);
printf("#define\tU_PROF %p\n", &up->u_stats.p_prof);
printf("#define\tU_PROFSCALE %p\n", &up->u_stats.p_prof.pr_scale);

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
* $Id: locore.s,v 1.81 1997/02/22 09:32:22 peter Exp $
* $Id: locore.s,v 1.82 1997/03/22 18:52:03 kato Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@ -86,14 +86,6 @@
.set _APTD,_APTmap + (APTDPTDI * PAGE_SIZE)
.set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
/*
* Access to each processes kernel stack is via a region of
* per-process address space (at the beginning), immediately above
* the user process stack.
*/
.set _kstack,USRSTACK
.globl _kstack
/*
* Globals
*/
@ -336,7 +328,8 @@ _pc98_system_parameter:
/* now running relocated at KERNBASE where the system is linked to run */
begin:
/* set up bootstrap stack */
movl $_kstack+UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
movl _proc0paddr,%esp /* location of in-kernel pages */
addl $UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
xorl %eax,%eax /* mark end of frames */
movl %eax,%ebp
movl _proc0paddr,%eax
@ -361,8 +354,13 @@ begin:
pushl %esp /* call main with frame pointer */
call _main /* autoconfiguration, mountroot etc */
addl $(13*4),%esp /* back to a frame we can return with */
hlt /* never returns to here */
/*
* When starting init, call this to configure the process for user
* mode. This will be inherited by other processes.
*/
NON_GPROF_ENTRY(prepare_usermode)
/*
* Now we've run main() and determined what cpu-type we are, we can
* enable write protection and alignment checking on i486 cpus and
@ -383,11 +381,14 @@ begin:
movl __ucodesel,%eax
movl __udatasel,%ecx
#if 0
movl %cx,%ds
#endif
movl %cx,%es
movl %ax,%fs /* double map cs to fs */
movl %cx,%gs /* and ds to gs */
iret /* goto user! */
ret /* goto user! */
#define LCALL(x,y) .byte 0x9a ; .long y ; .word x

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
* $Id: locore.s,v 1.81 1997/02/22 09:32:22 peter Exp $
* $Id: locore.s,v 1.82 1997/03/22 18:52:03 kato Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@ -86,14 +86,6 @@
.set _APTD,_APTmap + (APTDPTDI * PAGE_SIZE)
.set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
/*
* Access to each processes kernel stack is via a region of
* per-process address space (at the beginning), immediately above
* the user process stack.
*/
.set _kstack,USRSTACK
.globl _kstack
/*
* Globals
*/
@ -336,7 +328,8 @@ _pc98_system_parameter:
/* now running relocated at KERNBASE where the system is linked to run */
begin:
/* set up bootstrap stack */
movl $_kstack+UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
movl _proc0paddr,%esp /* location of in-kernel pages */
addl $UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
xorl %eax,%eax /* mark end of frames */
movl %eax,%ebp
movl _proc0paddr,%eax
@ -361,8 +354,13 @@ begin:
pushl %esp /* call main with frame pointer */
call _main /* autoconfiguration, mountroot etc */
addl $(13*4),%esp /* back to a frame we can return with */
hlt /* never returns to here */
/*
* When starting init, call this to configure the process for user
* mode. This will be inherited by other processes.
*/
NON_GPROF_ENTRY(prepare_usermode)
/*
* Now we've run main() and determined what cpu-type we are, we can
* enable write protection and alignment checking on i486 cpus and
@ -383,11 +381,14 @@ begin:
movl __ucodesel,%eax
movl __udatasel,%ecx
#if 0
movl %cx,%ds
#endif
movl %cx,%es
movl %ax,%fs /* double map cs to fs */
movl %cx,%gs /* and ds to gs */
iret /* goto user! */
ret /* goto user! */
#define LCALL(x,y) .byte 0x9a ; .long y ; .word x

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
* $Id: machdep.c,v 1.234 1997/03/31 11:10:37 davidg Exp $
* $Id: machdep.c,v 1.235 1997/04/07 06:45:13 peter Exp $
*/
#include "npx.h"
@ -755,6 +755,11 @@ static char dblfault_stack[PAGE_SIZE];
extern struct user *proc0paddr;
#ifdef TSS_IS_CACHED /* cpu_switch helper */
struct segment_descriptor *tssptr;
int gsel_tss;
#endif
/* software prototypes -- in more palatable form */
struct soft_segment_descriptor gdt_segs[] = {
/* GNULL_SEL 0 Null Descriptor */
@ -812,7 +817,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GPROC0_SEL 6 Proc 0 Tss Descriptor */
{ (int) &common_tss, /* segment base address */
{ (int) &common_tss, /* segment base address */
sizeof(struct i386tss)-1,/* length - all address space */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
@ -956,7 +961,9 @@ init386(first)
int x;
unsigned biosbasemem, biosextmem;
struct gate_descriptor *gdp;
#ifndef TSS_IS_CACHED
int gsel_tss;
#endif
struct isa_device *idp;
/* table descriptors - used to load tables by microp */
struct region_descriptor r_gdt, r_idt;
@ -1300,8 +1307,8 @@ init386(first)
avail_end + off, VM_PROT_ALL, TRUE);
msgbufmapped = 1;
/* make a initial tss so microp can get interrupt stack on syscall! */
common_tss.tss_esp0 = (int) kstack + UPAGES*PAGE_SIZE;
/* make an initial tss so cpu can get interrupt stack on syscall! */
common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
common_tss.tss_ioopt = (sizeof common_tss) << 16;
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
@ -1314,11 +1321,15 @@ init386(first)
dblfault_tss.tss_cr3 = IdlePTD;
dblfault_tss.tss_eip = (int) dblfault_handler;
dblfault_tss.tss_eflags = PSL_KERNEL;
dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs = dblfault_tss.tss_gs =
GSEL(GDATA_SEL, SEL_KPL);
dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
#ifdef TSS_IS_CACHED /* cpu_switch helper */
tssptr = &gdt[GPROC0_SEL].sd;
#endif
/* make a call gate to reenter kernel with */
gdp = &ldt[LSYS5CALLS_SEL].gd;
@ -1353,9 +1364,7 @@ init386(first)
* index into the user block. Don't you just *love* virtual memory?
* (I'm starting to think seymour is right...)
*/
#define TF_REGP(p) ((struct trapframe *) \
((char *)(p)->p_addr \
+ ((char *)(p)->p_md.md_regs - kstack)))
#define TF_REGP(p) ((struct trapframe *)(p)->p_md.md_regs)
int
ptrace_set_pc(p, addr)
@ -1387,7 +1396,7 @@ int ptrace_write_u(p, off, data)
* Privileged kernel state is scattered all over the user area.
* Only allow write access to parts of regs and to fpregs.
*/
min = (char *)p->p_md.md_regs - kstack;
min = (char *)p->p_md.md_regs - (char *)p->p_addr;
if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) {
tp = TF_REGP(p);
frame_copy = *tp;

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
* $Id$
* $Id: pmap.c,v 1.138 1997/02/22 09:32:40 peter Exp $
*/
/*
@ -685,32 +685,22 @@ pmap_new_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
struct user *up;
unsigned *ptep, *ptek;
pmap = &p->p_vmspace->vm_pmap;
unsigned *ptek;
/*
* allocate object for the upages
*/
upobj = vm_object_allocate( OBJT_DEFAULT,
UPAGES);
p->p_vmspace->vm_upages_obj = upobj;
p->p_upages_obj = upobj;
/* get a kernel virtual address for the UPAGES for this proc */
up = (struct user *) kmem_alloc_pageable(u_map, UPAGES * PAGE_SIZE);
if (up == NULL)
panic("vm_fork: u_map allocation failed");
panic("pmap_new_proc: u_map allocation failed");
/*
* Allocate the ptp and incr the hold count appropriately
*/
m = pmap_allocpte(pmap, (vm_offset_t) kstack);
m->hold_count += (UPAGES - 1);
ptep = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
ptek = (unsigned *) vtopte((vm_offset_t) up);
for(i=0;i<UPAGES;i++) {
@ -729,18 +719,15 @@ pmap_new_proc(p)
++cnt.v_wire_count;
/*
* Enter the page into both the kernel and the process
* address space.
* Enter the page into the kernel address space.
*/
*(ptep + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
*(ptek + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
*(ptek + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V | pgeflag;
m->flags &= ~(PG_ZERO|PG_BUSY);
m->flags |= PG_MAPPED|PG_WRITEABLE;
m->valid = VM_PAGE_BITS_ALL;
}
pmap->pm_stats.resident_count += UPAGES;
p->p_addr = up;
}
@ -754,26 +741,26 @@ pmap_dispose_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *ptep, *ptek;
unsigned *ptek;
pmap = &p->p_vmspace->vm_pmap;
ptep = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
ptek = (unsigned *) vtopte((vm_offset_t) p->p_addr);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
for(i=0;i<UPAGES;i++) {
unsigned oldpte;
if ((m = vm_page_lookup(upobj, i)) == NULL)
panic("pmap_dispose_proc: upage already missing???");
*(ptep + i) = 0;
oldpte = *(ptek + i);
*(ptek + i) = 0;
pmap_unuse_pt(pmap, (vm_offset_t) kstack + i * PAGE_SIZE, NULL);
if (oldpte & PG_G)
invlpg((vm_offset_t) p->p_addr + i * PAGE_SIZE);
vm_page_unwire(m);
vm_page_free(m);
}
pmap->pm_stats.resident_count -= UPAGES;
vm_object_deallocate(upobj);
kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
}
@ -787,29 +774,20 @@ pmap_swapout_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *pte;
pmap = &p->p_vmspace->vm_pmap;
pte = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
/*
* let the upages be paged
*/
for(i=0;i<UPAGES;i++) {
if ((m = vm_page_lookup(upobj, i)) == NULL)
panic("pmap_pageout_proc: upage already missing???");
panic("pmap_swapout_proc: upage already missing???");
m->dirty = VM_PAGE_BITS_ALL;
*(pte + i) = 0;
pmap_unuse_pt(pmap, (vm_offset_t) kstack + i * PAGE_SIZE, NULL);
vm_page_unwire(m);
vm_page_deactivate(m);
pmap_kremove( (vm_offset_t) p->p_addr + PAGE_SIZE * i);
}
pmap->pm_stats.resident_count -= UPAGES;
}
/*
@ -821,19 +799,10 @@ pmap_swapin_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *pte;
pmap = &p->p_vmspace->vm_pmap;
/*
* Allocate the ptp and incr the hold count appropriately
*/
m = pmap_allocpte(pmap, (vm_offset_t) kstack);
m->hold_count += (UPAGES - 1);
pte = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
for(i=0;i<UPAGES;i++) {
int s;
s = splvm();
@ -854,7 +823,6 @@ pmap_swapin_proc(p)
vm_page_wire(m);
splx(s);
*(pte+i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
pmap_kenter(((vm_offset_t) p->p_addr) + i * PAGE_SIZE,
VM_PAGE_TO_PHYS(m));
@ -862,13 +830,12 @@ pmap_swapin_proc(p)
int rv;
rv = vm_pager_get_pages(upobj, &m, 1, 0);
if (rv != VM_PAGER_OK)
panic("faultin: cannot get upages for proc: %d\n", p->p_pid);
panic("pmap_swapin_proc: cannot get upages for proc: %d\n", p->p_pid);
m->valid = VM_PAGE_BITS_ALL;
}
PAGE_WAKEUP(m);
m->flags |= PG_MAPPED|PG_WRITEABLE;
}
pmap->pm_stats.resident_count += UPAGES;
}
/***************************************************

View File

@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: swtch.s,v 1.43 1997/02/22 09:32:51 peter Exp $
*/
#include "apm.h"
@ -234,6 +234,19 @@ _idle:
movl $tmpstk,%esp
movl _IdlePTD,%ecx
movl %ecx,%cr3
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %esp, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
sti
/*
@ -406,6 +419,34 @@ swtch_com:
/* switch address space */
movl %ebx,%cr3
#ifdef HOW_TO_SWITCH_TSS /* example only */
/* Fix up tss pointer to floating pcb/stack structure */
/* XXX probably lots faster to store the 64 bits of tss entry
* in the pcb somewhere and copy them on activation.
*/
movl _tssptr, %ebx
movl %edx, %eax /* edx = pcb/tss */
movw %ax, 2(%ebx) /* store bits 0->15 */
roll $16, %eax /* swap upper and lower */
movb %al, 4(%ebx) /* store bits 16->23 */
movb %ah, 7(%ebx) /* store bits 24->31 */
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
#endif
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %edx, %ebx /* pcb */
addl $(UPAGES * PAGE_SIZE), %ebx
movl %ebx, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
/* restore context */
movl PCB_EBX(%edx),%ebx
movl PCB_ESP(%edx),%esp

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.89 1997/04/06 02:29:19 dyson Exp $
* $Id: trap.c,v 1.90 1997/04/07 06:45:15 peter Exp $
*/
/*
@ -938,3 +938,22 @@ syscall(frame)
ktrsysret(p->p_tracep, code, error, rval[0]);
#endif
}
/*
* Simplified back end of syscall(), used when returning from fork()
* directly into user mode.
*/
void
fork_return(p, frame)
struct proc *p;
struct trapframe frame;
{
frame.tf_eax = 0; /* Child returns zero */
frame.tf_eflags &= ~PSL_C; /* success */
userret(p, &frame, 0);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p->p_tracep, SYS_fork, 0, 0);
#endif
}

View File

@ -38,7 +38,7 @@
*
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
* $Id: vm_machdep.c,v 1.76 1997/03/22 04:28:16 dyson Exp $
* $Id: vm_machdep.c,v 1.77 1997/03/29 04:35:26 bde Exp $
*/
#include "npx.h"
@ -54,6 +54,8 @@
#include <machine/clock.h>
#include <machine/md_var.h>
#include <machine/cpu.h>
#include <machine/reg.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -558,61 +560,83 @@ vm_fault_quick(v, prot)
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the kernel stack and pcb, making the child
* ready to run, and marking it so that it can return differently
* than the parent. Returns 1 in the child process, 0 in the parent.
* We currently double-map the user area so that the stack is at the same
* address in each process; in the future we will probably relocate
* the frame pointers on the stack after copying.
* Copy and update the pcb, set up the stack so that the child
* ready to run and return to user mode.
*/
int
void
cpu_fork(p1, p2)
register struct proc *p1, *p2;
{
struct pcb *pcb2 = &p2->p_addr->u_pcb;
int sp, offset;
volatile int retval;
#ifdef USER_LDT
struct pcb *pcb = &p2->p_addr->u_pcb;
#endif
/*
* Copy pcb and stack from proc p1 to p2.
* We do this as cheaply as possible, copying only the active
* part of the stack. The stack and pcb need to agree;
* this is tricky, as the final pcb is constructed by savectx,
* but its frame isn't yet on the stack when the stack is copied.
* This should be done differently, with a single call
* that copies and updates the pcb+stack,
* replacing the bcopy and savectx.
* copy current pcb, and save current context into it while it's
* possibly in some writeback cache line.
*/
__asm __volatile("movl %%esp,%0" : "=r" (sp));
offset = sp - (int)kstack;
retval = 1; /* return 1 in child */
bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
(unsigned) ctob(UPAGES) - offset);
p2->p_md.md_regs = p1->p_md.md_regs;
*pcb2 = p1->p_addr->u_pcb;
bcopy(&p1->p_addr->u_pcb, pcb2, sizeof(struct pcb));
pcb2->pcb_cr3 = vtophys(p2->p_vmspace->vm_pmap.pm_pdir);
savectx(pcb2); /* irrelevant? fp registers? */
/*
* Create a new fresh stack for the new process.
* Copy the trap frame for the return to user mode as if from a syscall.
* This copies the user mode register values.
*/
p2->p_md.md_regs = (int *)(((struct trapframe *)
((int)p2->p_addr + (UPAGES * PAGE_SIZE))) - 1);
bcopy(p1->p_md.md_regs, p2->p_md.md_regs, sizeof(struct trapframe));
/*
* Set registers for trampoline to user mode. Leave space for the
* return address on stack. These are the kernel mode register values.
*/
/* XXX these overwrite most of the regs from savectx() above! */
pcb2->pcb_eip = (int)fork_trampoline;
pcb2->pcb_esi = (int)fork_return;
pcb2->pcb_ebx = (int)p2;
pcb2->pcb_esp = (int)p2->p_md.md_regs - sizeof(void *);
#ifdef USER_LDT
/* Copy the LDT, if necessary. */
if (pcb->pcb_ldt != 0) {
if (pcb2->pcb_ldt != 0) {
union descriptor *new_ldt;
size_t len = pcb->pcb_ldt_len * sizeof(union descriptor);
size_t len = pcb2->pcb_ldt_len * sizeof(union descriptor);
new_ldt = (union descriptor *)kmem_alloc(kernel_map, len);
bcopy(pcb->pcb_ldt, new_ldt, len);
pcb->pcb_ldt = (caddr_t)new_ldt;
bcopy(pcb2->pcb_ldt, new_ldt, len);
pcb2->pcb_ldt = (caddr_t)new_ldt;
}
#endif
retval = 0; /* return 0 in parent */
savectx(pcb2);
return (retval);
/*
* Now, cpu_switch() can schedule the new process.
* pcb_esp is loaded pointing to the cpu_switch() stack frame
* containing the return address when exiting cpu_switch.
* This will normally be to proc_trampoline(), which will have
* %ebx loaded with the new proc's pointer. proc_trampoline()
* will set up a stack to call fork_return(p, frame); to complete
* the return to user-mode.
*/
}
/*
* Intercept the return address from a freshly forked process that has NOT
* been scheduled yet.
*
* This is needed to make kernel threads stay in kernel mode.
*/
void
cpu_set_fork_handler(p, func, arg)
struct proc *p;
void (*func) __P((void *));
void *arg;
{
/*
* Note that the trap frame follows the args, so the function
* is really called like this: func(arg, frame);
*/
p->p_addr->u_pcb.pcb_esi = (int) func; /* function */
p->p_addr->u_pcb.pcb_ebx = (int) arg; /* first arg */
}
void

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
* $Id$
* $Id: cpu.h,v 1.28 1997/02/22 09:34:04 peter Exp $
*/
#ifndef _MACHINE_CPU_H_
@ -134,6 +134,10 @@ extern int cpu;
extern int cpu_class;
extern u_char intr_nesting_level;
extern int want_resched; /* resched was called */
void fork_trampoline __P((void));
void fork_return __P((struct proc *, struct trapframe));
void cpu_set_fork_handler __P((struct proc *, void (*pc)(void *), void *));
#endif
#endif /* !_MACHINE_CPU_H_ */

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: exception.s,v 1.21 1997/02/22 09:32:16 peter Exp $
*/
#include "npx.h" /* NNPX */
@ -250,6 +250,20 @@ IDTVEC(int0x80_syscall)
MEXITCOUNT
jmp _doreti
ENTRY(fork_trampoline)
pushl %ebx /* arg1 */
call %esi /* function */
addl $4,%esp
/* cut from syscall */
/*
* Return via _doreti to handle ASTs.
*/
pushl $0 /* cpl to restore */
subl $4,%esp
movb $1,_intr_nesting_level
MEXITCOUNT
jmp _doreti
/*
* Include what was once config+isa-dependent code.
* XXX it should be in a stand-alone file. It's still icu-dependent and

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)genassym.c 5.11 (Berkeley) 5/10/91
* $Id: genassym.c,v 1.42 1997/02/22 09:32:18 peter Exp $
* $Id: genassym.c,v 1.43 1997/04/07 06:45:11 peter Exp $
*/
#include <stdio.h>
@ -57,6 +57,7 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/bootinfo.h>
#include <machine/tss.h>
#include <sys/syscall.h>
#include <sys/vmmeter.h>
#include <vm/vm.h>
@ -84,6 +85,7 @@ main()
struct uprof *uprof = (struct uprof *)0;
struct vmspace *vms = (struct vmspace *)0;
struct pcb *pcb = (struct pcb *)0;
struct i386tss *tss = (struct i386tss *)0;
struct trapframe *tf = (struct trapframe *)0;
struct sigframe *sigf = (struct sigframe *)0;
struct bootinfo *bootinfo = (struct bootinfo *)0;
@ -127,6 +129,7 @@ main()
printf("#define\tPCB_ESP %p\n", &pcb->pcb_esp);
printf("#define\tPCB_EBX %p\n", &pcb->pcb_ebx);
printf("#define\tPCB_EIP %p\n", &pcb->pcb_eip);
printf("#define\tTSS_ESP0 %p\n", &tss->tss_esp0);
printf("#define\tPCB_USERLDT %p\n", &pcb->pcb_ldt);
printf("#define\tU_PROF %p\n", &up->u_stats.p_prof);
printf("#define\tU_PROFSCALE %p\n", &up->u_stats.p_prof.pr_scale);

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)locore.s 7.3 (Berkeley) 5/13/91
* $Id: locore.s,v 1.81 1997/02/22 09:32:22 peter Exp $
* $Id: locore.s,v 1.82 1997/03/22 18:52:03 kato Exp $
*
* originally from: locore.s, by William F. Jolitz
*
@ -86,14 +86,6 @@
.set _APTD,_APTmap + (APTDPTDI * PAGE_SIZE)
.set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
/*
* Access to each processes kernel stack is via a region of
* per-process address space (at the beginning), immediately above
* the user process stack.
*/
.set _kstack,USRSTACK
.globl _kstack
/*
* Globals
*/
@ -336,7 +328,8 @@ _pc98_system_parameter:
/* now running relocated at KERNBASE where the system is linked to run */
begin:
/* set up bootstrap stack */
movl $_kstack+UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
movl _proc0paddr,%esp /* location of in-kernel pages */
addl $UPAGES*PAGE_SIZE,%esp /* bootstrap stack end location */
xorl %eax,%eax /* mark end of frames */
movl %eax,%ebp
movl _proc0paddr,%eax
@ -361,8 +354,13 @@ begin:
pushl %esp /* call main with frame pointer */
call _main /* autoconfiguration, mountroot etc */
addl $(13*4),%esp /* back to a frame we can return with */
hlt /* never returns to here */
/*
* When starting init, call this to configure the process for user
* mode. This will be inherited by other processes.
*/
NON_GPROF_ENTRY(prepare_usermode)
/*
* Now we've run main() and determined what cpu-type we are, we can
* enable write protection and alignment checking on i486 cpus and
@ -383,11 +381,14 @@ begin:
movl __ucodesel,%eax
movl __udatasel,%ecx
#if 0
movl %cx,%ds
#endif
movl %cx,%es
movl %ax,%fs /* double map cs to fs */
movl %cx,%gs /* and ds to gs */
iret /* goto user! */
ret /* goto user! */
#define LCALL(x,y) .byte 0x9a ; .long y ; .word x

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
* $Id: machdep.c,v 1.234 1997/03/31 11:10:37 davidg Exp $
* $Id: machdep.c,v 1.235 1997/04/07 06:45:13 peter Exp $
*/
#include "npx.h"
@ -755,6 +755,11 @@ static char dblfault_stack[PAGE_SIZE];
extern struct user *proc0paddr;
#ifdef TSS_IS_CACHED /* cpu_switch helper */
struct segment_descriptor *tssptr;
int gsel_tss;
#endif
/* software prototypes -- in more palatable form */
struct soft_segment_descriptor gdt_segs[] = {
/* GNULL_SEL 0 Null Descriptor */
@ -812,7 +817,7 @@ struct soft_segment_descriptor gdt_segs[] = {
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* GPROC0_SEL 6 Proc 0 Tss Descriptor */
{ (int) &common_tss, /* segment base address */
{ (int) &common_tss, /* segment base address */
sizeof(struct i386tss)-1,/* length - all address space */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
@ -956,7 +961,9 @@ init386(first)
int x;
unsigned biosbasemem, biosextmem;
struct gate_descriptor *gdp;
#ifndef TSS_IS_CACHED
int gsel_tss;
#endif
struct isa_device *idp;
/* table descriptors - used to load tables by microp */
struct region_descriptor r_gdt, r_idt;
@ -1300,8 +1307,8 @@ init386(first)
avail_end + off, VM_PROT_ALL, TRUE);
msgbufmapped = 1;
/* make a initial tss so microp can get interrupt stack on syscall! */
common_tss.tss_esp0 = (int) kstack + UPAGES*PAGE_SIZE;
/* make an initial tss so cpu can get interrupt stack on syscall! */
common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE;
common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
common_tss.tss_ioopt = (sizeof common_tss) << 16;
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
@ -1314,11 +1321,15 @@ init386(first)
dblfault_tss.tss_cr3 = IdlePTD;
dblfault_tss.tss_eip = (int) dblfault_handler;
dblfault_tss.tss_eflags = PSL_KERNEL;
dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs = dblfault_tss.tss_gs =
GSEL(GDATA_SEL, SEL_KPL);
dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_fs =
dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL);
dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL);
dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL);
#ifdef TSS_IS_CACHED /* cpu_switch helper */
tssptr = &gdt[GPROC0_SEL].sd;
#endif
/* make a call gate to reenter kernel with */
gdp = &ldt[LSYS5CALLS_SEL].gd;
@ -1353,9 +1364,7 @@ init386(first)
* index into the user block. Don't you just *love* virtual memory?
* (I'm starting to think seymour is right...)
*/
#define TF_REGP(p) ((struct trapframe *) \
((char *)(p)->p_addr \
+ ((char *)(p)->p_md.md_regs - kstack)))
#define TF_REGP(p) ((struct trapframe *)(p)->p_md.md_regs)
int
ptrace_set_pc(p, addr)
@ -1387,7 +1396,7 @@ int ptrace_write_u(p, off, data)
* Privileged kernel state is scattered all over the user area.
* Only allow write access to parts of regs and to fpregs.
*/
min = (char *)p->p_md.md_regs - kstack;
min = (char *)p->p_md.md_regs - (char *)p->p_addr;
if (off >= min && off <= min + sizeof(struct trapframe) - sizeof(int)) {
tp = TF_REGP(p);
frame_copy = *tp;

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
* $Id$
* $Id: pmap.c,v 1.138 1997/02/22 09:32:40 peter Exp $
*/
/*
@ -685,32 +685,22 @@ pmap_new_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
struct user *up;
unsigned *ptep, *ptek;
pmap = &p->p_vmspace->vm_pmap;
unsigned *ptek;
/*
* allocate object for the upages
*/
upobj = vm_object_allocate( OBJT_DEFAULT,
UPAGES);
p->p_vmspace->vm_upages_obj = upobj;
p->p_upages_obj = upobj;
/* get a kernel virtual address for the UPAGES for this proc */
up = (struct user *) kmem_alloc_pageable(u_map, UPAGES * PAGE_SIZE);
if (up == NULL)
panic("vm_fork: u_map allocation failed");
panic("pmap_new_proc: u_map allocation failed");
/*
* Allocate the ptp and incr the hold count appropriately
*/
m = pmap_allocpte(pmap, (vm_offset_t) kstack);
m->hold_count += (UPAGES - 1);
ptep = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
ptek = (unsigned *) vtopte((vm_offset_t) up);
for(i=0;i<UPAGES;i++) {
@ -729,18 +719,15 @@ pmap_new_proc(p)
++cnt.v_wire_count;
/*
* Enter the page into both the kernel and the process
* address space.
* Enter the page into the kernel address space.
*/
*(ptep + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
*(ptek + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
*(ptek + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V | pgeflag;
m->flags &= ~(PG_ZERO|PG_BUSY);
m->flags |= PG_MAPPED|PG_WRITEABLE;
m->valid = VM_PAGE_BITS_ALL;
}
pmap->pm_stats.resident_count += UPAGES;
p->p_addr = up;
}
@ -754,26 +741,26 @@ pmap_dispose_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *ptep, *ptek;
unsigned *ptek;
pmap = &p->p_vmspace->vm_pmap;
ptep = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
ptek = (unsigned *) vtopte((vm_offset_t) p->p_addr);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
for(i=0;i<UPAGES;i++) {
unsigned oldpte;
if ((m = vm_page_lookup(upobj, i)) == NULL)
panic("pmap_dispose_proc: upage already missing???");
*(ptep + i) = 0;
oldpte = *(ptek + i);
*(ptek + i) = 0;
pmap_unuse_pt(pmap, (vm_offset_t) kstack + i * PAGE_SIZE, NULL);
if (oldpte & PG_G)
invlpg((vm_offset_t) p->p_addr + i * PAGE_SIZE);
vm_page_unwire(m);
vm_page_free(m);
}
pmap->pm_stats.resident_count -= UPAGES;
vm_object_deallocate(upobj);
kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
}
@ -787,29 +774,20 @@ pmap_swapout_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *pte;
pmap = &p->p_vmspace->vm_pmap;
pte = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
/*
* let the upages be paged
*/
for(i=0;i<UPAGES;i++) {
if ((m = vm_page_lookup(upobj, i)) == NULL)
panic("pmap_pageout_proc: upage already missing???");
panic("pmap_swapout_proc: upage already missing???");
m->dirty = VM_PAGE_BITS_ALL;
*(pte + i) = 0;
pmap_unuse_pt(pmap, (vm_offset_t) kstack + i * PAGE_SIZE, NULL);
vm_page_unwire(m);
vm_page_deactivate(m);
pmap_kremove( (vm_offset_t) p->p_addr + PAGE_SIZE * i);
}
pmap->pm_stats.resident_count -= UPAGES;
}
/*
@ -821,19 +799,10 @@ pmap_swapin_proc(p)
{
int i;
vm_object_t upobj;
pmap_t pmap;
vm_page_t m;
unsigned *pte;
pmap = &p->p_vmspace->vm_pmap;
/*
* Allocate the ptp and incr the hold count appropriately
*/
m = pmap_allocpte(pmap, (vm_offset_t) kstack);
m->hold_count += (UPAGES - 1);
pte = (unsigned *) pmap_pte(pmap, (vm_offset_t) kstack);
upobj = p->p_vmspace->vm_upages_obj;
upobj = p->p_upages_obj;
for(i=0;i<UPAGES;i++) {
int s;
s = splvm();
@ -854,7 +823,6 @@ pmap_swapin_proc(p)
vm_page_wire(m);
splx(s);
*(pte+i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V;
pmap_kenter(((vm_offset_t) p->p_addr) + i * PAGE_SIZE,
VM_PAGE_TO_PHYS(m));
@ -862,13 +830,12 @@ pmap_swapin_proc(p)
int rv;
rv = vm_pager_get_pages(upobj, &m, 1, 0);
if (rv != VM_PAGER_OK)
panic("faultin: cannot get upages for proc: %d\n", p->p_pid);
panic("pmap_swapin_proc: cannot get upages for proc: %d\n", p->p_pid);
m->valid = VM_PAGE_BITS_ALL;
}
PAGE_WAKEUP(m);
m->flags |= PG_MAPPED|PG_WRITEABLE;
}
pmap->pm_stats.resident_count += UPAGES;
}
/***************************************************

View File

@ -33,7 +33,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: swtch.s,v 1.43 1997/02/22 09:32:51 peter Exp $
*/
#include "apm.h"
@ -234,6 +234,19 @@ _idle:
movl $tmpstk,%esp
movl _IdlePTD,%ecx
movl %ecx,%cr3
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %esp, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
sti
/*
@ -406,6 +419,34 @@ swtch_com:
/* switch address space */
movl %ebx,%cr3
#ifdef HOW_TO_SWITCH_TSS /* example only */
/* Fix up tss pointer to floating pcb/stack structure */
/* XXX probably lots faster to store the 64 bits of tss entry
* in the pcb somewhere and copy them on activation.
*/
movl _tssptr, %ebx
movl %edx, %eax /* edx = pcb/tss */
movw %ax, 2(%ebx) /* store bits 0->15 */
roll $16, %eax /* swap upper and lower */
movb %al, 4(%ebx) /* store bits 16->23 */
movb %ah, 7(%ebx) /* store bits 24->31 */
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
#endif
/* update common_tss.tss_esp0 pointer */
movl $_common_tss, %eax
movl %edx, %ebx /* pcb */
addl $(UPAGES * PAGE_SIZE), %ebx
movl %ebx, TSS_ESP0(%eax)
#ifdef TSS_IS_CACHED /* example only */
/* Reload task register to force reload of selector */
movl _tssptr, %ebx
andb $~0x02, 5(%ebx) /* Flip 386BSY -> 386TSS */
movl _gsel_tss, %ebx
ltr %bx
#endif
/* restore context */
movl PCB_EBX(%edx),%ebx
movl PCB_ESP(%edx),%esp

View File

@ -1,6 +1,6 @@
# @(#)symbols.raw 7.6 (Berkeley) 5/8/91
#
# $Id$
# $Id: symbols.raw,v 1.8 1997/02/22 09:32:52 peter Exp $
#
@ -8,7 +8,6 @@
_IdlePTD
_PTD
_curpcb
_kstack
_panicstr
_atdevbase
# _version

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.89 1997/04/06 02:29:19 dyson Exp $
* $Id: trap.c,v 1.90 1997/04/07 06:45:15 peter Exp $
*/
/*
@ -938,3 +938,22 @@ syscall(frame)
ktrsysret(p->p_tracep, code, error, rval[0]);
#endif
}
/*
* Simplified back end of syscall(), used when returning from fork()
* directly into user mode.
*/
void
fork_return(p, frame)
struct proc *p;
struct trapframe frame;
{
frame.tf_eax = 0; /* Child returns zero */
frame.tf_eflags &= ~PSL_C; /* success */
userret(p, &frame, 0);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p->p_tracep, SYS_fork, 0, 0);
#endif
}

View File

@ -38,7 +38,7 @@
*
* from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
* Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
* $Id: vm_machdep.c,v 1.76 1997/03/22 04:28:16 dyson Exp $
* $Id: vm_machdep.c,v 1.77 1997/03/29 04:35:26 bde Exp $
*/
#include "npx.h"
@ -54,6 +54,8 @@
#include <machine/clock.h>
#include <machine/md_var.h>
#include <machine/cpu.h>
#include <machine/reg.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -558,61 +560,83 @@ vm_fault_quick(v, prot)
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the kernel stack and pcb, making the child
* ready to run, and marking it so that it can return differently
* than the parent. Returns 1 in the child process, 0 in the parent.
* We currently double-map the user area so that the stack is at the same
* address in each process; in the future we will probably relocate
* the frame pointers on the stack after copying.
* Copy and update the pcb, set up the stack so that the child
* ready to run and return to user mode.
*/
int
void
cpu_fork(p1, p2)
register struct proc *p1, *p2;
{
struct pcb *pcb2 = &p2->p_addr->u_pcb;
int sp, offset;
volatile int retval;
#ifdef USER_LDT
struct pcb *pcb = &p2->p_addr->u_pcb;
#endif
/*
* Copy pcb and stack from proc p1 to p2.
* We do this as cheaply as possible, copying only the active
* part of the stack. The stack and pcb need to agree;
* this is tricky, as the final pcb is constructed by savectx,
* but its frame isn't yet on the stack when the stack is copied.
* This should be done differently, with a single call
* that copies and updates the pcb+stack,
* replacing the bcopy and savectx.
* copy current pcb, and save current context into it while it's
* possibly in some writeback cache line.
*/
__asm __volatile("movl %%esp,%0" : "=r" (sp));
offset = sp - (int)kstack;
retval = 1; /* return 1 in child */
bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
(unsigned) ctob(UPAGES) - offset);
p2->p_md.md_regs = p1->p_md.md_regs;
*pcb2 = p1->p_addr->u_pcb;
bcopy(&p1->p_addr->u_pcb, pcb2, sizeof(struct pcb));
pcb2->pcb_cr3 = vtophys(p2->p_vmspace->vm_pmap.pm_pdir);
savectx(pcb2); /* irrelevant? fp registers? */
/*
* Create a new fresh stack for the new process.
* Copy the trap frame for the return to user mode as if from a syscall.
* This copies the user mode register values.
*/
p2->p_md.md_regs = (int *)(((struct trapframe *)
((int)p2->p_addr + (UPAGES * PAGE_SIZE))) - 1);
bcopy(p1->p_md.md_regs, p2->p_md.md_regs, sizeof(struct trapframe));
/*
* Set registers for trampoline to user mode. Leave space for the
* return address on stack. These are the kernel mode register values.
*/
/* XXX these overwrite most of the regs from savectx() above! */
pcb2->pcb_eip = (int)fork_trampoline;
pcb2->pcb_esi = (int)fork_return;
pcb2->pcb_ebx = (int)p2;
pcb2->pcb_esp = (int)p2->p_md.md_regs - sizeof(void *);
#ifdef USER_LDT
/* Copy the LDT, if necessary. */
if (pcb->pcb_ldt != 0) {
if (pcb2->pcb_ldt != 0) {
union descriptor *new_ldt;
size_t len = pcb->pcb_ldt_len * sizeof(union descriptor);
size_t len = pcb2->pcb_ldt_len * sizeof(union descriptor);
new_ldt = (union descriptor *)kmem_alloc(kernel_map, len);
bcopy(pcb->pcb_ldt, new_ldt, len);
pcb->pcb_ldt = (caddr_t)new_ldt;
bcopy(pcb2->pcb_ldt, new_ldt, len);
pcb2->pcb_ldt = (caddr_t)new_ldt;
}
#endif
retval = 0; /* return 0 in parent */
savectx(pcb2);
return (retval);
/*
* Now, cpu_switch() can schedule the new process.
* pcb_esp is loaded pointing to the cpu_switch() stack frame
* containing the return address when exiting cpu_switch.
* This will normally be to proc_trampoline(), which will have
* %ebx loaded with the new proc's pointer. proc_trampoline()
* will set up a stack to call fork_return(p, frame); to complete
* the return to user-mode.
*/
}
/*
* Intercept the return address from a freshly forked process that has NOT
* been scheduled yet.
*
* This is needed to make kernel threads stay in kernel mode.
*/
void
cpu_set_fork_handler(p, func, arg)
struct proc *p;
void (*func) __P((void *));
void *arg;
{
/*
* Note that the trap frame follows the args, so the function
* is really called like this: func(arg, frame);
*/
p->p_addr->u_pcb.pcb_esi = (int) func; /* function */
p->p_addr->u_pcb.pcb_ebx = (int) arg; /* first arg */
}
void

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
* $Id$
* $Id: cpu.h,v 1.28 1997/02/22 09:34:04 peter Exp $
*/
#ifndef _MACHINE_CPU_H_
@ -134,6 +134,10 @@ extern int cpu;
extern int cpu_class;
extern u_char intr_nesting_level;
extern int want_resched; /* resched was called */
void fork_trampoline __P((void));
void fork_return __P((struct proc *, struct trapframe));
void cpu_set_fork_handler __P((struct proc *, void (*pc)(void *), void *));
#endif
#endif /* !_MACHINE_CPU_H_ */

View File

@ -39,7 +39,7 @@
* SUCH DAMAGE.
*
* @(#)init_main.c 8.9 (Berkeley) 1/21/94
* $Id: init_main.c,v 1.58 1997/03/01 17:49:09 wosch Exp $
* $Id: init_main.c,v 1.59 1997/03/22 06:52:55 bde Exp $
*/
#include "opt_rlimit.h"
@ -145,7 +145,8 @@ main(framep)
int rval[2]; /* SI_TYPE_KTHREAD support*/
/*
* Save the locore.s frame pointer for start_init().
* Copy the locore.s frame pointer for proc0, this is forked into
* all other processes.
*/
init_framep = framep;
@ -189,21 +190,7 @@ main(framep)
/* kernel thread*/
if (fork(&proc0, NULL, rval))
panic("fork kernel process");
if (rval[1]) {
(*((*sipp)->func))( (*sipp)->udata);
/*
* The call to start "init" returns
* here after the scheduler has been
* started, and returns to the caller
* in i386/i386/locore.s. This is a
* necessary part of initialization
* and is rather non-obvious.
*
* No other "kernel threads" should
* return here. Call panic() instead.
*/
return;
}
cpu_set_fork_handler(pfind(rval[0]), (*sipp)->func, (*sipp)->udata);
break;
default:
@ -378,10 +365,7 @@ proc0_init(dummy)
#define INCOMPAT_LITES2
#ifdef INCOMPAT_LITES2
/*
* proc0 needs to have a coherent frame base, too.
* This probably makes the identical call for the init proc
* that happens later unnecessary since it should inherit
* it during the fork.
* proc0 needs to have a coherent frame base in it's stack.
*/
cpu_set_init_frame(p, init_framep); /* XXX! */
#endif /* INCOMPAT_LITES2*/
@ -499,7 +483,8 @@ static void kthread_init __P((void *dummy));
SYSINIT_KT(init,SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, kthread_init, NULL)
static void start_init __P((struct proc *p, void *framep));
extern void prepare_usermode __P((void));
static void start_init __P((struct proc *p));
/* ARGSUSED*/
static void
@ -508,11 +493,12 @@ kthread_init(dummy)
{
/* Create process 1 (init(8)). */
start_init(curproc, init_framep);
start_init(curproc);
prepare_usermode();
/*
* This is the only kernel thread allowed to return yo the
* caller!!!
* This returns to the fork trampoline, then to user mode.
*/
return;
}
@ -534,9 +520,8 @@ static char *initpaths[] = {
* The program is invoked with one argument containing the boot flags.
*/
static void
start_init(p, framep)
start_init(p)
struct proc *p;
void *framep;
{
vm_offset_t addr;
struct execve_args args;
@ -545,15 +530,6 @@ start_init(p, framep)
initproc = p;
/*
* We need to set the system call frame as if we were entered through
* a syscall() so that when we call execve() below, it will be able
* to set the entry point (see setregs) when it tries to exec. The
* startup code in "locore.s" has allocated space for the frame and
* passed a pointer to that space as main's argument.
*/
cpu_set_init_frame(p, framep);
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
* $Id: kern_exit.c,v 1.45 1997/02/22 09:39:04 peter Exp $
* $Id: kern_exit.c,v 1.46 1997/03/24 11:24:35 bde Exp $
*/
#include "opt_ktrace.h"
@ -171,8 +171,6 @@ exit1(p, rv)
/* The next two chunks should probably be moved to vmspace_exit. */
vm = p->p_vmspace;
if (vm->vm_shm)
shmexit(p);
/*
* Release user portion of address space.
* This releases references to vnodes,
@ -182,6 +180,8 @@ exit1(p, rv)
* may be mapped within that space also.
*/
if (vm->vm_refcnt == 1) {
if (vm->vm_shm)
shmexit(p);
pmap_remove_pages(&vm->vm_pmap, VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS);
(void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
* $Id$
* $Id: kern_fork.c,v 1.32 1997/02/22 09:39:05 peter Exp $
*/
#include "opt_ktrace.h"
@ -324,34 +324,10 @@ fork1(p1, flags, retval)
p1->p_flag |= P_NOSWAP;
/*
* share as much address space as possible
* XXX this should probably go in vm_fork()
* Finish creating the child process. It will return via a different
* execution path later. (ie: directly into user mode)
*/
if (flags & RFMEM)
(void) vm_map_inherit(&p1->p_vmspace->vm_map,
VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS - MAXSSIZ,
VM_INHERIT_SHARE);
/*
* Set return values for child before vm_fork,
* so they can be copied to child stack.
* We return parent pid, and mark as child in retval[1].
* NOTE: the kernel stack may be at a different location in the child
* process, and thus addresses of automatic variables (including retval)
* may be invalid after vm_fork returns in the child process.
*/
retval[0] = p1->p_pid;
retval[1] = 1;
if (vm_fork(p1, p2)) {
/*
* Child process. Set start time and get to work.
*/
microtime(&runtime);
(void) spl0();
p2->p_stats->p_start = runtime;
p2->p_acflag = AFORK;
return (0);
}
vm_fork(p1, p2, flags);
/*
* Both processes are set up, now check if any LKMs want
@ -366,6 +342,8 @@ fork1(p1, flags, retval)
/*
* Make child runnable and add to run queue.
*/
microtime(&(p2->p_stats->p_start));
p2->p_acflag = AFORK;
(void) splhigh();
p2->p_stat = SRUN;
setrunqueue(p2);

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.89 1997/04/06 02:29:19 dyson Exp $
* $Id: trap.c,v 1.90 1997/04/07 06:45:15 peter Exp $
*/
/*
@ -938,3 +938,22 @@ syscall(frame)
ktrsysret(p->p_tracep, code, error, rval[0]);
#endif
}
/*
* Simplified back end of syscall(), used when returning from fork()
* directly into user mode.
*/
void
fork_return(p, frame)
struct proc *p;
struct trapframe frame;
{
frame.tf_eax = 0; /* Child returns zero */
frame.tf_eflags &= ~PSL_C; /* success */
userret(p, &frame, 0);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p->p_tracep, SYS_fork, 0, 0);
#endif
}

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)proc.h 8.15 (Berkeley) 5/19/95
* $Id: proc.h,v 1.32 1997/02/22 09:45:41 peter Exp $
* $Id: proc.h,v 1.33 1997/03/03 09:51:12 ache Exp $
*/
#ifndef _SYS_PROC_H_
@ -91,6 +91,7 @@ struct proc {
struct filedesc *p_fd; /* Ptr to open files structure. */
struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */
struct plimit *p_limit; /* Process limits. */
struct vm_object *p_upages_obj;/* Upages object */
struct vmspace *p_vmspace; /* Address space. */
struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */
@ -306,7 +307,7 @@ void wakeup_one __P((void *chan));
void cpu_exit __P((struct proc *)) __dead2;
void exit1 __P((struct proc *, int)) __dead2;
int cpu_fork __P((struct proc *, struct proc *));
void cpu_fork __P((struct proc *, struct proc *));
int trace_req __P((struct proc *));
void cpu_wait __P((struct proc *));
int cpu_coredump __P((struct proc *, struct vnode *, struct ucred *));

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)vm_extern.h 8.2 (Berkeley) 1/12/94
* $Id: vm_extern.h,v 1.31 1997/02/22 09:48:11 peter Exp $
* $Id: vm_extern.h,v 1.32 1997/04/06 02:30:56 dyson Exp $
*/
#ifndef _VM_EXTERN_H_
@ -81,7 +81,7 @@ void vm_fault_copy_entry __P((vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t
void vm_fault_unwire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fault_wire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fault_user_wire __P((vm_map_t, vm_offset_t, vm_offset_t));
int vm_fork __P((struct proc *, struct proc *));
void vm_fork __P((struct proc *, struct proc *, int));
int vm_mmap __P((vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, caddr_t, vm_ooffset_t));
vm_offset_t vm_page_alloc_contig __P((vm_offset_t, vm_offset_t, vm_offset_t, vm_offset_t));
void vm_set_page_size __P((void));

View File

@ -59,7 +59,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id$
* $Id: vm_glue.c,v 1.61 1997/02/22 09:48:17 peter Exp $
*/
#include "opt_rlimit.h"
@ -74,6 +74,7 @@
#include <sys/kernel.h>
#include <sys/dkstat.h>
#include <sys/unistd.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -197,15 +198,13 @@ vsunlock(addr, len, dirtied)
* Here we arrange for the address space to be copied or referenced,
* allocate a user struct (pcb and kernel stack), then call the
* machine-dependent layer to fill those in and make the new process
* ready to run.
* NOTE: the kernel stack may be at a different location in the child
* process, and thus addresses of automatic variables may be invalid
* after cpu_fork returns in the child process. We do nothing here
* after cpu_fork returns.
* ready to run. The new process is set up so that it returns directly
* to user mode to avoid stack copying and relocation problems.
*/
int
vm_fork(p1, p2)
void
vm_fork(p1, p2, flags)
register struct proc *p1, *p2;
int flags;
{
register struct user *up;
int i;
@ -216,10 +215,15 @@ vm_fork(p1, p2)
VM_WAIT;
}
p2->p_vmspace = vmspace_fork(p1->p_vmspace);
if (flags & RFMEM) {
p2->p_vmspace = p1->p_vmspace;
p1->p_vmspace->vm_refcnt++;
} else {
p2->p_vmspace = vmspace_fork(p1->p_vmspace);
if (p1->p_vmspace->vm_shm)
shmfork(p1, p2);
if (p1->p_vmspace->vm_shm)
shmfork(p1, p2);
}
pmap_new_proc(p2);
@ -242,12 +246,10 @@ vm_fork(p1, p2)
/*
* cpu_fork will copy and update the kernel stack and pcb, and make
* the child ready to run. It marks the child so that it can return
* differently than the parent. It returns twice, once in the parent
* process and once in the child.
* cpu_fork will copy and update the pcb, set up the kernel stack,
* and make the child ready to run.
*/
return (cpu_fork(p1, p2));
cpu_fork(p1, p2);
}
/*

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_map.c,v 1.73 1997/04/06 02:29:43 dyson Exp $
* $Id: vm_map.c,v 1.74 1997/04/06 03:04:31 dyson Exp $
*/
/*
@ -256,9 +256,6 @@ vmspace_free(vm)
while( vm->vm_map.ref_count != 1)
tsleep(&vm->vm_map.ref_count, PVM, "vmsfre", 0);
--vm->vm_map.ref_count;
vm_object_pmap_remove(vm->vm_upages_obj,
0, vm->vm_upages_obj->size);
vm_object_deallocate(vm->vm_upages_obj);
pmap_release(&vm->vm_pmap);
FREE(vm, M_VMMAP);
} else {

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_map.h,v 1.24 1997/02/22 09:48:24 peter Exp $
* $Id: vm_map.h,v 1.25 1997/04/06 02:29:44 dyson Exp $
*/
/*
@ -152,7 +152,6 @@ struct vmspace {
struct pmap vm_pmap; /* private physical map */
int vm_refcnt; /* number of references */
caddr_t vm_shm; /* SYS5 shared memory private data XXX */
vm_object_t vm_upages_obj; /* UPAGES object */
/* we copy from vm_startcopy to the end of the structure on fork */
#define vm_startcopy vm_rssize
segsz_t vm_rssize; /* current resident set size in pages */