/* * MIPS emulation helpers for qemu. * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "cpu.h" #include "exec-all.h" /* MIPS32 4K MMU emulation */ #ifdef MIPS_USES_R4K_TLB static int map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { tlb_t *tlb; target_ulong tag; uint8_t ASID; int i, n; int ret; ret = -2; tag = (address & 0xFFFFE000); ASID = env->CP0_EntryHi & 0x000000FF; for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag && address < tlb->end2) { /* TLB match */ n = (address >> 12) & 1; /* Check access rights */ if (!(n ? tlb->V1 : tlb->V0)) return -3; if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & 0xFFF); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) *prot |= PAGE_WRITE; return 0; } return -4; } } return ret; } #endif int get_physical_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { int user_mode; int ret; /* User mode can only access useg */ user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0; #if 0 if (logfile) { fprintf(logfile, "user mode %d h %08x\n", user_mode, env->hflags); } #endif if (user_mode && address > 0x7FFFFFFFUL) return -1; ret = 0; if (address < 0x80000000UL) { if (!(env->hflags & MIPS_HFLAG_ERL)) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address + 0x40000000UL; *prot = PAGE_READ | PAGE_WRITE; #endif } else { *physical = address; *prot = PAGE_READ | PAGE_WRITE; } } else if (address < 0xA0000000UL) { /* kseg0 */ /* XXX: check supervisor mode */ *physical = address - 0x80000000UL; *prot = PAGE_READ | PAGE_WRITE; } else if (address < 0xC0000000UL) { /* kseg1 */ /* XXX: check supervisor mode */ *physical = address - 0xA0000000UL; *prot = PAGE_READ | PAGE_WRITE; } else if (address < 0xE0000000UL) { /* kseg2 */ #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address; *prot = PAGE_READ | PAGE_WRITE; #endif } else { /* kseg3 */ /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address; *prot = PAGE_READ | PAGE_WRITE; #endif } #if 0 if (logfile) { fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw, access_type, *physical, *prot, ret); } #endif return ret; } #if defined(CONFIG_USER_ONLY) target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } #else target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { target_ulong phys_addr; int prot; if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) return -1; return phys_addr; } void cpu_mips_init_mmu (CPUState *env) { } #endif /* !defined(CONFIG_USER_ONLY) */ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { target_ulong physical; int prot; int exception = 0, error_code = 0; int access_type; int ret = 0; if (logfile) { #if 0 cpu_dump_state(env, logfile, fprintf, 0); #endif fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", __func__, env->PC, address, rw, is_user, is_softmmu); } rw &= 1; /* data access */ /* XXX: put correct access by using cpu_restore_state() correctly */ access_type = ACCESS_INT; if (env->user_mode_only) { /* user mode only emulation */ ret = -2; goto do_fault; } ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (logfile) { fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n", __func__, address, ret, physical, prot); } if (ret == 0) { ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot, is_user, is_softmmu); } else if (ret < 0) { do_fault: switch (ret) { default: case -1: /* Reference to kernel address from user mode or supervisor mode */ /* Reference to supervisor address from user mode */ if (rw) exception = EXCP_AdES; else exception = EXCP_AdEL; break; case -2: /* No TLB match for a mapped address */ if (rw) exception = EXCP_TLBS; else exception = EXCP_TLBL; error_code = 1; break; case -3: /* TLB match with no valid bit */ if (rw) exception = EXCP_TLBS; else exception = EXCP_TLBL; error_code = 0; break; case -4: /* TLB match but 'D' bit is cleared */ exception = EXCP_LTLBL; break; } /* Raise exception */ env->CP0_BadVAddr = address; env->CP0_Context = (env->CP0_Context & 0xff8000# # This list is used by git-shortlog to fix a few botched name translations # in the git archive, either because the author's full name was messed up # and/or not always written the same way, making contributions from the # same person appearing not to be so or badly displayed. # # repo-abbrev: /pub/scm/linux/kernel/git/ # Aaron Durbin <adurbin@google.com> Adam Oldham <oldhamca@gmail.com> Adam Radford <aradford@gmail.com> Adrian Bunk <bunk@stusta.de> Alan Cox <alan@lxorguk.ukuu.org.uk> Alan Cox <root@hraefn.swansea.linux.org.uk> Aleksey Gorelov <aleksey_gorelov@phoenix.com> Al Viro <viro@ftp.linux.org.uk> Al Viro <viro@zenIV.linux.org.uk> Andreas Herrmann <aherrman@de.ibm.com> Andrew Morton <akpm@osdl.org> Andrew Vasquez <andrew.vasquez@qlogic.com> Andy Adamson <andros@citi.umich.edu> Arnaud Patard <arnaud.patard@rtp-net.org> Arnd Bergmann <arnd@arndb.de> Axel Dyks <xl@xlsigned.net> Ben Gardner <bgardner@wabtec.com> Ben M Cahill <ben.m.cahill@intel.com> Björn Steinbrink <B.Steinbrink@gmx.de> Brian Avery <b.avery@hp.com> Brian King <brking@us.ibm.com> Christoph Hellwig <hch@lst.de> Corey Minyard <minyard@acm.org> David Brownell <david-b@pacbell.net> David Woodhouse <dwmw2@shinybook.infradead.org> Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Domen Puncer <domen@coderock.org> Douglas Gilbert <dougg@torque.net> Ed L. Cashin <ecashin@coraid.com> Evgeniy Polyakov <johnpol@2ka.mipt.ru> Felipe W Damasio <felipewd@terra.com.br> Felix Kuhling <fxkuehl@gmx.de> Felix Moeller <felix@derklecks.de> Filipe Lautert <filipe@icewall.org> Franck Bui-Huu <vagabon.xyz@gmail.com> Frank Zago <fzago@systemfabricworks.com> Greg Kroah-Hartman <greg@echidna.(none)> Greg Kroah-Hartman <gregkh@suse.de> Greg Kroah-Hartman <greg@kroah.com> Henk Vergonet <Henk.Vergonet@gmail.com> Henrik Kretzschmar <henne@nachtwindheim.de> Herbert Xu <herbert@gondor.apana.org.au> Jacob Shin <Jacob.Shin@amd.com> James Bottomley <jejb@mulgrave.(none)> James Bottomley <jejb@titanic.il.steeleye.com> James E Wilson <wilson@specifix.com> James Ketrenos <jketreno@io.(none)> Jean Tourrilhes <jt@hpl.hp.com> Jeff Garzik <jgarzik@pretzel.yyz.us> Jens Axboe <axboe@suse.de> Jens Osterkamp <Jens.Osterkamp@de.ibm.com> John Stultz <johnstul@us.ibm.com> Juha Yrjola <at solidboot.com> Juha Yrjola <juha.yrjola@nokia.com> Juha Yrjola <juha.yrjola@solidboot.com> Kay Sievers <kay.sievers@vrfy.org> Kenneth W Chen <kenneth.w.chen@intel.com> Koushik <raghavendra.koushik@neterion.com> Leonid I Ananiev <leonid.i.ananiev@intel.com> Linas Vepstas <linas@austin.ibm.com> Mark Brown <broonie@sirena.org.uk> Matthieu CASTET <castet.matthieu@free.fr> Michael Buesch <mb@bu3sch.de> Michael Buesch <mbuesch@freenet.de> Michel Dänzer <michel@tungstengraphics.com> Mitesh shah <mshah@teja.com> Morten Welinder <terra@gnome.org> Morten Welinder <welinder@anemone.rentec.com> Morten Welinder <welinder@darter.rentec.com> Morten Welinder <welinder@troll.com> Nguyen Anh Quynh <aquynh@gmail.com> Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Patrick Mochel <mochel@digitalimplant.org> Peter A Jonsson <pj@ludd.ltu.se> Peter Oruba <peter@oruba.de> Peter Oruba <peter.oruba@amd.com> Praveen BP <praveenbp@ti.com> Rajesh Shah <rajesh.shah@intel.com> Ralf Baechle <ralf@linux-mips.org> Ralf Wildenhues <Ralf.Wildenhues@gmx.de> Rémi Denis-Courmont <rdenis@simphalempin.com> Rudolf Marek <R.Marek@sh.cvut.cz> Rui Saraiva <rmps@joel.ist.utl.pt> Sachin P Sant <ssant@in.ibm.com> Sam Ravnborg <sam@mars.ravnborg.org> Sascha Hauer <s.hauer@pengutronix.de> S.Çağlar Onur <caglar@pardus.org.tr> Simon Kelley <simon@thekelleys.org.uk> Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr> Stephen Hemminger <shemminger@osdl.org> Tejun Heo <htejun@gmail.com> Thomas Graf <tgraf@suug.ch> Tony Luck <tony.luck@intel.com> Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com> Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> Uwe Kleine-König <ukl@pengutronix.de> Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Takashi YOSHII <takashi.yoshii.zj@renesas.com> if (logfile) { fprintf(logfile, "Invalid MIPS exception %d. Exiting\n", env->exception_index); } printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); exit(1); } env->PC = pc; if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n" " S %08x C %08x A %08x D %08x\n", __func__, env->PC, env->CP0_EPC, cause, env->exception_index, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); } env->exception_index = EXCP_NONE; }