ppc_mmu.c

来自「skyeye是一个可以模拟嵌入式硬件开发板的系统软件」· C语言 代码 · 共 2,269 行 · 第 1/5 页

C
2,269
字号
/* *	PearPC *	ppc_mmu.cc * *	Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net) *	Portions Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu) *	Portions Copyright (C) 2004 Apple Computer, Inc. * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License version 2 as *	published by the Free Software Foundation. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//*	Pages marked: v.??? *	From: IBM PowerPC MicroProcessor Family: Altivec(tm) Technology... *		Programming Environments Manual */#include "debug.h"#include "tracers.h"#include "sysendian.h"#include "io.h"#include "ppc_cpu.h"#include "ppc_fpu.h"#include "ppc_vec.h"#include "ppc_mmu.h"#include "ppc_exc.h"#include "ppc_tools.h"#include "ppc_memory.h"#define DEFAULT_CCSR_MEM 0xFF700000#define CCSR_MEM_SIZE 0x100000#define GET_CCSR_BASE(reg)(((reg >> 8)&0xFFF) << 20)int ddr_write_counter = 0;static int ppc_pte_protection[] = {	// read(0)/write(1) key pp		// read	1, // r/w	1, // r/w	1, // r/w	1, // r	0, // -	1, // r	1, // r/w	1, // r		// write	1, // r/w	1, // r/w	1, // r/w	0, // r	0, // -	0, // r	1, // r/w	0, // r};typedef struct e500_mmu_s{	uint64 pid[3];		uint64 mmucsr0;	uint64 mmucfg;	uint64 tlbcfg[2];	uint64 mas[8];}e500_mmu_t;typedef struct tlb_entry_s{	uint v;	uint ts;	uint tid;	uint epn;	uint rpn;	uint size;	uint usxrw;	uint wimge;	uint x;	uint u;	uint iprot;	}tlb_entry_t;e500_mmu_t e500_mmu;tlb_entry_t l1_i_vsp[4]; /* instruction, filled by TLB1 hit */tlb_entry_t l1_i_tlb4k[64]; /* instruction, filled by TLB0 hit */tlb_entry_t l1_d_vsp[4]; /* data, filled by TLB1 hit */tlb_entry_t l1_d_tlb4k[64]; /* data, filled by TLB0 hit */#define L2_TLB0_SIZE 256#define L2_TLB1_SIZE 16tlb_entry_t l2_tlb0_4k[L2_TLB0_SIZE]; /* unified, filled by tlbwe instruction */tlb_entry_t l2_tlb1_vsp[L2_TLB1_SIZE]; /* filled by tlbwe insructions *//*ea = effective addressif translation is an instruction address then	as = MSR[IS];else // data address translation	as = MSR[DS]for all TLB entries	if !TLB[entry].v then		next // compare next TLB entry	if as != TLB[entry].ts then		next // compare next TLB entry	if TLB[entry].tid == 0 then		goto pid_match	for all PID registers		if this PID register == TLB[entry].tid then			goto pid_match	endfor	next // no PIDs matched 	pid_match://translation match	mask = ~(1024 << (2 * TLB[entry].tsize)) - 01	if (ea & mask) != TLB[entry].epn then		next // no address match	real address = TLB[entry].rpn | (ea & ~mask) // real address computed	end translation --success	endfor	end translation tlb miss*/int ppc_effective_to_physical(uint32 addr, int flags, uint32 *result){	int i,j;	uint32 mask;	tlb_entry_t *entry;	int tlb1_index;	int pid_match = 0;	i = 0;	/* walk over tlb0 and tlb1 to find the entry */	while(i++ < (L2_TLB0_SIZE + L2_TLB1_SIZE)){		if(i > (L2_TLB0_SIZE - 1)){			tlb1_index = i - L2_TLB0_SIZE;			entry = &l2_tlb1_vsp[tlb1_index];		}		else			entry = &l2_tlb0_4k[i];		if(!entry->v)			continue;		/* FIXME, not check ts bit now */		if(entry->ts & 0x0)			continue;		if(entry->tid != 0){			for(j = 0; j < 3; j++){				if(e500_mmu.pid[j] == entry->tid)					break;			}			if(e500_mmu.pid[j] != entry->tid)				continue;		}		if(i > (L2_TLB0_SIZE - 1)){			int k,s = 1;			for(k = 0; k < entry->size; k++)				s = s * 4; 			mask = ~(1024 * s - 0x1);		}		else			mask = ~(1024 * 4 - 0x1);		if((addr & mask) != (entry->epn << 12))			continue;		*result = (entry->rpn << 12) | (addr & ~mask); // get real address		return PPC_MMU_OK;	}	/* TLB miss */	fprintf(stderr, "TLB missed at 0x%x,addr=0x%x\n", gCPU.pc, addr);	skyeye_exit(-1);	return PPC_MMU_FATAL;	}int e500_mmu_init(){	tlb_entry_t * entry = &l2_tlb1_vsp[0];	entry->v = 1; /* entry is valid */	entry->ts = 0; /* address space 0 */	entry->tid = 0; /* TID value for shared(global) page */	entry->epn = 0xFFFFF; /* Address of last 4k byte in address space*/	entry->rpn = 0xFFFFF; /* Address of last 4k byte in address space*/	entry->size = 0x1; /* 4k byte page size */	/* usxrw should be initialized to 010101 */	entry->usxrw |= 0x15; /* Full supervisor mode access allowed */	entry->usxrw &= 0x15; /* No user mode access allowed */	entry->wimge = 0x8; /* Caching-inhibited, non-coherent,big-endian*/	entry->x = 0; /* Reserved system attributes */	entry->u = 0; /* User attribute bits */	entry->iprot = 1; /* Page is protected from invalidation */	gCPU.ccsr.ccsr = 0xFF700;	gCPU.lb_ctrl.lcrr = 0x80000008;	gCPU.i2c_reg.i2csr = 0x81;	gCPU.i2c_reg.i2cdfsrr = 0x10;}void ppc_mmu_tlb_invalidate(){	gCPU.effective_code_page = 0xffffffff;}/*pagetable:min. 2^10 (64k) PTEGsPTEG = 64byteThe page table can be any size 2^n where 16 <= n <= 25.A PTEG contains eightPTEs of eight bytes each; therefore, each PTEG is 64 bytes long.*/bool FASTCALL ppc_mmu_set_sdr1(uint32 newval, bool quiesce){	/* if (newval == gCPU.sdr1)*/ quiesce = false;	PPC_MMU_TRACE("new pagetable: sdr1 = 0x%08x\n", newval);	uint32 htabmask = SDR1_HTABMASK(newval);	uint32 x = 1;	uint32 xx = 0;	int n = 0;	while ((htabmask & x) && (n < 9)) {		n++;		xx|=x;		x<<=1;	}	if (htabmask & ~xx) {		PPC_MMU_TRACE("new pagetable: broken htabmask (%05x)\n", htabmask);		return false;	}	uint32 htaborg = SDR1_HTABORG(newval);	if (htaborg & xx) {		PPC_MMU_TRACE("new pagetable: broken htaborg (%05x)\n", htaborg);		return false;	}	gCPU.pagetable_base = htaborg<<16;	gCPU.sdr1 = newval;	gCPU.pagetable_hashmask = ((xx<<10)|0x3ff);	PPC_MMU_TRACE("new pagetable: sdr1 accepted\n");	PPC_MMU_TRACE("number of pages: 2^%d pagetable_start: 0x%08x size: 2^%d\n", n+13, gCPU.pagetable_base, n+16);	if (quiesce) {		prom_quiesce();	}	return true;}bool FASTCALL ppc_mmu_page_create(uint32 ea, uint32 pa){	uint32 sr = gCPU.sr[EA_SR(ea)];	uint32 page_index = EA_PageIndex(ea);  // 16 bit	uint32 VSID = SR_VSID(sr);             // 24 bit	uint32 api = EA_API(ea);               //  6 bit (part of page_index)	uint32 hash1 = (VSID ^ page_index);	uint32 pte, pte2;	uint32 h = 0;	int j;	for (j=0; j<2; j++) {		uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;		int i;		for (i=0; i<8; i++) {			if (ppc_read_physical_word(pteg_addr, &pte)) {				PPC_MMU_ERR("read physical in address translate failed\n");				return false;			}			if (!(pte & PTE1_V)) {				// free pagetable entry found				pte = PTE1_V | (VSID << 7) | h | api;				pte2 = (PA_RPN(pa) << 12) | 0;				if (ppc_write_physical_word(pteg_addr, pte)				 || ppc_write_physical_word(pteg_addr+4, pte2)) {					return false;				} else {					// ok					return true;				}			}			pteg_addr+=8;		}		hash1 = ~hash1;		h = PTE1_H;	}	return false;}inline bool FASTCALL ppc_mmu_page_free(uint32 ea){	return true;}inline int FASTCALL ppc_direct_physical_memory_handle(uint32 addr, byte *ptr){	if (addr < boot_romSize) {		ptr = &boot_rom[addr];		return PPC_MMU_OK;	}	return PPC_MMU_FATAL;}int FASTCALL ppc_direct_effective_memory_handle(uint32 addr, byte *ptr){	uint32 ea;	int r;	if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, &ea)))) {		return ppc_direct_physical_memory_handle(ea, ptr);	}	return r;}int FASTCALL ppc_direct_effective_memory_handle_code(uint32 addr, byte *ptr){	uint32 ea;	int r;	if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, &ea)))) {		return ppc_direct_physical_memory_handle(ea, ptr);	}	return r;}inline int FASTCALL ppc_read_physical_qword(uint32 addr, Vector_t *result){	if (addr < boot_romSize) {		// big endian		VECT_D(*result,0) = ppc_dword_from_BE(*((uint64*)(boot_rom+addr)));		VECT_D(*result,1) = ppc_dword_from_BE(*((uint64*)(boot_rom+addr+8)));		return PPC_MMU_OK;	}	return io_mem_read128(addr, (uint128 *)result);}inline int FASTCALL ppc_read_physical_dword(uint32 addr, uint64 *result){	if (addr < boot_romSize) {		// big endian		*result = ppc_dword_from_BE(*((uint64*)(boot_rom+addr)));		return PPC_MMU_OK;	}	int ret = io_mem_read64(addr, result);	*result = ppc_bswap_dword(result);	return ret;}int FASTCALL ppc_read_physical_word(uint32 addr, uint32 *result){	if (addr < boot_romSize) {		// big endian		*result = ppc_word_from_BE(*((uint32*)(boot_rom+addr)));		return PPC_MMU_OK;	}	int ret = io_mem_read(addr, result, 4);	*result = ppc_bswap_word(result);	return ret;}inline int FASTCALL ppc_read_physical_half(uint32 addr, uint16 *result){	if (addr < boot_romSize) {		// big endian		*result = ppc_half_from_BE(*((uint16*)(boot_rom+addr)));		return PPC_MMU_OK;	}	uint32 r;	int ret = io_mem_read(addr, r, 2);	*result = ppc_bswap_half(r);	return ret;}inline int FASTCALL ppc_read_physical_byte(uint32 addr, uint8 *result){	if (addr < boot_romSize) {		// big endian		*result = boot_rom[addr];		return PPC_MMU_OK;	}	uint32 r;	int ret = io_mem_read(addr, r, 1);	*result = r;	return ret;}inline int FASTCALL ppc_read_effective_code(uint32 addr, uint32 *result){	if (addr & 3) {		// EXC..bla		return PPC_MMU_FATAL;	}	uint32 p;	int r;	if (!((r=ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, &p)))) {		return ppc_read_physical_word(p, result);	}	return r;}inline int FASTCALL ppc_read_effective_qword(uint32 addr, Vector_t *result){	uint32 p;	int r;	addr &= ~0x0f;	if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, &p))) {		return ppc_read_physical_qword(p, result);	}	return r;}inline int FASTCALL ppc_read_effective_dword(uint32 addr, uint64 *result){	uint32 p;	int r;	if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, &p))) {#if 0		if (EA_Offset(addr) > 4088) {			// read overlaps two pages.. tricky			byte *r1, *r2;			byte b[14];			ppc_effective_to_physical((addr & ~0xfff)+4089, PPC_MMU_READ, &p);			if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;			if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, &p))) return r;			if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;			memmove(&b[0], r1, 7);			memmove(&b[7], r2, 7);			memmove(&result, &b[EA_Offset(addr)-4089], 8);			result = ppc_dword_from_BE(result);			return PPC_MMU_OK;		} else {			return ppc_read_physical_dword(p, result);		}#endif	}	return r;}int FASTCALL ppc_read_effective_word(uint32 addr, uint32 *result){	uint32 p;	int r;	if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, &p))) {		//printf("DBG:ccsr=0x%x,CCSR_BASE=0x%x\n",gCPU.ccsr.ccsr,GET_CCSR_BASE(gCPU.ccsr.ccsr));		if((p >= GET_CCSR_BASE(gCPU.ccsr.ccsr)) && (p < (GET_CCSR_BASE(gCPU.ccsr.ccsr) + CCSR_MEM_SIZE))){			int offset = p - GET_CCSR_BASE(gCPU.ccsr.ccsr);			//printf("DBG:in %s,read CCSR,offset=0x%x,pc=0x%x\n", __FUNCTION__, offset, gCPU.pc);			if(offset >= 0x919C0 && offset <= 0x919E0){                                switch(offset){                                        case 0x919C0:                                                *result = gCPU.cpm_reg.cpcr;                                                return r;                                        default:	                                        fprintf(stderr,"in %s, error when read CCSR.addr=0x%x,pc=0x%x\n",__FUNCTION__, addr, gCPU.pc);                                        	skyeye_exit(-1);                                }                        }			 if(offset >= 0x2000 && offset <= 0x2E58){                                switch(offset){                                        case 0x2E44:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?