2 * Alpha emulation - PALcode emulation for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 static void pal_reset (CPUState *env);
29 /* Console handlers */
30 static void pal_console_call (CPUState *env, uint32_t palcode);
31 /* OpenVMS handlers */
32 static void pal_openvms_call (CPUState *env, uint32_t palcode);
33 /* UNIX / Linux handlers */
34 static void pal_unix_call (CPUState *env, uint32_t palcode);
36 pal_handler_t pal_handlers[] = {
40 .call_pal = &pal_console_call,
45 .call_pal = &pal_openvms_call,
47 /* UNIX / Linux handler */
50 .call_pal = &pal_unix_call,
55 /* One must explicitly check that the TB is valid and the FOE bit is reset */
56 static void update_itb (void)
58 /* This writes into a temp register, not the actual one */
61 /* This commits the TB update */
65 static void update_dtb (void);
68 /* This write into a temp register, not the actual one */
70 /* This commits the TB update */
75 static void pal_reset (CPUState *env)
79 static void do_swappal (CPUState *env, uint64_t palid)
81 pal_handler_t *pal_handler;
87 pal_handler = &pal_handlers[palid];
88 env->pal_handler = pal_handler;
89 env->ipr[IPR_PAL_BASE] = -1ULL;
90 (*pal_handler->reset)(env);
93 /* Unknown identifier */
97 /* We were given the entry point address */
98 env->pal_handler = NULL;
99 env->ipr[IPR_PAL_BASE] = palid;
100 env->pc = env->ipr[IPR_PAL_BASE];
105 static void pal_console_call (CPUState *env, uint32_t palcode)
109 if (palcode < 0x00000080) {
110 /* Privileged palcodes */
111 if (!(env->ps >> 3)) {
112 /* TODO: generate privilege exception */
126 /* Implemented as no-op */
136 do_swappal(env, palid);
149 /* Implemented as no-op */
168 static void pal_openvms_call (CPUState *env, uint32_t palcode)
170 uint64_t palid, val, oldval;
172 if (palcode < 0x00000080) {
173 /* Privileged palcodes */
174 if (!(env->ps >> 3)) {
175 /* TODO: generate privilege exception */
189 /* Implemented as no-op */
202 if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
208 if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
214 if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
225 do_swappal(env, palid);
229 if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
235 if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
241 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
246 if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
252 if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
257 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
263 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
268 if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
273 if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
279 if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
284 if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
289 if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
295 if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
301 if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
306 if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
311 if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
317 if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
323 if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
329 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
334 if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
340 if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
345 if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
351 if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
356 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
362 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
368 if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
374 if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
379 if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
384 if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
389 if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
395 if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
401 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
407 if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
415 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
441 /* Implemented as no-op */
562 static void pal_unix_call (CPUState *env, uint32_t palcode)
564 uint64_t palid, val, oldval;
566 if (palcode < 0x00000080) {
567 /* Privileged palcodes */
568 if (!(env->ps >> 3)) {
569 /* TODO: generate privilege exception */
583 /* Implemented as no-op */
593 do_swappal(env, palid);
598 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
603 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
609 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
615 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
633 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
651 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
657 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
662 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
667 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
678 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
695 /* Implemented as no-op */
720 void call_pal (CPUState *env)
722 pal_handler_t *pal_handler = env->pal_handler;
724 switch (env->exception_index) {
726 (*pal_handler->reset)(env);
729 (*pal_handler->machine_check)(env);
732 (*pal_handler->arithmetic)(env);
735 (*pal_handler->interrupt)(env);
738 (*pal_handler->dfault)(env);
740 case EXCP_DTB_MISS_PAL:
741 (*pal_handler->dtb_miss_pal)(env);
743 case EXCP_DTB_MISS_NATIVE:
744 (*pal_handler->dtb_miss_native)(env);
747 (*pal_handler->unalign)(env);
750 (*pal_handler->itb_miss)(env);
753 (*pal_handler->itb_acv)(env);
756 (*pal_handler->opcdec)(env);
759 (*pal_handler->fen)(env);
762 if (env->exception_index >= EXCP_CALL_PAL &&
763 env->exception_index < EXCP_CALL_PALP) {
764 /* Unprivileged PAL call */
765 (*pal_handler->call_pal)
766 (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
767 } else if (env->exception_index >= EXCP_CALL_PALP &&
768 env->exception_index < EXCP_CALL_PALE) {
769 /* Privileged PAL call */
770 (*pal_handler->call_pal)
771 (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
773 /* Should never happen */
777 env->ipr[IPR_EXC_ADDR] &= ~1;
780 void pal_init (CPUState *env)
786 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
788 uint64_t virbnd, ptbr;
790 if ((env->features & FEATURE_VIRBND)) {
791 cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
793 cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
795 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
797 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
803 static int get_page_bits (CPUState *env)
809 static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
810 uint64_t ptebase, int page_bits, uint64_t level,
813 uint64_t pteaddr, pte, pfn;
815 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
818 is_user = mmu_idx == MMU_USER_IDX;
819 pteaddr = (ptebase << page_bits) + (8 * level);
820 pte = ldq_raw(pteaddr);
821 /* Decode all interresting PTE fields */
823 uwe = (pte >> 13) & 1;
824 kwe = (pte >> 12) & 1;
825 ure = (pte >> 9) & 1;
826 kre = (pte >> 8) & 1;
828 foE = (pte >> 3) & 1;
829 foW = (pte >> 2) & 1;
830 foR = (pte >> 1) & 1;
835 /* Check access rights */
864 *zbitsp = page_bits + (3 * gh);
871 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
872 uint64_t ptebase, int page_bits,
873 uint64_t vaddr, int mmu_idx, int rw)
875 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
878 page_mask = (1ULL << page_bits) - 1ULL;
879 lvl_bits = page_bits - 3;
880 lvl_mask = (1ULL << lvl_bits) - 1ULL;
881 level3 = (vaddr >> page_bits) & lvl_mask;
882 level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
883 level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
885 ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
888 /* Access violation */
891 /* translation not valid */
898 ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
901 /* Access violation */
904 /* translation not valid */
911 ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
913 /* Translation not valid */
915 } else if (ret & 2) {
916 /* Access violation */
929 /* Fault on execute */
938 *paddr = (pfn << page_bits) | (vaddr & page_mask);
943 static int virtual_to_physical (CPUState *env, uint64_t *physp,
944 int *zbitsp, int *protp,
945 uint64_t virtual, int mmu_idx, int rw)
947 uint64_t sva, ptebase;
948 int seg, page_bits, ret;
950 sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
954 seg = sva >> (VA_BITS - 2);
955 virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
956 ptebase = get_ptebase(env, virtual);
957 page_bits = get_page_bits(env);
961 /* seg1: 3 levels of PTE */
962 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
963 virtual, mmu_idx, rw);
966 /* seg1: 2 levels of PTE */
967 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
968 virtual, mmu_idx, rw);
979 /* seg1: TB mapped */
980 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
981 virtual, mmu_idx, rw);
991 /* XXX: code provision */
992 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
993 int mmu_idx, int is_softmmu)
995 uint64_t physical, page_size, end;
996 int prot, zbits, ret;
998 ret = virtual_to_physical(env, &physical, &zbits, &prot,
999 address, mmu_idx, rw);
1004 page_size = 1ULL << zbits;
1005 address &= ~(page_size - 1);
1006 /* FIXME: page_size should probably be passed to tlb_set_page,
1007 and this loop removed. */
1008 for (end = physical + page_size; physical < end; physical += 0x1000) {
1009 tlb_set_page(env, address, physical, prot, mmu_idx,
1017 env->exception_index = EXCP_DFAULT;
1018 env->ipr[IPR_EXC_ADDR] = address;
1022 env->exception_index = EXCP_ACCESS_VIOLATION;
1023 env->ipr[IPR_EXC_ADDR] = address;
1027 env->exception_index = EXCP_FAULT_ON_READ;
1028 env->ipr[IPR_EXC_ADDR] = address;
1032 env->exception_index = EXCP_FAULT_ON_EXECUTE;
1033 env->ipr[IPR_EXC_ADDR] = address;
1036 env->exception_index = EXCP_FAULT_ON_WRITE;
1037 env->ipr[IPR_EXC_ADDR] = address;
1041 /* Should never happen */
1042 env->exception_index = EXCP_MCHK;
1043 env->ipr[IPR_EXC_ADDR] = address;