ia64/xen-unstable

view tools/ioemu/hw/ppc.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children f7b43e5c42b9
line source
1 /*
2 * QEMU generic PPC hardware System Emulator
3 *
4 * Copyright (c) 2003-2004 Jocelyn Mayer
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
25 #include "m48t59.h"
27 /*****************************************************************************/
28 /* PPC time base and decrementer emulation */
29 //#define DEBUG_TB
31 struct ppc_tb_t {
32 /* Time base management */
33 int64_t tb_offset; /* Compensation */
34 uint32_t tb_freq; /* TB frequency */
35 /* Decrementer management */
36 uint64_t decr_next; /* Tick for next decr interrupt */
37 struct QEMUTimer *decr_timer;
38 };
40 static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
41 {
42 /* TB time in tb periods */
43 return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
44 tb_env->tb_freq, ticks_per_sec);
45 }
47 uint32_t cpu_ppc_load_tbl (CPUState *env)
48 {
49 ppc_tb_t *tb_env = env->tb_env;
50 uint64_t tb;
52 tb = cpu_ppc_get_tb(tb_env);
53 #ifdef DEBUG_TB
54 {
55 static int last_time;
56 int now;
57 now = time(NULL);
58 if (last_time != now) {
59 last_time = now;
60 printf("%s: tb=0x%016lx %d %08lx\n",
61 __func__, tb, now, tb_env->tb_offset);
62 }
63 }
64 #endif
66 return tb & 0xFFFFFFFF;
67 }
69 uint32_t cpu_ppc_load_tbu (CPUState *env)
70 {
71 ppc_tb_t *tb_env = env->tb_env;
72 uint64_t tb;
74 tb = cpu_ppc_get_tb(tb_env);
75 #ifdef DEBUG_TB
76 printf("%s: tb=0x%016lx\n", __func__, tb);
77 #endif
78 return tb >> 32;
79 }
81 static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
82 {
83 tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
84 - qemu_get_clock(vm_clock);
85 #ifdef DEBUG_TB
86 printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
87 #endif
88 }
90 void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
91 {
92 ppc_tb_t *tb_env = env->tb_env;
94 cpu_ppc_store_tb(tb_env,
95 ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
96 }
98 void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
99 {
100 ppc_tb_t *tb_env = env->tb_env;
102 cpu_ppc_store_tb(tb_env,
103 ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
104 }
106 uint32_t cpu_ppc_load_decr (CPUState *env)
107 {
108 ppc_tb_t *tb_env = env->tb_env;
109 uint32_t decr;
111 decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
112 tb_env->tb_freq, ticks_per_sec);
113 #if defined(DEBUG_TB)
114 printf("%s: 0x%08x\n", __func__, decr);
115 #endif
117 return decr;
118 }
120 /* When decrementer expires,
121 * all we need to do is generate or queue a CPU exception
122 */
123 static inline void cpu_ppc_decr_excp (CPUState *env)
124 {
125 /* Raise it */
126 #ifdef DEBUG_TB
127 printf("raise decrementer exception\n");
128 #endif
129 cpu_interrupt(env, CPU_INTERRUPT_TIMER);
130 }
132 static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
133 uint32_t value, int is_excp)
134 {
135 ppc_tb_t *tb_env = env->tb_env;
136 uint64_t now, next;
138 #ifdef DEBUG_TB
139 printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
140 #endif
141 now = qemu_get_clock(vm_clock);
142 next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
143 if (is_excp)
144 next += tb_env->decr_next - now;
145 if (next == now)
146 next++;
147 tb_env->decr_next = next;
148 /* Adjust timer */
149 qemu_mod_timer(tb_env->decr_timer, next);
150 /* If we set a negative value and the decrementer was positive,
151 * raise an exception.
152 */
153 if ((value & 0x80000000) && !(decr & 0x80000000))
154 cpu_ppc_decr_excp(env);
155 }
157 void cpu_ppc_store_decr (CPUState *env, uint32_t value)
158 {
159 _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
160 }
162 static void cpu_ppc_decr_cb (void *opaque)
163 {
164 _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
165 }
167 /* Set up (once) timebase frequency (in Hz) */
168 ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
169 {
170 ppc_tb_t *tb_env;
172 tb_env = qemu_mallocz(sizeof(ppc_tb_t));
173 if (tb_env == NULL)
174 return NULL;
175 env->tb_env = tb_env;
176 if (tb_env->tb_freq == 0 || 1) {
177 tb_env->tb_freq = freq;
178 /* Create new timer */
179 tb_env->decr_timer =
180 qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
181 /* There is a bug in 2.4 kernels:
182 * if a decrementer exception is pending when it enables msr_ee,
183 * it's not ready to handle it...
184 */
185 _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
186 }
188 return tb_env;
189 }
191 #if 0
192 /*****************************************************************************/
193 /* Handle system reset (for now, just stop emulation) */
194 void cpu_ppc_reset (CPUState *env)
195 {
196 printf("Reset asked... Stop emulation\n");
197 abort();
198 }
199 #endif
201 static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
202 {
203 cpu_outb(NULL, addr & 0xffff, value);
204 }
206 static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
207 {
208 uint32_t ret = cpu_inb(NULL, addr & 0xffff);
209 return ret;
210 }
212 static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
213 {
214 #ifdef TARGET_WORDS_BIGENDIAN
215 value = bswap16(value);
216 #endif
217 cpu_outw(NULL, addr & 0xffff, value);
218 }
220 static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
221 {
222 uint32_t ret = cpu_inw(NULL, addr & 0xffff);
223 #ifdef TARGET_WORDS_BIGENDIAN
224 ret = bswap16(ret);
225 #endif
226 return ret;
227 }
229 static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
230 {
231 #ifdef TARGET_WORDS_BIGENDIAN
232 value = bswap32(value);
233 #endif
234 cpu_outl(NULL, addr & 0xffff, value);
235 }
237 static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
238 {
239 uint32_t ret = cpu_inl(NULL, addr & 0xffff);
241 #ifdef TARGET_WORDS_BIGENDIAN
242 ret = bswap32(ret);
243 #endif
244 return ret;
245 }
247 CPUWriteMemoryFunc *PPC_io_write[] = {
248 &PPC_io_writeb,
249 &PPC_io_writew,
250 &PPC_io_writel,
251 };
253 CPUReadMemoryFunc *PPC_io_read[] = {
254 &PPC_io_readb,
255 &PPC_io_readw,
256 &PPC_io_readl,
257 };
259 /*****************************************************************************/
260 /* Debug port */
261 void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
262 {
263 addr &= 0xF;
264 switch (addr) {
265 case 0:
266 printf("%c", val);
267 break;
268 case 1:
269 printf("\n");
270 fflush(stdout);
271 break;
272 case 2:
273 printf("Set loglevel to %04x\n", val);
274 cpu_set_log(val | 0x100);
275 break;
276 }
277 }
279 /*****************************************************************************/
280 /* NVRAM helpers */
281 void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
282 {
283 m48t59_set_addr(nvram, addr);
284 m48t59_write(nvram, value);
285 }
287 uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
288 {
289 m48t59_set_addr(nvram, addr);
290 return m48t59_read(nvram);
291 }
293 void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
294 {
295 m48t59_set_addr(nvram, addr);
296 m48t59_write(nvram, value >> 8);
297 m48t59_set_addr(nvram, addr + 1);
298 m48t59_write(nvram, value & 0xFF);
299 }
301 uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
302 {
303 uint16_t tmp;
305 m48t59_set_addr(nvram, addr);
306 tmp = m48t59_read(nvram) << 8;
307 m48t59_set_addr(nvram, addr + 1);
308 tmp |= m48t59_read(nvram);
310 return tmp;
311 }
313 void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
314 {
315 m48t59_set_addr(nvram, addr);
316 m48t59_write(nvram, value >> 24);
317 m48t59_set_addr(nvram, addr + 1);
318 m48t59_write(nvram, (value >> 16) & 0xFF);
319 m48t59_set_addr(nvram, addr + 2);
320 m48t59_write(nvram, (value >> 8) & 0xFF);
321 m48t59_set_addr(nvram, addr + 3);
322 m48t59_write(nvram, value & 0xFF);
323 }
325 uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
326 {
327 uint32_t tmp;
329 m48t59_set_addr(nvram, addr);
330 tmp = m48t59_read(nvram) << 24;
331 m48t59_set_addr(nvram, addr + 1);
332 tmp |= m48t59_read(nvram) << 16;
333 m48t59_set_addr(nvram, addr + 2);
334 tmp |= m48t59_read(nvram) << 8;
335 m48t59_set_addr(nvram, addr + 3);
336 tmp |= m48t59_read(nvram);
338 return tmp;
339 }
341 void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
342 const unsigned char *str, uint32_t max)
343 {
344 int i;
346 for (i = 0; i < max && str[i] != '\0'; i++) {
347 m48t59_set_addr(nvram, addr + i);
348 m48t59_write(nvram, str[i]);
349 }
350 m48t59_set_addr(nvram, addr + max - 1);
351 m48t59_write(nvram, '\0');
352 }
354 int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
355 {
356 int i;
358 memset(dst, 0, max);
359 for (i = 0; i < max; i++) {
360 dst[i] = NVRAM_get_byte(nvram, addr + i);
361 if (dst[i] == '\0')
362 break;
363 }
365 return i;
366 }
368 static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
369 {
370 uint16_t tmp;
371 uint16_t pd, pd1, pd2;
373 tmp = prev >> 8;
374 pd = prev ^ value;
375 pd1 = pd & 0x000F;
376 pd2 = ((pd >> 4) & 0x000F) ^ pd1;
377 tmp ^= (pd1 << 3) | (pd1 << 8);
378 tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
380 return tmp;
381 }
383 uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
384 {
385 uint32_t i;
386 uint16_t crc = 0xFFFF;
387 int odd;
389 odd = count & 1;
390 count &= ~1;
391 for (i = 0; i != count; i++) {
392 crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
393 }
394 if (odd) {
395 crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
396 }
398 return crc;
399 }
401 #define CMDLINE_ADDR 0x017ff000
403 int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
404 const unsigned char *arch,
405 uint32_t RAM_size, int boot_device,
406 uint32_t kernel_image, uint32_t kernel_size,
407 const char *cmdline,
408 uint32_t initrd_image, uint32_t initrd_size,
409 uint32_t NVRAM_image,
410 int width, int height, int depth)
411 {
412 uint16_t crc;
414 /* Set parameters for Open Hack'Ware BIOS */
415 NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
416 NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
417 NVRAM_set_word(nvram, 0x14, NVRAM_size);
418 NVRAM_set_string(nvram, 0x20, arch, 16);
419 NVRAM_set_lword(nvram, 0x30, RAM_size);
420 NVRAM_set_byte(nvram, 0x34, boot_device);
421 NVRAM_set_lword(nvram, 0x38, kernel_image);
422 NVRAM_set_lword(nvram, 0x3C, kernel_size);
423 if (cmdline) {
424 /* XXX: put the cmdline in NVRAM too ? */
425 strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
426 NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
427 NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
428 } else {
429 NVRAM_set_lword(nvram, 0x40, 0);
430 NVRAM_set_lword(nvram, 0x44, 0);
431 }
432 NVRAM_set_lword(nvram, 0x48, initrd_image);
433 NVRAM_set_lword(nvram, 0x4C, initrd_size);
434 NVRAM_set_lword(nvram, 0x50, NVRAM_image);
436 NVRAM_set_word(nvram, 0x54, width);
437 NVRAM_set_word(nvram, 0x56, height);
438 NVRAM_set_word(nvram, 0x58, depth);
439 crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
440 NVRAM_set_word(nvram, 0xFC, crc);
442 return 0;
443 }
445 /*****************************************************************************/
446 void ppc_init (int ram_size, int vga_ram_size, int boot_device,
447 DisplayState *ds, const char **fd_filename, int snapshot,
448 const char *kernel_filename, const char *kernel_cmdline,
449 const char *initrd_filename)
450 {
451 if (prep_enabled) {
452 ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
453 snapshot, kernel_filename, kernel_cmdline,
454 initrd_filename);
455 } else {
456 ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
457 snapshot, kernel_filename, kernel_cmdline,
458 initrd_filename);
459 }
460 /* Special port to get debug messages from Open-Firmware */
461 register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
462 }