cpu_alpha_palcode.cc Source File

Back to the index.

cpu_alpha_palcode.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2018 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * Alpha PALcode-related functionality.
29  *
30  * (See http://www.alphalinux.org/docs/alphaahb.html for good descriptions
31  * of many PALcode functions.)
32  */
33 
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 
40 #include "console.h"
41 #include "cpu.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 #include "symbol.h"
46 
47 #include "thirdparty/alpha_prom.h"
48 
49 
50 /*
51  * alpha_palcode_name():
52  *
53  * Return the name of a PALcode number, as a string.
54  */
55 void alpha_palcode_name(uint32_t palcode, char *buf, size_t buflen)
56 {
57  switch (palcode) {
58  case 0x00: snprintf(buf, buflen, "PAL_halt"); break;
59  case 0x01: snprintf(buf, buflen, "PAL_cflush"); break;
60  case 0x02: snprintf(buf, buflen, "PAL_draina"); break;
61  case 0x09: snprintf(buf, buflen, "PAL_cserve"); break;
62  case 0x0a: snprintf(buf, buflen, "PAL_swppal"); break;
63  case 0x0d: snprintf(buf, buflen, "PAL_ipir"); break;
64  case 0x10: snprintf(buf, buflen, "PAL_OSF1_rdmces"); break;
65  case 0x11: snprintf(buf, buflen, "PAL_OSF1_wrmces"); break;
66  case 0x2b: snprintf(buf, buflen, "PAL_OSF1_wrfen"); break;
67  case 0x2d: snprintf(buf, buflen, "PAL_OSF1_wrvptptr"); break;
68  case 0x30: snprintf(buf, buflen, "PAL_OSF1_swpctx"); break;
69  case 0x31: snprintf(buf, buflen, "PAL_OSF1_wrval"); break;
70  case 0x32: snprintf(buf, buflen, "PAL_OSF1_rdval"); break;
71  case 0x33: snprintf(buf, buflen, "PAL_OSF1_tbi"); break;
72  case 0x34: snprintf(buf, buflen, "PAL_OSF1_wrent"); break;
73  case 0x35: snprintf(buf, buflen, "PAL_OSF1_swpipl"); break;
74  case 0x36: snprintf(buf, buflen, "PAL_rdps"); break;
75  case 0x37: snprintf(buf, buflen, "PAL_OSF1_wrkgp"); break;
76  case 0x38: snprintf(buf, buflen, "PAL_OSF1_wrusp"); break;
77  case 0x39: snprintf(buf, buflen, "PAL_OSF1_wrperfmon"); break;
78  case 0x3a: snprintf(buf, buflen, "PAL_OSF1_rdusp"); break;
79  case 0x3c: snprintf(buf, buflen, "PAL_whami"); break;
80  case 0x3d: snprintf(buf, buflen, "PAL_OSF1_retsys"); break;
81  case 0x3e: snprintf(buf, buflen, "PAL_wtint"); break;
82  case 0x3f: snprintf(buf, buflen, "PAL_OSF1_rti"); break;
83  case 0x80: snprintf(buf, buflen, "PAL_bpt"); break;
84  case 0x81: snprintf(buf, buflen, "PAL_bugchk"); break;
85  case 0x83: snprintf(buf, buflen, "PAL_OSF1_callsys"); break;
86  case 0x86: snprintf(buf, buflen, "PAL_imb"); break;
87  case 0x92: snprintf(buf, buflen, "PAL_OSF1_urti"); break;
88  case 0x9e: snprintf(buf, buflen, "PAL_rdunique"); break;
89  case 0x9f: snprintf(buf, buflen, "PAL_wrunique"); break;
90  case 0xaa: snprintf(buf, buflen, "PAL_gentrap"); break;
91  case 0xae: snprintf(buf, buflen, "PAL_clrfen"); break;
92  case 0x3fffffe: snprintf(buf, buflen, "GXemul_PROM"); break;
93  default:snprintf(buf, buflen, "UNKNOWN 0x%" PRIx32, palcode);
94  }
95 }
96 
97 
98 /*
99  * alpha_prom_call():
100  */
101 void alpha_prom_call(struct cpu *cpu)
102 {
103  uint64_t addr, a1 = cpu->cd.alpha.r[ALPHA_A1];
104  uint64_t a2 = cpu->cd.alpha.r[ALPHA_A2], a3 = cpu->cd.alpha.r[ALPHA_A3];
105  uint64_t len;
106  const char *s = "";
107 
108  switch (cpu->cd.alpha.r[ALPHA_A0]) {
109 
110  case PROM_R_PUTS:
111  /* a1 = channel, a2 = ptr to buf, a3 = len */
112  for (addr = a2; addr < a2 + a3; addr ++) {
113  unsigned char ch;
114  cpu->memory_rw(cpu, cpu->mem, addr, &ch, sizeof(ch),
117  }
118  cpu->cd.alpha.r[ALPHA_V0] = a3;
119  break;
120 
121  case PROM_R_GETENV:
122  /* a1 = variable id, a2 = char *buf, a3 = bufsize */
123  switch (a1) {
124  case PROM_E_BOOTED_DEV:
125  s = ""; /* TODO */
126  break;
127  case PROM_E_BOOTED_FILE:
128  s = cpu->machine->boot_kernel_filename;
129  break;
131  s = cpu->machine->boot_string_argument;
132  break;
133  case PROM_E_TTY_DEV:
134  s = ""; /* TODO */
135  break;
136  default:fatal("[ Alpha PALcode: GXemul PROM getenv %i: TODO "
137  "]\n", cpu->cd.alpha.r[ALPHA_A1]);
138  cpu->running = 0;
139  }
140  /* Copy at most a3 bytes. */
141  len = a3;
142  if (strlen(s) < len)
143  len = strlen(s) + 1;
144  store_buf(cpu, a2, s, len);
145  break;
146 
147  default:fatal("[ Alpha PALcode: GXemul PROM call, a0=0x%" PRIx64" ]\n",
148  (uint64_t) cpu->cd.alpha.r[ALPHA_A0]);
149  cpu->running = 0;
150  }
151 
152  /* Return from the PROM call. */
153  cpu->pc = cpu->cd.alpha.r[ALPHA_RA];
154 }
155 
156 
157 /*
158  * alpha_palcode():
159  *
160  * Execute an Alpha PALcode instruction. (Most of these correspond to
161  * OSF1 palcodes, used by for example NetBSD/alpha.)
162  */
163 void alpha_palcode(struct cpu *cpu, uint32_t palcode)
164 {
165  uint64_t a0 = cpu->cd.alpha.r[ALPHA_A0], a1 = cpu->cd.alpha.r[ALPHA_A1];
166  bool userMode = cpu->cd.alpha.ps & ALPHA_PSL_USERMODE;
167 
168  /*
169  * Only these are unprivileged, i.e. can be invoked in user mode,
170  * according to the manual:
171  *
172  * bpt kernel and user
173  * bugchk kernel and user
174  * callsys user
175  * clrfen user
176  * gentrap kernel and user
177  * imb kernel and user
178  * rdunique kernel and user
179  * urti user
180  * wrunique kernel and user
181  */
182 
183  if (userMode && !(
184  palcode == 0x80 || palcode == 0x81 || palcode == 0x83 ||
185  palcode == 0xae || palcode == 0xaa || palcode == 0x86 ||
186  palcode == 0x9e || palcode == 0x92 || palcode == 0x9f)) {
187  // opDec fault.
188  fatal("[ Privileged Alpha PALcode called from user mode: TODO ]");
189  cpu->running = 0;
190  return;
191  }
192 
193  switch (palcode) {
194 #if 0
195 TODO: Uncomment more again, as I progress with the emulation...
196 Make sure they are correct, as documented in the Manual.
197 
198  case 0x02: /* PAL_draina */
199  /* TODO? */
200  break;
201 #endif
202  case 0x10: /* PAL_OSF1_rdmces */
203  /* Return Machine Check status in v0. */
204  cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.mces;
205  break;
206  case 0x11: /* PAL_OSF1_wrmces */
207  /* Clear bits 0, 1, and 2 of the Machine Check and Error status. */
208  cpu->cd.alpha.mces = ~(cpu->cd.alpha.r[ALPHA_A0] & 7);
209 
210  /* Set bits 3 and 4 of the Machine Check and Error status. */
211  cpu->cd.alpha.mces &= ~0x18;
212  cpu->cd.alpha.mces |= (cpu->cd.alpha.r[ALPHA_A0] & 0x18);
213  break;
214  case 0x2b: /* PAL_OSF1_wrfen */
215  /* Floating point enable: a0 = 1 or 0. */
216  /* TODO. Since clrfen is documented as:
217  FEN ← 0
218  (PCBB+40)<0> ← 0
219  then most likely wrfen should do the reverse.
220  */
221  cpu->cd.alpha.pcb.apcb_flags = cpu->cd.alpha.r[ALPHA_A0];
222  store_64bit_word(cpu, cpu->cd.alpha.ctx + 40,
223  cpu->cd.alpha.pcb.apcb_flags);
224  break;
225  case 0x2d: /* PAL_OSF1_wrvptptr */
226  /* Write Virtual Page Table Pointer. a0 = value */
227  cpu->cd.alpha.vptptr = a0;
228  break;
229  case 0x30: /* PAL_OSF1_swpctx */
230  /* Save old context: */
231  store_64bit_word(cpu, cpu->cd.alpha.ctx + 0,
232  cpu->cd.alpha.pcb.apcb_ksp);
233  store_64bit_word(cpu, cpu->cd.alpha.ctx + 8,
234  cpu->cd.alpha.pcb.apcb_usp);
235  store_64bit_word(cpu, cpu->cd.alpha.ctx + 16,
236  cpu->cd.alpha.pcb.apcb_ptbr);
237  store_32bit_word(cpu, cpu->cd.alpha.ctx + 24,
238  cpu->cd.alpha.pcb.apcb_cpc);
239  store_32bit_word(cpu, cpu->cd.alpha.ctx + 28,
240  cpu->cd.alpha.pcb.apcb_asn);
241  store_64bit_word(cpu, cpu->cd.alpha.ctx + 32,
242  cpu->cd.alpha.pcb.apcb_unique);
243  store_64bit_word(cpu, cpu->cd.alpha.ctx + 40,
244  cpu->cd.alpha.pcb.apcb_flags);
245  store_64bit_word(cpu, cpu->cd.alpha.ctx + 48,
246  cpu->cd.alpha.pcb.apcb_decrsv0);
247  store_64bit_word(cpu, cpu->cd.alpha.ctx + 56,
248  cpu->cd.alpha.pcb.apcb_decrsv1);
249 
250  /* Return old context in v0. */
251  cpu->cd.alpha.r[ALPHA_A0] = cpu->cd.alpha.ctx;
252 
253  /* Load new context: */
254  {
255  cpu->cd.alpha.ctx = a0;
256  uint64_t new_ksp =
257  load_64bit_word(cpu, cpu->cd.alpha.ctx + 0);
258  uint64_t new_usp =
259  load_64bit_word(cpu, cpu->cd.alpha.ctx + 8);
260  uint64_t new_ptbr =
261  load_64bit_word(cpu, cpu->cd.alpha.ctx + 16);
262  uint64_t new_cpc =
263  load_32bit_word(cpu, cpu->cd.alpha.ctx + 24);
264  uint64_t new_asn =
265  load_32bit_word(cpu, cpu->cd.alpha.ctx + 28);
266  uint64_t new_unique =
267  load_64bit_word(cpu, cpu->cd.alpha.ctx + 32);
268  uint64_t new_flags =
269  load_64bit_word(cpu, cpu->cd.alpha.ctx + 40);
270  uint64_t new_decrsv0 =
271  load_64bit_word(cpu, cpu->cd.alpha.ctx + 48);
272  uint64_t new_decrsv1 =
273  load_64bit_word(cpu, cpu->cd.alpha.ctx + 56);
274 
275  // Update all variables in the pcb simultaneously:
276  cpu->cd.alpha.pcb.apcb_ksp = new_ksp;
277  cpu->cd.alpha.pcb.apcb_usp = new_usp;
278  cpu->cd.alpha.pcb.apcb_ptbr = new_ptbr;
279  cpu->cd.alpha.pcb.apcb_cpc = new_cpc;
280  cpu->cd.alpha.pcb.apcb_asn = new_asn;
281  cpu->cd.alpha.pcb.apcb_unique = new_unique;
282  cpu->cd.alpha.pcb.apcb_ptbr = new_flags;
283  cpu->cd.alpha.pcb.apcb_decrsv0 = new_decrsv0;
284  cpu->cd.alpha.pcb.apcb_decrsv1 = new_decrsv1;
285 
286  // TODO: Don't invalidate EVERYTHING!
288  }
289  break;
290 #if 0
291  case 0x31: /* PAL_OSF1_wrval */
292  /* a0 = value */
293  cpu->cd.alpha.sysvalue = a0;
294  break;
295  case 0x32: /* PAL_OSF1_rdval */
296  /* return: v0 = value */
297  cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.sysvalue;
298  break;
299 #endif
300  case 0x33: /* PAL_OSF1_tbi */
301  /*
302  * a0 = op, a1 = vaddr
303  * a0 is ignored for now. TODO.
304  * a0 = 1: ITB invalidate
305  * a0 = 2: DTB invalidate
306  * a0 = 3: both ITB and DTB
307  * a0 = -1: invalidate everything with ASM=0.
308  * a0 = -2: invalidate everything
309  */
310  // debug("[ Alpha PALcode: PAL_OSF1_tbi: a0=%" PRIi64" a1=0x%"
311  // PRIx64" ]\n", (int64_t)a0, (uint64_t)a1);
312  if (a0 >= 1)
314  else
316  break;
317  case 0x34: /* PAL_OSF1_wrent (Write System Entry Address) */
318  /* a0 = new vector, a1 = vector selector */
319  if (a1 < N_ALPHA_KENTRY)
320  cpu->cd.alpha.kentry[a1] = a0;
321  else {
322  fatal("[ Alpha PALcode: PAL_OSF1_wrent: attempt to "
323  "write to non-implemented selector %i ]\n",
324  (int)a1);
325  cpu->running = 0;
326  }
327  break;
328  case 0x35: /* PAL_OSF1_swpipl */
329  /* a0 = new ipl, v0 = return old ipl */
330  cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.ps & ALPHA_PSL_IPL_MASK;
331  cpu->cd.alpha.ps &= ~ALPHA_PSL_IPL_MASK;
332  cpu->cd.alpha.ps |= (a0 & ALPHA_PSL_IPL_MASK);
333  break;
334  case 0x36: /* PAL_rdps */
335  cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.ps;
336  break;
337  case 0x37: /* PAL_OSF1_wrkgp */
338  cpu->cd.alpha.kgp = a0;
339  break;
340 #if 0
341  case 0x38: /* PAL_OSF1_wrusp */
342  /* a0 = value */
343  cpu->cd.alpha.pcb.apcb_usp = a0;
344  break;
345  case 0x3a: /* PAL_OSF1_rdusp */
346  /* return: v0 = value */
347  cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.pcb.apcb_usp;
348  break;
349 #endif
350  case 0x3c: /* PAL_whami */
351  /* Returns CPU id in v0: */
352  cpu->cd.alpha.r[ALPHA_V0] = cpu->cpu_id;
353  break;
354 #if 0
355  case 0x81: /* PAL_bugchk */
356  cpu->running = 0;
357  break;
358  case 0x83: /* PAL_OSF1_syscall */
359  fatal("[ Alpha PALcode: syscall, but no syscall handler ]\n");
360  cpu->running = 0;
361  break;
362 #endif
363  case 0x86: /* PAL_imb */
364  /* TODO */
365  break;
366 #if 0
367  case 0x3fffffc:
368  fatal("[ Alpha: KENTRY not set! Halting. ]");
369  cpu->running = 0;
370  break;
371  case 0x3fffffd:
372  fatal("[ Alpha PALcode: Fixup: TODO ]\n");
373  /* Return from the fixup call. */
374  cpu->cd.alpha.r[ALPHA_V0] = 0; /* Success? */
375  cpu->pc = cpu->cd.alpha.r[ALPHA_RA];
376  break;
377 #endif
378  case 0x3fffffe:
379  alpha_prom_call(cpu);
380  break;
381  default:fatal("[ Alpha PALcode 0x%x unimplemented! ]\n", palcode);
382  cpu->running = 0;
383  }
384 
385  /*
386  * Many PALcode instructions in the Alpha manual (and in NetBSD/Alpha
387  * source code) are described with "clobbers t0, t8-t11", some also
388  * with a0, and some also with a1 included.
389  *
390  * However, it's easier to just leave the registers as they are.
391  */
392 }
393 
#define PROM_E_TTY_DEV
Definition: alpha_prom.h:86
#define PROM_E_BOOTED_DEV
Definition: alpha_prom.h:83
void fatal(const char *fmt,...)
Definition: main.cc:152
#define ALPHA_A1
Definition: cpu_alpha.h:94
#define I
#define CACHE_DATA
Definition: memory.h:121
#define INVALIDATE_VADDR
Definition: cpu.h:480
int main_console_handle
Definition: machine.h:128
int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
Definition: memory.cc:783
#define PROM_E_BOOTED_OSFLAGS
Definition: alpha_prom.h:85
#define INVALIDATE_ALL
Definition: cpu.h:478
uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:875
union cpu::@1 cd
struct memory * mem
Definition: cpu.h:362
#define ALPHA_RA
Definition: cpu_alpha.h:104
struct machine * machine
Definition: cpu.h:328
#define MEM_READ
Definition: memory.h:116
uint64_t apcb_ksp
Definition: alpha_cpu.h:62
#define ALPHA_A0
Definition: cpu_alpha.h:93
void console_putchar(int handle, int ch)
Definition: console.cc:405
#define ALPHA_A2
Definition: cpu_alpha.h:95
void alpha_prom_call(struct cpu *cpu)
void alpha_palcode(struct cpu *cpu, uint32_t palcode)
int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
Definition: memory.cc:752
uint64_t kgp
Definition: cpu_alpha.h:168
uint32_t apcb_asn
Definition: alpha_cpu.h:66
char * boot_string_argument
Definition: machine.h:171
uint64_t pc
Definition: cpu.h:383
char * boot_kernel_filename
Definition: machine.h:170
struct alpha_pcb pcb
Definition: cpu_alpha.h:171
uint64_t ctx
Definition: cpu_alpha.h:170
#define PROM_E_BOOTED_FILE
Definition: alpha_prom.h:84
void alpha_palcode_name(uint32_t palcode, char *buf, size_t buflen)
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:365
#define PROM_R_GETENV
Definition: alpha_prom.h:69
uint64_t apcb_ptbr
Definition: alpha_cpu.h:64
uint8_t running
Definition: cpu.h:353
uint64_t mces
Definition: cpu_alpha.h:167
uint64_t apcb_unique
Definition: alpha_cpu.h:67
uint64_t apcb_decrsv0
Definition: alpha_cpu.h:70
#define N_ALPHA_KENTRY
Definition: cpu_alpha.h:73
uint32_t addr
uint64_t ps
Definition: cpu_alpha.h:164
uint64_t r[N_ALPHA_REGS]
Definition: cpu_alpha.h:151
int cpu_id
Definition: cpu.h:359
uint64_t vptptr
Definition: cpu_alpha.h:165
Definition: cpu.h:326
#define NO_EXCEPTIONS
Definition: memory.h:125
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
Definition: memory.cc:902
uint32_t apcb_cpc
Definition: alpha_cpu.h:65
uint64_t sysvalue
Definition: cpu_alpha.h:166
struct alpha_cpu alpha
Definition: cpu.h:440
#define PROM_R_PUTS
Definition: alpha_prom.h:71
#define ALPHA_V0
Definition: cpu_alpha.h:75
uint64_t apcb_decrsv1
Definition: alpha_cpu.h:71
void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len)
Definition: memory.cc:826
uint64_t kentry[N_ALPHA_KENTRY]
Definition: cpu_alpha.h:169
#define ALPHA_PSL_USERMODE
Definition: alpha_cpu.h:103
uint64_t apcb_flags
Definition: alpha_cpu.h:69
#define ALPHA_PSL_IPL_MASK
Definition: alpha_cpu.h:104
#define ALPHA_A3
Definition: cpu_alpha.h:96
uint64_t apcb_usp
Definition: alpha_cpu.h:63
void(* invalidate_translation_caches)(struct cpu *, uint64_t paddr, int flags)
Definition: cpu.h:374

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13