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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #if !defined (CONFIG_USER_ONLY)
31 static void pal_reset (CPUState *env);
32 /* Console handlers */
33 static void pal_console_call (CPUState *env, uint32_t palcode);
34 /* OpenVMS handlers */
35 static void pal_openvms_call (CPUState *env, uint32_t palcode);
36 /* UNIX / Linux handlers */
37 static void pal_unix_call (CPUState *env, uint32_t palcode);
39 pal_handler_t pal_handlers[] = {
43 .call_pal = &pal_console_call,
48 .call_pal = &pal_openvms_call,
50 /* UNIX / Linux handler */
53 .call_pal = &pal_unix_call,
58 /* One must explicitely check that the TB is valid and the FOE bit is reset */
59 static void update_itb ()
61 /* This writes into a temp register, not the actual one */
64 /* This commits the TB update */
68 static void update_dtb ();
71 /* This write into a temp register, not the actual one */
73 /* This commits the TB update */
78 static void pal_reset (CPUState *env)
82 static void do_swappal (CPUState *env, uint64_t palid)
84 pal_handler_t *pal_handler;
90 pal_handler = &pal_handlers[palid];
91 env->pal_handler = pal_handler;
92 env->ipr[IPR_PAL_BASE] = -1ULL;
93 (*pal_handler->reset)(env);
96 /* Unknown identifier */
100 /* We were given the entry point address */
101 env->pal_handler = NULL;
102 env->ipr[IPR_PAL_BASE] = palid;
103 env->pc = env->ipr[IPR_PAL_BASE];
108 static void pal_console_call (CPUState *env, uint32_t palcode)
112 if (palcode < 0x00000080) {
113 /* Privileged palcodes */
114 if (!(env->ps >> 3)) {
115 /* TODO: generate privilege exception */
129 /* Implemented as no-op */
139 do_swappal(env, palid);
152 /* Implemented as no-op */
171 static void pal_openvms_call (CPUState *env, uint32_t palcode)
173 uint64_t palid, val, oldval;
175 if (palcode < 0x00000080) {
176 /* Privileged palcodes */
177 if (!(env->ps >> 3)) {
178 /* TODO: generate privilege exception */
192 /* Implemented as no-op */
205 if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
211 if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
217 if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
228 do_swappal(env, palid);
232 if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
238 if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
244 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
249 if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
255 if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
260 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
266 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
271 if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
276 if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
282 if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
287 if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
292 if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
298 if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
304 if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
309 if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
314 if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
320 if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
326 if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
332 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
337 if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
343 if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
348 if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
354 if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
359 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
365 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
371 if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
377 if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
382 if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
387 if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
392 if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
398 if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
404 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
410 if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
418 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
444 /* Implemented as no-op */
565 static void pal_unix_call (CPUState *env, uint32_t palcode)
567 uint64_t palid, val, oldval;
569 if (palcode < 0x00000080) {
570 /* Privileged palcodes */
571 if (!(env->ps >> 3)) {
572 /* TODO: generate privilege exception */
586 /* Implemented as no-op */
596 do_swappal(env, palid);
601 if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
606 if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
612 if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
618 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
636 if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
654 if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
660 if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
665 if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
670 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
681 if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
698 /* Implemented as no-op */
723 void call_pal (CPUState *env)
725 pal_handler_t *pal_handler = env->pal_handler;
727 switch (env->exception_index) {
729 (*pal_handler->reset)(env);
732 (*pal_handler->machine_check)(env);
735 (*pal_handler->arithmetic)(env);
738 (*pal_handler->interrupt)(env);
741 (*pal_handler->dfault)(env);
743 case EXCP_DTB_MISS_PAL:
744 (*pal_handler->dtb_miss_pal)(env);
746 case EXCP_DTB_MISS_NATIVE:
747 (*pal_handler->dtb_miss_native)(env);
750 (*pal_handler->unalign)(env);
753 (*pal_handler->itb_miss)(env);
756 (*pal_handler->itb_acv)(env);
759 (*pal_handler->opcdec)(env);
762 (*pal_handler->fen)(env);
765 if (env->exception_index >= EXCP_CALL_PAL &&
766 env->exception_index < EXCP_CALL_PALP) {
767 /* Unprivileged PAL call */
768 (*pal_handler->call_pal)
769 (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
770 } else if (env->exception_index >= EXCP_CALL_PALP &&
771 env->exception_index < EXCP_CALL_PALE) {
772 /* Privileged PAL call */
773 (*pal_handler->call_pal)
774 (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
776 /* Should never happen */
780 env->ipr[IPR_EXC_ADDR] &= ~1;
783 void pal_init (CPUState *env)
789 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
791 uint64_t virbnd, ptbr;
793 if ((env->features & FEATURE_VIRBND)) {
794 cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
796 cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
798 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
800 cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
806 static int get_page_bits (CPUState *env)
812 static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
813 uint64_t ptebase, int page_bits, uint64_t level,
816 uint64_t pteaddr, pte, pfn;
818 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar;
820 pteaddr = (ptebase << page_bits) + (8 * level);
821 pte = ldq_raw(pteaddr);
822 /* Decode all interresting PTE fields */
824 uwe = (pte >> 13) & 1;
825 kwe = (pte >> 12) & 1;
826 ure = (pte >> 9) & 1;
827 kre = (pte >> 8) & 1;
829 foE = (pte >> 3) & 1;
830 foW = (pte >> 2) & 1;
831 foR = (pte >> 1) & 1;
836 /* Check access rights */
865 *zbitsp = page_bits + (3 * gh);
872 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
873 uint64_t ptebase, int page_bits,
874 uint64_t vaddr, int is_user, int rw)
876 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
879 page_mask = (1ULL << page_bits) - 1ULL;
880 lvl_bits = page_bits - 3;
881 lvl_mask = (1ULL << lvl_bits) - 1ULL;
882 level3 = (vaddr >> page_bits) & lvl_mask;
883 level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
884 level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
886 ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
889 /* Access violation */
892 /* translation not valid */
899 ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
902 /* Access violation */
905 /* translation not valid */
912 ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw);
914 /* Translation not valid */
916 } else if (ret & 2) {
917 /* Access violation */
930 /* Fault on execute */
939 *paddr = (pfn << page_bits) | (vaddr & page_mask);
944 static int virtual_to_physical (CPUState *env, uint64_t *physp,
945 int *zbitsp, int *protp,
946 uint64_t virtual, int is_user, int rw)
948 uint64_t sva, ptebase;
949 int seg, page_bits, ret;
951 sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
955 seg = sva >> (VA_BITS - 2);
956 virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
957 ptebase = get_ptebase(env, virtual);
958 page_bits = get_page_bits(env);
962 /* seg1: 3 levels of PTE */
963 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
964 virtual, is_user, rw);
967 /* seg1: 2 levels of PTE */
968 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
969 virtual, is_user, rw);
980 /* seg1: TB mapped */
981 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
982 virtual, is_user, rw);
992 /* XXX: code provision */
993 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
994 int is_user, int is_softmmu)
996 uint64_t physical, page_size, end;
997 int prot, zbits, ret;
999 if (env->user_mode_only) {
1002 ret = virtual_to_physical(env, &physical, &zbits, &prot,
1003 address, is_user, rw);
1008 page_size = 1ULL << zbits;
1009 address &= ~(page_size - 1);
1010 for (end = physical + page_size; physical < end; physical += 0x1000) {
1011 ret = tlb_set_page(env, address, physical, prot,
1012 is_user, is_softmmu);
1018 env->exception_index = EXCP_DFAULT;
1019 env->ipr[IPR_EXC_ADDR] = address;
1023 env->exception_index = EXCP_ACCESS_VIOLATION;
1024 env->ipr[IPR_EXC_ADDR] = address;
1028 env->exception_index = EXCP_FAULT_ON_READ;
1029 env->ipr[IPR_EXC_ADDR] = address;
1033 env->exception_index = EXCP_FAULT_ON_EXECUTE;
1034 env->ipr[IPR_EXC_ADDR] = address;
1037 env->exception_index = EXCP_FAULT_ON_WRITE;
1038 env->ipr[IPR_EXC_ADDR] = address;
1042 /* Should never happen */
1043 env->exception_index = EXCP_MCHK;
1044 env->ipr[IPR_EXC_ADDR] = address;
1053 #else /* !defined (CONFIG_USER_ONLY) */
1054 void pal_init (CPUState *env)
1058 void call_pal (CPUState *env, int palcode)
1062 printf("%s: palcode %02x\n", __func__, palcode);
1063 if (logfile != NULL)
1064 fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
1068 printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1069 if (logfile != NULL)
1070 fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1071 ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1072 env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1074 env->ir[IR_A3] = ret;
1075 if (ret > (target_ulong)(-515)) {
1083 env->ir[IR_V0] = env->unique;
1084 printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1088 env->unique = env->ir[IR_A0];
1089 printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1092 printf("%s: unhandled palcode %02x\n", __func__, palcode);
1093 if (logfile != NULL)
1094 fprintf(logfile, "%s: unhandled palcode %02x\n",