--- np2/i386c/ia32/paging.c 2004/02/20 16:09:04 1.12 +++ np2/i386c/ia32/paging.c 2004/03/05 14:17:35 1.13 @@ -1,4 +1,4 @@ -/* $Id: paging.c,v 1.12 2004/02/20 16:09:04 monaka Exp $ */ +/* $Id: paging.c,v 1.13 2004/03/05 14:17:35 monaka Exp $ */ /* * Copyright (c) 2003 NONAKA Kimihiro @@ -187,10 +187,49 @@ static const UINT8 page_access_bit[32] = static UINT32 paging(UINT32 laddr, int crw, int user_mode); #if defined(IA32_SUPPORT_TLB) static BOOL tlb_lookup(UINT32 vaddr, int crw, UINT32 *paddr); -static void tlb_update(UINT32 paddr, UINT entry, int crw); +static void tlb_update(UINT32 laddr, UINT entry, int crw); #endif +void +cpu_memory_access_la_region(UINT32 laddr, UINT length, int crw, int user_mode, BYTE *data) +{ + UINT32 paddr; + UINT remain; /* page remain */ + UINT r; + + if (length == 0) + return; + + remain = 0x1000 - (laddr & 0x00000fff); + for (;;) { + if (!CPU_STAT_PAGING) { + paddr = laddr; + } else { + paddr = paging(laddr, crw, user_mode); + } + + r = (remain > length) ? length : remain; + if (!(crw & CPU_PAGE_WRITE)) { + cpu_memoryread_region(paddr, data, r); + } else { + cpu_memorywrite_region(paddr, data, r); + } + + length -= r; + if (length == 0) + break; + + data += r; + laddr += r; + remain -= r; + if (remain <= 0) { + /* next page */ + remain += 0x1000; + } + } +} + UINT32 MEMCALL cpu_linear_memory_read(UINT32 laddr, UINT length, int crw, int user_mode) { @@ -200,7 +239,6 @@ cpu_linear_memory_read(UINT32 laddr, UIN UINT r; int shift = 0; - /* XXX: 4MB pages... */ remain = 0x1000 - (laddr & 0x00000fff); for (;;) { paddr = paging(laddr, crw, user_mode); @@ -254,7 +292,6 @@ cpu_linear_memory_write(UINT32 laddr, UI UINT r; int crw = (CPU_PAGE_WRITE|CPU_PAGE_DATA); - /* XXX: 4MB pages... */ remain = 0x1000 - (laddr & 0x00000fff); for (;;) { paddr = paging(laddr, crw, user_mode); @@ -305,7 +342,6 @@ paging_check(UINT32 laddr, UINT length, UINT remain; /* page remain */ UINT r; - /* XXX: 4MB pages... */ remain = 0x1000 - (laddr & 0x00000fff); for (;;) { paddr = paging(laddr, crw, user_mode); @@ -355,40 +391,22 @@ paging(UINT32 laddr, int crw, int user_m cpu_memorywrite_d(pde_addr, pde); } -#if CPU_FAMILY >= 5 - /* no support PAE */ - __ASSERT(!(CPU_CR4 & CPU_CR4_PAE)); - - if ((CPU_CR4 & CPU_CR4_PSE) && (pde & CPU_PDE_PAGE_SIZE)) { - /* 4MB page size */ - - /* fake PTE bit */ - pte = pde | CPU_PTE_DIRTY; - pte_addr = 0; /* compiler happy */ - - /* make physical address */ - paddr = (pde & CPU_PDE_4M_BASEADDR_MASK) + (laddr & 0x003fffff); - } else -#endif /* CPU_FAMILY >= 5 */ - { - /* 4KB page size */ - pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((laddr >> 10) & 0xffc); - pte = cpu_memoryread_d(pte_addr); - if (!(pte & CPU_PTE_PRESENT)) { - VERBOSE(("paging: page is not present")); - VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); - VERBOSE(("paging: pte_addr = 0x%08x, pte = 0x%08x", pte_addr, pte)); - err = 0; - goto pf_exception; - } - if (!(pte & CPU_PTE_ACCESS)) { - pte |= CPU_PTE_ACCESS; - cpu_memorywrite_d(pte_addr, pte); - } - - /* make physical address */ - paddr = (pte & CPU_PTE_BASEADDR_MASK) + (laddr & 0x00000fff); + pte_addr = (pde & CPU_PDE_BASEADDR_MASK) + ((laddr >> 10) & 0xffc); + pte = cpu_memoryread_d(pte_addr); + if (!(pte & CPU_PTE_PRESENT)) { + VERBOSE(("paging: page is not present")); + VERBOSE(("paging: laddr = 0x%08x, pde_addr = 0x%08x, pde = 0x%08x", laddr, pde_addr, pde)); + VERBOSE(("paging: pte_addr = 0x%08x, pte = 0x%08x", pte_addr, pte)); + err = 0; + goto pf_exception; } + if (!(pte & CPU_PTE_ACCESS)) { + pte |= CPU_PTE_ACCESS; + cpu_memorywrite_d(pte_addr, pte); + } + + /* make physical address */ + paddr = (pte & CPU_PTE_BASEADDR_MASK) + (laddr & 0x00000fff); bit = crw & CPU_PAGE_WRITE; bit |= (pde & pte & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)); @@ -415,7 +433,7 @@ paging(UINT32 laddr, int crw, int user_m } #if defined(IA32_SUPPORT_TLB) - tlb_update(paddr, pte, crw); + tlb_update(laddr, pte, crw); #endif /* IA32_SUPPORT_TLB */ return paddr; @@ -431,94 +449,83 @@ pf_exception: /* * TLB */ + +#if defined(IA32_PROFILE_TLB) +/* profiling */ typedef struct { - UINT8 valid; /* TLB entry is valid */ - UINT8 global; /* this TLB entry is global */ - UINT8 score; - UINT8 pad; + UINT64 tlb_hits; + UINT64 tlb_misses; + UINT64 tlb_lookups; + UINT64 tlb_updates; + UINT64 tlb_flushes; + UINT64 tlb_global_flushes; + UINT64 tlb_entry_flushes; +} TLB_PROFILE_T; - UINT32 tag; - UINT32 mask; /* 4K or 2M or 4M */ +static TLB_PROFILE_T tlb_profile; + +#define PROFILE_INC(v) tlb_profile.v++ +#else /* !IA32_PROFILE_TLB */ +#define PROFILE_INC(v) +#endif /* IA32_PROFILE_TLB */ - UINT32 paddr; /* physical addr */ -} TLB_ENTRY_T; typedef struct { - UINT8 kind; -#define TLB_KIND_INSTRUCTION (1 << 1) -#define TLB_KIND_DATA (1 << 2) -#define TLB_KIND_COMBINE (TLB_KIND_INSTRUCTION|TLB_KIND_DATA) -#define TLB_KIND_SMALL (1 << 3) -#define TLB_KIND_LARGE (1 << 4) -#define TLB_KIND_BOTH (TLB_KIND_SMALL|TLB_KIND_LARGE) - - UINT8 way; /* n-way associative */ - UINT8 idx; /* number of TLB index */ - UINT8 bpad; + UINT32 tag; /* linear address */ +#define TLB_ENTRY_VALID (1 << 0) +#define TLB_ENTRY_GLOBAL CPU_PTE_GLOBAL_PAGE - UINT16 num; /* number of TLB entry */ - UINT16 wpad; + UINT32 paddr; /* physical address */ +} TLB_ENTRY_T; - TLB_ENTRY_T *entry; /* entry[assoc][idx] or entry[assoc] if idx == 1*/ -} TLB_T; +#define TLB_GET_PADDR(ep, addr) ((ep)->paddr + ((addr) & ~CPU_PTE_BASEADDR_MASK)) +#define TLB_SET_PADDR(ep, addr) ((ep)->paddr = (addr) & CPU_PTE_BASEADDR_MASK) -static int ntlb; -static TLB_T tlb[4]; /* i TLB, i (lp) TLB, d TLB, d (lp) TLB */ +#define TLB_TAG_SHIFT 17 +#define TLB_TAG_MASK ~((1 << TLB_TAG_SHIFT) - 1) +#define TLB_GET_TAG_ADDR(ep) ((ep)->tag & TLB_TAG_MASK) +#define TLB_SET_TAG_ADDR(ep, addr) \ + ((ep)->tag = ((addr) & TLB_TAG_MASK) + ((ep)->tag & ~TLB_TAG_MASK)) + +#define TLB_IS_VALID(ep) ((ep)->tag & TLB_ENTRY_VALID) +#define TLB_SET_VALID(ep) ((ep)->tag |= TLB_ENTRY_VALID) +#define TLB_CLEAR_VALID(ep) ((ep)->tag &= ~TLB_ENTRY_VALID) -#if defined(IA32_PROFILE_TLB) -/* profiling */ -static UINT64 tlb_hits; -static UINT64 tlb_misses; -static UINT64 tlb_lookups; -static UINT64 tlb_updates; -static UINT64 tlb_flushes; -static UINT64 tlb_global_flushes; -static UINT64 tlb_entry_flushes; +#if CPU_FAMILY == 4 +#define TLB_IS_GLOBAL(ep) FALSE +#define TLB_SET_GLOBAL(ep) (void)(ep) +#define TLB_CLEAR_GLOBAL(ep) (void)(ep) +#else +#define TLB_IS_GLOBAL(ep) ((ep)->tag & TLB_ENTRY_GLOBAL) +#define TLB_SET_GLOBAL(ep) ((ep)->tag |= TLB_ENTRY_GLOBAL) +#define TLB_CLEAR_GLOBAL(ep) ((ep)->tag &= ~TLB_ENTRY_GLOBAL) +#endif + + +#if CPU_FAMILY == 4 +#define NTLB 1 +#define NENTRY 8 +#define NWAY 4 + +#define TLB_ENTRY_SHIFT 12 +#define TLB_WAY_SHIFT 14 +#endif + +typedef struct { + TLB_ENTRY_T entry[NENTRY][NWAY]; +} TLB_T; + +static TLB_T tlb; -#define PROFILE_INC(v) (v)++; -#else /* !IA32_PROFILE_TLB */ -#define PROFILE_INC(v) -#endif /* IA32_PROFILE_TLB */ void tlb_init(void) { - int i; - - for (i = 0; i < NELEMENTS(tlb); i++) { - if (tlb[i].entry) { - free(tlb[i].entry); - } - } - memset(tlb, 0, sizeof(tlb)); + memset(&tlb, 0, sizeof(tlb)); #if defined(IA32_PROFILE_TLB) - tlb_hits = 0; - tlb_misses = 0; - tlb_lookups = 0; - tlb_updates = 0; - tlb_flushes = 0; - tlb_global_flushes = 0; - tlb_entry_flushes = 0; + memset(&tlb_profile, 0, sizeof(tlb_profile)); #endif /* IA32_PROFILE_TLB */ - -#if CPU_FAMILY == 4 - /* とりあえず i486 形式で… */ - /* combine (I/D) TLB: 4KB Pages, 4-way set associative 32 entries */ - ntlb = 1; - tlb[0].kind = TLB_KIND_COMBINE | TLB_KIND_SMALL; - tlb[0].num = 32; - tlb[0].way = 4; -#endif - - for (i = 0; i < ntlb; i++) { - tlb[i].idx = tlb[i].num / tlb[i].way; - - tlb[i].entry = (TLB_ENTRY_T*)calloc(sizeof(TLB_ENTRY_T), tlb[i].num); - if (tlb[i].entry == 0) { - ia32_panic("tlb_init(): can't alloc TLB entry\n"); - } - } } void @@ -533,11 +540,11 @@ tlb_flush(BOOL allflush) PROFILE_INC(tlb_flushes); } - for (i = 0; i < ntlb; i++) { - ep = tlb[i].entry; - for (j = 0; j < tlb[i].num; j++, ep++) { - if (ep->valid && (allflush || !ep->global)) { - ep->valid = 0; + for (i = 0; i < NENTRY ; i++) { + for (j = 0; j < NWAY; j++) { + ep = &tlb.entry[i][j]; + if (TLB_IS_VALID(ep) && (allflush || !TLB_IS_GLOBAL(ep))) { + TLB_CLEAR_VALID(ep); PROFILE_INC(tlb_entry_flushes); } } @@ -545,34 +552,22 @@ tlb_flush(BOOL allflush) } void -tlb_flush_page(UINT32 vaddr) +tlb_flush_page(UINT32 laddr) { TLB_ENTRY_T *ep; int idx; - int i; + int way; - for (i = 0; i < ntlb; i++) { - if (tlb[i].idx == 1) { - /* fully set associative */ - idx = 0; - } else { - if (tlb[i].kind & TLB_KIND_SMALL) { - idx = (vaddr >> 12) & (tlb[i].idx - 1); - } else { - idx = (vaddr >> 22) & (tlb[i].idx - 1); - } - } + PROFILE_INC(tlb_flushes); - /* search */ - ep = &tlb[i].entry[idx * tlb[i].way]; - for (i = 0; i < tlb[i].way; i++) { - if (ep->valid) { - if ((vaddr & ep->mask) == ep->tag) { - ep->valid = 0; - PROFILE_INC(tlb_entry_flushes); - break; - } - } + idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); + way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); + ep = &tlb.entry[idx][way]; + + if (TLB_IS_VALID(ep)) { + if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { + TLB_CLEAR_VALID(ep); + return; } } } @@ -582,99 +577,48 @@ tlb_lookup(UINT32 laddr, int crw, UINT32 { TLB_ENTRY_T *ep; int idx; - int i; + int way; PROFILE_INC(tlb_lookups); - crw &= CPU_PAGE_CODE | CPU_PAGE_DATA; - for (i = 0; i < ntlb; i++) { - if (tlb[i].kind & crw) { - if (tlb[i].idx == 1) { - /* fully set associative */ - idx = 0; - } else { - if (tlb[i].kind & TLB_KIND_SMALL) { - idx = (laddr >> 12) & (tlb[i].idx - 1); - } else { - idx = (laddr >> 22) & (tlb[i].idx - 1); - } - } - - /* search */ - ep = &tlb[i].entry[idx * tlb[i].way]; - for (i = 0; i < tlb[i].way; i++) { - if (ep->valid) { - if ((laddr & ep->mask) == ep->tag) { - if (ep->score != (UINT8)~0) - ep->score++; - *paddr = ep->paddr; - PROFILE_INC(tlb_hits); - return TRUE; - } - } - } + idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); + way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); + ep = &tlb.entry[idx][way]; + + ep = &tlb.entry[idx][way]; + if (TLB_IS_VALID(ep)) { + if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) { + *paddr = TLB_GET_PADDR(ep, laddr); + PROFILE_INC(tlb_hits); + return TRUE; } } + (void)crw; PROFILE_INC(tlb_misses); return FALSE; } static void -tlb_update(UINT32 paddr, UINT entry, int crw) +tlb_update(UINT32 laddr, UINT entry, int crw) { TLB_ENTRY_T *ep; int idx; - int i, j; - int min_way; - UINT16 min_score = ~0; + int way; PROFILE_INC(tlb_updates); - crw &= CPU_PAGE_CODE | CPU_PAGE_DATA; - for (i = 0; i < ntlb; i++) { - if (tlb[i].kind & crw) { - if (tlb[i].idx == 1) { - /* fully set associative */ - idx = 0; - } else { - /* n-way set associative */ - if (!(entry & CPU_PDE_PAGE_SIZE)) { - if (!(tlb[i].kind & TLB_KIND_SMALL)) - continue; - idx = (entry >> 12) & (tlb[i].idx - 1); - } else { - if (!(tlb[i].kind & TLB_KIND_LARGE)) - continue; - idx = (entry >> 22) & (tlb[i].idx - 1); - } - } + idx = (laddr >> TLB_ENTRY_SHIFT) & (NENTRY - 1); + way = (laddr >> TLB_WAY_SHIFT) & (NWAY - 1); + ep = &tlb.entry[idx][way]; - /* search */ - ep = &tlb[i].entry[idx * tlb[i].way]; - for (min_way = 0, j = 0; j < tlb[i].way; j++, ep++) { - if (ep->valid) { - if (min_score >= ep->score) { - min_way = j; - min_score = ep->score; - } - } else { - min_way = j; - min_score = 0; - break; - } - } - - /* replace */ - ep = &tlb[i].entry[idx * tlb[i].way + min_way]; - ep->valid = 1; - ep->global = (entry & CPU_PTE_GLOBAL_PAGE) ? 1 : 0; - ep->score = 0; - ep->mask = (entry & CPU_PDE_PAGE_SIZE) ? CPU_PDE_4M_BASEADDR_MASK : CPU_PTE_BASEADDR_MASK; - ep->tag = entry & ep->mask; - ep->paddr = paddr; - break; - } + TLB_SET_VALID(ep); +#if CPU_FAMILY >= 5 + if (entry & CPU_PTE_GLOBAL_PAGE) { + TLB_SET_GLOBAL(ep); } - __ASSERT(i != ntlb); +#endif + TLB_SET_TAG_ADDR(ep, laddr); + TLB_SET_PADDR(ep, entry); + (void)crw; } #endif /* IA32_SUPPORT_TLB */