Subject: USPACE hardwiring on cxtswitch
To: None <port-mips@netbsd.org>
From: Toru Nishimura <nisimura@itc.aist-nara.ac.jp>
List: port-mips
Date: 04/03/2000 18:42:04
Here goes the hack job made last night to change MIPS context
switch code path.  Not well tested well, yet.  Code verification is
welcome.

Process USPACE (a storage for pcb and kernel stack) is hardwired in
TLB when a process newly gets CPU tick is about to start the
execution.  cpu_switch_resume() should be followings;

void
cpu_switch_resume(p)
        struct proc *p;
{
        vaddr_t va = (vaddr_t)p->p_addr;

        if (va <= MIPS_KSEG2_START)
                return;

        MIPS_TBIS(va);
        MIPS_TBIS(va + PAGE_SIZE);
        MIPS_TBDATA(0, va, p->p_md.md_upte[0] | PG_G); /* misnomer? */
        MIPS_TBDATA(1, va, p->p_md.md_upte[1] | PG_G);
}

Now, it'd be invoked as;

3:
/*
 * Switch to new context.
 */
        jal     _C_LABEL(cpu_switch_resume)     # wiredown USPACE
        move    s7, a0                          # save newproc
        lw      a0, P_ADDR(s7)
        sw      s7, _C_LABEL(curproc)           
        sw      a0, _C_LABEL(curpcb)
        jal     _C_LABEL(pmap_activate)		# assign new ASID
        move    a0, s7
        sw      zero, _C_LABEL(want_resched)    # we've context switched
        REG_PROLOGUE
        REG_L   v0, U_PCB_CONTEXT+SF_REG_SR(a0)
	...
 
The sample implementation of mips1_cpu_switch_resume() is;

LEAF_NOPROFILE(mips1_cpu_switch_resume)
        lw      a1, P_MD_UPTE_0(a0)             # a1 = upte[0]
        lw      a2, P_MD_UPTE_1(a0)             # a2 = upte[1]
        lw      s0, P_ADDR(a0)                  # va = p->p_addr
        li      s2, MIPS_KSEG2_START
        blt     s0, s2, resume
        nop
        mtc0    s0, MIPS_COP_0_TLB_HI           # VPN = va
        nop
        tlbp                                    # probe 1st VPN
        mfc0    s1, MIPS_COP_0_TLB_INDEX
        nop
        bltz    s1, entry0set
        li      s1, MIPS_KSEG0_START            # found, then
        mtc0    s1, MIPS_COP_0_TLB_HI
        mtc0    zero, MIPS_COP_0_TLB_LOW
        nop
        tlbwi                                   # TBIS(va)
        nop
        mtc0    s0, MIPS_COP_0_TLB_HI           # set 1st VPN again
entry0set:
        mtc0    zero, MIPS_COP_0_TLB_INDEX      # TLB index #0
        ori     a1, a1, MIPS1_PG_G
        mtc0    a1, MIPS_COP_0_TLB_LOW          # 1st PFN w/ PG_G
        nop
        tlbwi                                   # set TLB entry #0
        addu    s0, s0, NBPG
        mtc0    s0, MIPS_COP_0_TLB_HI           # VPN = va+NBPG
        nop
        tlbp                                    # probe 2nd VPN
        mfc0    s1, MIPS_COP_0_TLB_INDEX
        nop
        bltz    s1, entry1set
        li      s1, MIPS_KSEG0_START            # found, then
        mtc0    s1, MIPS_COP_0_TLB_HI
        mtc0    zero, MIPS_COP_0_TLB_LOW
        nop
        tlbwi                                   # TBIS(va+NBPG)
        nop
        mtc0    s0, MIPS_COP_0_TLB_HI           # set 2nd VPN again
entry1set:
        li      s1, 1 << MIPS1_TLB_INDEX_SHIFT
        mtc0    s1, MIPS_COP_0_TLB_INDEX        # TLB index #1
        ori     a2, a2, MIPS1_PG_G
        mtc0    a2, MIPS_COP_0_TLB_LOW          # 2nd PFN w/ PG_G
        nop
        tlbwi                                   # set TLB entry #1
resume:
        j       ra
        nop
        END(mips1_cpu_switch_resume)


pmap_activate() would be;

void 
pmap_activate(p)
        struct proc *p;
{
        pmap_t pmap = p->p_vmspace->vm_map.pmap;

        if (p == curproc) {
#ifdef  MIPS3
                if (CPUISMIPS3)
                        mips3_write_xcontext_upper((u_int32_t)pmap->pm_segtab);
#endif
                MachSetPID(pmap->pm_asid);
        }       
        p->p_addr->u_pcb.pcb_segtab = pmap->pm_segtab; /* XXX */
}

and pmap_asid_alloc(), which was renamed from pmap_alloc_asid(), is;

void 
pmap_asid_alloc(pmap)
        struct pmap *pmap;
{
        if (pmap == pmap_kernel())
                return;
        if (pmap->pm_asid == PMAP_ASID_RESERVED &&
            pmap->pm_asidgen == pmap_asid_generation)
                return;
        if (pmap_next_asid >= pmap_max_asid) {
                MIPS_TBIAP();  
                pmap_next_asid = 1;
                pmap_asid_generation += 1;
        }       
        pmap->pm_asid = pmap_next_asid++;
        pmap->pm_asidgen = pmap_asid_generation;
}

I'll post mips3_cpu_switch_resume() later.

Tohru Nishimura
Nara Institute of Science and Technology