diff options
| author | gwr <gwr@NetBSD.org> | 1994-06-29 05:35:55 +0000 |
|---|---|---|
| committer | gwr <gwr@NetBSD.org> | 1994-06-29 05:35:55 +0000 |
| commit | 76511003fc8b47aa765dc7bc87b005e43cd71cb1 (patch) | |
| tree | 17edbeaa04fa1be954ae9308857543b09ec6eecb /sys | |
| parent | ab9bc34d8d590ae7926c7db279c43998b2f7f43c (diff) | |
Make setsoft* use the real software interrupt register.
Integrate several fixes from the amiga port (and drop COMPAT_HPUX for now).
Add lots of debugging checks to pmap.c - still needs work.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/arch/sun3/sun3/pmap.c | 619 | ||||
| -rw-r--r-- | sys/arch/sun3/sun3/trap.c | 470 |
2 files changed, 663 insertions, 426 deletions
diff --git a/sys/arch/sun3/sun3/pmap.c b/sys/arch/sun3/sun3/pmap.c index 378ea5cceae..9ad1762e6a7 100644 --- a/sys/arch/sun3/sun3/pmap.c +++ b/sys/arch/sun3/sun3/pmap.c @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pmap.c,v 1.25 1994/05/27 14:58:35 gwr Exp $ + * $Id: pmap.c,v 1.26 1994/06/29 05:35:55 gwr Exp $ */ #include <sys/param.h> #include <sys/systm.h> @@ -141,7 +141,22 @@ struct pv_entry { typedef struct pv_entry *pv_entry_t; pv_entry_t pv_head_table = NULL; +#ifdef PMAP_DEBUG +struct pv_entry * +pa_to_pvp(pa) + vm_offset_t pa; +{ + struct pv_entry *pvp; + if (pa < avail_start || pa >= avail_end) { + printf("pa_to_pvp: bad pa=0x%x\n", pa); + Debugger(); + } + pvp = &pv_head_table[PA_PGNUM(pa)]; + return pvp; +} +#else #define pa_to_pvp(pa) &pv_head_table[PA_PGNUM(pa)] +#endif #define PV_VALID 8 #define PV_WRITE 4 @@ -190,11 +205,22 @@ static unsigned int protection_converter[8]; /* pmeg structures, queues, and macros */ TAILQ_HEAD(pmeg_tailq, pmeg_state); -struct pmeg_tailq pmeg_free_queue, pmeg_inactive_queue, pmeg_active_queue; +struct pmeg_tailq pmeg_free_queue, pmeg_inactive_queue, + pmeg_active_queue, pmeg_kernel_queue; + +static struct pmeg_state pmeg_array[NPMEG]; +#ifdef PMAP_DEBUG +pmeg_t pmeg_p(segnum) + int segnum; +{ + return &pmeg_array[segnum]; +} +#else #define pmeg_p(x) &pmeg_array[x] +#endif + #define is_pmeg_wired(pmegp) (pmegp->pmeg_wired_count) -static struct pmeg_state pmeg_array[NPMEG]; /* context structures, and queues */ TAILQ_HEAD(context_tailq, context_state); @@ -202,10 +228,12 @@ struct context_tailq context_free_queue, context_active_queue; static struct context_state context_array[NCONTEXT]; -/* location to store virtual addresses +/* + * location to store virtual addresses * to be used in copy/zero operations + * (set in sun3_startup.c) */ -vm_offset_t tmp_vpages[2]; +vm_offset_t tmp_vpages[2]; /* context support */ @@ -288,6 +316,71 @@ void pmap_protect __P((pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t void pmap_update __P((void)); +/* + * Debugging support. + */ +#define PMD_ENTER 1 +#define PMD_LINK 2 +#define PMD_PROTECT 4 +#define PMD_SWITCH 8 +#define PMD_COW 0x10 +#define PMD_MODBIT 0x20 +#define PMD_REFBIT 0x40 +#define PMD_WIRING 0x80 +#define PMD_CONTEXT 0x100 +#define PMD_CREATE 0x200 +#define PMD_REMOVE PMD_ENTER +#define PMD_UNLINK PMD_LINK +int pmap_debug; + +#ifdef PMAP_DEBUG /* XXX */ + +int pmap_db_minphys; +void set_pte_debug(va, pte) + vm_offset_t va, pte; +{ + if ((va >= 0xfd00000) || + ((pte & PG_VALID) && (PG_PA(pte) < pmap_db_minphys))) + { + printf("set_pte_debug: va=%x pa=%x\n", va, PG_PA(pte)); + Debugger(); + } + set_pte(va, pte); +} +#define set_pte set_pte_debug + +int pmap_db_watchpmeg; +void set_segmap_debug(va, sme) + vm_offset_t va; + unsigned char sme; +{ + vm_offset_t kva; + + if (sme == pmap_db_watchpmeg) { + printf("set_segmap_debug: watch pmeg %x\n", sme); + Debugger(); + } + if ( (va < VM_MAXUSER_ADDRESS) && (sme != SEGINV) ) { + /* Make sure this pmeg is not in the kernel_pmap. */ + for (kva = VM_MIN_KERNEL_ADDRESS; + kva < VM_MAX_KERNEL_ADDRESS; + kva += NBSG) + { + if (sme == get_segmap(kva)) + panic("set_segmap_debug: stealing kern pmeg, kva=%x", kva); + } + } + set_segmap(va,sme); +} +#define set_segmap set_segmap_debug + +#endif /* PMAP_DEBUG */ + + +/* + * Get a PTE from either the hardware or the pmeg cache. + * Return non-zero if PTE was found for this VA. + */ int get_pte_val(pmap, va, ptep) pmap_t pmap; vm_offset_t va, *ptep; @@ -296,30 +389,34 @@ int get_pte_val(pmap, va, ptep) unsigned char sme; pmeg_t pmegp; int module_debug; + int rc=0; +#ifdef PMAP_DEBUG /* XXX */ + if (pmap == kernel_pmap) + panic("get_pte_val: kernel_pmap"); +#endif + + PMAP_LOCK(); if (pmap->pm_context) { - PMAP_LOCK(); saved_context = get_context(); set_context(pmap->pm_context->context_num); sme = get_segmap(va); - if (sme == SEGINV) { - PMAP_UNLOCK(); - return 0; + if (sme != SEGINV) { + *ptep = get_pte(va); + rc = 1; } - *ptep = get_pte(va); set_context(saved_context); } else { /* we don't have a context */ pmegp = pmeg_cache(pmap, sun3_trunc_seg(va), PM_UPDATE_CACHE); - if (!pmegp) { - PMAP_UNLOCK(); - return 0; + if (pmegp) { + *ptep = get_pte_pmeg(pmegp->pmeg_index, VA_PTE_NUM(va)); + pmeg_release(pmegp); + rc = 1; } - *ptep = get_pte_pmeg(pmegp->pmeg_index, VA_PTE_NUM(va)); - pmeg_release(pmegp); } PMAP_UNLOCK(); - return 1; + return rc; } void set_pte_val(pmap, va,pte) @@ -330,23 +427,26 @@ void set_pte_val(pmap, va,pte) pmeg_t pmegp; unsigned char sme; +#ifdef PMAP_DEBUG /* XXX */ + if (pmap == kernel_pmap) + panic("set_pte_val: kernel_pmap"); +#endif + PMAP_LOCK(); if (pmap->pm_context) { saved_context = get_context(); set_context(pmap->pm_context->context_num); sme = get_segmap(va); - if (sme == SEGINV) goto outta_here; - set_pte(va, pte); + if (sme != SEGINV) + set_pte(va, pte); set_context(saved_context); - } - else { - /* we don't have a context */ + } else { + /* we don't have a context */ pmegp = pmeg_cache(pmap, sun3_trunc_seg(va), PM_UPDATE_CACHE); if (!pmegp) panic("pmap: no pmeg to set pte in"); set_pte_pmeg(pmegp->pmeg_index, VA_PTE_NUM(va), pte); pmeg_release(pmegp); } -outta_here: PMAP_UNLOCK(); } @@ -357,18 +457,22 @@ void context_allocate(pmap) int s; PMAP_LOCK(); -#ifdef CONTEXT_DEBUG - printf("context_allocate: for pmap %x\n", pmap); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_allocate: for pmap %x\n", pmap); #endif + if (pmap == kernel_pmap) + panic("context_allocate: kernel_pmap"); if (pmap->pm_context) panic("pmap: pmap already has context allocated to it"); if (TAILQ_EMPTY(&context_free_queue)) { /* steal one from active*/ if (TAILQ_EMPTY(&context_active_queue)) panic("pmap: no contexts to be found"); context_free((&context_active_queue)->tqh_first->context_upmap); -#ifdef CONTEXT_DEBUG - printf("context_allocate: pmap %x, stealing context %x num %d\n", - pmap, context, context->context_num); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_allocate: pmap %x, take context %x num %d\n", + pmap, context, context->context_num); #endif } TAILQ_REMOVE_FIRST(context, &context_free_queue, context_link); @@ -377,12 +481,14 @@ void context_allocate(pmap) panic("pmap: context in use???"); pmap->pm_context = context; context->context_upmap = pmap; -#ifdef CONTEXT_DEBUG - printf("context_allocate: pmap %x associated with context %x num %d\n", - pmap, context, context->context_num); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_allocate: pmap %x given context %x num %d\n", + pmap, context, context->context_num); #endif PMAP_UNLOCK(); } + void context_free(pmap) /* :) */ pmap_t pmap; { @@ -392,13 +498,14 @@ void context_free(pmap) /* :) */ vm_offset_t va; PMAP_LOCK(); -#ifdef CONTEXT_DEBUG - printf("context_free: freeing pmap %x of context %x num %d\n", - pmap, pmap->pm_context, pmap->pm_context->context_num); -#endif - saved_context = get_context(); if (!pmap->pm_context) panic("pmap: can't free a non-existent context"); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_free: freeing pmap %x of context %x num %d\n", + pmap, pmap->pm_context, pmap->pm_context->context_num); +#endif + saved_context = get_context(); context = pmap->pm_context; set_context(context->context_num); va = 0; @@ -414,8 +521,9 @@ void context_free(pmap) /* :) */ TAILQ_INSERT_TAIL(&context_free_queue, context, context_link);/* active??? XXX */ pmap->pm_context = NULL; -#ifdef CONTEXT_DEBUG - printf("context_free: pmap %x context removed\n", pmap); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_free: pmap %x context removed\n", pmap); #endif PMAP_UNLOCK(); } @@ -427,29 +535,55 @@ void context_init() TAILQ_INIT(&context_free_queue); TAILQ_INIT(&context_active_queue); - for (i=0; i <NCONTEXT; i++) { + /* XXX - Can we use context zero? (Adam says yes.) */ + for (i=0; i < NCONTEXT; i++) { context_array[i].context_num = i; context_array[i].context_upmap = NULL; TAILQ_INSERT_TAIL(&context_free_queue, &context_array[i], context_link); -#ifdef CONTEXT_DEBUG - printf("context_init: context num %d is %x\n", i, &context_array[i]); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_CONTEXT) + printf("context_init: context num %d is %x\n", + i, &context_array[i]); #endif } } +#ifdef PMAP_DEBUG +void context_print(context) + context_t context; +{ + printf(" context_num= 0x%x\n", context->context_num); + printf(" context_upmap=0x%x\n", context->context_upmap); +} +void pmap_print(pmap) + pmap_t pmap; +{ + printf(" pm_context=0x%x\n", pmap->pm_context); + printf(" pm_version=0x%x\n", pmap->pm_version); + printf(" pm_segmap=0x%x\n", pmap->pm_segmap); + if (pmap->pm_context) context_print(pmap->pm_context); +} +#endif + /* steal a pmeg without altering its mapping */ void pmeg_steal(pmeg_num) int pmeg_num; { - pmeg_t pmegp; + pmeg_t pmegp; pmegp = pmeg_p(pmeg_num); if (pmegp->pmeg_reserved) mon_panic("pmeg_steal: attempt to steal an already reserved pmeg\n"); if (pmegp->pmeg_owner) mon_panic("pmeg_steal: pmeg is already owned\n"); + +#ifdef PMAP_DEBUG + mon_printf("pmeg_steal: 0x%x\n", pmegp->pmeg_index); +#endif + + /* XXX - Owned by kernel, but not "managed"... */ pmegp->pmeg_owner = NULL; pmegp->pmeg_reserved++; /* keep count, just in case */ TAILQ_REMOVE(&pmeg_free_queue, pmegp, pmeg_link); @@ -481,28 +615,49 @@ void pmeg_clean_free() panic("pmap: no free pmegs available to clean"); pmegp_first = NULL; - TAILQ_REMOVE_FIRST(pmegp, &pmeg_free_queue, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_NONE; - while (pmegp != pmegp_first) { + + for (;;) { + + TAILQ_REMOVE_FIRST(pmegp, &pmeg_free_queue, pmeg_link); + +#ifdef PMAP_DEBUG + if (pmegp->pmeg_index == pmap_db_watchpmeg) { + printf("pmeg_clean_free: watch pmeg 0x%x\n", pmegp->pmeg_index); + Debugger(); + } +#endif + + pmegp->pmeg_qstate = PMEGQ_NONE; + pmeg_clean(pmegp); - if (pmegp_first == NULL) - pmegp_first = pmegp; + TAILQ_INSERT_TAIL(&pmeg_free_queue, pmegp, pmeg_link); pmegp->pmeg_qstate = PMEGQ_FREE; - TAILQ_REMOVE_FIRST(pmegp, &pmeg_free_queue, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_NONE; + + if (pmegp == pmegp_first) + break; + if (pmegp_first == NULL) + pmegp_first = pmegp; + } } + void pmeg_flush(pmegp) pmeg_t pmegp; { vm_offset_t pte; int i; -/* if (!pmegp->pmeg_vpages) - printf("pmap: pmeg_flush() on clean pmeg\n");*/ +#if 0 + if (!pmegp->pmeg_vpages) + printf("pmap: pmeg_flush() on clean pmeg\n"); +#endif for (i = 0; i < NPAGSEG; i++) { if (pmegp->pmeg_owner) { +#ifdef PMAP_DEBUG /* XXX */ + if (pmegp->pmeg_owner == kernel_pmap) + panic("pmeg_flush: kernel_pmap, pmeg=0x%x", pmegp); +#endif pte = get_pte_pmeg(pmegp->pmeg_index, i); if (pte & PG_VALID) { if (pv_initialized) @@ -529,71 +684,121 @@ pmeg_t pmeg_allocate_invalid(pmap, va) if (!TAILQ_EMPTY(&pmeg_free_queue)) { TAILQ_REMOVE_FIRST(pmegp, &pmeg_free_queue, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_NONE; } else if (!TAILQ_EMPTY(&pmeg_inactive_queue)) { TAILQ_REMOVE_FIRST(pmegp, &pmeg_inactive_queue, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_NONE; +#ifdef PMAP_DEBUG + printf("pmeg_alloc_inv: take inactive %d\n", pmegp->pmeg_index); +#endif pmeg_flush(pmegp); } else if (!TAILQ_EMPTY(&pmeg_active_queue)) { TAILQ_REMOVE_FIRST(pmegp, &pmeg_active_queue, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_NONE; +#ifdef PMAP_DEBUG + printf("pmeg_alloc_inv: take active %d\n", pmegp->pmeg_index); +#endif +#if 0 /* XXX - Now keeping kernel pmegs on pmeg_kernel_queue */ while (pmegp->pmeg_owner == kernel_pmap) { TAILQ_INSERT_TAIL(&pmeg_active_queue, pmegp, pmeg_link); pmegp->pmeg_qstate = PMEGQ_ACTIVE; TAILQ_REMOVE_FIRST(pmegp, &pmeg_active_queue, pmeg_link); pmegp->pmeg_qstate = PMEGQ_NONE; } +#else /* XXX */ + if (pmegp->pmeg_owner == kernel_pmap) { + panic("pmeg_alloc_invalid: kernel pmeg: %x\n", pmegp); + } +#endif /* XXX */ + pmap_remove_range(pmegp->pmeg_owner, pmegp->pmeg_va, pmegp->pmeg_va+NBSG); } else panic("pmeg_allocate_invalid: failed\n"); if (!pmegp) panic("pmeg_allocate_invalid: unable to allocate pmeg"); + +#ifdef PMAP_DEBUG + if (pmegp->pmeg_index == pmap_db_watchpmeg) { + printf("pmeg_alloc_inv: watch pmeg 0x%x\n", pmegp->pmeg_index); + Debugger(); + } +#endif + pmegp->pmeg_owner = pmap; pmegp->pmeg_owner_version = pmap->pm_version; pmegp->pmeg_va = va; pmegp->pmeg_wired_count = 0; pmegp->pmeg_reserved = 0; pmegp->pmeg_vpages = 0; - TAILQ_INSERT_TAIL(&pmeg_active_queue, pmegp, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_ACTIVE; - if (pmap != kernel_pmap) + if (pmap == kernel_pmap) { + TAILQ_INSERT_TAIL(&pmeg_kernel_queue, pmegp, pmeg_link); + pmegp->pmeg_qstate = PMEGQ_KERNEL; + } else { + TAILQ_INSERT_TAIL(&pmeg_active_queue, pmegp, pmeg_link); + pmegp->pmeg_qstate = PMEGQ_ACTIVE; pmap->pm_segmap[VA_SEGNUM(va)] = pmegp->pmeg_index; + } return pmegp; } +/* Put pmeg on the inactive queue. */ void pmeg_release(pmegp) pmeg_t pmegp; { - TAILQ_REMOVE(&pmeg_active_queue, pmegp, pmeg_link); + switch (pmegp->pmeg_qstate) { + case PMEGQ_ACTIVE: + TAILQ_REMOVE(&pmeg_active_queue, pmegp, pmeg_link); + break; + case PMEGQ_KERNEL: + TAILQ_REMOVE(&pmeg_kernel_queue, pmegp, pmeg_link); + break; + defualt: + panic("pmeg_release: releasing bad pmeg"); + break; + } pmegp->pmeg_qstate = PMEGQ_NONE; TAILQ_INSERT_TAIL(&pmeg_inactive_queue, pmegp, pmeg_link); pmegp->pmeg_qstate = PMEGQ_INACTIVE; } +/* + * Put pmeg on the free queue. + * The pmeg might be in kernel_pmap + */ void pmeg_release_empty(pmegp, segnum, update) pmeg_t pmegp; int segnum; int update; { - switch (pmegp->pmeg_qstate) { - case PMEGQ_ACTIVE: - TAILQ_REMOVE(&pmeg_active_queue, pmegp, pmeg_link); - break; - case PMEGQ_INACTIVE: - TAILQ_REMOVE(&pmeg_inactive_queue, pmegp, pmeg_link); /* XXX */ - break; - defualt: - panic("pmeg_release_empty: releasing free or bad pmeg"); - break; - } - pmegp->pmeg_qstate = PMEGQ_NONE; - TAILQ_INSERT_TAIL(&pmeg_free_queue, pmegp, pmeg_link); - pmegp->pmeg_qstate = PMEGQ_FREE; - if (update && (pmegp->pmeg_owner != kernel_pmap)) - pmegp->pmeg_owner->pm_segmap[segnum] = SEGINV; + switch (pmegp->pmeg_qstate) { + case PMEGQ_ACTIVE: + TAILQ_REMOVE(&pmeg_active_queue, pmegp, pmeg_link); + break; + case PMEGQ_INACTIVE: + TAILQ_REMOVE(&pmeg_inactive_queue, pmegp, pmeg_link); /* XXX */ + break; + case PMEGQ_KERNEL: + TAILQ_REMOVE(&pmeg_kernel_queue, pmegp, pmeg_link); + update = 0; + break; + defualt: + panic("pmeg_release_empty: releasing bad pmeg"); + break; + } + +#ifdef PMAP_DEBUG + if (pmegp->pmeg_index == pmap_db_watchpmeg) { + printf("pmeg_release_empty: watch pmeg 0x%x\n", + pmegp->pmeg_index); + Debugger(); + } +#endif + + pmegp->pmeg_qstate = PMEGQ_NONE; + TAILQ_INSERT_TAIL(&pmeg_free_queue, pmegp, pmeg_link); + pmegp->pmeg_qstate = PMEGQ_FREE; + if (update) + pmegp->pmeg_owner->pm_segmap[segnum] = SEGINV; } pmeg_t pmeg_cache(pmap, va, update) @@ -604,7 +809,13 @@ pmeg_t pmeg_cache(pmap, va, update) unsigned char seg; pmeg_t pmegp; - if (!pmap->pm_segmap || (pmap == kernel_pmap)) return PMEG_NULL; +#ifdef PMAP_DEBUG + if (pmap == kernel_pmap) + panic("pmeg_cache: kernel_pmap"); +#endif + + if (pmap->pm_segmap == NULL) + return PMEG_NULL; seg = VA_SEGNUM(va); if (seg > NUSEG) /* out of range */ return PMEG_NULL; @@ -612,6 +823,13 @@ pmeg_t pmeg_cache(pmap, va, update) return PMEG_NULL; pmegp = pmeg_p(pmap->pm_segmap[seg]); +#ifdef PMAP_DEBUG + if (pmegp->pmeg_index == pmap_db_watchpmeg) { + printf("pmeg_cache: watch pmeg 0x%x\n", pmegp->pmeg_index); + Debugger(); + } +#endif + if ((pmegp->pmeg_owner != pmap) || (pmegp->pmeg_owner_version != pmap->pm_version) || (pmegp->pmeg_va != va)) { @@ -644,8 +862,9 @@ void pmeg_init() /* clear pmeg array, put it all on the free pmeq queue */ TAILQ_INIT(&pmeg_free_queue); - TAILQ_INIT(&pmeg_inactive_queue); - TAILQ_INIT(&pmeg_active_queue); + TAILQ_INIT(&pmeg_inactive_queue); + TAILQ_INIT(&pmeg_active_queue); + TAILQ_INIT(&pmeg_kernel_queue); bzero(pmeg_array, NPMEG*sizeof(struct pmeg_state)); for (x =0 ; x<NPMEG; x++) { @@ -703,7 +922,6 @@ int pv_compute_modified(head) int modified; vm_offset_t pte; unsigned int seg; - if (!pv_initialized) return 0; if (!head->pv_pmap) return 0; @@ -729,20 +947,31 @@ int pv_compute_modified(head) void pv_remove_all(pa) vm_offset_t pa; { - pv_entry_t npv,head,last; + pv_entry_t pv; + pmap_t pmap; + vm_offset_t va; #ifdef PMAP_DEBUG - printf("pv_remove_all(%x)\n", pa); + if (pmap_debug & PMD_REMOVE) + printf("pv_remove_all(%x)\n", pa); #endif - if (!pv_initialized) return; - head = pa_to_pvp(pa); - for (npv = head ; npv != NULL; last= npv, npv = npv->pv_next ) { - if (npv->pv_pmap == NULL) continue; /* empty */ -#ifdef PMAP_DEBUG - printf("pv_remove_all: removing pmap %x, va %x mapping\n", - npv->pv_pmap, npv->pv_va); -#endif - pmap_remove(npv->pv_pmap, npv->pv_va, npv->pv_va+NBPG); + if (!pv_initialized) + return; + + for (;;) { + pv = pa_to_pvp(pa); + if (pv->pv_pmap == NULL) + break; + pmap = pv->pv_pmap; + va = pv->pv_va; + /* + * XXX - Have to do pv_unlink here because the call + * pmap_remove_range might not unlink the pv entry. + * This also implies extra pv_unlink calls... + */ + pv_unlink(pmap, pa, va); + pmap_remove_range(pmap, va, va + NBPG); + /* The list was modified, so restart at head. */ } } @@ -756,12 +985,14 @@ unsigned char pv_link(pmap, pa, va, flags) int s; #ifdef PMAP_DEBUG - printf("pv_link(%x, %x, %x, %x)\n", pmap, pa, va, flags); - pv_print(pa); + if (pmap_debug & PMD_LINK) { + printf("pv_link(%x, %x, %x, %x)\n", pmap, pa, va, flags); + pv_print(pa); + } #endif if (!pv_initialized) return 0; - head = pv = pa_to_pvp(pa); PMAP_LOCK(); + head = pv = pa_to_pvp(pa); if (pv->pv_pmap == NULL) { /* not currently "managed" */ pv->pv_va = va; pv->pv_pmap = pmap, @@ -816,6 +1047,7 @@ void pv_change_pte(pv_list, set_bits, clear_bits) if (pv_list->pv_pmap == NULL) /* nothing to hack on */ return; if (!set_bits && !clear_bits) return; /* nothing to do */ + context = get_context(); for (pv = pv_list; pv != NULL; pv=pv->pv_next) { if (pv->pv_pmap == NULL) panic("pv_list corrupted"); @@ -835,6 +1067,7 @@ void pv_change_pte(pv_list, set_bits, clear_bits) } set_context(context); } + void pv_unlink(pmap, pa, va) pmap_t pmap; vm_offset_t pa, va; @@ -844,12 +1077,18 @@ void pv_unlink(pmap, pa, va) if (!pv_initialized) return; #ifdef PMAP_DEBUG - printf("pv_unlink(%x, %x, %x)\n", pmap, pa, va); + if (pmap_debug & PMD_UNLINK) { + printf("pv_unlink(%x, %x, %x)\n", pmap, pa, va); + } #endif pv_list = pa_to_pvp(pa); + if (pv_list->pv_pmap == NULL) { #ifdef PMAP_DEBUG - panic("pv_unlinking too many times"); + if (pmap_debug & PMD_UNLINK) { + printf("pv_unlink: empty list\n"); + Debugger(); /* XXX */ + } #endif return; } @@ -892,7 +1131,10 @@ void pv_unlink(pmap, pa, va) return; } #ifdef PMAP_DEBUG - panic("pv_unlink: couldn't find entry"); + if (pmap_debug & PMD_UNLINK) { + printf("pv_unlink: not on list\n"); + Debugger(); /* XXX */ + } #endif } void pv_init() @@ -1041,6 +1283,7 @@ pmap_map(virt, start, end, prot) } return(virt); } + void pmap_user_pmap_init(pmap) pmap_t pmap; { @@ -1086,6 +1329,9 @@ void pmap_release(pmap) struct pmap *pmap; { + + if (pmap == kernel_pmap) + panic("pmap_release: kernel_pmap!"); if (pmap->pm_context) context_free(pmap); @@ -1104,12 +1350,15 @@ pmap_destroy(pmap) { int count; + if (pmap == NULL) + return; /* XXX - Duh! */ + #ifdef PMAP_DEBUG - printf("pmap_destroy(%x)\n", pmap); + if (pmap_debug & PMD_CREATE) + printf("pmap_destroy(%x)\n", pmap); #endif - if (pmap == NULL) return; if (pmap == kernel_pmap) - panic("pmap: attempted to destroy kernel_pmap"); + panic("pmap_destroy: kernel_pmap!"); pmap_lock(pmap); count = pmap_del_ref(pmap); pmap_unlock(pmap); @@ -1118,9 +1367,6 @@ pmap_destroy(pmap) free((caddr_t)pmap, M_VMPMAP); /* XXXX -- better make sure we it this way allocate */ } -#ifdef PMAP_DEBUG - printf("pmap_successful(%x)\n", pmap); -#endif } /* @@ -1136,7 +1382,8 @@ pmap_page_protect(pa, prot) int s; #ifdef PMAP_DEBUG - printf("pmap_page_protect(%x, %x)\n", pa, prot); + if (pmap_debug & PMD_PROTECT) + printf("pmap_page_protect(%x, %x)\n", pa, prot); #endif PMAP_LOCK(); switch (prot) { @@ -1170,6 +1417,7 @@ pmap_reference(pmap) pmap_unlock(pmap); } } + void pmap_remove_range_mmu(pmap, sva, eva) pmap_t pmap; vm_offset_t sva, eva; @@ -1193,39 +1441,44 @@ void pmap_remove_range_mmu(pmap, sva, eva) else pmegp = pmeg_p(sme); /* have pmeg, will travel */ - if (!pmegp->pmeg_vpages) goto outta_here; /* no valid pages anyway */ + if (pmegp->pmeg_vpages <= 0) + goto outta_here; /* no valid pages anyway */ - va = sva; - while (va < eva) { + for (va = sva; va < eva; va += NBPG) { pte = get_pte(va); if (pte & PG_VALID) { + vm_offset_t pa; + pa = PG_PA(pte); +#ifdef PMAP_DEBUG + if (pte & PG_TYPE) + panic("pmap_remove_range_mmu: not memory, va=%x", va); + if (pa < avail_start || pa >= avail_end) + panic("pmap_remove_range_mmu: not managed, va=%x", va); +#endif if (pv_initialized) save_modified_bits(pte); - pv_unlink(pmap, PG_PA(pte), va); + pv_unlink(pmap, pa, va); pmegp->pmeg_vpages--; set_pte(va, PG_INVAL); } - va+= NBPG; } if (pmegp->pmeg_vpages <= 0) { if (is_pmeg_wired(pmegp)) - printf("pmap: removing wired pmeg sva %x eva%x\n", - sva, eva); + panic("pmap: removing wired pmeg"); pmeg_release_empty(pmegp, VA_SEGNUM(sva), PM_UPDATE_CACHE); if (kernel_pmap == pmap) { for (i=0; i < NCONTEXT; i++) { /* map out of all segments */ set_context(i); set_segmap(sva,SEGINV); } - } - else + } else set_segmap(sva, SEGINV); } outta_here: set_context(saved_context); } -void pmap_remove_range_contextless(pmap, sva, eva,pmegp) +void pmap_remove_range_contextless(pmap, sva, eva, pmegp) pmap_t pmap; vm_offset_t sva, eva; pmeg_t pmegp; @@ -1233,6 +1486,12 @@ void pmap_remove_range_contextless(pmap, sva, eva,pmegp) int sp,ep,i; vm_offset_t pte,va; +#ifdef PMAP_DEBUG /* XXX */ + /* Kernel always in a context (actually, in all contexts). */ + if (pmap == kernel_pmap) + panic("pmap_remove_range_contextless: kernel_pmap"); +#endif + sp = VA_PTE_NUM(sva); ep = VA_PTE_NUM(eva); va = sva; @@ -1249,14 +1508,13 @@ void pmap_remove_range_contextless(pmap, sva, eva,pmegp) } if (pmegp->pmeg_vpages <= 0) { if (is_pmeg_wired(pmegp)) - printf("pmap: removing wired pmeg sva %x eva %x\n", - sva, eva); + panic("pmap: removing wired"); pmeg_release_empty(pmegp,VA_SEGNUM(sva), PM_UPDATE_CACHE); } else pmeg_release(pmegp); } -/* guaraunteed to be within one pmeg */ +/* guaraunteed to be within one pmeg */ void pmap_remove_range(pmap, sva, eva) pmap_t pmap; vm_offset_t sva, eva; @@ -1269,14 +1527,11 @@ void pmap_remove_range(pmap, sva, eva) * user: has no context, is not available (NOTHING) |_ together * user: has context, isn't available (NOTHING) | */ - if ((pmap != kernel_pmap)) - if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV) { + if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV) return; - } - if ((pmap == kernel_pmap) || - (pmap->pm_context)) { + if ((pmap == kernel_pmap) || (pmap->pm_context)) { pmap_remove_range_mmu(pmap, sva, eva); return; } @@ -1308,7 +1563,8 @@ void pmap_remove(pmap, sva, eva) return; #ifdef PMAP_DEBUG - printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); + if (pmap_debug & PMD_REMOVE) + printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); #endif /* do something about contexts */ if (pmap == kernel_pmap) { @@ -1316,8 +1572,7 @@ void pmap_remove(pmap, sva, eva) sva = VM_MIN_KERNEL_ADDRESS; if (eva > VM_MAX_KERNEL_ADDRESS) eva = VM_MAX_KERNEL_ADDRESS; - } - else { + } else { if (eva > VM_MAXUSER_ADDRESS) eva = VM_MAXUSER_ADDRESS; } @@ -1353,7 +1608,7 @@ void pmap_enter_kernel(va, pa, prot, wired, pte_proto, mem_type) need to handle possibly allocating additional pmegs need to make sure they cant be stolen from the kernel; map any new pmegs into all contexts, make sure rest of pmeg is null; - deal with pv_stuff; poossibly caching problems; + deal with pv_stuff; possibly caching problems; must also deal with changes too. */ pte_proto |= PG_SYSTEM | MAKE_PGTYPE(mem_type); @@ -1370,7 +1625,7 @@ void pmap_enter_kernel(va, pa, prot, wired, pte_proto, mem_type) * (e) change/add pte */ if (va < VM_MIN_KERNEL_ADDRESS) - panic("pmap: kernel trying to allocate virtual space below itself\n"); + panic("pmap: kernel trying to allocate virtual space below minkva\n"); PMAP_LOCK(); sme = get_segmap(va); /* XXXX -- lots of non-defined routines, need to see if pmap has a @@ -1386,8 +1641,16 @@ void pmap_enter_kernel(va, pa, prot, wired, pte_proto, mem_type) set_context(c); goto add_pte; } - else + else { + /* Found an existing pmeg. Modify it... */ pmegp = pmeg_p(sme); + /* Don't try to unlink if in DVMA map. */ + if (va >= VM_MAX_KERNEL_ADDRESS) + goto add_pte; + /* Make sure we own it. */ + if (pmegp->pmeg_owner != kernel_pmap) + panic("pmap_enter_kernel: found unknown pmeg"); + } /* does mapping already exist */ /* (a) if so, is it same pa then really a protection change @@ -1395,7 +1658,8 @@ void pmap_enter_kernel(va, pa, prot, wired, pte_proto, mem_type) * (c) */ current_pte = get_pte(va); - if (!(current_pte & PG_VALID)) goto add_pte; /* just adding */ + if (!(current_pte & PG_VALID)) + goto add_pte; /* just adding */ pmegp->pmeg_vpages--; /* removing valid page here, way lame XXX*/ if (pv_initialized) save_modified_bits(current_pte); @@ -1463,8 +1727,12 @@ void pmap_enter_user(pmap, va, pa, prot, wired, pte_proto, mem_type) if (!pmegp) /* no cached pmeg */ pmegp = pmeg_allocate_invalid(pmap, sun3_trunc_seg(va)); set_segmap(va,pmegp->pmeg_index); - } else + } else { + /* Found an existing pmeg. Make sure we own it. */ pmegp = pmeg_p(sme); + if (pmegp->pmeg_owner != pmap) + panic("pmap_enter_user: unknown pmeg"); + } /* does mapping already exist */ /* (a) if so, is it same pa then really a protection change @@ -1488,6 +1756,7 @@ add_pte: set_pte(va, pte_proto); pmegp->pmeg_vpages++; /* assumes pmap_enter can never insert a non-valid page */ + set_context(saved_context); PMAP_UNLOCK(); } /* @@ -1515,8 +1784,9 @@ pmap_enter(pmap, va, pa, prot, wired) int s; if (pmap == NULL) return; -#if defined(PMAP_ENTER_DEBUG) || defined(PMAP_DEBUG) - printf("pmap_enter(%x, %x, %x, %x, %x)\n", +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_ENTER) + printf("pmap_enter(%x, %x, %x, %x, %x)\n", pmap, va, pa, prot, wired); #endif mem_type = pa & PMAP_MEMMASK; @@ -1545,12 +1815,13 @@ pmap_clear_modify(pa) int s; if (!pv_initialized) return; -#if defined(PMAP_DEBUG) || defined(PMPA_COW_DEBUG) - printf("pmap_clear_modified: %x\n", pa); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_MODBIT) + printf("pmap_clear_modified: %x\n", pa); #endif PMAP_LOCK(); pv_modified_table[PA_PGNUM(pa)] = 0; - pv_change_pte(&pv_head_table[PA_PGNUM(pa)], 0, PG_MOD); + pv_change_pte(pa_to_pvp(pa), 0, PG_MOD); PMAP_UNLOCK(); } boolean_t @@ -1559,8 +1830,9 @@ pmap_is_modified(pa) { int s; -#if defined(PMAP_DEBUG) || defined(PMPA_COW_DEBUG) - printf("pmap_is_modified: %x\n", pa); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_MODBIT) + printf("pmap_is_modified: %x\n", pa); #endif if (!pv_initialized) return 0; if (pv_modified_table[PA_PGNUM(pa)]) return 1; @@ -1577,7 +1849,8 @@ void pmap_clear_reference(pa) if (!pv_initialized) return; #ifdef PMAP_DEBUG - printf("pmap_clear_referenced: %x\n", pa); + if (pmap_debug & PMD_REFBIT) + printf("pmap_clear_referenced: %x\n", pa); #endif PMAP_LOCK(); pv_remove_all(pa); @@ -1588,8 +1861,11 @@ boolean_t pmap_is_referenced(pa) vm_offset_t pa; { - printf("pmap_is_referenced: %x\n", pa); - return FALSE; +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_REFBIT) + printf("pmap_is_referenced: %x\n", pa); +#endif + return FALSE; /* XXX */ } @@ -1597,35 +1873,34 @@ void pmap_activate(pmap, pcbp) pmap_t pmap; struct pcb *pcbp; { - int s; + int s, newctx; + if (pmap == kernel_pmap) + panic("pmap_activate: kernel_pmap"); + + if (pmap->pm_context == NULL) + context_allocate(pmap); + + newctx = pmap->pm_context->context_num; + + if (newctx != get_context()) { #ifdef PMAP_DEBUG - printf("pmap_activate(%x, %x)\n", pmap, pcbp); -#endif - if (pmap->pm_context) { -#ifdef PMAP_DEBUG - printf("pmap_activate(%x, %x) switching to context %d\n", pmap, pcbp, - pmap->pm_context->context_num); -#endif - set_context(pmap->pm_context->context_num); -#ifdef PMAP_DEBUG - printf("pmap_activate(%x, %x) completed\n", pmap, pcbp); + if (pmap_debug & PMD_SWITCH) + printf("pmap_activate(%x, %x) switching to context %d\n", + pmap, pcbp, newctx); #endif - return; + set_context(newctx); } - context_allocate(pmap); - set_context(pmap->pm_context->context_num); -#ifdef PMAP_DEBUG - printf("pmap_activate(%x, %x) completed\n", pmap, pcbp); -#endif } void pmap_deactivate(pmap, pcbp) pmap_t pmap; struct pcb *pcbp; { #ifdef PMAP_DEBUG - printf("pmap_deactivate(%x, %x)\n", pmap, pcbp); + if (pmap_debug & PMD_SWITCH) + printf("pmap_deactivate(%x, %x)\n", pmap, pcbp); #endif + /* XXX - Why bother? -gwr */ TAILQ_INSERT_TAIL(&context_active_queue, pmap->pm_context, context_link); } @@ -1643,7 +1918,8 @@ pmap_change_wiring(pmap, va, wired) boolean_t wired; { #ifdef PMAP_DEBUG - printf("pmap: call to pmap_change_wiring(). ignoring.\n"); + if (pmap_debug & PMD_WIRING) + printf("pmap: call to pmap_change_wiring(). ignoring.\n"); #endif } /* @@ -1674,8 +1950,9 @@ void pmap_copy_page(src, dst) vm_offset_t pte; int s; -#if defined(PMAP_DEBUG) || defined(PMPA_COW_DEBUG) - printf("pmap_copy_page: %x -> %x\n", src, dst); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_COW) + printf("pmap_copy_page: %x -> %x\n", src, dst); #endif PMAP_LOCK(); pte = PG_VALID |PG_SYSTEM|PG_WRITE|PG_NC|PG_MMEM| PA_PGNUM(src); @@ -1821,7 +2098,8 @@ void pmap_protect_range_mmu(pmap, sva, eva,pte_proto) else pmegp = pmeg_p(sme); /* have pmeg, will travel */ - if (!pmegp->pmeg_vpages) return; /* no valid pages anyway */ + if (pmegp->pmeg_vpages <= 0) + return; /* no valid pages anyway */ va = sva; while (va < eva) { pte = get_pte(va); @@ -1850,9 +2128,10 @@ void pmap_protect_range(pmap, sva, eva, pte_proto) pmeg_t pmegp; if ((pmap != kernel_pmap)) - if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV) return; - if ((pmap == kernel_pmap) || - (pmap->pm_context)) + if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV) + return; + + if ((pmap == kernel_pmap) || (pmap->pm_context)) pmap_protect_range_mmu(pmap, sva, eva,pte_proto); else { pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva),PM_UPDATE_CACHE); @@ -1884,8 +2163,9 @@ pmap_protect(pmap, sva, eva, prot) if (eva > VM_MAX_ADDRESS) eva = VM_MAX_ADDRESS; } -#if defined(PMAP_DEBUG) || defined(PMPA_COW_DEBUG) - printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_PROTECT) + printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); #endif if ((prot & VM_PROT_READ) == VM_PROT_NONE) { pmap_remove(pmap, sva, eva); @@ -1927,8 +2207,9 @@ void pmap_zero_page(pa) vm_offset_t pte; int s; -#if defined(PMAP_DEBUG) || defined(PMAP_COW_DEBUG) - printf("pmap_zero_page: %x\n", pa); +#ifdef PMAP_DEBUG + if (pmap_debug & PMD_COW) + printf("pmap_zero_page: %x\n", pa); #endif PMAP_LOCK(); pte = PG_VALID |PG_SYSTEM|PG_WRITE|PG_NC|PG_MMEM| PA_PGNUM(pa); @@ -1938,4 +2219,8 @@ void pmap_zero_page(pa) PMAP_UNLOCK(); } - +/* + * Local Variables: + * tab-width: 8 + * End: + */ diff --git a/sys/arch/sun3/sun3/trap.c b/sys/arch/sun3/sun3/trap.c index dac053ca8ac..5125a2cf5ee 100644 --- a/sys/arch/sun3/sun3/trap.c +++ b/sys/arch/sun3/sun3/trap.c @@ -1,8 +1,8 @@ /* * Copyright (c) 1993 Adam Glass * Copyright (c) 1988 University of Utah. - * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer @@ -36,10 +36,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: Utah Hdr: trap.c 1.32 91/04/06 - * from: @(#)trap.c 7.15 (Berkeley) 8/2/91 - * trap.c,v 1.3 1993/07/07 07:08:47 cgd Exp - * $Id: trap.c,v 1.22 1994/05/27 14:58:41 gwr Exp $ + * from: Utah Hdr: trap.c 1.37 92/12/20 + * from: @(#)trap.c 8.5 (Berkeley) 1/4/94 + * $Id: trap.c,v 1.23 1994/06/29 05:35:59 gwr Exp $ */ #include <sys/param.h> @@ -56,21 +55,19 @@ #include <sys/ktrace.h> #endif +#include <vm/vm.h> +#include <vm/pmap.h> + #include <machine/cpu.h> #include <machine/endian.h> #include <machine/psl.h> #include <machine/trap.h> #include <machine/reg.h> -#include <vm/vm.h> -#include <vm/pmap.h> - -#ifdef COMPAT_HPUX -#include <hp300/hpux/hpux.h> -#endif - #ifdef COMPAT_SUNOS #include <compat/sunos/sun_syscall.h> +extern struct sysent sun_sysent[]; +extern int nsun_sysent; #endif @@ -79,14 +76,12 @@ * Chris's new syscall debug stuff */ -struct sysent sysent[]; -int nsysent; +extern struct sysent sysent[]; +extern int nsysent; +extern int fubail(), subail(); + int astpending; int want_resched; -#ifdef COMPAT_SUNOS -struct sysent sun_sysent[]; -int nsun_sysent; -#endif char *trap_type[] = { "Bus error", @@ -104,8 +99,8 @@ char *trap_type[] = { "Coprocessor violation", "Async system trap" }; -#define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0]) -int trap_types = TRAP_TYPES; +int trap_types = sizeof(trap_type) / sizeof(trap_type[0]); + /* * Size of various exception stack frames (minus the standard 8 bytes) */ @@ -146,17 +141,20 @@ userret(p, fp, oticks) u_quad_t oticks; { int sig, s; - - while ((sig = CURSIG(p)) !=0) + + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) postsig(sig); + p->p_priority = p->p_usrpri; + if (want_resched) { /* * Since we are curproc, clock will normally just change * our priority without moving us from one queue to another * (since the running process is not on a queue.) - * If that happened after we setrunqueue ourselves but - * before we switch()'ed, we might not be on the queue + * If that happened after we put ourselves on the run queue + * but before we switch()'ed, we might not be on the queue * indicated by our priority. */ s = splstatclock(); @@ -169,7 +167,7 @@ userret(p, fp, oticks) } /* - * If profiling, charge recent system time to the trapped pc. + * If profiling, charge system time to the trapped pc. */ if (p->p_flag & P_PROFIL) { extern int psratio; @@ -179,6 +177,7 @@ userret(p, fp, oticks) curpriority = p->p_priority; } + /* * Trap is called from locore to handle most types of processor traps, * including events such as simulated software interrupts/AST's. @@ -187,22 +186,26 @@ userret(p, fp, oticks) /*ARGSUSED*/ trap(type, code, v, frame) int type; - unsigned code; - register unsigned v; + u_int code, v; struct frame frame; { - extern char fuswintr[]; register struct proc *p; - register int i = 0; - unsigned ucode = 0; + register int sig; + unsigned ucode; u_quad_t sticks; unsigned ncode; int s; cnt.v_trap++; p = curproc; - if ((p = curproc) == NULL) - p = &proc0; + ucode = 0; + sig = 0; + +#ifdef DIAGNOSTIC + if (p == NULL) + panic("trap: curproc == NULL"); +#endif + if (USERMODE(frame.f_sr)) { type |= T_USER; sticks = p->p_sticks; @@ -215,34 +218,36 @@ trap(type, code, v, frame) return; } #endif +#if 0 + printf("trap: t %x c %x v %x pad %x adj %x sr %x pc %x fmt %x vc %x\n", + type, code, v, frame.f_pad, frame.f_stackadj, frame.f_sr, + frame.f_pc, frame.f_format, frame.f_vector); +#endif switch (type) { default: -dopanic: - printf("trap type %d, code = %x, v = %x, pc=%x\n", - type, code, v, frame.f_pc); -#ifdef DDB - if (kdb_trap(type, &frame)) - return; -#endif - regdump(frame.f_regs, 128); + dopanic: + if (panicstr == NULL) { + printf("trap type %d, code = %x, v = %x\n", type, code, v); + regdump(&frame, 128); + } type &= ~T_USER; - if ((unsigned)type < TRAP_TYPES) + if ((u_int)type < trap_types) panic(trap_type[type]); panic("trap"); case T_BUSERR: /* kernel bus error */ - if (!p->p_addr->u_pcb.pcb_onfault) + if (p->p_addr->u_pcb.pcb_onfault == 0) goto dopanic; + /*FALLTHROUGH*/ + copyfault: /* * If we have arranged to catch this fault in any of the * copy to/from user space routines, set PC to return to * indicated location and set flag informing buserror code * that it may need to clean up stack frame. */ -copyfault: - frame.f_stackadj = exframesize[frame.f_format]; frame.f_format = frame.f_vector = 0; frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; @@ -251,112 +256,71 @@ copyfault: case T_BUSERR|T_USER: /* bus error */ case T_ADDRERR|T_USER: /* address error */ ucode = v; - i = SIGBUS; + sig = SIGBUS; break; -#ifdef FPCOPROC - case T_COPERR: /* kernel coprocessor violation */ -#endif - case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ - case T_FMTERR: /* ...just in case... */ - /* - * The user has most likely trashed the RTE or FP state info - * in the stack frame of a signal handler. - */ - type |= T_USER; - printf("pid %d: kernel %s exception\n", p->p_pid, - type==T_COPERR ? "coprocessor" : "format"); - p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; - i = sigmask(SIGILL); - p->p_sigignore &= ~i; - p->p_sigcatch &= ~i; - p->p_sigmask &= ~i; - i = SIGILL; - ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ + case T_ILLINST|T_USER: /* illegal instruction fault */ + case T_PRIVINST|T_USER: /* privileged instruction fault */ + ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ + sig = SIGILL; + break; + + case T_ZERODIV|T_USER: /* Divide by zero */ + case T_CHKINST|T_USER: /* CHK instruction trap */ + case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ + ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ + sig = SIGFPE; break; #ifdef FPCOPROC case T_COPERR|T_USER: /* user coprocessor violation */ - /* What is a proper response here? */ + /* What is a proper response here? */ ucode = 0; - i = SIGFPE; + sig = SIGFPE; break; case T_FPERR|T_USER: /* 68881 exceptions */ - /* - * We pass along the 68881 status register which locore stashed - * in code for us. Note that there is a possibility that the - * bit pattern of this register will conflict with one of the - * FPE_* codes defined in signal.h. Fortunately for us, the - * only such codes we use are all in the range 1-7 and the low - * 3 bits of the status register are defined as 0 so there is - * no clash. - */ + /* + * We pass along the 68881 status register which locore stashed + * in code for us. Note that there is a possibility that the + * bit pattern of this register will conflict with one of the + * FPE_* codes defined in signal.h. Fortunately for us, the + * only such codes we use are all in the range 1-7 and the low + * 3 bits of the status register are defined as 0 so there is + * no clash. + */ ucode = code; - i = SIGFPE; - break; -#endif - - case T_ILLINST|T_USER: /* illegal instruction fault */ -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) { - ucode = HPUX_ILL_ILLINST_TRAP; - i = SIGILL; - break; - } - /* fall through */ -#endif - case T_PRIVINST|T_USER: /* privileged instruction fault */ -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) - ucode = HPUX_ILL_PRIV_TRAP; - else -#endif - ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ - i = SIGILL; - break; - - case T_ZERODIV|T_USER: /* Divide by zero */ -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) - ucode = HPUX_FPE_INTDIV_TRAP; - else -#endif - ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ - i = SIGFPE; + sig = SIGFPE; break; - case T_CHKINST|T_USER: /* CHK instruction trap */ -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) { - /* handled differently under hp-ux */ - i = SIGILL; - ucode = HPUX_ILL_CHK_TRAP; - break; - } + case T_COPERR: /* kernel coprocessor violation */ + /*FALLTHROUGH*/ #endif - ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ - i = SIGFPE; - break; - - case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) { - /* handled differently under hp-ux */ - i = SIGILL; - ucode = HPUX_ILL_TRAPV_TRAP; - break; - } + case T_FMTERR: /* kernel format error */ + case T_FMTERR|T_USER: /* XXX ...just in case... */ + /* + * The user has most likely trashed the RTE or FP state info + * in the stack frame of a signal handler. + */ + type |= T_USER; +#ifdef DEBUG + printf("pid %d: kernel %s exception\n", p->p_pid, + type==T_COPERR ? "coprocessor" : "format"); #endif - ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ - i = SIGFPE; + p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; + sig = sigmask(SIGILL); + p->p_sigignore &= ~sig; + p->p_sigcatch &= ~sig; + p->p_sigmask &= ~sig; + sig = SIGILL; + ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ break; /* * XXX: Trace traps are a nightmare. * * HP-UX uses trap #1 for breakpoints, - * HPBSD uses trap #2, + * NetBSD/m68k uses trap #2, * SUN 3.x uses trap #15, * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). * @@ -367,19 +331,22 @@ copyfault: case T_TRACE: /* kernel trace trap */ case T_TRAP15: /* SUN trace trap */ frame.f_sr &= ~PSL_T; - i = SIGTRAP; + sig = SIGTRAP; break; case T_TRACE|T_USER: /* user trace trap */ case T_TRAP15|T_USER: /* SUN user trace trap */ #ifdef COMPAT_SUNOS - /* SunOS seems to use Trap #2 for some obscure fpu operations. - So far, just ignore it, but DONT trap on it.. */ + /* + * SunOS seems to use Trap #2 for some obscure fpu operations. + * So far, just ignore it, but DONT trap on it... + * (i.e. do not deliver a signal for it) + */ if (p->p_emul == EMUL_SUNOS) break; #endif frame.f_sr &= ~PSL_T; - i = SIGTRAP; + sig = SIGTRAP; break; case T_ASTFLT: /* system async trap, cannot happen */ @@ -387,6 +354,7 @@ copyfault: case T_ASTFLT|T_USER: /* user async trap */ astpending = 0; +#ifdef NEED_SSIR /* Now using isr_soft_request() */ /* * We check for software interrupts first. This is because * they are at a higher level than ASTs, and on a VAX would @@ -396,7 +364,7 @@ copyfault: * IPL while processing the SIR. */ spl1(); - /* fall into... */ + /*FALLTHROUGH*/ case T_SSIR: /* software interrupt */ case T_SSIR|T_USER: @@ -418,6 +386,7 @@ copyfault: return; } spl0(); +#endif /* NEED_SSIR */ if (p->p_flag & P_OWEUPC) { p->p_flag &= ~P_OWEUPC; ADDUPROF(p); @@ -428,11 +397,14 @@ copyfault: /* * If we were doing profiling ticks or other user mode * stuff from interrupt code, Just Say No. - * XXX - Can this test ever succeed? -gwr + * XXX - Should this be a range test? -gwr */ - if (p->p_addr->u_pcb.pcb_onfault == fuswintr) + if (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fubail || + p->p_addr->u_pcb.pcb_onfault == (caddr_t)subail) + { goto copyfault; - /* fall into ... */ + } + /*FALLTHROUGH*/ case T_MMUFLT|T_USER: /* page fault */ { @@ -458,7 +430,7 @@ copyfault: * argument space is lazy-allocated. */ if (type == T_MMUFLT && - (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code))) + ((p->p_addr->u_pcb.pcb_onfault == 0) || KDFAULT(code))) map = kernel_map; else map = &vm->vm_map; @@ -468,29 +440,25 @@ copyfault: ftype = VM_PROT_READ; va = trunc_page((vm_offset_t)v); #ifdef DIAGNOSTIC - if (map == kernel_map && va == 0) { - printf("trap: bad kernel access at %x\n", v); - goto dopanic; - } -#endif -#if 0 /* XXX def COMPAT_HPUX */ - if (ISHPMMADDR(va)) { - vm_offset_t bva; - - rv = pmap_mapmulti(map->pmap, va); - if (rv != KERN_SUCCESS) { - bva = HPMMBASEADDR(va); - rv = vm_fault(map, bva, ftype, FALSE); - if (rv == KERN_SUCCESS) - (void) pmap_mapmulti(map->pmap, va); + if (map == kernel_map) { + if (va == 0) { + printf("trap: bad kernel access at %x\n", v); + goto dopanic; + } + } else { + if (va >= VM_MAXUSER_ADDRESS) { + printf("trap: user access at kern addr %x\n", v); + Debugger(); } - } else + } #endif rv = vm_fault(map, va, ftype, FALSE); -#ifdef DEBUG - if (rv && MDB_ISPID(p->p_pid)) +#if 1 /* def DEBUG */ + if (rv) { printf("vm_fault(%x, %x, %x, 0) -> %x\n", map, va, ftype, rv); + Debugger(); + } #endif #ifdef VMFAULT_TRACE printf("vm_fault(%x, %x, %x, 0) -> %x in context %d at %x\n", @@ -534,18 +502,20 @@ copyfault: ((int *) frame.f_regs)[PC], rv); printf(" type %x, code [mmu,,ssw]: %x\n", type, code); - goto dopanic; } ucode = v; - i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; break; } } +#ifdef DIAGNOSTIC + if (sig == 0) + panic("trap: sig not set"); +#endif + trapsignal(p, sig, ucode); if ((type & T_USER) == 0) return; - if (i) - trapsignal(p, i, ucode); out: userret(p, &frame, sticks); } @@ -560,73 +530,72 @@ syscall(code, frame) register caddr_t params; register int i; register struct sysent *callp; - register struct proc *p = curproc; + register struct proc *p; int error, opc, numsys, s; + u_int argsize; u_quad_t sticks; - struct args { - int i[8]; - } args; + int args[8]; int rval[2]; struct timeval syst; struct sysent *systab; -#ifdef COMPAT_HPUX - extern struct sysent hpuxsysent[]; - extern int hpux_nsysent, notimp(); -#endif - cnt.v_syscall++; - sticks = p->p_sticks; if (!USERMODE(frame.f_sr)) panic("syscall"); + + cnt.v_syscall++; + p = curproc; p->p_md.md_regs = frame.f_regs; + p->p_md.md_flags &= ~MDP_STACKADJ; + sticks = p->p_sticks; opc = frame.f_pc - 2; + error = 0; + switch (p->p_emul) { #ifdef COMPAT_SUNOS - case EMUL_SUNOS: { - extern char *sun_syscallnames[]; - - systab = sun_sysent; - numsys = nsun_sysent; - /* SunOS passes the syscall-number on the stack, whereas - BSD passes it in D0. So, we have to get the real "code" - from the stack, and clean up the stack, as SunOS glue - code assumes the kernel pops the syscall argument the - glue pushed on the stack. Sigh... */ - code = fuword ((caddr_t) frame.f_regs[SP]); - /* XXX don't do this for sun_sigreturn, as there's no - XXX stored pc on the stack to skip, the argument follows - XXX the syscall number without a gap. */ + case EMUL_SUNOS: + systab = sun_sysent; + numsys = nsun_sysent; + /* + * SunOS passes the syscall-number on the stack, whereas + * BSD passes it in D0. So, we have to get the real "code" + * from the stack, and clean up the stack, as SunOS glue + * code assumes the kernel pops the syscall argument the + * glue pushed on the stack. Sigh... + */ + code = fuword ((caddr_t) frame.f_regs[SP]); + + /* + * XXX don't do this for sun_sigreturn, as there's no + * XXX stored pc on the stack to skip, the argument follows + * XXX the syscall number without a gap. + */ if (code != SUN_SYS_sigreturn) { frame.f_regs[SP] += sizeof (int); - /* remember that we adjusted the SP, might have to undo - this if the system call returns ERESTART. */ + /* + * remember that we adjusted the SP, might have to + * undo this if the system call returns ERESTART. + */ p->p_md.md_flags |= MDP_STACKADJ; } - } - break; -#endif -#ifdef COMPAT_HPUX - case EMUL_HPUX: - systab = hpux_sysent; - numsys = hpux_nsysent; - break; - + break; #endif case EMUL_NETBSD: - systab = sysent; - numsys = nsysent; - break; + systab = sysent; + numsys = nsysent; + break; default: panic("syscall: bad syscall emulation type"); } + params = (caddr_t)frame.f_regs[SP] + sizeof(int); + switch (code) { case SYS_syscall: /* * Code is first argument, followed by actual args. */ - code = fuword(params); /* indir */ + code = fuword(params); params += sizeof(int); /* * XXX sigreturn requires special stack manipulation @@ -642,89 +611,72 @@ syscall(code, frame) * Like syscall, but code is a quad, so as to maintain * quad alignment for the rest of the arguments. */ - if (p->p_emul != EMUL_NETBSD) + if (systab != sysent) break; - code = fuword(params + _QUAD_LOWWORD*sizeof(int)); /* indir */ + code = fuword(params + _QUAD_LOWWORD * sizeof(int)); params += sizeof(quad_t); break; + default: } - if (code >= numsys) - callp = &systab[0]; /* indir (illegal) */ + + callp = systab; + if (code < numsys) + callp += code; else - callp = &systab[code]; - if ((i = callp->sy_narg * sizeof (int)) && - (error = copyin(params, (caddr_t)&args, (u_int)i))) { -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) - error = bsdtohpuxerrno(error); -#endif - frame.f_regs[D0] = error; - frame.f_sr |= PSL_C; /* carry bit */ -#ifdef SYSCALL_DEBUG - if (p->p_emul == EMUL_NETBSD) /* XXX */ - scdebug_call(p, code, callp->sy_narg, args.i); -#endif + callp += SYS_syscall; /* => nosys */ + + argsize = callp->sy_narg * sizeof(int); + if (argsize != 0) + error = copyin(params, (caddr_t)args, argsize); + #ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_narg, args); #endif - goto done; - } #ifdef SYSCALL_DEBUG if (p->p_emul == EMUL_NETBSD) /* XXX */ - scdebug_call(p, code, callp->sy_narg, args.i); -#endif -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); + scdebug_call(p, code, callp->sy_narg, args); #endif - rval[0] = 0; - rval[1] = frame.f_regs[D1]; -#ifdef COMPAT_HPUX - /* debug kludge */ - if (callp->sy_call == notimp) - error = notimp(p, args.i, rval, code, callp->sy_narg); - else -#endif - error = (*callp->sy_call)(p, &args, rval); - if (error == ERESTART) + if (error == 0) { + rval[0] = 0; + rval[1] = frame.f_regs[D1]; + error = (*callp->sy_call)(p, &args, rval); + } + + switch (error) { + case 0: + frame.f_regs[D0] = rval[0]; + frame.f_regs[D1] = rval[1]; + frame.f_sr &= ~PSL_C; + break; + case ERESTART: frame.f_pc = opc; - else if (error != EJUSTRETURN) { - if (error) { -#ifdef COMPAT_HPUX - if (p->p_flag & SHPUX) - error = bsdtohpuxerrno(error); -#endif - frame.f_regs[D0] = error; - frame.f_sr |= PSL_C; /* carry bit */ - } else { - frame.f_regs[D0] = rval[0]; - frame.f_regs[D1] = rval[1]; - frame.f_sr &= ~PSL_C; - } + break; + case EJUSTRETURN: + break; + default: + frame.f_regs[D0] = error; + frame.f_sr |= PSL_C; /* carry bit */ + break; } - /* else if (error == EJUSTRETURN) */ - /* nothing to do */ -done: /* * Reinitialize proc pointer `p' as it may be different * if this is a child returning from fork syscall. */ p = curproc; #ifdef SYSCALL_DEBUG - if (p->p_emul == EMUL_NETBSD) /* XXX */ - scdebug_ret(p, code, error, rval[0]); + if (p->p_emul == EMUL_NETBSD) /* XXX */ + scdebug_ret(p, code, error, rval[0]); #endif #ifdef COMPAT_SUNOS /* need new p-value for this */ - if (error == ERESTART && (p->p_md.md_flags & MDP_STACKADJ)) - { - frame.f_regs[SP] -= sizeof (int); - p->p_md.md_flags &= ~MDP_STACKADJ; - } + if (error == ERESTART && (p->p_md.md_flags & MDP_STACKADJ)) { + frame.f_regs[SP] -= sizeof (int); + p->p_md.md_flags &= ~MDP_STACKADJ; + } #endif userret(p, &frame, sticks); #ifdef KTRACE |
