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 #if !defined (CONFIG_USER_ONLY)
30 static void pal_reset (CPUState *env);
31 /* Console handlers */
32 static void pal_console_call (CPUState *env, uint32_t palcode);
33 /* OpenVMS handlers */
34 static void pal_openvms_call (CPUState *env, uint32_t palcode);
35 /* UNIX / Linux handlers */
36 static void pal_unix_call (CPUState *env, uint32_t palcode);
38 pal_handler_t pal_handlers[] = {
42 .call_pal = &pal_console_call,
47 .call_pal = &pal_openvms_call,
49 /* UNIX / Linux handler */
52 .call_pal = &pal_unix_call,
57 /* One must explicitly check that the TB is valid and the FOE bit is reset */
58 static void update_itb (void)
60 /* This writes into a temp register, not the actual one */
63 /* This commits the TB update */
67 static void update_dtb (void);
70 /* This write into a temp register, not the actual one */
72 /* This commits the TB update */
77 static void pal_reset (CPUState *env)
81 static void do_swappal (CPUState *env, uint64_t palid)
83 pal_handler_t *pal_handler;
89 pal_handler = &pal_handlers[palid];
90 env->pal_handler = pal_handler;
91 env->ipr[IPR_PAL_BASE] = -1ULL;
92 (*pal_handler->reset)(env);
95 /* Unknown identifier */
99 /* We were given the entry point address */
100 env->pal_handler = NULL;
101 env->ipr[IPR_PAL_BASE] = palid;
102 env->pc = env->ipr[IPR_PAL_BASE];
107 static void pal_console_call (CPUState *env, uint32_t palcode)
111 if (palcode < 0x00000080) {
112 /* Privileged palcodes */
113 if (!(env->ps >> 3)) {
114 /* TODO: generate privilege exception */
128 /* Implemented as no-op */
138 do_swappal(env, palid);
151 /* Implemented as no-op */
170 static void pal_openvms_call (CPUState *env, uint32_t palcode)
172 uint64_t palid, val, oldval;
174 if (palcode < 0x00000080) {
175 /* Privileged palcodes */
176 if (!(env->ps >> 3)) {
177 /* TODO: generate privilege exception */
191 /* Implemented as no-op */
204 if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
210 if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
216 if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
227 do_swappal(env, palid);
231 if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
237 if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
243 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
248 if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
254 if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
259 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
265 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
270 if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
275 if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
281 if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
286 if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
291 if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
297 if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
303 if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
308 if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
313 if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
319 if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
325 if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
331 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
336 if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
342 if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
347 if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
353 if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
358 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
364 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
370 if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
376 if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
381 if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
386 if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
391 if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
397 if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
403 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
409 if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
417 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
443 /* Implemented as no-op */
564 static void pal_unix_call (CPUState *env, uint32_t palcode)
566 uint64_t palid, val, oldval;
568 if (palcode < 0x00000080) {
569 /* Privileged palcodes */
570 if (!(env->ps >> 3)) {
571 /* TODO: generate privilege exception */
585 /* Implemented as no-op */
595 do_swappal(env, palid);
600 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
605 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
611 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
617 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
635 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
653 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
659 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
664 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
669 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
680 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
697 /* Implemented as no-op */
722 void call_pal (CPUState *env)
724 pal_handler_t *pal_handler = env->pal_handler;
726 switch (env->exception_index) {
728 (*pal_handler->reset)(env);
731 (*pal_handler->machine_check)(env);
734 (*pal_handler->arithmetic)(env);
737 (*pal_handler->interrupt)(env);
740 (*pal_handler->dfault)(env);
742 case EXCP_DTB_MISS_PAL:
743 (*pal_handler->dtb_miss_pal)(env);
745 case EXCP_DTB_MISS_NATIVE:
746 (*pal_handler->dtb_miss_native)(env);
749 (*pal_handler->unalign)(env);
752 (*pal_handler->itb_miss)(env);
755 (*pal_handler->itb_acv)(env);
758 (*pal_handler->opcdec)(env);
761 (*pal_handler->fen)(env);
764 if (env->exception_index >= EXCP_CALL_PAL &&
765 env->exception_index < EXCP_CALL_PALP) {
766 /* Unprivileged PAL call */
767 (*pal_handler->call_pal)
768 (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
769 } else if (env->exception_index >= EXCP_CALL_PALP &&
770 env->exception_index < EXCP_CALL_PALE) {
771 /* Privileged PAL call */
772 (*pal_handler->call_pal)
773 (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
775 /* Should never happen */
779 env->ipr[IPR_EXC_ADDR] &= ~1;
782 void pal_init (CPUState *env)
788 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
790 uint64_t virbnd, ptbr;
792 if ((env->features & FEATURE_VIRBND)) {
793 cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
795 cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
797 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
799 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
805 static int get_page_bits (CPUState *env)
811 static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
812 uint64_t ptebase, int page_bits, uint64_t level,
815 uint64_t pteaddr, pte, pfn;
817 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
820 is_user = mmu_idx == MMU_USER_IDX;
821 pteaddr = (ptebase << page_bits) + (8 * level);
822 pte = ldq_raw(pteaddr);
823 /* Decode all interresting PTE fields */
825 uwe = (pte >> 13) & 1;
826 kwe = (pte >> 12) & 1;
827 ure = (pte >> 9) & 1;
828 kre = (pte >> 8) & 1;
830 foE = (pte >> 3) & 1;
831 foW = (pte >> 2) & 1;
832 foR = (pte >> 1) & 1;
837 /* Check access rights */
866 *zbitsp = page_bits + (3 * gh);
873 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
874 uint64_t ptebase, int page_bits,
875 uint64_t vaddr, int mmu_idx, int rw)
877 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
880 page_mask = (1ULL << page_bits) - 1ULL;
881 lvl_bits = page_bits - 3;
882 lvl_mask = (1ULL << lvl_bits) - 1ULL;
883 level3 = (vaddr >> page_bits) & lvl_mask;
884 level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
885 level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
887 ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
890 /* Access violation */
893 /* translation not valid */
900 ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
903 /* Access violation */
906 /* translation not valid */
913 ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
915 /* Translation not valid */
917 } else if (ret & 2) {
918 /* Access violation */
931 /* Fault on execute */
940 *paddr = (pfn << page_bits) | (vaddr & page_mask);
945 static int virtual_to_physical (CPUState *env, uint64_t *physp,
946 int *zbitsp, int *protp,
947 uint64_t virtual, int mmu_idx, int rw)
949 uint64_t sva, ptebase;
950 int seg, page_bits, ret;
952 sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
956 seg = sva >> (VA_BITS - 2);
957 virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
958 ptebase = get_ptebase(env, virtual);
959 page_bits = get_page_bits(env);
963 /* seg1: 3 levels of PTE */
964 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
965 virtual, mmu_idx, rw);
968 /* seg1: 2 levels of PTE */
969 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
970 virtual, mmu_idx, rw);
981 /* seg1: TB mapped */
982 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
983 virtual, mmu_idx, rw);
993 /* XXX: code provision */
994 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
995 int mmu_idx, int is_softmmu)
997 uint64_t physical, page_size, end;
998 int prot, zbits, ret;
1000 #if defined(CONFIG_USER_ONLY)
1003 ret = virtual_to_physical(env, &physical, &zbits, &prot,
1004 address, mmu_idx, rw);
1009 page_size = 1ULL << zbits;
1010 address &= ~(page_size - 1);
1011 for (end = physical + page_size; physical < end; physical += 0x1000) {
1012 ret = tlb_set_page(env, address, physical, prot,
1013 mmu_idx, is_softmmu);
1019 env->exception_index = EXCP_DFAULT;
1020 env->ipr[IPR_EXC_ADDR] = address;
1024 env->exception_index = EXCP_ACCESS_VIOLATION;
1025 env->ipr[IPR_EXC_ADDR] = address;
1029 env->exception_index = EXCP_FAULT_ON_READ;
1030 env->ipr[IPR_EXC_ADDR] = address;
1034 env->exception_index = EXCP_FAULT_ON_EXECUTE;
1035 env->ipr[IPR_EXC_ADDR] = address;
1038 env->exception_index = EXCP_FAULT_ON_WRITE;
1039 env->ipr[IPR_EXC_ADDR] = address;
1043 /* Should never happen */
1044 env->exception_index = EXCP_MCHK;
1045 env->ipr[IPR_EXC_ADDR] = address;
1054 #else /* !defined (CONFIG_USER_ONLY) */
1055 void pal_init (CPUState *env)
1059 void call_pal (CPUState *env, int palcode)
1063 qemu_log("%s: palcode %02x\n", __func__, palcode);
1067 qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1068 ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1069 env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1073 env->ir[IR_V0] = ret;
1076 env->ir[IR_V0] = -ret;
1081 env->ir[IR_V0] = env->unique;
1082 qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1086 env->unique = env->ir[IR_A0];
1087 qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1090 qemu_log("%s: unhandled palcode %02x\n",