diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-03-15 21:44:19 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-03-15 21:44:19 +0000 |
commit | 272e5ac533a4d733e5bb17d6eb9b1a8ce4c26df5 (patch) | |
tree | 1f73911329d48df3f982381c1abebeeb499bdb8a | |
parent | 95b13325476dd5114a97010e5cffb1a38740bb62 (diff) |
rewrite a pmap to use multilevel page tables.
lower 12 bits contain the perms, no unused bits left,
but a couple for off-tlb use (as the ref implemented now).
do not use the hvt, which might get some use later
if proven to speed thigs up, tlb handlers would po
another dozen of insns though, but if that's worth its...
move on the data seg and map kernel text rdonly (idea form fredette),
since all of the page0 mods done before that we are all fine
except for some viper fluff, but later w/ that.
this also picks up a bit more of ddb magic for bpt and ss.
tlb handlers can use a little bit more of attention,
but things, visually, seem to be much faster already, --
sorry, no benchmarks for now.
* effort sponsored in part by the `henry st. old ale house'
* and mr.pete and mr.lee in particular in thier generous entrirety.
* the proj took a little more that 72man*h as it was expected,
* but within murhy's law estimations.
-rw-r--r-- | sys/arch/hppa/conf/ld.script | 3 | ||||
-rw-r--r-- | sys/arch/hppa/dev/mem.c | 5 | ||||
-rw-r--r-- | sys/arch/hppa/gsc/if_ie_gsc.c | 10 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/genassym.cf | 21 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/locore.S | 293 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/machdep.c | 117 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/pmap.c | 1855 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/trap.c | 10 | ||||
-rw-r--r-- | sys/arch/hppa/hppa/vm_machdep.c | 7 | ||||
-rw-r--r-- | sys/arch/hppa/include/cpu.h | 4 | ||||
-rw-r--r-- | sys/arch/hppa/include/cpufunc.h | 7 | ||||
-rw-r--r-- | sys/arch/hppa/include/db_machdep.h | 30 | ||||
-rw-r--r-- | sys/arch/hppa/include/pmap.h | 240 | ||||
-rw-r--r-- | sys/arch/hppa/include/pte.h | 50 | ||||
-rw-r--r-- | sys/arch/hppa/include/vmparam.h | 4 |
15 files changed, 1075 insertions, 1581 deletions
diff --git a/sys/arch/hppa/conf/ld.script b/sys/arch/hppa/conf/ld.script index a05233c4c5a..7134843aae7 100644 --- a/sys/arch/hppa/conf/ld.script +++ b/sys/arch/hppa/conf/ld.script @@ -1,4 +1,4 @@ -/* $OpenBSD: ld.script,v 1.8 2001/11/29 17:28:09 mickey Exp $ */ +/* $OpenBSD: ld.script,v 1.9 2002/03/15 21:44:14 mickey Exp $ */ OUTPUT_FORMAT("elf32-hppa") OUTPUT_ARCH(hppa) @@ -22,6 +22,7 @@ SECTIONS __unwind_end = .; . = ALIGN(4096); } = 0 /* 0x08000240 nop filled, does not work */ + . = 0x400000; etext = ABSOLUTE(.); .data : diff --git a/sys/arch/hppa/dev/mem.c b/sys/arch/hppa/dev/mem.c index 2032abbb72c..008b4fcc63d 100644 --- a/sys/arch/hppa/dev/mem.c +++ b/sys/arch/hppa/dev/mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mem.c,v 1.9 2002/03/14 01:26:31 millert Exp $ */ +/* $OpenBSD: mem.c,v 1.10 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1998,1999 Michael Shalayeff @@ -164,14 +164,15 @@ memattach(parent, self, aux) printf (" viper rev %x, ctrl %b", sc->sc_vp->vi_status.hw_rev, VI_CTRL, VIPER_BITS); - s = splhigh(); +#if 0 VI_CTRL |= VI_CTRL_ANYDEN; ((struct vi_ctrl *)&VI_CTRL)->core_den = 0; ((struct vi_ctrl *)&VI_CTRL)->sgc0_den = 0; ((struct vi_ctrl *)&VI_CTRL)->sgc1_den = 0; ((struct vi_ctrl *)&VI_CTRL)->core_prf = 1; sc->sc_vp->vi_control = VI_CTRL; +#endif splx(s); #ifdef DEBUG printf (" >> %b", VI_CTRL, VIPER_BITS); diff --git a/sys/arch/hppa/gsc/if_ie_gsc.c b/sys/arch/hppa/gsc/if_ie_gsc.c index c37b285d2d7..a630796325f 100644 --- a/sys/arch/hppa/gsc/if_ie_gsc.c +++ b/sys/arch/hppa/gsc/if_ie_gsc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ie_gsc.c,v 1.10 2002/03/14 01:26:31 millert Exp $ */ +/* $OpenBSD: if_ie_gsc.c,v 1.11 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1998,1999 Michael Shalayeff @@ -85,7 +85,7 @@ static int ie_gsc_media[] = { }; #define IE_NMEDIA (sizeof(ie_gsc_media) / sizeof(ie_gsc_media[0])) -static char mem[IE_SIZE+16]; +char *ie_mem; void ie_gsc_reset(struct ie_softc *sc, int what); void ie_gsc_attend(struct ie_softc *sc); @@ -154,7 +154,7 @@ ie_gsc_attend(sc) { register volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh; - fdcache(0, (vaddr_t)&mem, sizeof(mem)); + fdcache(0, (vaddr_t)ie_mem, IE_SIZE); r->ie_attn = 0; } @@ -328,8 +328,8 @@ ie_gsc_attach(parent, self, aux) sc->sc_maddr = kvtop((caddr_t)sc->bh); #else - bzero(mem, sizeof(mem)); - sc->bh = ((u_int)&mem + 15) & ~0xf; + printf("%x ", ie_mem); + sc->bh = (u_int)ie_mem; sc->sc_maddr = sc->bh; #endif sc->sysbus = 0x40 | IE_SYSBUS_82586 | IE_SYSBUS_INTLOW | IE_SYSBUS_TRG | IE_SYSBUS_BE; diff --git a/sys/arch/hppa/hppa/genassym.cf b/sys/arch/hppa/hppa/genassym.cf index 53f2b449a17..6d3f4cb87e3 100644 --- a/sys/arch/hppa/hppa/genassym.cf +++ b/sys/arch/hppa/hppa/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.19 2002/01/16 20:50:16 miod Exp $ +# $OpenBSD: genassym.cf,v 1.20 2002/03/15 21:44:18 mickey Exp $ # # Copyright (c) 1982, 1990, 1993 @@ -69,24 +69,9 @@ export HPPA_BREAK_GET_PSW export HPPA_BREAK_SET_PSW # pte things -export TLB_REF_POS +#export TLB_REF_POS export TLB_GATE_PROT -export TLB_DIRTY_POS - -# hpt_table fields -struct hpt_entry -member hpt_tlbprot -member hpt_tlbpage -member hpt_entry -define HPT_TAG 0 - -# pv_entry fields -struct pv_entry -member pv_hash -member pv_space -member pv_va -member pv_tlbpage -member pv_tlbprot +#export TLB_DIRTY_POS # saved state fields struct trapframe diff --git a/sys/arch/hppa/hppa/locore.S b/sys/arch/hppa/hppa/locore.S index a6dbee2a517..e4108956232 100644 --- a/sys/arch/hppa/hppa/locore.S +++ b/sys/arch/hppa/hppa/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.59 2002/03/15 19:53:49 mickey Exp $ */ +/* $OpenBSD: locore.S,v 1.60 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1998-2002 Michael Shalayeff @@ -117,6 +117,11 @@ fpu_curpcb .comm 4 fpu_enable .comm 4 +$trap_tmp_save /* XXX assumed to be aligned on 2048 */ + .align 2048 + .block TF_PHYS /* XXX must be aligned to 64 */ + .align 64 + .text /* @@ -517,10 +522,6 @@ $bsd_syscall .export gateway_page_end, entry gateway_page_end -$trap_tmp_save /* XXX assumed to be aligned on 2048 */ - .block TF_PHYS /* XXX must be aligned to 64 */ - .align 64 - .export $syscall,entry .proc .callinfo calls @@ -898,6 +899,7 @@ $syscall_end #ifdef HP7000_CPU LDILDO(itlb_x) +LDILDO(itlbna_x) LDILDO(dtlb_x) LDILDO(dtlbna_x) LDILDO(tlbd_x) @@ -905,6 +907,7 @@ LDILDO(tlbd_x) #ifdef HP7100_CPU LDILDO(itlb_s) +LDILDO(itlbna_s) LDILDO(dtlb_s) LDILDO(dtlbna_s) LDILDO(tlbd_s) @@ -912,6 +915,7 @@ LDILDO(tlbd_s) #ifdef HP7200_CPU LDILDO(itlb_t) +LDILDO(itlbna_t) LDILDO(dtlb_t) LDILDO(dtlbna_t) LDILDO(tlbd_t) @@ -919,6 +923,7 @@ LDILDO(tlbd_t) #ifdef HP7100LC_CPU LDILDO(itlb_l) +LDILDO(itlbna_l) LDILDO(dtlb_l) LDILDO(dtlbna_l) LDILDO(tlbd_l) @@ -960,8 +965,8 @@ hpmc_v ATRAP(excpt,T_EXCEPTION) #endif STRAP(dtlb,T_DTLBMISS,DTLBPRE) /* 15. data TLB miss fault */ - STRAP(itlb,T_ITLBMISSNA,ITLBPRE)/* 16. ITLB non-access miss fault */ - STRAP(dtlb,T_DTLBMISSNA,DTLBPRE)/* 17. DTLB non-access miss fault */ + STRAP(itlbna,T_ITLBMISSNA,ITLBPRE)/* 16. ITLB non-access miss fault */ + STRAP(dtlbna,T_DTLBMISSNA,DTLBPRE)/* 17. DTLB non-access miss fault */ ATRAP(dprot,T_DPROT) /* 18. data protection trap unalligned data reference trap */ ATRAP(dbrk,T_DBREAK) /* 19. data break trap */ @@ -1303,48 +1308,54 @@ LEAF_ENTRY(desidhash_t) EXIT(desidhash_t) #endif +#if defined(HP7000_CPU) || defined(HP7100_CPU) || defined(HP7200_CPU) +#define TLB_PULL(bits) ! \ + /* space:pgaddr -- r8:r9 */ ! \ + mfctl vtop, r16 ! \ + ldwax,s r8(r16), r17 /* space -> page directory */ ! \ + extru r9, 9, 10, r25 ! \ + combt,=,n r0, r17, TLABEL(all) ! \ + ldwax,s r25(r17), r24 /* page -> page table */ ! \ + extru r9, 19, 10, r16 ! \ + combt,=,n r0, r24, TLABEL(all) ! \ + ldwax,s r16(r24), r17 /* va -> pa:prot */ ! \ + sh2addl r16, r24, r25 ! \ + combt,=,n r0, r17, TLABEL(all) ! \ + depi (bits), 21+bits, 1+bits, r17 ! \ + mfctl tr7, r1 ! \ + stwas r17, 0(r25) /* store back w/ the bits */ ! \ + shd r17, r0, 13, r25 ! \ + dep r8, 30, 15, r25 /* mix0r the pid from the sid */! \ + dep r0, 31, 12, r17 /* needed ? */ ! \ + addi 2, r25, r25 ! \ + extru r17, 24, 25, r17 + $tlbd_x $tlbd_s $tlbd_t -#if 1 - HPTENT - mtctl r24, cr28 - - /* - * Chase the list of entries for this hash bucket until we find - * the correct mapping or NULL. - */ - ldw HPT_ENTRY(r24), r24 -$hash_loop_tlbd_t - comb,=,n r0, r24, TLABEL(all) - ldw PV_VA(r24), r25 - ldw PV_SPACE(r24), r17 - comb,<>,n r9, r25, $hash_loop_tlbd_t - ldw PV_HASH(r24), r24 - comb,<>,n r8, r17, $hash_loop_tlbd_t - ldw PV_HASH(r24), r24 - - VTAG /* (r8,r9) -> r16 */ - /* Set the dirty bit for this physical page. */ - ldw PV_TLBPROT(r24), r25 - b $tlb_inshpt_t - depi 1, TLB_DIRTY_POS, 1, r25 -#else - - mfsp %sr1, %r25 - mtsp %r8, %sr1 - lpa %r0(%sr1, %r9), %r17 - mfctl %cr29, %r16 - mtsp %r25, %sr1 - extru %r17, 20, 21, %r24 - sh3add %r24, %r16, %r16 - -#endif + TLB_PULL(1) + mfsp sr1, r16 + mtsp r8, sr1 + idtlba r17,(sr1, r9) + idtlbp r25,(sr1, r9) + mtsp r16, sr1 + rfir + nop $itlb_x +$itlbna_x $itlb_s +$itlbna_s $itlb_t - depi 1, TFF_ITLB_POS, 1, r1 /* mark for ITLB insert */ +$itlbna_t + TLB_PULL(0) + mfsp sr1, r16 + mtsp r8, sr1 + iitlba r17,(sr1, r9) + iitlbp r25,(sr1, r9) + mtsp r16, sr1 + rfir + nop $dtlb_x $dtlbna_x @@ -1352,77 +1363,15 @@ $dtlb_s $dtlbna_s $dtlb_t $dtlbna_t - /* - * r1 is the trap type - * r8 is the space of the address that had the TLB miss - * r9 is the offset of the address that had the TLB miss - * r24 is the correspondent HPT entry pointer - */ - - HPTENT - mtctl r24, cr28 - - ldw HPT_TAG(r24),r17 - VTAG /* (r8,r9) -> r16 */ - - /* Compare the tag against the HPT entry. - If it matches, then do the TLB insertion. */ - comb,<>,n r16, r17, $tlb_gottalook_t - - ldw HPT_TLBPAGE(r24), r17 - b $tlb_gothpt_t - ldw HPT_TLBPROT(r24), r25 - -$tlb_gottalook_t - /* - * Chase the list of entries for this hash bucket until we find - * the correct mapping or NULL. - */ - ldw HPT_ENTRY(r24),r24 -$hash_loop_t - comb,=,n r0, r24, TLABEL(all) - ldw PV_VA(r24),r25 - ldw PV_SPACE(r24),r17 - comb,<>,n r9,r25,$hash_loop_t - ldw PV_HASH(r24),r24 - comb,<>,n r8,r17,$hash_loop_t - ldw PV_HASH(r24),r24 - - /* Now set things up to enter the real mapping that we want */ - ldw PV_TLBPROT(r24),r25 - depi 1, TLB_REF_POS, 1, r25 - - /* - * Load the HPT cache with the miss information for the next time. - */ -$tlb_inshpt_t - stw r25, PV_TLBPROT(r24) - ldw PV_TLBPAGE(r24),r17 - mfctl cr28, r24 - - stw r16, HPT_TAG(r24) - stw r25, HPT_TLBPROT(r24) - stw r17, HPT_TLBPAGE(r24) - -$tlb_gothpt_t + TLB_PULL(0) mfsp sr1, r16 - bb,< r1, TFF_ITLB_POS, $tlb_itlb_t mtsp r8, sr1 - idtlba r17,(sr1, r9) idtlbp r25,(sr1, r9) - nop ! nop - mtsp r16, sr1 - rfir - nop - -$tlb_itlb_t - iitlba r17,(sr1, r9) - iitlbp r25,(sr1, r9) - nop ! nop mtsp r16, sr1 rfir nop +#endif /* defined(HP7000_CPU) || defined(HP7100_CPU) || defined(HP7200_CPU) */ #ifdef HP7100LC_CPU /* @@ -1481,98 +1430,58 @@ EXIT(desidhash_l) .align 32 -$tlbd_l - mfctl cr28, r24 +#define IITLBAF(r) .word 0x04000440 | ((r) << 16) +#define IITLBPF(r) .word 0x04000400 | ((r) << 16) +#define IDTLBAF(r) .word 0x04001440 | ((r) << 16) +#define IDTLBPF(r) .word 0x04001400 | ((r) << 16) - /* - * Chase the list of entries for this hash bucket until we find - * the correct mapping or NULL. - */ - ldw HPT_ENTRY(r24), r16 -$hash_loop_tlbd_l - comb,=,n r0, r16, TLABEL(all) - ldw PV_VA(r16), r25 - ldw PV_SPACE(r16), r17 - comb,<>,n r9, r25, $hash_loop_tlbd_l - ldw PV_HASH(r16), r16 - comb,<>,n r8, r17, $hash_loop_tlbd_l - ldw PV_HASH(r16), r16 - - /* Set the dirty bit for this physical page. */ - ldw PV_TLBPAGE(r16), r17 - ldw PV_TLBPROT(r16), r25 - depi 1, TLB_DIRTY_POS, 1, r25 - depi 1, TLB_REF_POS, 1, r25 - stw r25, PV_TLBPROT(r16) - VTAG /* (r8,r9) -> r16 */ - - stw r16, HPT_TAG(r24) - stw r25, HPT_TLBPROT(r24) - stw r17, HPT_TLBPAGE(r24) - - .word 0x04111440 ; idtlbaf r17 - .word 0x04191400 ; idtlbpf r25 - nop ! nop +/* + * possible optimizations: + * change pte to reduce number of shifts + * reorder to reduce stalls + * check if stwas is needed (if we changed the bits) + */ +#define TLB_PULL_L(bits) ! \ + /* space:pgaddr -- r8:r9 */ ! \ + mfctl vtop, r16 ! \ + ldwax,s r8(r16), r17 /* space -> page directory */ ! \ + extru r9, 9, 10, r25 ! \ + combt,=,n r0, r17, TLABEL(all) ! \ + ldwax,s r25(r17), r24 /* page -> page table */ ! \ + extru r9, 19, 10, r16 ! \ + combt,=,n r0, r24, TLABEL(all) ! \ + ldwax,s r16(r24), r17 /* va -> pa:prot */ ! \ + sh2addl r16, r24, r25 ! \ + combt,=,n r0, r17, TLABEL(all) ! \ + depi (bits), 21+bits, 1+bits, r17 ! \ + mfctl tr7, r1 ! \ + stwas r17, 0(r25) /* store back w/ the bits */ ! \ + shd r17, r0, 13, r25 ! \ + dep r8, 30, 15, r25 /* mix0r the pid from the sid */! \ + dep r0, 31, 12, r17 /* needed ? */ ! \ + addi 2, r25, r25 ! \ + extru r17, 24, 25, r17 + +$tlbd_l + TLB_PULL_L(1) + IDTLBAF(17) + IDTLBPF(25) rfir nop - - .align 8 +$itlbna_l $itlb_l - depi 1, TFF_ITLB_POS, 1, r1 /* mark for ITLB insert */ -$dtlbna_l - HPTENT - mtctl r24, cr28 - -$dtlb_l - mfctl cr28, r24 - /* - * r1 is the trap type - * r8 is the space of the address that had the TLB miss - * r9 is the offset of the address that had the TLB miss - * r24 is the correspondent HPT entry pointer - */ - - /* - * Chase the list of entries for this hash bucket until we find - * the correct mapping or NULL. - */ - ldw HPT_ENTRY(r24), r16 -$hash_loop_l - comb,=,n r0, r16, TLABEL(all) - ldw PV_VA(r16), r25 - ldw PV_SPACE(r16), r17 - comb,<>,n r9, r25, $hash_loop_l - ldw PV_HASH(r16), r16 - comb,<>,n r8, r17, $hash_loop_l - ldw PV_HASH(r16), r16 - - /* Now set things up to enter the real mapping that we want */ - ldw PV_TLBPAGE(r16), r17 - ldw PV_TLBPROT(r16), r25 - - /* - * Load the HPT cache with the miss information for the next time. - * The HPT entry address was saved by the HPTENT - */ - depi 1, TLB_REF_POS, 1, r25 - stw r25, PV_TLBPROT(r16) - VTAG /* (r8,r9) -> r16 */ - - stw r16, HPT_TAG(r24) - stw r25, HPT_TLBPROT(r24) - bb,< r1, TFF_ITLB_POS, $tlb_itlb_l - stw r17, HPT_TLBPAGE(r24) - - .word 0x04111440 ; idtlbaf r17 - .word 0x04191400 ; idtlbpf r25 - nop ! nop +#if 0 /* XXX assume combined TLB */ + TLB_PULL_L(0) + IITLBAF(17) + IITLBPF(25) rfir nop - -$tlb_itlb_l - .word 0x04110440 ; iitlbaf r17 - .word 0x04190400 ; iitlbpf r25 - nop ! nop +#endif +$dtlbna_l +$dtlb_l + TLB_PULL_L(0) + IDTLBAF(17) + IDTLBPF(25) rfir nop #endif /* HP7100LC_CPU */ diff --git a/sys/arch/hppa/hppa/machdep.c b/sys/arch/hppa/hppa/machdep.c index ebacbf7c8ab..48ace22fc02 100644 --- a/sys/arch/hppa/hppa/machdep.c +++ b/sys/arch/hppa/hppa/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.61 2002/03/14 01:26:31 millert Exp $ */ +/* $OpenBSD: machdep.c,v 1.62 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1999-2002 Michael Shalayeff @@ -184,7 +184,9 @@ void hppa_user2frame(struct trapframe *sf, struct trapframe *tf); /* * wide used hardware params */ +#if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) struct pdc_hwtlb pdc_hwtlb PDC_ALIGNMENT; +#endif struct pdc_coproc pdc_coproc PDC_ALIGNMENT; struct pdc_coherence pdc_coherence PDC_ALIGNMENT; struct pdc_spidb pdc_spidbits PDC_ALIGNMENT; @@ -198,10 +200,10 @@ pid_t sigpid = 0; /* * Whatever CPU types we support */ -extern const u_int itlb_x[], dtlb_x[], dtlbna_x[], tlbd_x[]; -extern const u_int itlb_s[], dtlb_s[], dtlbna_s[], tlbd_s[]; -extern const u_int itlb_t[], dtlb_t[], dtlbna_t[], tlbd_t[]; -extern const u_int itlb_l[], dtlb_l[], dtlbna_l[], tlbd_l[]; +extern const u_int itlb_x[], itlbna_x[], dtlb_x[], dtlbna_x[], tlbd_x[]; +extern const u_int itlb_s[], itlbna_s[], dtlb_s[], dtlbna_s[], tlbd_s[]; +extern const u_int itlb_t[], itlbna_t[], dtlb_t[], dtlbna_t[], tlbd_t[]; +extern const u_int itlb_l[], itlbna_l[], dtlb_l[], dtlbna_l[], tlbd_l[]; int iibtlb_s(int i, pa_space_t sp, vaddr_t va, paddr_t pa, vsize_t sz, u_int prot); int idbtlb_s(int i, pa_space_t sp, vaddr_t va, paddr_t pa, @@ -226,7 +228,7 @@ const struct hppa_cpu_typed { int arch; int features; int (*desidhash)(void); - const u_int *itlbh, *dtlbh, *dtlbnah, *tlbdh; + const u_int *itlbh, *itlbnah, *dtlbh, *dtlbnah, *tlbdh; int (*dbtlbins)(int i, pa_space_t sp, vaddr_t va, paddr_t pa, vsize_t sz, u_int prot); int (*ibtlbins)(int i, pa_space_t sp, vaddr_t va, paddr_t pa, @@ -236,50 +238,50 @@ const struct hppa_cpu_typed { } cpu_types[] = { #ifdef HP7000_CPU { "PCX", hpcx, 0x10, 0, - desidhash_x, itlb_x, dtlb_x, dtlbna_x, tlbd_x, + desidhash_x, itlb_x, itlbna_l, dtlb_x, dtlbna_x, tlbd_x, ibtlb_g, NULL, pbtlb_g}, #endif #ifdef HP7100_CPU - { "PCXS", hpcxs, 0x11, HPPA_FTRS_BTLBS, - desidhash_s, itlb_s, dtlb_s, dtlbna_s, tlbd_s, + { "PCXS", hpcxs, 0x11, 0, + desidhash_s, itlb_s, itlbna_l, dtlb_s, dtlbna_s, tlbd_s, ibtlb_g, NULL, pbtlb_g}, #endif #ifdef HP7200_CPU { "PCXT", hpcxt, 0x11, HPPA_FTRS_BTLBU, - desidhash_t, itlb_t, dtlb_t, dtlbna_t, tlbd_t, + desidhash_t, itlb_t, itlbna_l, dtlb_t, dtlbna_t, tlbd_t, ibtlb_g, NULL, pbtlb_g}, /* HOW? { "PCXT'", hpcxta,0x11, HPPA_FTRS_BTLBU, - desidhash_t, itlb_t, dtlb_t, dtlbna_t, tlbd_t, + desidhash_t, itlb_t, itlbna_l, dtlb_t, dtlbna_t, tlbd_t, ibtlb_g, NULL, pbtlb_g}, */ #endif #ifdef HP7100LC_CPU { "PCXL", hpcxl, 0x11, HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_l, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_l, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, #endif #ifdef HP7300LC_CPU /* HOW? { "PCXL2", hpcxl2,0x11, HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_l, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_l, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, */ #endif #ifdef HP8000_CPU { "PCXU", hpcxu, 0x20, HPPA_FTRS_W32B|HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_g, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_g, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, #endif #ifdef HP8200_CPU /* HOW? { "PCXU2", hpcxu2,0x20, HPPA_FTRS_W32B|HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_g, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_g, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, */ #endif #ifdef HP8500_CPU /* HOW? { "PCXW", hpcxw, 0x20, HPPA_FTRS_W32B|HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_g, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_g, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, */ #endif #ifdef HP8600_CPU /* HOW? { "PCXW+", hpcxw, 0x20, HPPA_FTRS_W32B|HPPA_FTRS_BTLBU|HPPA_FTRS_HVT, - desidhash_g, itlb_l, dtlb_l, dtlbna_l, tlbd_l, + desidhash_g, itlb_l, itlbna_l, dtlb_l, dtlbna_l, tlbd_l, ibtlb_g, NULL, pbtlb_g, hpti_g}, */ #endif { "", 0 } @@ -290,10 +292,8 @@ hppa_init(start) paddr_t start; { extern int kernel_text; - vaddr_t v, vstart, vend; - register int error; - int hptsize; /* size of HPT table if supported */ - int cpu_features = 0; + vaddr_t v, v1; + int error, cpu_features = 0; boothowto |= RB_SINGLE; /* XXX always go into single-user while debug */ @@ -364,6 +364,9 @@ hppa_init(start) PAGE0->ivec_mempflen = (hppa_pfr_end - hppa_pfr + 1) * 4; } + /* may the scientific guessing begin */ + cpu_features = 0; + /* BTLB params */ if ((error = pdc_call((iodcio_t)pdc, 0, PDC_BLOCK_TLB, PDC_BTLB_DEFAULT, &pdc_btlb)) < 0) { @@ -388,8 +391,8 @@ hppa_init(start) PDC_BTLB_PURGE_ALL) < 0) printf("WARNING: BTLB purge failed\n"); - cpu_features = pdc_btlb.finfo.num_c? - HPPA_FTRS_BTLBU : HPPA_FTRS_BTLBS; + if (pdc_btlb.finfo.num_c) + cpu_features |= HPPA_FTRS_BTLBU; } ptlball(); @@ -398,24 +401,14 @@ hppa_init(start) totalphysmem = PAGE0->imm_max_mem / NBPG; resvmem = ((vaddr_t)&kernel_text) / NBPG; - /* calculate HPT size */ - for (hptsize = 256; hptsize < totalphysmem; hptsize *= 2); - hptsize *= 16; /* sizeof(hpt_entry) */ - +#if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) if (pdc_call((iodcio_t)pdc, 0, PDC_TLB, PDC_TLB_INFO, &pdc_hwtlb) && !pdc_hwtlb.min_size && !pdc_hwtlb.max_size) { printf("WARNING: no HPT support, fine!\n"); - mtctl(hptsize - 1, CR_HPTMASK); - hptsize = 0; - } else { + pmap_hptsize = 0; + } else cpu_features |= HPPA_FTRS_HVT; - - if (hptsize > pdc_hwtlb.max_size) - hptsize = pdc_hwtlb.max_size; - else if (hptsize < pdc_hwtlb.min_size) - hptsize = pdc_hwtlb.min_size; - mtctl(hptsize - 1, CR_HPTMASK); - } +#endif /* * Deal w/ CPU now @@ -452,8 +445,13 @@ hppa_init(start) LDILDO(trap_ep_T_TLB_DIRTY , p->tlbdh); LDILDO(trap_ep_T_DTLBMISS , p->dtlbh); LDILDO(trap_ep_T_DTLBMISSNA, p->dtlbnah); - LDILDO(trap_ep_T_ITLBMISS , p->itlbh); - LDILDO(trap_ep_T_ITLBMISSNA, p->itlbh); + if (pdc_cache.dt_conf.tc_sh) { + LDILDO(trap_ep_T_DTLBMISS , p->dtlbh); + LDILDO(trap_ep_T_DTLBMISSNA, p->dtlbnah); + } else { + LDILDO(trap_ep_T_ITLBMISS , p->itlbh); + LDILDO(trap_ep_T_ITLBMISSNA, p->itlbnah); + } #undef LDILDO } } @@ -466,9 +464,6 @@ hppa_init(start) EX_NOWAIT)) panic("cannot reserve main memory"); - vstart = hppa_round_page(start); - vend = VM_MAX_KERNEL_ADDRESS; - /* * Now allocate kernel dynamic variables */ @@ -491,7 +486,7 @@ hppa_init(start) if (bufpages > nbuf * MAXBSIZE / PAGE_SIZE) bufpages = nbuf * MAXBSIZE / PAGE_SIZE; - v = vstart; + v1 = v = hppa_round_page(start); #define valloc(name, type, num) (name) = (type *)v; v = (vaddr_t)((name)+(num)) valloc(buf, struct buf, nbuf); @@ -514,34 +509,16 @@ hppa_init(start) #undef valloc v = hppa_round_page(v); - bzero ((void *)vstart, (v - vstart)); - vstart = v; + bzero ((void *)v1, (v - v1)); /* sets physmem */ - pmap_bootstrap(&vstart, &vend); + pmap_bootstrap(v); /* alloc msgbuf */ if (!(msgbufp = (void *)pmap_steal_memory(MSGBUFSIZE, NULL, NULL))) panic("cannot allocate msgbuf"); msgbufmapped = 1; - /* Turn on the HW TLB assist */ - if (hptsize) { - u_int hpt; - - mfctl(CR_VTOP, hpt); - if ((error = (cpu_hpt_init)(hpt, hptsize)) < 0) { -#ifdef DEBUG - printf("WARNING: HPT init error %d\n", error); -#endif - } else { -#ifdef PMAPDEBUG - printf("HPT: %d entries @ 0x%x\n", - hptsize / sizeof(struct hpt_entry), hpt); -#endif - } - } - /* locate coprocessors and SFUs */ if ((error = pdc_call((iodcio_t)pdc, 0, PDC_COPROC, PDC_COPROC_DFLT, &pdc_coproc)) < 0) @@ -630,10 +607,6 @@ cpu_startup() printf("real mem = %d (%d reserved for PROM, %d used by OpenBSD)\n", ctob(totalphysmem), ctob(resvmem), ctob(physmem)); - /* - * Now allocate buffers proper. They are different than the above - * in that they usually occupy more virtual memory than physical. - */ size = MAXBSIZE * nbuf; if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, @@ -661,9 +634,8 @@ cpu_startup() if ((pg = uvm_pagealloc(NULL, 0, NULL, 0)) == NULL) panic("cpu_startup: not enough memory for " "buffer cache"); - pmap_enter(kernel_map->pmap, curbuf, - VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE, - VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); + pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), + VM_PROT_READ|VM_PROT_WRITE); curbuf += PAGE_SIZE; curbufsize -= PAGE_SIZE; } @@ -890,11 +862,12 @@ btlb_insert(space, va, pa, lenp, prot) va >>= PGSHIFT; /* check address alignment */ if (pa & (len - 1)) - printf("WARNING: BTLB address misaligned\n"); + printf("WARNING: BTLB address misaligned pa=0x%x, len=0x%x\n", + pa, len); /* ensure IO space is uncached */ if ((pa & 0xF0000) == 0xF0000) - prot |= TLB_UNCACHEABLE; + prot |= TLB_UNCACHABLE; #ifdef BTLBDEBUG printf("btlb_insert(%d): %x:%x=%x[%x,%x]\n", i, space, va, pa, len, prot); diff --git a/sys/arch/hppa/hppa/pmap.c b/sys/arch/hppa/hppa/pmap.c index aeb1b1ff72e..30bb0d71213 100644 --- a/sys/arch/hppa/hppa/pmap.c +++ b/sys/arch/hppa/hppa/pmap.c @@ -1,7 +1,7 @@ -/* $OpenBSD: pmap.c,v 1.61 2002/03/14 01:26:31 millert Exp $ */ +/* $OpenBSD: pmap.c,v 1.62 2002/03/15 21:44:18 mickey Exp $ */ /* - * Copyright (c) 1998-2001 Michael Shalayeff + * Copyright (c) 1998-2002 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,104 +24,12 @@ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * MOND, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Copyright 1996 1995 by Open Software Foundation, Inc. - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Mach Operating System - * Copyright (c) 1990,1991,1992,1993,1994 The University of Utah and - * the Computer Systems Laboratory (CSL). - * Copyright (c) 1991,1987 Carnegie Mellon University. - * All rights reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation, - * and that all advertising materials mentioning features or use of - * this software display the following acknowledgement: ``This product - * includes software developed by the Computer Systems Laboratory at - * the University of Utah.'' - * - * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF - * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY - * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF - * THIS SOFTWARE. - * - * CSL requests users of this software to return to csl-dist@cs.utah.edu any - * improvements that they make and grant CSL redistribution rights. - * - * Carnegie Mellon requests users of this software to return to - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - * - * Utah $Hdr: pmap.c 1.49 94/12/15$ - * Author: Mike Hibler, Bob Wheeler, University of Utah CSL, 10/90 - */ -/* - * Manages physical address maps for hppa. - * - * In addition to hardware address maps, this - * module is called upon to provide software-use-only - * maps which may or may not be stored in the same - * form as hardware maps. These pseudo-maps are - * used to store intermediate results from copy - * operations to and from address spaces. - * - * Since the information managed by this module is - * also stored by the logical address mapping module, - * this module may throw away valid virtual-to-physical - * mappings at almost any time. However, invalidations - * of virtual-to-physical mappings must be done as - * requested. - * - * In order to cope with hardware architectures which - * make virtual-to-physical map invalidates expensive, - * this module may delay invalidate or reduced protection - * operations until such time as they are actually - * necessary. This module is given full information to - * when physical maps must be made correct. - * - */ -/* - * CAVEATS: - * - * PAGE_SIZE must equal NBPG - * Needs more work for MP support - * page maps are stored as linear linked lists, some - * improvement may be achieved should we use smth else - * protection id (pid) allocation should be done in a pid_t fashion - * (maybe just use the pid itself) - * some ppl say, block tlb entries should be maintained somewhere in uvm - * and be ready for reloads in the fault handler. - * * References: * 1. PA7100LC ERS, Hewlett-Packard, March 30 1999, Public version 1.0 * 2. PA7300LC ERS, Hewlett-Packard, March 18 1996, Version 1.0 @@ -133,6 +41,7 @@ #include <sys/lock.h> #include <sys/user.h> #include <sys/proc.h> +#include <sys/pool.h> #include <sys/malloc.h> #include <uvm/uvm.h> @@ -161,17 +70,18 @@ #define PDB_BITS 0x00000080 #define PDB_COLLECT 0x00000100 #define PDB_PROTECT 0x00000200 -#define PDB_PDRTAB 0x00000400 -#define PDB_VA 0x00000800 +#define PDB_EXTRACT 0x00000400 +#define PDB_VP 0x00000800 #define PDB_PV 0x00001000 #define PDB_PARANOIA 0x00002000 #define PDB_WIRING 0x00004000 -#define PDB_PVDUMP 0x00008000 +#define PDB_PMAP 0x00008000 #define PDB_STEAL 0x00010000 #define PDB_PHYS 0x00020000 +#define PDB_POOL 0x00040000 int pmapdebug = 0 /* | PDB_FOLLOW */ -/* | PDB_VA */ +/* | PDB_VP */ /* | PDB_PV */ /* | PDB_INIT */ /* | PDB_ENTER */ @@ -184,35 +94,35 @@ int pmapdebug = 0 #define DPRINTF(l,s) /* */ #endif -vaddr_t virtual_steal, virtual_avail, virtual_end; +vaddr_t virtual_steal, virtual_avail; + +#if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) +int pmap_hptsize = 256; /* patchable */ +#endif struct pmap kernel_pmap_store; -pmap_t kernel_pmap; +int pmap_sid_counter, hppa_sid_max = HPPA_SID_MAX; boolean_t pmap_initialized = FALSE; +struct pool pmap_pmap_pool; +struct pool pmap_pv_pool; +struct simplelock pvalloc_lock; -TAILQ_HEAD(, pmap) pmap_freelist; /* list of free pmaps */ -u_int pmap_nfree; -struct simplelock pmap_freelock; /* and lock */ - -struct simplelock pmap_lock; /* XXX this is all broken */ -struct simplelock sid_pid_lock; /* pids */ - -u_int pages_per_vm_page; -u_int sid_counter; +void *pmap_pv_page_alloc(struct pool *, int); +void pmap_pv_page_free(struct pool *, void *); -TAILQ_HEAD(, pv_page) pv_page_freelist; -u_int pv_nfree; - -#ifdef PMAPDEBUG -void pmap_hptdump(int sp); -#endif +struct pool_allocator pmap_allocator_pv = { + pmap_pv_page_alloc, pmap_pv_page_free, 0 +}; -u_int kern_prot[8], user_prot[8]; +u_int hppa_prot[8]; -void pmap_pinit(pmap_t); #define pmap_sid(pmap, va) \ (((va & 0xc0000000) != 0xc0000000)? pmap->pmap_space : HPPA_SID_KERNEL) +#define pmap_pvh_attrs(a) \ + (((a) & PTE_PROT(TLB_DIRTY)) | ((a) ^ PTE_PROT(TLB_REFTRAP))) + +#if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) /* * This hash function is the one used by the hardware TLB walker on the 7100LC. */ @@ -231,497 +141,368 @@ pmap_hash(pa_space_t sp, vaddr_t va) : "=r" (hpt) : "r" (sp), "r" (va) : "r22", "r23"); return hpt; } +#endif -/* - * pmap_enter_va(space, va, pv) - * insert mapping entry into va->pa translation hash table. - */ static __inline void -pmap_enter_va(struct pv_entry *pv) +pmap_sdir_set(pa_space_t space, paddr_t pa) { - struct hpt_entry *hpt = pmap_hash(pv->pv_space, pv->pv_va); -#if defined(PMAPDEBUG) || defined(DIAGNOSTIC) - struct pv_entry *pvp = hpt->hpt_entry; -#endif - DPRINTF(PDB_FOLLOW | PDB_VA, - ("pmap_enter_va(%x,%x,%p): hpt=%p, pvp=%p\n", - pv->pv_space, pv->pv_va, pv, hpt, pvp)); -#ifdef DIAGNOSTIC - while(pvp && (pvp->pv_va != pv->pv_va || pvp->pv_space != pv->pv_space)) - pvp = pvp->pv_hash; - if (pvp) - panic("pmap_enter_va: pv_entry is already in hpt_table"); + paddr_t vtop; + + mfctl(CR_VTOP, vtop); +#ifdef PMAPDEBUG + if (!vtop) + panic("pmap_sdir_set: zero vtop"); #endif - /* we assume that normally there are no duplicate entries - would be inserted (use DIAGNOSTIC should you want a proof) */ - pv->pv_hash = hpt->hpt_entry; - hpt->hpt_entry = pv; + asm("stwas %0, 0(%1)":: "r" (pa), "r" (vtop + (space << 2))); } -/* - * pmap_find_va(space, va) - * returns address of the pv_entry correspondent to sp:va - */ -static __inline struct pv_entry * -pmap_find_va(pa_space_t space, vaddr_t va) +static __inline paddr_t +pmap_sdir_get(pa_space_t space) { - struct pv_entry *pvp = pmap_hash(space, va)->hpt_entry; + paddr_t vtop, pa; - DPRINTF(PDB_FOLLOW | PDB_VA, ("pmap_find_va(%x,%x)\n", space, va)); + mfctl(CR_VTOP, vtop); + asm("ldwax,s %2(%1), %0": "=&r" (pa) : "r" (vtop), "r" (space)); - while(pvp && (pvp->pv_va != va || pvp->pv_space != space)) - pvp = pvp->pv_hash; - - return pvp; + return (pa); } -/* - * Clear the HPT table entry for the corresponding space/offset to reflect - * the fact that we have possibly changed the mapping, and need to pick - * up new values from the mapping structure on the next access. - */ -static __inline void -pmap_clear_va(pa_space_t space, vaddr_t va) +static __inline pt_entry_t * +pmap_pde_get(paddr_t pa, vaddr_t va) { - struct hpt_entry *hpt = pmap_hash(space, va); + pt_entry_t *pde; + + asm("ldwax,s %2(%1), %0": "=&r" (pde) : "r" (pa), "r" (va >> 22)); - hpt->hpt_valid = 0; - hpt->hpt_space = -1; + return (pde); } -/* - * pmap_remove_va(pv) - * removes pv_entry from the va->pa translation hash table - */ static __inline void -pmap_remove_va(struct pv_entry *pv) +pmap_pde_set(struct pmap *pm, vaddr_t va, paddr_t ptp) { - struct hpt_entry *hpt = pmap_hash(pv->pv_space, pv->pv_va); - struct pv_entry **pvp = (struct pv_entry **)&hpt->hpt_entry; - - DPRINTF(PDB_FOLLOW | PDB_VA, - ("pmap_remove_va(%p), hpt=%p, pvp=%p\n", pv, hpt, pvp)); - - while(*pvp && *pvp != pv) - pvp = &(*pvp)->pv_hash; - if (*pvp) { - *pvp = (*pvp)->pv_hash; - pv->pv_hash = NULL; - if (hptbtop(pv->pv_va) == hpt->hpt_vpn && - pv->pv_space == hpt->hpt_space) { - hpt->hpt_space = -1; - hpt->hpt_valid = 0; - } - } else { -#ifdef DIAGNOSTIC - printf("pmap_remove_va: entry not found\n"); -#endif - } + asm("stwas %0, 0(%1)" + :: "r" (ptp), "r" ((paddr_t)pm->pm_pdir + ((va >> 20) & 0xffc))); } -/* - * pmap_insert_pvp(pvp, flag) - * loads the passed page into pv_entries free list. - * flag specifies how the page was allocated where possible - * choices are (0)static, (1)malloc; (probably bogus, but see free_pv) - */ -static __inline void -pmap_insert_pvp(struct pv_page *pvp, u_int flag) +static __inline pt_entry_t * +pmap_pde_alloc(struct pmap *pm, vaddr_t va, struct vm_page **pdep) { - struct pv_entry *pv; + struct vm_page *pg; + paddr_t pa; + + DPRINTF(PDB_FOLLOW|PDB_VP, + ("pmap_pde_alloc(%p, 0x%x, %p)\n", pm, va, pdep)); + + va &= PDE_MASK; + pg = uvm_pagealloc(&pm->pm_obj, va, NULL, + UVM_PGA_USERESERVE|UVM_PGA_ZERO); + if (pg == NULL) { + /* try to steal somewhere */ + return (NULL); + } + + pa = VM_PAGE_TO_PHYS(pg); + + DPRINTF(PDB_FOLLOW|PDB_VP, ("pmap_pde_alloc: pde %x\n", pa)); - bzero(pvp, sizeof(*pvp)); - for (pv = &pvp->pvp_pv[0]; pv < &pvp->pvp_pv[NPVPPG - 1]; pv++) - pv->pv_next = pv + 1; - pvp->pvp_flag = flag; - pvp->pvp_freelist = &pvp->pvp_pv[0]; - pv_nfree += pvp->pvp_nfree = NPVPPG; - TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_list); + pg->flags &= ~PG_BUSY; /* never busy */ + pg->wire_count = 1; /* no mappings yet */ + pmap_pde_set(pm, va, pa); + pm->pm_stats.resident_count++; /* count PTP as resident */ + pm->pm_ptphint = pg; + if (pdep) + *pdep = pg; + return ((pt_entry_t *)pa); } -/* - * pmap_alloc_pv() - * allocates the pv_entry from the pv_entries free list. - * once we've ran out of preallocated pv_entries, nothing - * can be done, since tlb fault handlers work in phys mode. - */ -static __inline struct pv_entry * -pmap_alloc_pv(void) +static __inline struct vm_page * +pmap_pde_ptp(struct pmap *pm, pt_entry_t *pde) { - struct pv_page *pvp; - struct pv_entry *pv; + paddr_t pa = (paddr_t)pde; - DPRINTF(PDB_FOLLOW | PDB_PV, ("pmap_alloc_pv()\n")); + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pde_ptp(%p, %p)\n", pm, pde)); - if (pv_nfree == 0) { -#if notyet - MALLOC(pvp, struct pv_page *, NBPG, M_VMPVENT, M_WAITOK); - - if (!pvp) - panic("pmap_alloc_pv: alloc failed"); - pmap_insert_pvp(pvp, 0); -#else - panic("out of pv_entries"); -#endif - } + if (pm->pm_ptphint && VM_PAGE_TO_PHYS(pm->pm_ptphint) == pa) + return (pm->pm_ptphint); - --pv_nfree; - pvp = TAILQ_FIRST(&pv_page_freelist); - if (--pvp->pvp_nfree == 0) - TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_list); - pv = pvp->pvp_freelist; -#ifdef DIAGNOSTIC - if (pv == 0) - panic("pmap_alloc_pv: pgi_nfree inconsistent"); -#endif - pvp->pvp_freelist = pv->pv_next; - pv->pv_next = NULL; - pv->pv_hash = NULL; - pv->pv_pmap = NULL; + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pde_ptp: lookup 0x%x\n", pa)); - return pv; + return (PHYS_TO_VM_PAGE(pa)); } -/* - * pmap_free_pv(pv) - * return pv_entry back into free list. - * once full page of entries has been freed and that page - * was allocated dynamically, free the page. - */ static __inline void -pmap_free_pv(struct pv_entry *pv) +pmap_pde_release(struct pmap *pmap, vaddr_t va, struct vm_page *ptp) { - struct pv_page *pvp; - - DPRINTF(PDB_FOLLOW | PDB_PV, ("pmap_free_pv(%p)\n", pv)); - - pvp = (struct pv_page *) trunc_page((vaddr_t)pv); - switch (++pvp->pvp_nfree) { - case 1: - TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_list); - default: - pv->pv_next = pvp->pvp_freelist; - pvp->pvp_freelist = pv; - ++pv_nfree; - break; - case NPVPPG: - if (!pvp->pvp_flag) { -#ifdef notyet - pv_nfree -= NPVPPG - 1; - TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_list); - FREE((vaddr_t) pvp, M_VMPVENT); -#else - panic("pmap_free_pv: mallocated pv page"); -#endif - } - break; + ptp->wire_count--; + if (ptp->wire_count <= 1) { + pmap_pde_set(pmap, va, 0); + pmap->pm_stats.resident_count--; + if (pmap->pm_ptphint == ptp) + pmap->pm_ptphint = TAILQ_FIRST(&pmap->pm_obj.memq); + ptp->wire_count = 0; + uvm_pagefree(ptp); } } -/* - * pmap_enter_pv(pmap, va, tlbprot, tlbpage, pv) - * insert specified mapping into pa->va translation list, - * where pv specifies the list head (for particular pa) - */ -static __inline struct pv_entry * -pmap_enter_pv(pmap_t pmap, vaddr_t va, u_int tlbprot, u_int tlbpage, - struct pv_entry *pv) +static __inline pt_entry_t +pmap_pte_get(pt_entry_t *pde, vaddr_t va) { - struct pv_entry *npv, *hpv; + pt_entry_t pte; - if (!pmap_initialized) - return NULL; + asm("ldwax,s %2(%1),%0" : "=&r" (pte) + : "r" (pde), "r" ((va >> 12) & 0x3ff)); -#ifdef DEBUG - if (pv == NULL) - printf("pmap_enter_pv: zero pv\n"); -#endif + return (pte); +} - DPRINTF(PDB_FOLLOW | PDB_PV, ("pmap_enter_pv: pv %p: %lx/%p/%p\n", - pv, pv->pv_va, pv->pv_pmap, pv->pv_next)); +static __inline void +pmap_pte_set(pt_entry_t *pde, vaddr_t va, pt_entry_t pte) +{ + DPRINTF(PDB_FOLLOW|PDB_VP, ("pmap_pte_set(%p, 0x%x, 0x%x)\n", + pde, va, pte)); - if (pv->pv_pmap == NULL) { - /* - * No entries yet, use header as the first entry - */ - DPRINTF(PDB_ENTER, ("pmap_enter_pv: no entries yet\n")); - hpv = npv = NULL; - } else { - /* - * There is at least one other VA mapping this page. - * Place this entry after the header. - */ - DPRINTF(PDB_ENTER, ("pmap_enter_pv: adding to the list\n")); #ifdef PMAPDEBUG - for (npv = pv; npv; npv = npv->pv_next) - if (pmap == npv->pv_pmap && va == npv->pv_va) { - printf("pmap_enter_pv: %p already in pv_tab", - npv); - pmap_enter_va(npv); /* HACK UGLY HACK HACK */ - return (npv); - } + if (!pde) + panic("pmap_pte_set: zero pde"); + if (pte && pte < virtual_steal && + hppa_trunc_page(pte) != (paddr_t)&gateway_page) + panic("pmap_pte_set: invalid pte"); #endif - hpv = pv; - npv = pv->pv_next; - pv = pmap_alloc_pv(); - } - pv->pv_va = va; - pv->pv_pmap = pmap; - pv->pv_space = pmap->pmap_space; - pv->pv_tlbprot = tlbprot; - pv->pv_tlbpage = tlbpage; - pv->pv_next = npv; - if (hpv) - hpv->pv_next = pv; - pmap_enter_va(pv); - - return pv; + asm("stwas %0, 0(%1)" + :: "r" (pte), "r" ((paddr_t)pde + ((va >> 10) & 0xffc))); } -/* - * pmap_remove_pv(ppv, pv) - * remove mapping for specified va and pmap, from - * pa->va translation list, having pv as a list head. - */ -static __inline void -pmap_remove_pv(struct pv_entry *ppv, struct pv_entry *pv) +static __inline pt_entry_t +pmap_vp_find(struct pmap *pm, vaddr_t va) { + pt_entry_t *pde; - DPRINTF(PDB_FOLLOW | PDB_PV, ("pmap_remove_pv(%p,%p)\n", ppv, pv)); + if (!(pde = pmap_pde_get(pm->pm_pdir, va))) + return (NULL); - /* - * Clear it from cache and TLB - */ - ficache(ppv->pv_space, ppv->pv_va, PAGE_SIZE); - pitlb(ppv->pv_space, ppv->pv_va); + return (pmap_pte_get(pde, va)); +} - fdcache(ppv->pv_space, ppv->pv_va, PAGE_SIZE); - pdtlb(ppv->pv_space, ppv->pv_va); +void +pmap_dump_table(pa_space_t space) +{ + pa_space_t sp; - /* - * If it is the first entry on the list, it is actually - * in the header and we must copy the following entry up - * to the header. Otherwise we must search the list for - * the entry. In either case we free the now unused entry. - */ - if (ppv == pv) { - ppv = pv->pv_next; - pmap_remove_va(pv); - if (ppv) { - ppv->pv_tlbprot |= pv->pv_tlbprot & - (TLB_DIRTY | TLB_REF); - *pv = *ppv; - pmap_free_pv(ppv); - } else - pv->pv_pmap = NULL; - } else { - for (; pv && pv->pv_next != ppv; pv = pv->pv_next) - ; - - if (pv) { - pv->pv_tlbprot |= ppv->pv_tlbprot & - (TLB_DIRTY | TLB_REF); - pv->pv_next = ppv->pv_next; - pmap_remove_va(ppv); - pmap_free_pv(ppv); - } else { -#ifdef DEBUG - panic("pmap_remove_pv: npv == NULL\n"); -#endif + for (sp = 0; sp <= hppa_sid_max; sp++) { + paddr_t pa; + pt_entry_t *pde, pte; + vaddr_t va, pdemask = virtual_avail + 1; + + if (((int)space >= 0 && sp != space) || + !(pa = pmap_sdir_get(sp))) + continue; + + for (va = virtual_avail; va < VM_MAX_KERNEL_ADDRESS; + va += PAGE_SIZE) { + if (pdemask != (va & PDE_MASK)) { + pdemask = va & PDE_MASK; + if (!(pde = pmap_pde_get(pa, va))) { + va += ~PDE_MASK + 1 - PAGE_SIZE; + continue; + } + printf("%x:0x%08x:\n", sp, pde); + } + + if (!(pte = pmap_pte_get(pde, va))) + continue; + + printf("0x%08x-0x%08x\n", va, pte); } } } -/* - * pmap_find_pv(pa) - * returns head of the pa->va translation list for specified pa. - */ static __inline struct pv_entry * -pmap_find_pv(paddr_t pa) +pmap_pv_alloc(void) { - int bank, off; + struct pv_entry *pv; - if ((bank = vm_physseg_find(atop(pa), &off)) != -1) { - DPRINTF(PDB_PV, ("pmap_find_pv(%x): %d:%d\n", pa, bank, off)); - return &vm_physmem[bank].pmseg.pvent[off]; - } else - return NULL; + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_alloc()\n")); + + simple_lock(&pvalloc_lock); + + pv = pool_get(&pmap_pv_pool, 0); + + simple_unlock(&pvalloc_lock); + + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_alloc: %p\n", pv)); + + return (pv); } -/* - * Flush caches and TLB entries refering to physical page pa. If cmp is - * non-zero, we do not affect the cache or TLB entires for that mapping. - */ static __inline void -pmap_clear_pv(paddr_t pa, struct pv_entry *cpv) +pmap_pv_free(struct pv_entry *pv) { - struct pv_entry *pv; + simple_lock(&pvalloc_lock); - DPRINTF(PDB_FOLLOW | PDB_PV, ("pmap_clear_pv(%x,%p)\n", pa, cpv)); + if (pv->pv_ptp) + pmap_pde_release(pv->pv_pmap, pv->pv_va, pv->pv_ptp); - if (!(pv = pmap_find_pv(pa)) || !pv->pv_pmap) - return; + pool_put(&pmap_pv_pool, pv); - for (; pv; pv = pv->pv_next) { - if (pv == cpv) - continue; - DPRINTF(PDB_PV, - ("pmap_clear_pv: %x:%x\n", pv->pv_space, pv->pv_va)); - /* - * have to clear the icache first since fic uses the dtlb. - */ - ficache(pv->pv_space, pv->pv_va, NBPG); - pitlb(pv->pv_space, pv->pv_va); - - fdcache(pv->pv_space, pv->pv_va, NBPG); - pdtlb(pv->pv_space, pv->pv_va); - - pmap_clear_va(pv->pv_space, pv->pv_va); - } + simple_unlock(&pvalloc_lock); +} + +static __inline void +pmap_pv_enter(struct pv_head *pvh, struct pv_entry *pve, struct pmap *pm, + vaddr_t va, struct vm_page *pdep) +{ + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_enter(%p, %p, %p, 0x%x, %p)\n", + pvh, pve, pm, va, pdep)); + + pve->pv_pmap = pm; + pve->pv_va = va; + pve->pv_ptp = pdep; + simple_lock(&pvh->pvh_lock); /* lock pv_head */ + pve->pv_next = pvh->pvh_list; + pvh->pvh_list = pve; + simple_unlock(&pvh->pvh_lock); /* unlock, done! */ +} + +static __inline struct pv_entry * +pmap_pv_remove(struct pv_head *pvh, struct pmap *pmap, vaddr_t va) +{ + struct pv_entry **pve, *pv; + + for(pv = *(pve = &pvh->pvh_list); pv; pv = *(pve = &(*pve)->pv_next)) + if (pv->pv_pmap == pmap && pv->pv_va == va) { + *pve = pv->pv_next; + break; + } + return (pv); } -/* - * Bootstrap the system enough to run with virtual memory. - * Map the kernel's code and data, and allocate the system page table. - * Called with mapping OFF. - * - * Parameters: - * vstart PA of first available physical page - * vend PA of last available physical page - */ void -pmap_bootstrap(vstart, vend) - vaddr_t *vstart; - vaddr_t *vend; +pmap_bootstrap(vstart) + vaddr_t vstart; { - extern int maxproc; /* used to estimate pv_entries pool size */ - extern u_int totalphysmem; - vaddr_t addr; + extern char etext; + extern u_int totalphysmem, *ie_mem; + vaddr_t addr = hppa_round_page(vstart), t; vsize_t size; - struct pv_page *pvp; - struct hpt_entry *hptp; +#if 0 && (defined(HP7100LC_CPU) || defined(HP7300LC_CPU)) + struct vp_entry *hptp; +#endif + struct pmap *kpm; int i; - DPRINTF(PDB_FOLLOW, ("pmap_bootstrap(%p, %p)\n", vstart, vend)); + DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_bootstrap(0x%x)\n", vstart)); uvm_setpagesize(); - pages_per_vm_page = PAGE_SIZE / NBPG; - /* XXX for now */ - if (pages_per_vm_page != 1) - panic("HPPA page != VM page"); - - kern_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_NA; - kern_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_KR; - kern_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_KRW; - kern_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_KRW; - kern_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_KRX; - kern_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_KRX; - kern_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_KRWX; - kern_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_KRWX; - - user_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_NA; - user_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_UR; - user_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_URW; - user_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_URW; - user_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_URX; - user_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_URX; - user_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_URWX; - user_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_URWX; + hppa_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_NA; + hppa_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE] =TLB_AR_R; + hppa_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_RW; + hppa_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE] =TLB_AR_RW; + hppa_prot[VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_RX; + hppa_prot[VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE] =TLB_AR_RX; + hppa_prot[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_RWX; + hppa_prot[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE] =TLB_AR_RWX; /* * Initialize kernel pmap */ - kernel_pmap = &kernel_pmap_store; -#if NCPUS > 1 - lock_init(&pmap_lock, FALSE, ETAP_VM_PMAP_SYS, ETAP_VM_PMAP_SYS_I); -#endif /* NCPUS > 1 */ - simple_lock_init(&kernel_pmap->pmap_lock); - simple_lock_init(&pmap_freelock); - simple_lock_init(&sid_pid_lock); - - kernel_pmap->pmap_refcnt = 1; - kernel_pmap->pmap_space = HPPA_SID_KERNEL; + kpm = &kernel_pmap_store; + bzero(kpm, sizeof(*kpm)); + simple_lock_init(&kpm->pm_obj.vmobjlock); + kpm->pm_obj.pgops = NULL; + TAILQ_INIT(&kpm->pm_obj.memq); + kpm->pm_obj.uo_npages = 0; + kpm->pm_obj.uo_refs = 1; + kpm->pm_space = HPPA_SID_KERNEL; + kpm->pm_pid = HPPA_PID_KERNEL; + kpm->pm_pdir_pg = NULL; + kpm->pm_pdir = addr; + addr += PAGE_SIZE; + bzero((void *)addr, PAGE_SIZE); + fdcache(HPPA_SID_KERNEL, addr, PAGE_SIZE); /* * Allocate various tables and structures. */ - addr = hppa_round_page(*vstart); - virtual_end = *vend; - pvp = (struct pv_page *)addr; - - mfctl(CR_HPTMASK, size); - addr = (addr + size) & ~(size); - - DPRINTF(PDB_INIT, ("pmap_bootstrap: allocating %d pv_pages\n", - (struct pv_page *)addr - pvp)); - - TAILQ_INIT(&pv_page_freelist); - for (; pvp + 1 <= (struct pv_page *)addr; pvp++) - pmap_insert_pvp(pvp, 1); - - /* Allocate the HPT */ - for (hptp = (struct hpt_entry *)addr; - ((u_int)hptp - addr) <= size; hptp++) { - hptp->hpt_valid = 0; - hptp->hpt_vpn = 0; - hptp->hpt_space = -1; - hptp->hpt_tlbpage = 0; - hptp->hpt_tlbprot = 0; - hptp->hpt_entry = NULL; - } - - DPRINTF(PDB_INIT, ("hpt_table: 0x%x @ %p\n", size + 1, addr)); - /* load cr25 with the address of the HPT table - NB: It sez CR_VTOP, but we (and the TLB handlers) know better ... */ mtctl(addr, CR_VTOP); - addr += size + 1; + bzero((void *)addr, (hppa_sid_max + 1) * 4); + fdcache(HPPA_SID_KERNEL, addr, (hppa_sid_max + 1) * 4); + printf("vtop: 0x%x @ 0x%x\n", (hppa_sid_max + 1) * 4, addr); + addr += (hppa_sid_max + 1) * 4; + pmap_sdir_set(HPPA_SID_KERNEL, kpm->pm_pdir); + + ie_mem = (u_int *)addr; + addr += 0x8000; + +#if 0 && (defined(HP7100LC_CPU) || defined(HP7300LC_CPU)) + if (pmap_hptsize && (cpu_type == hpcxl || cpu_type == hpcxl2)) { + int error; + + if (pmap_hptsize > pdc_hwtlb.max_size) + pmap_hptsize = pdc_hwtlb.max_size; + else if (pmap_hptsize < pdc_hwtlb.min_size) + pmap_hptsize = pdc_hwtlb.min_size; + + size = pmap_hptsize * sizeof(*hptp); + bzero((void *)addr, size); + /* Allocate the HPT */ + for (hptp = (struct vp_entry *)addr, i = pmap_hptsize; i--;) + hptp[i].vp_tag = 0xffff; + + DPRINTF(PDB_INIT, ("hpt_table: 0x%x @ %p\n", size, addr)); + + if ((error = (cpu_hpt_init)(addr, size)) < 0) { + printf("WARNING: HPT init error %d\n", error); + } else { + printf("HPT: %d entries @ 0x%x\n", + pmap_hptsize / sizeof(struct vp_entry), addr); + } - /* - * we know that btlb_insert() will round it up to the next - * power of two at least anyway - */ - for (physmem = 1; physmem < btoc(addr); physmem *= 2); + /* TODO find a way to avoid using cr*, use cpu regs instead */ + mtctl(addr, CR_VTOP); + mtctl(size - 1, CR_HPTMASK); + addr += size; + } +#endif /* HP7100LC_CPU | HP7300LC_CPU */ /* map the kernel space, which will give us virtual_avail */ - *vstart = hppa_round_page(addr + (totalphysmem - physmem) * - (sizeof(struct pv_entry) * maxproc / 8 + - sizeof(struct vm_page))); + vstart = hppa_round_page(addr + (totalphysmem - (atop(addr))) * + (16 + sizeof(struct pv_head) + sizeof(struct vm_page))); /* XXX PCXS needs two separate inserts in separate btlbs */ - if (btlb_insert(HPPA_SID_KERNEL, 0, 0, vstart, + t = (vaddr_t)&etext; + if (btlb_insert(HPPA_SID_KERNEL, 0, 0, &t, pmap_sid2pid(HPPA_SID_KERNEL) | - pmap_prot(kernel_pmap, VM_PROT_ALL)) < 0) + pmap_prot(pmap_kernel(), VM_PROT_READ|VM_PROT_EXECUTE)) < 0) + panic("pmap_bootstrap: cannot block map kernel text"); + t = vstart - (vaddr_t)&etext; + if (btlb_insert(HPPA_SID_KERNEL, (vaddr_t)&etext, (vaddr_t)&etext, &t, + pmap_sid2pid(HPPA_SID_KERNEL) | TLB_UNCACHABLE | + pmap_prot(pmap_kernel(), VM_PROT_ALL)) < 0) panic("pmap_bootstrap: cannot block map kernel"); - virtual_avail = *vstart; + vstart = (vaddr_t)&etext + t; + virtual_avail = vstart; + kpm->pm_stats.wired_count = kpm->pm_stats.resident_count = + physmem = atop(vstart); /* * NOTE: we no longer trash the BTLB w/ unused entries, * lazy map only needed pieces (see bus_mem_add_mapping() for refs). */ - size = hppa_round_page(sizeof(struct pv_entry) * totalphysmem); + addr = hppa_round_page(addr); + size = hppa_round_page(sizeof(struct pv_head) * totalphysmem); bzero ((caddr_t)addr, size); - DPRINTF(PDB_INIT, ("pv_array: 0x%x @ 0x%x\n", size, addr)); + DPRINTF(PDB_INIT, ("pmseg.pvent: 0x%x @ 0x%x\n", size, addr)); + /* XXX we might need to split this for isa */ virtual_steal = addr + size; i = atop(virtual_avail - virtual_steal); uvm_page_physload(0, totalphysmem + i, atop(virtual_avail), totalphysmem + i, VM_FREELIST_DEFAULT); /* we have only one initial phys memory segment */ - vm_physmem[0].pmseg.pvent = (struct pv_entry *)addr; - /* mtctl(addr, CR_PSEG); */ - - /* here will be a hole due to the kernel memory alignment - and we use it for pmap_steal_memory */ -} - -void -pmap_virtual_space(vaddr_t *vstartp, vaddr_t *vendp) -{ - *vstartp = virtual_avail; - *vendp = virtual_end; + vm_physmem[0].pmseg.pvhead = (struct pv_head *)addr; } /* @@ -738,13 +519,13 @@ pmap_steal_memory(size, startp, endp) { vaddr_t va; - DPRINTF(PDB_FOLLOW, + DPRINTF(PDB_FOLLOW|PDB_STEAL, ("pmap_steal_memory(%x, %x, %x)\n", size, startp, endp)); if (startp) *startp = virtual_avail; if (endp) - *endp = virtual_end; + *endp = VM_MAX_KERNEL_ADDRESS; size = hppa_round_page(size); if (size <= virtual_avail - virtual_steal) { @@ -765,38 +546,20 @@ pmap_steal_memory(size, startp, endp) return va; } -/* - * Finishes the initialization of the pmap module. - * This procedure is called from vm_mem_init() in vm/vm_init.c - * to initialize any remaining data structures that the pmap module - * needs to map virtual memory (VM is already ON). - */ void pmap_init() { - struct pv_page *pvp; + DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_init()\n")); -#ifdef PMAPDEBUG - int opmapdebug = pmapdebug; - DPRINTF(PDB_FOLLOW, ("pmap_init()\n")); - pmapdebug = 0; -#endif + pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl", + &pool_allocator_nointr); + pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pmappv", + &pmap_allocator_pv); + /* depleet the steal area */ + pool_prime(&pmap_pv_pool, (virtual_avail - virtual_steal) / PAGE_SIZE * + pmap_pv_pool.pr_itemsperpage); - /* allocate the rest of the steal area for pv_pages */ -#ifdef PMAPDEBUG - printf("pmap_init: %d pv_pages @ %x allocated\n", - (virtual_avail - virtual_steal) / sizeof(struct pv_page), - virtual_steal); -#endif - while ((pvp = (struct pv_page *) - pmap_steal_memory(sizeof(*pvp), NULL, NULL))) - pmap_insert_pvp(pvp, 1); - -#ifdef PMAPDEBUG - pmapdebug = opmapdebug /* | PDB_VA | PDB_PV */; -#endif - TAILQ_INIT(&pmap_freelist); - sid_counter = HPPA_SID_KERNEL + 1; + simple_lock_init(&pvalloc_lock); pmap_initialized = TRUE; @@ -807,465 +570,497 @@ pmap_init() * * no spls since no interrupts. */ - pmap_enter_pv(pmap_kernel(), SYSCALLGATE, TLB_GATE_PROT, - tlbbtop((paddr_t)&gateway_page), - pmap_find_pv((paddr_t)&gateway_page)); -} + { + pt_entry_t *pde; -/* - * Initialize a preallocated and zeroed pmap structure, - * such as one in a vmspace structure. - */ -void -pmap_pinit(pmap) - pmap_t pmap; -{ - pa_space_t sid; - int s; - - DPRINTF(PDB_FOLLOW, ("pmap_pinit(%p)\n", pmap)); - - if (!(sid = pmap->pmap_space)) { + if (!(pde = pmap_pde_get(pmap_kernel()->pm_pdir, SYSCALLGATE)) && + !(pde = pmap_pde_alloc(pmap_kernel(), SYSCALLGATE, NULL))) + panic("pmap_init: cannot allocate pde"); - /* - * Allocate space and protection IDs for the pmap. - * If all are allocated, there is nothing we can do. - */ - s = splimp(); - if (sid_counter < HPPA_SID_MAX) { - sid = sid_counter; - sid_counter++; - } else - sid = 0; - splx(s); - - if (sid == 0) - panic("no more space ids\n"); - - simple_lock_init(&pmap->pmap_lock); + pmap_pte_set(pde, SYSCALLGATE, (paddr_t)&gateway_page | + PTE_PROT(TLB_GATE_PROT)); } - - s = splimp(); - pmap->pmap_space = sid; - pmap->pmap_refcnt = 1; - pmap->pmap_stats.resident_count = 0; - pmap->pmap_stats.wired_count = 0; - splx(s); } -/* - * pmap_create() - * - * Create and return a physical map. - * the map is an actual physical map, and may be referenced by the hardware. - */ -pmap_t +struct pmap * pmap_create() { - register pmap_t pmap; - int s; + struct pmap *pmap; + pa_space_t space; - DPRINTF(PDB_FOLLOW, ("pmap_create()\n")); + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_create()\n")); + pmap = pool_get(&pmap_pmap_pool, PR_WAITOK); - /* - * If there is a pmap in the pmap free list, reuse it. - */ - s = splimp(); - if (pmap_nfree) { - pmap = pmap_freelist.tqh_first; - TAILQ_REMOVE(&pmap_freelist, pmap, pmap_list); - pmap_nfree--; - splx(s); - } else { - splx(s); - MALLOC(pmap, struct pmap *, sizeof(*pmap), M_VMMAP, M_NOWAIT); - if (pmap == NULL) - return NULL; - bzero(pmap, sizeof(*pmap)); - } + simple_lock_init(&pmap->pm_obj.vmobjlock); + pmap->pm_obj.pgops = NULL; /* currently not a mappable object */ + TAILQ_INIT(&pmap->pm_obj.memq); + pmap->pm_obj.uo_npages = 0; + pmap->pm_obj.uo_refs = 1; + pmap->pm_stats.wired_count = 0; + pmap->pm_stats.resident_count = 1; - pmap_pinit(pmap); + if (pmap_sid_counter >= hppa_sid_max) { + /* collect some */ + panic("pmap_create: outer space"); + } else + space = ++pmap_sid_counter; + + pmap->pm_space = space; + pmap->pm_pid = (space + 1) << 1; + pmap->pm_pdir_pg = uvm_pagealloc(NULL, 0, NULL, + UVM_PGA_USERESERVE|UVM_PGA_ZERO); + if (!pmap->pm_pdir_pg) + panic("pmap_create: no pages"); + pmap->pm_pdir = VM_PAGE_TO_PHYS(pmap->pm_pdir_pg); + + pmap_sdir_set(space, pmap->pm_pdir); return(pmap); } -/* - * pmap_destroy(pmap) - * Gives up a reference to the specified pmap. When the reference count - * reaches zero the pmap structure is added to the pmap free list. - * Should only be called if the map contains no valid mappings. - */ void pmap_destroy(pmap) - pmap_t pmap; + struct pmap *pmap; { - int ref_count; - int s; - - DPRINTF(PDB_FOLLOW, ("pmap_destroy(%p)\n", pmap)); - - if (!pmap) - return; + struct vm_page *pg; + pa_space_t space; + int refs; - s = splimp(); + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_destroy(%p)\n", pmap)); - ref_count = --pmap->pmap_refcnt; + simple_lock(&pmap->pm_obj.vmobjlock); + refs = --pmap->pm_obj.uo_refs; + simple_unlock(&pmap->pm_obj.vmobjlock); - if (ref_count < 0) - panic("pmap_destroy(): ref_count < 0"); - if (!ref_count) { - assert(pmap->pmap_stats.resident_count == 0); + if (refs > 0) + return; - /* - * Add the pmap to the pmap free list - * We cannot free() disposed pmaps because of - * PID shortage of 2^16 - * (do some random pid allocation later) - */ - TAILQ_INSERT_HEAD(&pmap_freelist, pmap, pmap_list); - pmap_nfree++; + TAILQ_FOREACH(pg, &pmap->pm_obj.memq, listq) { +#ifdef DIAGNOSTIC + if (pg->flags & PG_BUSY) + panic("pmap_release: busy page table page"); +#endif + pg->wire_count = 0; + uvm_pagefree(pg); } - splx(s); + + uvm_pagefree(pmap->pm_pdir_pg); + pmap->pm_pdir_pg = NULL; /* XXX cache it? */ + pmap_sdir_set(space, 0); + pool_put(&pmap_pmap_pool, pmap); } + /* - * pmap_enter(pmap, va, pa, prot, flags) - * Create a translation for the virtual address (va) to the physical - * address (pa) in the pmap with the protection requested. If the - * translation is wired then we can not allow a page fault to occur - * for this mapping. + * Add a reference to the specified pmap. */ +void +pmap_reference(pmap) + struct pmap *pmap; +{ + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_reference(%p)\n", pmap)); + + simple_lock(&pmap->pm_obj.vmobjlock); + pmap->pm_obj.uo_refs++; + simple_unlock(&pmap->pm_obj.vmobjlock); +} + +void +pmap_collect(struct pmap *pmap) +{ + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_collect(%p)\n", pmap)); + /* nothing yet */ +} + int pmap_enter(pmap, va, pa, prot, flags) - pmap_t pmap; + struct pmap *pmap; vaddr_t va; paddr_t pa; vm_prot_t prot; int flags; { - register struct pv_entry *pv, *ppv; - u_int tlbpage, tlbprot; - pa_space_t space; - boolean_t waswired; + pt_entry_t *pde, pte; + struct vm_page *ptp = NULL; + struct pv_head *pvh; + struct pv_entry *pve; + int bank, off; boolean_t wired = (flags & PMAP_WIRED) != 0; - int s; - pa = hppa_trunc_page(pa); - va = hppa_trunc_page(va); - space = pmap_sid(pmap, va); -#ifdef PMAPDEBUG - if (pmapdebug & PDB_FOLLOW && - (!pmap_initialized || pmapdebug & PDB_ENTER)) - printf("pmap_enter(%p, %x, %x, %x, %swired)\n", pmap, va, pa, - prot, wired? "" : "un"); -#endif + DPRINTF(PDB_FOLLOW|PDB_ENTER, + ("pmap_enter(%p, 0x%x, 0x%x, 0x%x, 0x%x)\n", + pmap, va, pa, prot, flags)); - s = splimp(); /* are we already high enough? XXX */ + simple_lock(&pmap->pm_obj.vmobjlock); - if (!(pv = pmap_find_pv(pa))) - panic("pmap_enter: pmap_find_pv failed"); + if (!(pde = pmap_pde_get(pmap->pm_pdir, va)) && + !(pde = pmap_pde_alloc(pmap, va, &ptp))) { + if (flags & PMAP_CANFAIL) + return (KERN_RESOURCE_SHORTAGE); - tlbpage = tlbbtop(pa); - tlbprot = TLB_UNCACHEABLE | pmap_prot(pmap, prot) | pmap_sid2pid(space); + panic("pmap_kenter: cannot allocate pde"); + } - if (!(ppv = pmap_find_va(space, va))) { - /* - * Mapping for this virtual address doesn't exist. - * Enter a new mapping. - */ - DPRINTF(PDB_ENTER, ("pmap_enter: new mapping\n")); - pv = pmap_enter_pv(pmap, va, tlbprot, tlbpage, pv); - pmap->pmap_stats.resident_count++; + if (!ptp) + ptp = pmap_pde_ptp(pmap, pde); - } else { + if ((pte = pmap_pte_get(pde, va))) { - /* see if we are remapping the page to another PA */ - if (ppv->pv_tlbpage != tlbpage) { - DPRINTF(PDB_ENTER, ("pmap_enter: moving pa %x -> %x\n", - ppv->pv_tlbpage, tlbpage)); - /* update tlbprot to avoid extra subsequent fault */ - pmap_remove_pv(ppv, pmap_find_pv(tlbptob(ppv->pv_tlbpage))); - pv = pmap_enter_pv(pmap, va, tlbprot, tlbpage, pv); - } else { - /* We are just changing the protection. */ - DPRINTF(PDB_ENTER, ("pmap_enter: changing %b->%b\n", - ppv->pv_tlbprot, TLB_BITS, tlbprot, TLB_BITS)); - pv = ppv; - ppv->pv_tlbprot = (tlbprot & ~TLB_PID_MASK) | - (ppv->pv_tlbprot & ~(TLB_AR_MASK|TLB_PID_MASK)); - pmap_clear_pv(pa, NULL); + DPRINTF(PDB_ENTER, + ("pmap_enter: remapping 0x%x -> 0x%x\n", pte, pa)); + + if (pte & PTE_PROT(TLB_EXECUTE)) + ficache(pmap->pm_space, va, NBPG); + pitlb(pmap->pm_space, va); + fdcache(pmap->pm_space, va, NBPG); + pdtlb(pmap->pm_space, va); + + if (wired && !(pte & PTE_PROT(TLB_WIRED)) == 0) + pmap->pm_stats.wired_count++; + else if (!wired && (pte & PTE_PROT(TLB_WIRED)) != 0) + pmap->pm_stats.wired_count--; + + if (PTE_PAGE(pte) == pa) { + DPRINTF(PDB_FOLLOW|PDB_ENTER, + ("pmap_enter: same page\n")); + goto enter; } + + bank = vm_physseg_find(atop(PTE_PAGE(pte)), &off); + if (bank != -1) { + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + simple_lock(&pvh->pvh_lock); + pve = pmap_pv_remove(pvh, pmap, va); + pvh->pvh_attrs |= pmap_pvh_attrs(pte); + simple_unlock(&pvh->pvh_lock); + } else + pve = NULL; + } else { + DPRINTF(PDB_ENTER, + ("pmap_enter: new mapping 0x%x -> 0x%x\n", va, pa)); + pte = PTE_PROT(TLB_REFTRAP); + pve = NULL; + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + if (ptp) + ptp->wire_count++; } - /* - * Add in software bits and adjust statistics - */ - waswired = pv->pv_tlbprot & TLB_WIRED; - if (wired && !waswired) { - pv->pv_tlbprot |= TLB_WIRED; - pmap->pmap_stats.wired_count++; - } else if (!wired && waswired) { - pv->pv_tlbprot &= ~TLB_WIRED; - pmap->pmap_stats.wired_count--; + bank = vm_physseg_find(atop(pa), &off); + if (pmap_initialized && bank != -1) { + if (!pve && !(pve = pmap_pv_alloc())) { + if (flags & PMAP_CANFAIL) { + simple_unlock(&pmap->pm_obj.vmobjlock); + return (KERN_RESOURCE_SHORTAGE); + } + panic("pmap_enter: no pv entries available"); + } + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + pmap_pv_enter(pvh, pve, pmap, va, ptp); + } else { + pvh = NULL; + if (pve) + pmap_pv_free(pve); } - splx(s); - simple_unlock(&pmap->pmap_lock); - DPRINTF(PDB_ENTER, ("pmap_enter: leaving\n")); +enter: + /* preserve old ref & mod */ + pte = pa | PTE_PROT(pmap_prot(pmap, prot)) | + (pte & PTE_PROT(TLB_UNCACHABLE|TLB_DIRTY|TLB_REFTRAP)); + if (wired) + pte |= PTE_PROT(TLB_WIRED); + pmap_pte_set(pde, va, pte); + + simple_unlock(&pmap->pm_obj.vmobjlock); + + DPRINTF(PDB_FOLLOW, ("pmap_enter: leaving\n")); return (0); } -/* - * pmap_remove(pmap, sva, eva) - * unmaps all virtual addresses v in the virtual address - * range determined by [sva, eva) and pmap. - * sva and eva must be on machine independent page boundaries and - * sva must be less than or equal to eva. - */ void pmap_remove(pmap, sva, eva) - register pmap_t pmap; - register vaddr_t sva; - register vaddr_t eva; + struct pmap *pmap; + vaddr_t sva; + vaddr_t eva; { - register struct pv_entry *pv; - register pa_space_t space; - int s; + struct pv_head *pvh; + struct pv_entry *pve; + pt_entry_t *pde, pte; + int bank, off; + u_int pdemask; - DPRINTF(PDB_FOLLOW, ("pmap_remove(%p, %x, %x)\n", pmap, sva, eva)); + DPRINTF(PDB_FOLLOW|PDB_REMOVE, + ("pmap_remove(%p, 0x%x, 0x%x\n", pmap, sva, eva)); - if(!pmap) - return; + simple_lock(&pmap->pm_obj.vmobjlock); - s = splimp(); + for (pdemask = sva + 1; sva < eva; sva += PAGE_SIZE) { + if (pdemask != (sva & PDE_MASK)) { + pdemask = sva & PDE_MASK; + if (!(pde = pmap_pde_get(pmap->pm_pdir, sva))) { + sva += ~PDE_MASK + 1 - PAGE_SIZE; + continue; + } + } - sva = hppa_trunc_page(sva); - space = pmap_sid(pmap, sva); - - while (pmap->pmap_stats.resident_count && ((sva < eva))) { - pv = pmap_find_va(space, sva); - - DPRINTF(PDB_REMOVE, ("pmap_remove: removing %p for 0x%x:0x%x\n", - pv, space, sva)); - if (pv) { - pmap->pmap_stats.resident_count--; - if (pv->pv_tlbprot & TLB_WIRED) - pmap->pmap_stats.wired_count--; - pmap_remove_pv(pv, - pmap_find_pv(tlbptob(pv->pv_tlbpage))); + if ((pte = pmap_pte_get(pde, sva))) { + + if (pte & PTE_PROT(TLB_WIRED)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + if (pte & PTE_PROT(pte)) + ficache(pmap->pm_space, sva, PAGE_SIZE); + pitlb(pmap->pm_space, sva); + fdcache(pmap->pm_space, sva, PAGE_SIZE); + pdtlb(pmap->pm_space, sva); + + pmap_pte_set(pde, sva, 0); + + bank = vm_physseg_find(atop(pte), &off); + if (pmap_initialized && bank != -1) { + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + pve = pmap_pv_remove(pvh, pmap, sva); + if (pve) { + pvh->pvh_attrs |= pmap_pvh_attrs(pte); + pmap_pv_free(pve); + } + } } - sva += PAGE_SIZE; } - splx(s); + simple_unlock(&pmap->pm_obj.vmobjlock); + + DPRINTF(PDB_FOLLOW|PDB_REMOVE, ("pmap_remove: leaving\n")); } -/* - * pmap_page_protect(pa, prot) - * - * Lower the permission for all mappings to a given page. - */ void -pmap_page_protect(pg, prot) - struct vm_page *pg; +pmap_write_protect(pmap, sva, eva, prot) + struct pmap *pmap; + vaddr_t sva; + vaddr_t eva; vm_prot_t prot; { - register struct pv_entry *pv; - register pmap_t pmap; - register u_int tlbprot; - paddr_t pa = VM_PAGE_TO_PHYS(pg); - int s; + pt_entry_t *pde, pte; + u_int tlbprot, pdemask; - DPRINTF(PDB_FOLLOW|PDB_PROTECT, - ("pmap_page_protect(%x, %x)\n", pa, prot)); + DPRINTF(PDB_FOLLOW|PDB_PMAP, + ("pmap_write_protect(%p, %x, %x, %x)\n", pmap, sva, eva, prot)); - switch (prot) { - case VM_PROT_ALL: - return; - case VM_PROT_READ: - case VM_PROT_READ|VM_PROT_EXECUTE: - s = splimp(); - if (!(pv = pmap_find_pv(pa)) || !pv->pv_pmap) { - splx(s); - break; + sva = hppa_trunc_page(sva); + tlbprot = PTE_PROT(pmap_prot(pmap, prot)); + + simple_lock(&pmap->pm_obj.vmobjlock); + + for(pdemask = sva + 1; sva < eva; sva += PAGE_SIZE) { + if (pdemask != (sva & PDE_MASK)) { + pdemask = sva & PDE_MASK; + if (!(pde = pmap_pde_get(pmap->pm_pdir, sva))) { + sva += ~PDE_MASK + 1 - PAGE_SIZE; + continue; + } } + if ((pte = pmap_pte_get(pde, sva))) { - for ( ; pv; pv = pv->pv_next) { /* - * Compare new protection with old to see if - * anything needs to be changed. + * Determine if mapping is changing. + * If not, nothing to do. */ - tlbprot = pmap_prot(pv->pv_pmap, prot); - - if ((pv->pv_tlbprot & TLB_AR_MASK) != tlbprot) { - pv->pv_tlbprot &= ~TLB_AR_MASK; - pv->pv_tlbprot |= tlbprot; - - /* - * Purge the current TLB entry (if any) - * to force a fault and reload with the - * new protection. - */ - ficache(pv->pv_space, pv->pv_va, NBPG); - pitlb(pv->pv_space, pv->pv_va); - fdcache(pv->pv_space, pv->pv_va, NBPG); - pdtlb(pv->pv_space, pv->pv_va); - pmap_clear_va(pv->pv_space, pv->pv_va); - } - } - splx(s); - break; - default: - s = splimp(); - while ((pv = pmap_find_pv(pa)) && pv->pv_pmap) { - - DPRINTF(PDB_PROTECT, ("pv={%p,%x:%x,%b,%x}->%p\n", - pv->pv_pmap, pv->pv_space, pv->pv_va, - pv->pv_tlbprot, TLB_BITS, - tlbptob(pv->pv_tlbpage), pv->pv_hash)); - pmap = pv->pv_pmap; - pmap_remove_pv(pv, pv); - pmap->pmap_stats.resident_count--; + if ((pte & PTE_PROT(TLB_AR_MASK)) == tlbprot) + continue; + + if (pte & PTE_PROT(TLB_EXECUTE)) + ficache(pmap->pm_space, sva, PAGE_SIZE); + pitlb(pmap->pm_space, sva); + fdcache(pmap->pm_space, sva, PAGE_SIZE); + pdtlb(pmap->pm_space, sva); + + pte &= ~PTE_PROT(TLB_AR_MASK); + pte |= tlbprot; + pmap_pte_set(pde, sva, pte); } - splx(s); - break; } + + simple_unlock(&pmap->pm_obj.vmobjlock); } -/* - * pmap_protect(pmap, s, e, prot) - * changes the protection on all virtual addresses v in the - * virtual address range determined by [s, e) and pmap to prot. - * s and e must be on machine independent page boundaries and - * s must be less than or equal to e. - */ void -pmap_protect(pmap, sva, eva, prot) - pmap_t pmap; - vaddr_t sva; - vaddr_t eva; - vm_prot_t prot; +pmap_page_remove(pg) + struct vm_page *pg; { - register struct pv_entry *pv; - u_int tlbprot; - pa_space_t space; - - DPRINTF(PDB_FOLLOW, - ("pmap_protect(%p, %x, %x, %x)\n", pmap, sva, eva, prot)); + struct pv_head *pvh; + struct pv_entry *pve, *ppve; + pt_entry_t *pde, pte; + int bank, off; - if (!pmap) - return; + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_page_remove(%p)\n", pg)); - if (prot == VM_PROT_NONE) { - pmap_remove(pmap, sva, eva); + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_page_remove: unmanaged page?\n"); return; } - if (prot & VM_PROT_WRITE) + + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + if (pvh->pvh_list == NULL) return; - sva = hppa_trunc_page(sva); - space = pmap_sid(pmap, sva); - tlbprot = pmap_prot(pmap, prot); + simple_lock(&pvh->pvh_lock); - for(; sva < eva; sva += PAGE_SIZE) { - if((pv = pmap_find_va(space, sva))) { - /* - * Determine if mapping is changing. - * If not, nothing to do. - */ - if ((pv->pv_tlbprot & TLB_AR_MASK) == tlbprot) - continue; + for (pve = pvh->pvh_list; pve; ) { + simple_lock(&pve->pv_pmap->pm_obj.vmobjlock); - pv->pv_tlbprot &= ~TLB_AR_MASK; - pv->pv_tlbprot |= tlbprot; + pde = pmap_pde_get(pve->pv_pmap->pm_pdir, pve->pv_va); + pte = pmap_pte_get(pde, pve->pv_va); + pmap_pte_set(pde, pve->pv_va, 0); - /* - * Purge the current TLB entry (if any) to force - * a fault and reload with the new protection. - */ - ficache(space, sva, NBPG); - pitlb(space, sva); - fdcache(space, sva, NBPG); - pdtlb(space, sva); - pmap_clear_va(space, sva); - } + if (pte & PTE_PROT(TLB_WIRED)) + pve->pv_pmap->pm_stats.wired_count--; + pve->pv_pmap->pm_stats.resident_count--; + + simple_unlock(&pve->pmap->pm_obj.vmobjlock); + + pvh->pvh_attrs |= pmap_pvh_attrs(pte); + ppve = pve; + pve = pve->pv_next; + pmap_pv_free(ppve); } + simple_unlock(&pvh->pvh_lock); + + DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_page_remove: leaving\n")); + } -/* - * Routine: pmap_unwire - * Function: Change the wiring attribute for a map/virtual-address - * pair. - * In/out conditions: - * The mapping must already exist in the pmap. - * - * Change the wiring for a given virtual page. This routine currently is - * only used to unwire pages and hence the mapping entry will exist. - */ void pmap_unwire(pmap, va) - pmap_t pmap; + struct pmap *pmap; vaddr_t va; { - struct pv_entry *pv; - int s; + pt_entry_t *pde, pte = 0; - va = hppa_trunc_page(va); - DPRINTF(PDB_FOLLOW, ("pmap_unwire(%p, %x)\n", pmap, va)); + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_unwire(%p, 0x%x)\n", pmap, va)); - if (!pmap) - return; + simple_lock(&pmap->pm_obj.vmobjlock); + if ((pde = pmap_pde_get(pmap->pm_pdir, va))) { + pte = pmap_pte_get(pde, va); + + if (pte & PTE_PROT(TLB_WIRED)) { + pte &= ~PTE_PROT(TLB_WIRED); + pmap->pm_stats.wired_count--; + pmap_pte_set(pde, va, pte); + } + } + simple_unlock(&pmap->pm_obj.vmobjlock); + + DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_unwire: leaving\n")); - simple_lock(&pmap->pmap_lock); +#ifdef DIAGNOSTIC + if (!pte) + panic("pmap_unwire: invalid va 0x%x", va); +#endif +} + +boolean_t +pmap_changebit(struct vm_page *pg, u_int set, u_int clear) +{ + struct pv_head *pvh; + struct pv_entry *pve; + pt_entry_t *pde, pte, res; + int bank, off; - s = splimp(); - if ((pv = pmap_find_va(pmap_sid(pmap, va), va)) == NULL) - panic("pmap_unwire: can't find mapping entry"); + DPRINTF(PDB_FOLLOW|PDB_BITS, + ("pmap_changebit(%p, %x, %x)\n", pg, set, clear)); - if (pv->pv_tlbprot & TLB_WIRED) { - pv->pv_tlbprot &= ~TLB_WIRED; - pmap->pmap_stats.wired_count--; + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_testbits: unmanaged page?\n"); + return(FALSE); } - splx(s); - simple_unlock(&pmap->pmap_lock); + + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + res = pvh->pvh_attrs = 0; + + simple_lock(&pvh->pvh_lock); + for(pve = pvh->pvh_list; pve; pve = pve->pv_next) { + simple_lock(&pve->pv_pmap->pm_obj.vmobjlock); + if ((pde = pmap_pde_get(pve->pv_pmap->pm_pdir, pve->pv_va))) { + pte = pmap_pte_get(pde, pve->pv_va); + res |= pmap_pvh_attrs(pte); + pte &= ~clear; + pte |= set; + + pitlb(pve->pv_pmap->pm_space, pve->pv_va); + /* XXX flush only if there was mod ? */ + fdcache(pve->pv_pmap->pm_space, pve->pv_va, PAGE_SIZE); + pdtlb(pve->pv_pmap->pm_space, pve->pv_va); + + pmap_pte_set(pde, pve->pv_va, pte); + } + simple_unlock(&pve->pv_pmap->pm_obj.vmobjlock); + } + pvh->pvh_attrs = res; + simple_unlock(&pvh->pvh_lock); + + return ((res & clear) != 0); +} + +boolean_t +pmap_testbit(struct vm_page *pg, u_int bits) +{ + struct pv_head *pvh; + struct pv_entry *pve; + pt_entry_t pte; + int bank, off; + + DPRINTF(PDB_FOLLOW|PDB_BITS, ("pmap_testbit(%p, %x)\n", pg, bits)); + + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_testbits: unmanaged page?\n"); + return(FALSE); + } + + simple_lock(&pvh->pvh_lock); + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + for(pve = pvh->pvh_list; !(pvh->pvh_attrs & bits) && pve; + pve = pve->pv_next) { + simple_lock(&pve->pv_pmap->pm_obj.vmobjlock); + pte = pmap_vp_find(pve->pv_pmap, pve->pv_va); + simple_unlock(&pve->pv_pmap->pm_obj.vmobjlock); + pvh->pvh_attrs |= pmap_pvh_attrs(pte); + } + simple_unlock(&pvh->pvh_lock); + + return ((pvh->pvh_attrs & bits) != 0); } -/* - * pmap_extract(pmap, va, pap) - * fills in the physical address corrsponding to the - * virtual address specified by pmap and va into the - * storage pointed to by pap and returns TRUE if the - * virtual address is mapped. returns FALSE in not mapped. - */ boolean_t pmap_extract(pmap, va, pap) - pmap_t pmap; + struct pmap *pmap; vaddr_t va; paddr_t *pap; { - struct pv_entry *pv; - int s; + pt_entry_t pte; + + DPRINTF(PDB_FOLLOW|PDB_EXTRACT, ("pmap_extract(%p, %x)\n", pmap, va)); - DPRINTF(PDB_FOLLOW, ("pmap_extract(%p, %x)\n", pmap, va)); + simple_lock(&pmap->pm_obj.vmobjlock); + pte = pmap_vp_find(pmap, va); + simple_unlock(&pmap->pm_obj.vmobjlock); - s = splimp(); - if (!(pv = pmap_find_va(pmap_sid(pmap, va), hppa_trunc_page(va)))) - return (FALSE); - else { - *pap = tlbptob(pv->pv_tlbpage) + (va & PGOFSET); + if (pte) { + if (pap) + *pap = (pte & ~PGOFSET) | (va & PGOFSET); return (TRUE); } - splx(s); + + return (FALSE); } -/* - * pmap_zero_page(pa) - * - * Zeros the specified page. - */ void pmap_zero_page(pa) - register paddr_t pa; + paddr_t pa; { extern int dcache_line_mask; register paddr_t pe = pa + PAGE_SIZE; @@ -1281,10 +1076,9 @@ pmap_zero_page(pa) * instead, keep 'em pending (or verify by the book). */ s = splhigh(); - pmap_clear_pv(pa, NULL); while (pa < pe) { - __asm volatile( + __asm volatile( /* can use ,bc */ "stwas,ma %%r0,4(%0)\n\t" "stwas,ma %%r0,4(%0)\n\t" "stwas,ma %%r0,4(%0)\n\t" @@ -1302,14 +1096,6 @@ pmap_zero_page(pa) splx(s); } -/* - * pmap_copy_page(src, dst) - * - * pmap_copy_page copies the src page to the destination page. If a mapping - * can be found for the source, we use that virtual address. Otherwise, a - * slower physical page copy must be done. The destination is always a - * physical address sivnce there is usually no mapping for it. - */ void pmap_copy_page(spa, dpa) paddr_t spa; @@ -1322,11 +1108,10 @@ pmap_copy_page(spa, dpa) DPRINTF(PDB_FOLLOW|PDB_PHYS, ("pmap_copy_page(%x, %x)\n", spa, dpa)); s = splhigh(); - pmap_clear_pv(spa, NULL); - pmap_clear_pv(dpa, NULL); + /* XXX flush cache for the spa ??? */ while (spa < spe) { - __asm volatile( + __asm volatile( /* can use ,bc */ "ldwas,ma 4(%0),%%r22\n\t" "ldwas,ma 4(%0),%%r21\n\t" "stwas,ma %%r22,4(%1)\n\t" @@ -1351,239 +1136,105 @@ pmap_copy_page(spa, dpa) splx(s); } -/* - * pmap_clear_modify(pa) - * clears the hardware modified ("dirty") bit for one - * machine independant page starting at the given - * physical address. phys must be aligned on a machine - * independant page boundary. - */ -boolean_t -pmap_clear_modify(pg) - struct vm_page *pg; -{ - register struct pv_entry *pv; - register paddr_t pa = VM_PAGE_TO_PHYS(pg); - int s, ret; - - DPRINTF(PDB_FOLLOW, ("pmap_clear_modify(%x)\n", pa)); - - s = splimp(); - for (pv = pmap_find_pv(pa); pv; pv = pv->pv_next) - if (pv->pv_tlbprot & TLB_DIRTY) { - pitlb(pv->pv_space, pv->pv_va); - pdtlb(pv->pv_space, pv->pv_va); - pv->pv_tlbprot &= ~(TLB_DIRTY); - pmap_clear_va(pv->pv_space, pv->pv_va); - ret = TRUE; - } - splx(s); - - return (ret); -} - -/* - * pmap_is_modified(pa) - * returns TRUE if the given physical page has been modified - * since the last call to pmap_clear_modify(). - */ -boolean_t -pmap_is_modified(pg) - struct vm_page *pg; -{ - register struct pv_entry *pv; - register paddr_t pa = VM_PAGE_TO_PHYS(pg); - int s, f = 0; - - DPRINTF(PDB_FOLLOW, ("pmap_is_modified(%x)\n", pa)); - - s = splhigh(); - for (pv = pmap_find_pv(pa); pv && pv->pv_pmap && !f; pv = pv->pv_next) - f |= pv->pv_tlbprot & TLB_DIRTY; - splx(s); - - return f? TRUE : FALSE; -} - -/* - * pmap_clear_reference(pa) - * clears the hardware referenced bit in the given machine - * independant physical page. - * - * Currently, we treat a TLB miss as a reference; i.e. to clear - * the reference bit we flush all mappings for pa from the TLBs. - */ -boolean_t -pmap_clear_reference(pg) - struct vm_page *pg; +void +pmap_kenter_pa(va, pa, prot) + vaddr_t va; + paddr_t pa; + vm_prot_t prot; { - register struct pv_entry *pv; - register paddr_t pa = VM_PAGE_TO_PHYS(pg); - int s, ret; - - DPRINTF(PDB_FOLLOW, ("pmap_clear_reference(%x)\n", pa)); - - s = splimp(); - for (pv = pmap_find_pv(pa); pv; pv = pv->pv_next) - if (pv->pv_tlbprot & TLB_REF) { - pitlb(pv->pv_space, pv->pv_va); - pdtlb(pv->pv_space, pv->pv_va); - pv->pv_tlbprot &= ~(TLB_REF); - pmap_clear_va(pv->pv_space, pv->pv_va); - ret = TRUE; - } - splx(s); + pt_entry_t *pde, pte; - return (ret); -} - -/* - * pmap_is_referenced(pa) - * returns TRUE if the given physical page has been referenced - * since the last call to pmap_clear_reference(). - */ -boolean_t -pmap_is_referenced(pg) - struct vm_page *pg; -{ - register struct pv_entry *pv; - register paddr_t pa = VM_PAGE_TO_PHYS(pg); - int s, f; + DPRINTF(PDB_FOLLOW|PDB_ENTER, + ("pmap_kenter_pa(%x, %x, %x)\n", va, pa, prot)); - DPRINTF(PDB_FOLLOW, ("pmap_is_referenced(%x)\n", pa)); + if (!(pde = pmap_pde_get(pmap_kernel()->pm_pdir, va)) && + !(pde = pmap_pde_alloc(pmap_kernel(), va, NULL))) + panic("pmap_kenter_pa: cannot allocate pde"); +#ifdef DIAGNOSTIC + if ((pte = pmap_pte_get(pde, va))) + panic("pmap_kenter_pa: 0x%x is already mapped %p:0x%x", + va, pde, pte); +#endif - s = splhigh(); - for (pv = pmap_find_pv(pa); pv && pv->pv_pmap && !f; pv = pv->pv_next) - f |= pv->pv_tlbprot & TLB_REF; - splx(s); + pte = pa | PTE_PROT(TLB_UNCACHABLE|TLB_WIRED|TLB_DIRTY|pmap_prot(pmap_kernel(), prot)); + pmap_pte_set(pde, va, pte); - return f? TRUE : FALSE; + DPRINTF(PDB_FOLLOW|PDB_ENTER, ("pmap_kenter_pa: leaving\n")); } -#ifdef notused void -pmap_changebit(va, set, reset) +pmap_kremove(va, size) vaddr_t va; - u_int set, reset; + vsize_t size; { - register struct pv_entry *pv; - int s; - - DPRINTF(PDB_FOLLOW, ("pmap_changebit(%x, %x, %x)\n", va, set, reset)); + pt_entry_t *pde, pte; + vaddr_t eva = va + size, pdemask; - s = splimp(); - if (!(pv = pmap_find_va(HPPA_SID_KERNEL, va))) { - splx(s); - return; - } + DPRINTF(PDB_FOLLOW|PDB_REMOVE, + ("pmap_kremove(%x, %x)\n", va, size)); - pv->pv_tlbprot |= set; - pv->pv_tlbprot &= ~reset; - splx(s); + for (pdemask = va + 1; va < eva; va += PAGE_SIZE) { + if (pdemask != (va & PDE_MASK)) { + pdemask = va & PDE_MASK; + if (!(pde = pmap_pde_get(pmap_kernel()->pm_pdir, va))) { + va += ~PDE_MASK + 1 - PAGE_SIZE; + continue; + } + } + if (!(pte = pmap_pte_get(pde, va))) { +#ifdef DEBUG + printf("pmap_kremove: unmapping unmapped 0x%x\n", va); +#endif + continue; + } - ficache(HPPA_SID_KERNEL, va, NBPG); - pitlb(HPPA_SID_KERNEL, va); + if (pte & PTE_PROT(TLB_EXECUTE)) + ficache(HPPA_SID_KERNEL, va, NBPG); + pitlb(HPPA_SID_KERNEL, va); + fdcache(HPPA_SID_KERNEL, va, NBPG); + pdtlb(HPPA_SID_KERNEL, va); - fdcache(HPPA_SID_KERNEL, va, NBPG); - pdtlb(HPPA_SID_KERNEL, va); + pmap_pte_set(pde, va, 0); + } - pmap_clear_va(HPPA_SID_KERNEL, va); + DPRINTF(PDB_FOLLOW|PDB_REMOVE, ("pmap_kremove: leaving\n")); } -#endif -void -pmap_kenter_pa(va, pa, prot) - vaddr_t va; - paddr_t pa; - vm_prot_t prot; +void * +pmap_pv_page_alloc(struct pool *pp, int flags) { - register struct pv_entry *pv; + vaddr_t va; - DPRINTF(PDB_FOLLOW|PDB_ENTER, - ("pmap_kenter_pa(%x, %x, %x)\n", va, pa, prot)); + DPRINTF(PDB_FOLLOW|PDB_POOL, + ("pmap_pv_page_alloc(%p, %x)\n", pp, flags)); - va = hppa_trunc_page(va); - pv = pmap_find_va(HPPA_SID_KERNEL, va); - if (pv && (pa & HPPA_IOSPACE) == HPPA_IOSPACE) - /* if already mapped i/o space, nothing to do */ - ; - else { - if (pv) - panic("pmap_kenter_pa: mapped already %x", va); - else - pmap_kernel()->pmap_stats.resident_count++; - - pv = pmap_alloc_pv(); - pv->pv_va = va; - pv->pv_pmap = pmap_kernel(); - pv->pv_space = HPPA_SID_KERNEL; - pv->pv_tlbpage = tlbbtop(pa); - pv->pv_tlbprot = TLB_WIRED | TLB_DIRTY | TLB_REF | - HPPA_PID_KERNEL | pmap_prot(pmap_kernel(), prot) | - ((pa & HPPA_IOSPACE) == HPPA_IOSPACE? TLB_UNCACHEABLE : 0); - pmap_enter_va(pv); + if ((va = pmap_steal_memory(PAGE_SIZE, NULL, NULL))) + return (void *)va; + + /* + TODO + if (list not empty) { + get from the list; + return (va); } + */ - DPRINTF(PDB_ENTER, ("pmap_kenter_pa: leaving\n")); -} + DPRINTF(PDB_FOLLOW|PDB_POOL, + ("pmap_pv_page_alloc: uvm_km_alloc_poolpage1\n")); -void -pmap_kremove(va, size) - vaddr_t va; - vsize_t size; -{ - register struct pv_entry *pv; - - for (va = hppa_trunc_page(va); size > 0; - size -= PAGE_SIZE, va += PAGE_SIZE) { - pv = pmap_find_va(HPPA_SID_KERNEL, va); - if (pv) { - ficache(pv->pv_space, pv->pv_va, NBPG); - pitlb(pv->pv_space, pv->pv_va); - fdcache(pv->pv_space, pv->pv_va, NBPG); - pdtlb(pv->pv_space, pv->pv_va); - pmap_remove_va(pv); - } else - DPRINTF(PDB_REMOVE, - ("pmap_kremove: no pv for 0x%x\n", va)); - } + return ((void *)uvm_km_alloc_poolpage1(kernel_map, uvm.kernel_object, + (flags & PR_WAITOK) ? TRUE : FALSE)); } -#if defined(PMAPDEBUG) && defined(DDB) -#include <ddb/db_output.h> -/* - * prints whole va->pa (aka HPT or HVT) - */ void -pmap_hptdump(sp) - int sp; +pmap_pv_page_free(struct pool *pp, void *v) { - register struct hpt_entry *hpt, *ehpt; - register struct pv_entry *pv; - register int hpthf; - - mfctl(CR_HPTMASK, ehpt); - mfctl(CR_VTOP, hpt); - ehpt = (struct hpt_entry *)((int)hpt + (int)ehpt + 1); - db_printf("HPT dump %p-%p:\n", hpt, ehpt); - for (hpthf = 0; hpt < ehpt; hpt++, hpthf = 0) - for (pv = hpt->hpt_entry; pv; pv = pv->pv_hash) - if (sp < 0 || sp == pv->pv_space) { - if (!hpthf) { - db_printf( - "hpt@%p: %x{%sv=%x:%x},%b,%x\n", - hpt, *(u_int *)hpt, - (hpt->hpt_valid?"ok,":""), - hpt->hpt_space, hpt->hpt_vpn << 9, - hpt->hpt_tlbprot, TLB_BITS, - tlbptob(hpt->hpt_tlbpage)); - - hpthf++; - } - db_printf(" pv={%p,%x:%x,%b,%x}->%p\n", - pv->pv_pmap, pv->pv_space, pv->pv_va, - pv->pv_tlbprot, TLB_BITS, - tlbptob(pv->pv_tlbpage), pv->pv_hash); - } + vaddr_t va = (vaddr_t)v; + + DPRINTF(PDB_FOLLOW|PDB_POOL, ("pmap_pv_page_free(%p, %p)\n", pp, v)); + + if (va < virtual_avail) { + /* TODO save on list somehow */ + } else + uvm_km_free_poolpage1(kernel_map, va); } -#endif diff --git a/sys/arch/hppa/hppa/trap.c b/sys/arch/hppa/hppa/trap.c index e74257bedb6..a4d4322fd66 100644 --- a/sys/arch/hppa/hppa/trap.c +++ b/sys/arch/hppa/hppa/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.39 2002/03/14 01:26:32 millert Exp $ */ +/* $OpenBSD: trap.c,v 1.40 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1998-2001 Michael Shalayeff @@ -311,10 +311,10 @@ trap(type, frame) else map = &vm->vm_map; - if (map->pmap->pmap_space != space) { + if (map->pmap->pm_space != space) { #ifdef TRAPDEBUG printf("trap: space missmatch %d != %d\n", - space, map->pmap->pmap_space); + space, map->pmap->pm_space); #endif /* actually dump the user, crap the kernel */ goto dead_end; @@ -371,7 +371,7 @@ trap(type, frame) pcbp->pcb_onfault = 0; break; } -#if 1 +#if 0 if (kdb_trap (type, va, frame)) return; #else @@ -434,7 +434,7 @@ return; } /* FALLTHROUGH to unimplemented */ default: -#if 1 +#if 0 if (kdb_trap (type, va, frame)) return; #endif diff --git a/sys/arch/hppa/hppa/vm_machdep.c b/sys/arch/hppa/hppa/vm_machdep.c index 90293feb08e..d0eb3c2be74 100644 --- a/sys/arch/hppa/hppa/vm_machdep.c +++ b/sys/arch/hppa/hppa/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.33 2002/02/21 06:12:30 mickey Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.34 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1999-2002 Michael Shalayeff @@ -198,7 +198,7 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) pcbp = &p2->p_addr->u_pcb; bcopy(&p1->p_addr->u_pcb, pcbp, sizeof(*pcbp)); /* space is cached for the copy{in,out}'s pleasure */ - pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pmap_space; + pcbp->pcb_space = p2->p_vmspace->vm_map.pmap->pm_space; pcbp->pcb_uva = (vaddr_t)p2->p_addr; sp = (register_t)p2->p_addr + NBPG; @@ -214,9 +214,8 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) tf->tf_sr0 = tf->tf_sr1 = tf->tf_sr2 = tf->tf_sr3 = tf->tf_sr4 = tf->tf_sr5 = tf->tf_sr6 = - p2->p_vmspace->vm_map.pmap->pmap_space; tf->tf_iisq_head = tf->tf_iisq_tail = - p2->p_vmspace->vm_map.pmap->pmap_space; + p2->p_vmspace->vm_map.pmap->pm_space; tf->tf_pidr1 = tf->tf_pidr2 = pmap_sid2pid(tf->tf_sr0); /* diff --git a/sys/arch/hppa/include/cpu.h b/sys/arch/hppa/include/cpu.h index 3dae3c6d2aa..46b0f66abd5 100644 --- a/sys/arch/hppa/include/cpu.h +++ b/sys/arch/hppa/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.28 2002/03/14 01:26:32 millert Exp $ */ +/* $OpenBSD: cpu.h,v 1.29 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 2000-2001 Michael Shalayeff @@ -62,7 +62,7 @@ /* * CPU types and features */ -#define HPPA_FTRS_BTLBS 0x00000001 +#define HPPA_FTRS_TLBU 0x00000001 #define HPPA_FTRS_BTLBU 0x00000002 #define HPPA_FTRS_HVT 0x00000004 #define HPPA_FTRS_W32B 0x00000008 diff --git a/sys/arch/hppa/include/cpufunc.h b/sys/arch/hppa/include/cpufunc.h index b967a53614d..6b85c9e3aef 100644 --- a/sys/arch/hppa/include/cpufunc.h +++ b/sys/arch/hppa/include/cpufunc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.h,v 1.18 2002/03/14 01:26:32 millert Exp $ */ +/* $OpenBSD: cpufunc.h,v 1.19 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1998,2000 Michael Shalayeff @@ -218,13 +218,14 @@ ledctl(int on, int off, int toggle) #endif #ifdef _KERNEL +extern int (*cpu_hpt_init)(vaddr_t hpt, vsize_t hptsize); + void ficache(pa_space_t sp, vaddr_t va, vsize_t size); void fdcache(pa_space_t sp, vaddr_t va, vsize_t size); void pdcache(pa_space_t sp, vaddr_t va, vsize_t size); void fcacheall(void); void ptlball(void); -int btlb_insert(pa_space_t space, vaddr_t va, paddr_t pa, - vsize_t *lenp, u_int prot); +int btlb_insert(pa_space_t space, vaddr_t va, paddr_t pa, vsize_t *lenp, u_int prot); hppa_hpa_t cpu_gethpa(int n); #endif diff --git a/sys/arch/hppa/include/db_machdep.h b/sys/arch/hppa/include/db_machdep.h index d4003aa932a..4951a23fb47 100644 --- a/sys/arch/hppa/include/db_machdep.h +++ b/sys/arch/hppa/include/db_machdep.h @@ -1,7 +1,7 @@ -/* $OpenBSD: db_machdep.h,v 1.7 2002/03/14 01:26:32 millert Exp $ */ +/* $OpenBSD: db_machdep.h,v 1.8 2002/03/15 21:44:18 mickey Exp $ */ /* - * Copyright (c) 1998 Michael Shalayeff + * Copyright (c) 1998-2002 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,6 +35,7 @@ #include <uvm/uvm_extern.h> +#define DB_AOUT_SYMBOLS #define DB_ELF_SYMBOLS #define DB_ELFSIZE 32 @@ -53,8 +54,8 @@ extern db_regs_t ddb_regs; #define BKPT_SIZE sizeof(int) #define BKPT_SET(inst) BKPT_INST -#define IS_BREAKPOINT_TRAP(type, code) 1 -#define IS_WATCHPOINT_TRAP(type, code) 0 +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_IBREAK) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_DBREAK) #define FIXUP_PC_AFTER_BREAK(regs) ((regs)->tf_iioq_head -= sizeof(int)) @@ -90,8 +91,25 @@ static __inline int inst_trap_return(u_int ins) { return (ins & 0xfc001fc0) == 0x00000ca0; } -#define db_clear_single_step(r) ((r)->tf_flags |= 0) -#define db_set_single_step(r) ((r)->tf_flags |= 0) +#if 0 +#define db_clear_single_step(r) ((r)->tf_flags &= ~(PSW_Z)) +#define db_set_single_step(r) ((r)->tf_flags |= (PSW_Z)) +#else +#define SOFTWARE_SSTEP 1 +#define SOFTWARE_SSTEP_EMUL 1 + +static __inline db_addr_t +next_instr_address(db_addr_t addr, int b) { + return (addr + 4); +} + +#define branch_taken(ins,pc,f,regs) branch_taken1(ins, pc, regs) +static __inline db_addr_t +branch_taken1(int ins, db_addr_t pc, db_regs_t *regs) { + return (pc); +} + +#endif int db_valid_breakpoint(db_addr_t); int kdb_trap(int, int, db_regs_t *); diff --git a/sys/arch/hppa/include/pmap.h b/sys/arch/hppa/include/pmap.h index 872c71e20d0..43c16c4a067 100644 --- a/sys/arch/hppa/include/pmap.h +++ b/sys/arch/hppa/include/pmap.h @@ -1,7 +1,7 @@ -/* $OpenBSD: pmap.h,v 1.18 2002/03/14 01:26:32 millert Exp $ */ +/* $OpenBSD: pmap.h,v 1.19 2002/03/15 21:44:18 mickey Exp $ */ /* - * Copyright (c) 1998,1999 Michael Shalayeff + * Copyright (c) 2002 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -14,142 +14,84 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Michael Shalayeff. + * This product includes software developed by Michael Shalayeff. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright 1996 1995 by Open Software Foundation, Inc. - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Copyright (c) 1990,1993,1994 The University of Utah and - * the Computer Systems Laboratory at the University of Utah (CSL). - * All rights reserved. - * - * Permission to use, copy, modify and distribute this software is hereby - * granted provided that (1) source code retains these copyright, permission, - * and disclaimer notices, and (2) redistributions including binaries - * reproduce the notices in supporting documentation, and (3) all advertising - * materials mentioning features or use of this software display the following - * acknowledgement: ``This product includes software developed by the - * Computer Systems Laboratory at the University of Utah.'' - * - * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS - * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF - * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * CSL requests users of this software to return to csl-dist@cs.utah.edu any - * improvements that they make and grant CSL redistribution rights. - * - * Utah $Hdr: pmap.h 1.24 94/12/14$ - * Author: Mike Hibler, Bob Wheeler, University of Utah CSL, 9/90 - */ - -/* - * Pmap header for hppa. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MACHINE_PMAP_H_ -#define _MACHINE_PMAP_H_ +#ifndef _MACHINE_PMAP_H_ +#define _MACHINE_PMAP_H_ #include <machine/pte.h> +#include <uvm/uvm_pglist.h> +#include <uvm/uvm_object.h> -typedef struct pmap { - TAILQ_ENTRY(pmap) pmap_list; /* pmap free list */ - struct simplelock pmap_lock; /* lock on map */ - int pmap_refcnt; /* reference count */ - pa_space_t pmap_space; /* space for this pmap */ - struct pmap_statistics pmap_stats; /* statistics */ -} *pmap_t; -extern pmap_t kernel_pmap; /* The kernel's map */ - -/* - * If HPT is defined, we cache the last miss for each bucket using a - * structure defined for the 7100 hardware TLB walker. On non-7100s, this - * acts as a software cache that cuts down on the number of times we have - * to search the hash chain. (thereby reducing the number of instructions - * and cache misses incurred during the TLB miss). - * - * The pv_entry pointer is the address of the associated hash bucket - * list for fast tlbmiss search. - */ -struct hpt_entry { - u_int hpt_valid:1, /* Valid bit */ - hpt_vpn:15, /* Virtual Page Number */ - hpt_space:16; /* Space ID */ - u_int hpt_tlbprot; /* prot/access rights (for TLB load) */ - u_int hpt_tlbpage; /* physical page (<<5 for TLB load) */ - void *hpt_entry; /* Pointer to associated hash list */ + struct uvm_object pm_obj; /* object (lck by object lock) */ +#define pm_lock pm_obj.vmobjlock + struct vm_page *pm_ptphint; + struct vm_page *pm_pdir_pg; /* vm_page for pdir */ + paddr_t pm_pdir; /* PA of PD (read-only after create) */ + pa_space_t pm_space; /* space id (read-only after create) */ + u_int pm_pid; /* prot id (read-only after create) */ + + struct pmap_statistics pm_stats; }; -#ifdef _KERNEL -extern struct hpt_entry *hpt_table; -#endif /* _KERNEL */ +typedef struct pmap *pmap_t; -/* - * keep it at 32 bytes for the cache overall satisfaction - * also, align commonly used pairs on double-word boundary - */ -struct pv_entry { - struct pv_entry *pv_next; /* list of mappings of a given PA */ - pmap_t pv_pmap; /* back link to pmap */ - u_int pv_va; /* virtual page number */ - u_int pv_space; /* copy of space id from pmap */ - u_int pv_tlbpage; /* physical page (for TLB load) */ - u_int pv_tlbprot; /* TLB format protection */ - struct pv_entry *pv_hash; /* VTOP hash bucket list */ - u_int pv_pad; /* pad to 32 bytes */ -}; +#define HPPA_MAX_PID 0xfffa +#define HPPA_SID_MAX 0x7fff +#define HPPA_SID_KERNEL 0 +#define HPPA_PID_KERNEL 2 -#define NPVPPG (NBPG/32-1) -struct pv_page { - TAILQ_ENTRY(pv_page) pvp_list; /* Chain of pages */ - u_int pvp_nfree; - struct pv_entry *pvp_freelist; - u_int pvp_flag; /* is it direct mapped (unused) */ - u_int pvp_pad[3]; /* align to 32 */ - struct pv_entry pvp_pv[NPVPPG]; +#define KERNEL_ACCESS_ID 1 +#define KERNEL_TEXT_PROT (TLB_AR_KRX | (KERNEL_ACCESS_ID << 1)) +#define KERNEL_DATA_PROT (TLB_AR_KRW | (KERNEL_ACCESS_ID << 1)) + +struct pv_entry; + +struct pv_head { + struct simplelock pvh_lock; /* locks every pv on this list */ + struct pv_entry *pvh_list; /* head of list (locked by pvh_lock) */ + pt_entry_t pvh_attrs; /* to preserve ref/mod */ }; -#define HPPA_SID_MAX 0x7fff -#define HPPA_SID_KERNEL 0 -#define HPPA_PID_KERNEL 2 +struct pv_entry { /* locked by its list's pvh_lock */ + struct pv_entry *pv_next; + struct pmap *pv_pmap; /* the pmap */ + vaddr_t pv_va; /* the virtual address */ + struct vm_page *pv_ptp; /* the vm_page of the PTP */ +}; -#define KERNEL_ACCESS_ID 1 +/* also match the hardware tlb walker definition */ +struct vp_entry { + u_int vp_tag; + u_int vp_tlbprot; + u_int vp_tlbpage; + u_int vp_ptr; +}; -#define KERNEL_TEXT_PROT (TLB_AR_KRX | (KERNEL_ACCESS_ID << 1)) -#define KERNEL_DATA_PROT (TLB_AR_KRW | (KERNEL_ACCESS_ID << 1)) +#ifdef _KERNEL -#ifdef _KERNEL extern void gateway_page(void); +extern struct pmap kernel_pmap_store; + +#if defined(HP7100LC_CPU) || defined(HP7300LC_CPU) +extern int pmap_hptsize; +extern struct pdc_hwtlb pdc_hwtlb; +#endif #define PMAP_STEAL_MEMORY /* we have some memory to steal */ @@ -165,36 +107,56 @@ extern void gateway_page(void); *(h) = pmap_prefer_hint; \ } while(0) -#define pmap_kernel_va(VA) \ - (((VA) >= VM_MIN_KERNEL_ADDRESS) && ((VA) <= VM_MAX_KERNEL_ADDRESS)) - #define pmap_sid2pid(s) (((s) + 1) << 1) -#define pmap_kernel() (kernel_pmap) -#define pmap_resident_count(pmap) ((pmap)->pmap_stats.resident_count) -#define pmap_reference(pmap) \ -do { if (pmap) { \ - simple_lock(&pmap->pmap_lock); \ - pmap->pmap_refcnt++; \ - simple_unlock(&pmap->pmap_lock); \ -} } while (0) -#define pmap_collect(pmap) -#define pmap_release(pmap) +#define pmap_kernel() (&kernel_pmap_store) +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_update(pm) (void)(pm) +#define pmap_activate(pm) (void)(pm) +#define pmap_deactivate(pm) (void)(pm) #define pmap_copy(dpmap,spmap,da,len,sa) -#define pmap_update(pm) -#define pmap_activate(p) -#define pmap_deactivate(p) -#define pmap_phys_address(x) ((x) << PGSHIFT) -#define pmap_phys_to_frame(x) ((x) >> PGSHIFT) +#define pmap_clear_modify(pg) pmap_changebit(pg, 0, PTE_PROT(TLB_DIRTY)) +#define pmap_clear_reference(pg) pmap_changebit(pg, PTE_PROT(TLB_REFTRAP), 0) +#define pmap_is_modified(pg) pmap_testbit(pg, PTE_PROT(TLB_DIRTY)) +#define pmap_is_referenced(pg) pmap_testbit(pg, PTE_PROT(TLB_REFTRAP)) +#define pmap_phys_address(ppn) ((ppn) << PAGE_SHIFT) + +void pmap_bootstrap(vaddr_t); +boolean_t pmap_changebit(struct vm_page *, u_int, u_int); +boolean_t pmap_testbit(struct vm_page *, u_int); +void pmap_write_protect(struct pmap *, vaddr_t, vaddr_t, vm_prot_t); +void pmap_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva); +void pmap_page_remove(struct vm_page *pg); static __inline int pmap_prot(struct pmap *pmap, int prot) { - extern u_int kern_prot[], user_prot[]; - return (pmap == kernel_pmap? kern_prot: user_prot)[prot]; + extern u_int hppa_prot[]; + return (hppa_prot[prot] | (pmap == pmap_kernel()? 0 : TLB_USER)); } -void pmap_bootstrap(vaddr_t *, vaddr_t *); -#endif /* _KERNEL */ +static __inline void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + if ((prot & VM_PROT_WRITE) == 0) { + if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) + (void) pmap_changebit(pg, PTE_PROT(TLB_READ), + PTE_PROT(TLB_WRITE)); + else + pmap_page_remove(pg); + } +} +static __inline void +pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) +{ + if ((prot & VM_PROT_WRITE) == 0) { + if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) + pmap_write_protect(pmap, sva, eva, prot); + else + pmap_remove(pmap, sva, eva); + } +} + +#endif /* _KERNEL */ #endif /* _MACHINE_PMAP_H_ */ diff --git a/sys/arch/hppa/include/pte.h b/sys/arch/hppa/include/pte.h index 9e550cf5f02..d6f5f7650e9 100644 --- a/sys/arch/hppa/include/pte.h +++ b/sys/arch/hppa/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.8 2001/01/12 23:37:49 mickey Exp $ */ +/* $OpenBSD: pte.h,v 1.9 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1990,1993,1994 The University of Utah and @@ -27,42 +27,36 @@ #ifndef _MACHINE_PTE_H_ #define _MACHINE_PTE_H_ +typedef u_int32_t pt_entry_t; + +#define PTE_PROT_SHIFT 19 +#define PTE_PROT(tlb) ((tlb) >> PTE_PROT_SHIFT) +#define TLB_PROT(pte) ((pte) << PTE_PROT_SHIFT) +#define PDE_MASK (0xffc00000) +#define PTE_MASK (0x003ff000) +#define PTE_PAGE(pte) ((pte) & ~PGOFSET) + /* TLB access/protection values */ -#define TLB_REF 0x80000000 /* software only */ -#define TLB_ALIGNED 0x40000000 /* software only */ -#define TLB_TRAP 0x20000000 +#define TLB_WIRED 0x40000000 /* software only */ +#define TLB_REFTRAP 0x20000000 #define TLB_DIRTY 0x10000000 #define TLB_BREAK 0x08000000 #define TLB_AR_MASK 0x07f00000 +#define TLB_READ 0x00000000 +#define TLB_WRITE 0x01000000 +#define TLB_EXECUTE 0x02000000 +#define TLB_GATEWAY 0x04000000 +#define TLB_USER 0x00f00000 #define TLB_AR_NA 0x07300000 -#define TLB_AR_KR 0x00000000 -#define TLB_AR_KRW 0x01000000 -#define TLB_AR_KRX 0x02000000 -#define TLB_AR_KRWX 0x03000000 -#define TLB_AR_UR 0x00f00000 -#define TLB_AR_URW 0x01f00000 -#define TLB_AR_URX 0x02f00000 -#define TLB_AR_URWX 0x03f00000 -#define TLB_UNCACHEABLE 0x00080000 -#define TLB_ICACHE 0x00040000 /* software only */ -#define TLB_NOTUSED 0x00020000 /* software only */ -#define TLB_DCACHE 0x00010000 /* software only */ +#define TLB_AR_R TLB_READ +#define TLB_AR_RW TLB_READ|TLB_WRITE +#define TLB_AR_RX TLB_READ|TLB_EXECUTE +#define TLB_AR_RWX TLB_READ|TLB_WRITE|TLB_EXECUTE +#define TLB_UNCACHABLE 0x00080000 #define TLB_PID_MASK 0x0000fffe -#define TLB_WIRED 0x00000001 /* software only */ #define TLB_BITS "\020\024U\031W\032X\033N\034B\035D\036T\037A\040R" -#define TLB_REF_POS 0 -#define TLB_ALIGNED_POS 1 -#define TLB_TRAP_POS 2 -#define TLB_DIRTY_POS 3 -#define TLB_BREAK_POS 4 -#define TLB_ITLB_POS 12 -#define TLB_ICACHE_POS 13 -#define TLB_DTLB_POS 14 -#define TLB_DCACHE_POS 15 -#define TLB_WIRED_POS 31 - /* protection for a gateway page */ #define TLB_GATE_PROT 0x04c00000 diff --git a/sys/arch/hppa/include/vmparam.h b/sys/arch/hppa/include/vmparam.h index 22992486c53..3b6be168ea2 100644 --- a/sys/arch/hppa/include/vmparam.h +++ b/sys/arch/hppa/include/vmparam.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmparam.h,v 1.21 2002/02/17 22:59:52 maja Exp $ */ +/* $OpenBSD: vmparam.h,v 1.22 2002/03/15 21:44:18 mickey Exp $ */ /* * Copyright (c) 1988-1994, The University of Utah and @@ -106,7 +106,7 @@ #ifndef _LOCORE #define __HAVE_PMAP_PHYSSEG struct pmap_physseg { - struct pv_entry *pvent; + struct pv_head *pvhead; }; #endif |