| File: | hw/sparc64/sun4u.c |
| Location: | line 883, column 5 |
| Description: | Function call argument is an uninitialized value |
| 1 | /* | |||
| 2 | * QEMU Sun4u/Sun4v System Emulator | |||
| 3 | * | |||
| 4 | * Copyright (c) 2005 Fabrice Bellard | |||
| 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 "hw/hw.h" | |||
| 25 | #include "hw/pci/pci.h" | |||
| 26 | #include "hw/pci-host/apb.h" | |||
| 27 | #include "hw/i386/pc.h" | |||
| 28 | #include "hw/char/serial.h" | |||
| 29 | #include "hw/timer/m48t59.h" | |||
| 30 | #include "hw/block/fdc.h" | |||
| 31 | #include "net/net.h" | |||
| 32 | #include "qemu/timer.h" | |||
| 33 | #include "sysemu/sysemu.h" | |||
| 34 | #include "hw/boards.h" | |||
| 35 | #include "hw/nvram/openbios_firmware_abi.h" | |||
| 36 | #include "hw/nvram/fw_cfg.h" | |||
| 37 | #include "hw/sysbus.h" | |||
| 38 | #include "hw/ide.h" | |||
| 39 | #include "hw/loader.h" | |||
| 40 | #include "elf.h" | |||
| 41 | #include "sysemu/blockdev.h" | |||
| 42 | #include "exec/address-spaces.h" | |||
| 43 | ||||
| 44 | //#define DEBUG_IRQ | |||
| 45 | //#define DEBUG_EBUS | |||
| 46 | //#define DEBUG_TIMER | |||
| 47 | ||||
| 48 | #ifdef DEBUG_IRQ | |||
| 49 | #define CPUIRQ_DPRINTF(fmt, ...) \ | |||
| 50 | do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) | |||
| 51 | #else | |||
| 52 | #define CPUIRQ_DPRINTF(fmt, ...) | |||
| 53 | #endif | |||
| 54 | ||||
| 55 | #ifdef DEBUG_EBUS | |||
| 56 | #define EBUS_DPRINTF(fmt, ...) \ | |||
| 57 | do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0) | |||
| 58 | #else | |||
| 59 | #define EBUS_DPRINTF(fmt, ...) | |||
| 60 | #endif | |||
| 61 | ||||
| 62 | #ifdef DEBUG_TIMER | |||
| 63 | #define TIMER_DPRINTF(fmt, ...) \ | |||
| 64 | do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0) | |||
| 65 | #else | |||
| 66 | #define TIMER_DPRINTF(fmt, ...) | |||
| 67 | #endif | |||
| 68 | ||||
| 69 | #define KERNEL_LOAD_ADDR0x00404000 0x00404000 | |||
| 70 | #define CMDLINE_ADDR0x003ff000 0x003ff000 | |||
| 71 | #define PROM_SIZE_MAX(4 * 1024 * 1024) (4 * 1024 * 1024) | |||
| 72 | #define PROM_VADDR0x000ffd00000ULL 0x000ffd00000ULL | |||
| 73 | #define APB_SPECIAL_BASE0x1fe00000000ULL 0x1fe00000000ULL | |||
| 74 | #define APB_MEM_BASE0x1ff00000000ULL 0x1ff00000000ULL | |||
| 75 | #define APB_PCI_IO_BASE(0x1fe00000000ULL + 0x02000000ULL) (APB_SPECIAL_BASE0x1fe00000000ULL + 0x02000000ULL) | |||
| 76 | #define PROM_FILENAME"openbios-sparc64" "openbios-sparc64" | |||
| 77 | #define NVRAM_SIZE0x2000 0x2000 | |||
| 78 | #define MAX_IDE_BUS2 2 | |||
| 79 | #define BIOS_CFG_IOPORT0x510 0x510 | |||
| 80 | #define FW_CFG_SPARC64_WIDTH(0x8000 + 0x00) (FW_CFG_ARCH_LOCAL0x8000 + 0x00) | |||
| 81 | #define FW_CFG_SPARC64_HEIGHT(0x8000 + 0x01) (FW_CFG_ARCH_LOCAL0x8000 + 0x01) | |||
| 82 | #define FW_CFG_SPARC64_DEPTH(0x8000 + 0x02) (FW_CFG_ARCH_LOCAL0x8000 + 0x02) | |||
| 83 | ||||
| 84 | #define IVEC_MAX0x40 0x40 | |||
| 85 | ||||
| 86 | #define TICK_MAX0x7fffffffffffffffULL 0x7fffffffffffffffULL | |||
| 87 | ||||
| 88 | struct hwdef { | |||
| 89 | const char * const default_cpu_model; | |||
| 90 | uint16_t machine_id; | |||
| 91 | uint64_t prom_addr; | |||
| 92 | uint64_t console_serial_base; | |||
| 93 | }; | |||
| 94 | ||||
| 95 | typedef struct EbusState { | |||
| 96 | PCIDevice pci_dev; | |||
| 97 | MemoryRegion bar0; | |||
| 98 | MemoryRegion bar1; | |||
| 99 | } EbusState; | |||
| 100 | ||||
| 101 | int DMA_get_channel_mode (int nchan) | |||
| 102 | { | |||
| 103 | return 0; | |||
| 104 | } | |||
| 105 | int DMA_read_memory (int nchan, void *buf, int pos, int size) | |||
| 106 | { | |||
| 107 | return 0; | |||
| 108 | } | |||
| 109 | int DMA_write_memory (int nchan, void *buf, int pos, int size) | |||
| 110 | { | |||
| 111 | return 0; | |||
| 112 | } | |||
| 113 | void DMA_hold_DREQ (int nchan) {} | |||
| 114 | void DMA_release_DREQ (int nchan) {} | |||
| 115 | void DMA_schedule(int nchan) {} | |||
| 116 | ||||
| 117 | void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) | |||
| 118 | { | |||
| 119 | } | |||
| 120 | ||||
| 121 | void DMA_register_channel (int nchan, | |||
| 122 | DMA_transfer_handler transfer_handler, | |||
| 123 | void *opaque) | |||
| 124 | { | |||
| 125 | } | |||
| 126 | ||||
| 127 | static int fw_cfg_boot_set(void *opaque, const char *boot_device) | |||
| 128 | { | |||
| 129 | fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE0x0c, boot_device[0]); | |||
| 130 | return 0; | |||
| 131 | } | |||
| 132 | ||||
| 133 | static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, | |||
| 134 | const char *arch, ram_addr_t RAM_size, | |||
| 135 | const char *boot_devices, | |||
| 136 | uint32_t kernel_image, uint32_t kernel_size, | |||
| 137 | const char *cmdline, | |||
| 138 | uint32_t initrd_image, uint32_t initrd_size, | |||
| 139 | uint32_t NVRAM_image, | |||
| 140 | int width, int height, int depth, | |||
| 141 | const uint8_t *macaddr) | |||
| 142 | { | |||
| 143 | unsigned int i; | |||
| 144 | uint32_t start, end; | |||
| 145 | uint8_t image[0x1ff0]; | |||
| 146 | struct OpenBIOS_nvpart_v1 *part_header; | |||
| 147 | ||||
| 148 | memset(image, '\0', sizeof(image)); | |||
| 149 | ||||
| 150 | start = 0; | |||
| 151 | ||||
| 152 | // OpenBIOS nvram variables | |||
| 153 | // Variable partition | |||
| 154 | part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; | |||
| 155 | part_header->signature = OPENBIOS_PART_SYSTEM0x70; | |||
| 156 | pstrcpy(part_header->name, sizeof(part_header->name), "system"); | |||
| 157 | ||||
| 158 | end = start + sizeof(struct OpenBIOS_nvpart_v1); | |||
| 159 | for (i = 0; i < nb_prom_envs; i++) | |||
| 160 | end = OpenBIOS_set_var(image, end, prom_envs[i]); | |||
| 161 | ||||
| 162 | // End marker | |||
| 163 | image[end++] = '\0'; | |||
| 164 | ||||
| 165 | end = start + ((end - start + 15) & ~15); | |||
| 166 | OpenBIOS_finish_partition(part_header, end - start); | |||
| 167 | ||||
| 168 | // free partition | |||
| 169 | start = end; | |||
| 170 | part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; | |||
| 171 | part_header->signature = OPENBIOS_PART_FREE0x7f; | |||
| 172 | pstrcpy(part_header->name, sizeof(part_header->name), "free"); | |||
| 173 | ||||
| 174 | end = 0x1fd0; | |||
| 175 | OpenBIOS_finish_partition(part_header, end - start); | |||
| 176 | ||||
| 177 | Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80); | |||
| 178 | ||||
| 179 | for (i = 0; i < sizeof(image); i++) | |||
| 180 | m48t59_write(nvram, i, image[i]); | |||
| 181 | ||||
| 182 | return 0; | |||
| 183 | } | |||
| 184 | ||||
| 185 | static uint64_t sun4u_load_kernel(const char *kernel_filename, | |||
| 186 | const char *initrd_filename, | |||
| 187 | ram_addr_t RAM_size, uint64_t *initrd_size, | |||
| 188 | uint64_t *initrd_addr, uint64_t *kernel_addr, | |||
| 189 | uint64_t *kernel_entry) | |||
| 190 | { | |||
| 191 | int linux_boot; | |||
| 192 | unsigned int i; | |||
| 193 | long kernel_size; | |||
| 194 | uint8_t *ptr; | |||
| 195 | uint64_t kernel_top; | |||
| 196 | ||||
| 197 | linux_boot = (kernel_filename != NULL((void*)0)); | |||
| 198 | ||||
| 199 | kernel_size = 0; | |||
| 200 | if (linux_boot) { | |||
| 201 | int bswap_needed; | |||
| 202 | ||||
| 203 | #ifdef BSWAP_NEEDED | |||
| 204 | bswap_needed = 1; | |||
| 205 | #else | |||
| 206 | bswap_needed = 0; | |||
| 207 | #endif | |||
| 208 | kernel_size = load_elf(kernel_filename, NULL((void*)0), NULL((void*)0), kernel_entry, | |||
| 209 | kernel_addr, &kernel_top, 1, ELF_MACHINE43, 0); | |||
| 210 | if (kernel_size < 0) { | |||
| 211 | *kernel_addr = KERNEL_LOAD_ADDR0x00404000; | |||
| 212 | *kernel_entry = KERNEL_LOAD_ADDR0x00404000; | |||
| 213 | kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR0x00404000, | |||
| 214 | RAM_size - KERNEL_LOAD_ADDR0x00404000, bswap_needed, | |||
| 215 | TARGET_PAGE_SIZE(1 << 13)); | |||
| 216 | } | |||
| 217 | if (kernel_size < 0) { | |||
| 218 | kernel_size = load_image_targphys(kernel_filename, | |||
| 219 | KERNEL_LOAD_ADDR0x00404000, | |||
| 220 | RAM_size - KERNEL_LOAD_ADDR0x00404000); | |||
| 221 | } | |||
| 222 | if (kernel_size < 0) { | |||
| 223 | fprintf(stderrstderr, "qemu: could not load kernel '%s'\n", | |||
| 224 | kernel_filename); | |||
| 225 | exit(1); | |||
| 226 | } | |||
| 227 | /* load initrd above kernel */ | |||
| 228 | *initrd_size = 0; | |||
| 229 | if (initrd_filename) { | |||
| 230 | *initrd_addr = TARGET_PAGE_ALIGN(kernel_top)(((kernel_top) + (1 << 13) - 1) & ~((1 << 13) - 1)); | |||
| 231 | ||||
| 232 | *initrd_size = load_image_targphys(initrd_filename, | |||
| 233 | *initrd_addr, | |||
| 234 | RAM_size - *initrd_addr); | |||
| 235 | if ((int)*initrd_size < 0) { | |||
| 236 | fprintf(stderrstderr, "qemu: could not load initial ram disk '%s'\n", | |||
| 237 | initrd_filename); | |||
| 238 | exit(1); | |||
| 239 | } | |||
| 240 | } | |||
| 241 | if (*initrd_size > 0) { | |||
| 242 | for (i = 0; i < 64 * TARGET_PAGE_SIZE(1 << 13); i += TARGET_PAGE_SIZE(1 << 13)) { | |||
| 243 | ptr = rom_ptr(*kernel_addr + i); | |||
| 244 | if (ldl_p(ptr + 8)ldl_be_p(ptr + 8) == 0x48647253) { /* HdrS */ | |||
| 245 | stl_p(ptr + 24, *initrd_addr + *kernel_addr)stl_be_p(ptr + 24, *initrd_addr + *kernel_addr); | |||
| 246 | stl_p(ptr + 28, *initrd_size)stl_be_p(ptr + 28, *initrd_size); | |||
| 247 | break; | |||
| 248 | } | |||
| 249 | } | |||
| 250 | } | |||
| 251 | } | |||
| 252 | return kernel_size; | |||
| 253 | } | |||
| 254 | ||||
| 255 | void cpu_check_irqs(CPUSPARCState *env) | |||
| 256 | { | |||
| 257 | CPUState *cs; | |||
| 258 | uint32_t pil = env->pil_in | | |||
| 259 | (env->softint & ~(SOFTINT_TIMER1 | SOFTINT_STIMER(1 << 16))); | |||
| 260 | ||||
| 261 | /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ | |||
| 262 | if (env->ivec_status & 0x20) { | |||
| 263 | return; | |||
| 264 | } | |||
| 265 | cs = CPU(sparc_env_get_cpu(env))((CPUState *)object_dynamic_cast_assert(((Object *)((sparc_env_get_cpu (env)))), ("cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 265, __func__)); | |||
| 266 | /* check if TM or SM in SOFTINT are set | |||
| 267 | setting these also causes interrupt 14 */ | |||
| 268 | if (env->softint & (SOFTINT_TIMER1 | SOFTINT_STIMER(1 << 16))) { | |||
| 269 | pil |= 1 << 14; | |||
| 270 | } | |||
| 271 | ||||
| 272 | /* The bit corresponding to psrpil is (1<< psrpil), the next bit | |||
| 273 | is (2 << psrpil). */ | |||
| 274 | if (pil < (2 << env->psrpil)){ | |||
| 275 | if (cs->interrupt_request & CPU_INTERRUPT_HARD0x0002) { | |||
| 276 | CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", | |||
| 277 | env->interrupt_index); | |||
| 278 | env->interrupt_index = 0; | |||
| 279 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD0x0002); | |||
| 280 | } | |||
| 281 | return; | |||
| 282 | } | |||
| 283 | ||||
| 284 | if (cpu_interrupts_enabled(env)) { | |||
| 285 | ||||
| 286 | unsigned int i; | |||
| 287 | ||||
| 288 | for (i = 15; i > env->psrpil; i--) { | |||
| 289 | if (pil & (1 << i)) { | |||
| 290 | int old_interrupt = env->interrupt_index; | |||
| 291 | int new_interrupt = TT_EXTINT0x40 | i; | |||
| 292 | ||||
| 293 | if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt__builtin_expect(!!(env->tl > 0 && cpu_tsptr(env )->tt > new_interrupt && ((cpu_tsptr(env)->tt & 0x1f0) == 0x40)), 0) | |||
| 294 | && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))__builtin_expect(!!(env->tl > 0 && cpu_tsptr(env )->tt > new_interrupt && ((cpu_tsptr(env)->tt & 0x1f0) == 0x40)), 0)) { | |||
| 295 | CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d " | |||
| 296 | "current %x >= pending %x\n", | |||
| 297 | env->tl, cpu_tsptr(env)->tt, new_interrupt); | |||
| 298 | } else if (old_interrupt != new_interrupt) { | |||
| 299 | env->interrupt_index = new_interrupt; | |||
| 300 | CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i, | |||
| 301 | old_interrupt, new_interrupt); | |||
| 302 | cpu_interrupt(cs, CPU_INTERRUPT_HARD0x0002); | |||
| 303 | } | |||
| 304 | break; | |||
| 305 | } | |||
| 306 | } | |||
| 307 | } else if (cs->interrupt_request & CPU_INTERRUPT_HARD0x0002) { | |||
| 308 | CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " | |||
| 309 | "current interrupt %x\n", | |||
| 310 | pil, env->pil_in, env->softint, env->interrupt_index); | |||
| 311 | env->interrupt_index = 0; | |||
| 312 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD0x0002); | |||
| 313 | } | |||
| 314 | } | |||
| 315 | ||||
| 316 | static void cpu_kick_irq(SPARCCPU *cpu) | |||
| 317 | { | |||
| 318 | CPUState *cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 318, __func__)); | |||
| 319 | CPUSPARCState *env = &cpu->env; | |||
| 320 | ||||
| 321 | cs->halted = 0; | |||
| 322 | cpu_check_irqs(env); | |||
| 323 | qemu_cpu_kick(cs); | |||
| 324 | } | |||
| 325 | ||||
| 326 | static void cpu_set_ivec_irq(void *opaque, int irq, int level) | |||
| 327 | { | |||
| 328 | SPARCCPU *cpu = opaque; | |||
| 329 | CPUSPARCState *env = &cpu->env; | |||
| 330 | CPUState *cs; | |||
| 331 | ||||
| 332 | if (level) { | |||
| 333 | if (!(env->ivec_status & 0x20)) { | |||
| 334 | CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq); | |||
| 335 | cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 335, __func__)); | |||
| 336 | cs->halted = 0; | |||
| 337 | env->interrupt_index = TT_IVEC0x60; | |||
| 338 | env->ivec_status |= 0x20; | |||
| 339 | env->ivec_data[0] = (0x1f << 6) | irq; | |||
| 340 | env->ivec_data[1] = 0; | |||
| 341 | env->ivec_data[2] = 0; | |||
| 342 | cpu_interrupt(cs, CPU_INTERRUPT_HARD0x0002); | |||
| 343 | } | |||
| 344 | } else { | |||
| 345 | if (env->ivec_status & 0x20) { | |||
| 346 | CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq); | |||
| 347 | cs = CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 347, __func__)); | |||
| 348 | env->ivec_status &= ~0x20; | |||
| 349 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD0x0002); | |||
| 350 | } | |||
| 351 | } | |||
| 352 | } | |||
| 353 | ||||
| 354 | typedef struct ResetData { | |||
| 355 | SPARCCPU *cpu; | |||
| 356 | uint64_t prom_addr; | |||
| 357 | } ResetData; | |||
| 358 | ||||
| 359 | void cpu_put_timer(QEMUFile *f, CPUTimer *s) | |||
| 360 | { | |||
| 361 | qemu_put_be32s(f, &s->frequency); | |||
| 362 | qemu_put_be32s(f, &s->disabled); | |||
| 363 | qemu_put_be64s(f, &s->disabled_mask); | |||
| 364 | qemu_put_sbe64s(f, &s->clock_offset); | |||
| 365 | ||||
| 366 | timer_put(f, s->qtimer); | |||
| 367 | } | |||
| 368 | ||||
| 369 | void cpu_get_timer(QEMUFile *f, CPUTimer *s) | |||
| 370 | { | |||
| 371 | qemu_get_be32s(f, &s->frequency); | |||
| 372 | qemu_get_be32s(f, &s->disabled); | |||
| 373 | qemu_get_be64s(f, &s->disabled_mask); | |||
| 374 | qemu_get_sbe64s(f, &s->clock_offset); | |||
| 375 | ||||
| 376 | timer_get(f, s->qtimer); | |||
| 377 | } | |||
| 378 | ||||
| 379 | static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, | |||
| 380 | QEMUBHFunc *cb, uint32_t frequency, | |||
| 381 | uint64_t disabled_mask) | |||
| 382 | { | |||
| 383 | CPUTimer *timer = g_malloc0(sizeof (CPUTimer)); | |||
| 384 | ||||
| 385 | timer->name = name; | |||
| 386 | timer->frequency = frequency; | |||
| 387 | timer->disabled_mask = disabled_mask; | |||
| 388 | ||||
| 389 | timer->disabled = 1; | |||
| 390 | timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |||
| 391 | ||||
| 392 | timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu); | |||
| 393 | ||||
| 394 | return timer; | |||
| 395 | } | |||
| 396 | ||||
| 397 | static void cpu_timer_reset(CPUTimer *timer) | |||
| 398 | { | |||
| 399 | timer->disabled = 1; | |||
| 400 | timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |||
| 401 | ||||
| 402 | timer_del(timer->qtimer); | |||
| 403 | } | |||
| 404 | ||||
| 405 | static void main_cpu_reset(void *opaque) | |||
| 406 | { | |||
| 407 | ResetData *s = (ResetData *)opaque; | |||
| 408 | CPUSPARCState *env = &s->cpu->env; | |||
| 409 | static unsigned int nr_resets; | |||
| 410 | ||||
| 411 | cpu_reset(CPU(s->cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((s->cpu ))), ("cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 411, __func__))); | |||
| 412 | ||||
| 413 | cpu_timer_reset(env->tick); | |||
| 414 | cpu_timer_reset(env->stick); | |||
| 415 | cpu_timer_reset(env->hstick); | |||
| 416 | ||||
| 417 | env->gregs[1] = 0; // Memory start | |||
| 418 | env->gregs[2] = ram_size; // Memory size | |||
| 419 | env->gregs[3] = 0; // Machine description XXX | |||
| 420 | if (nr_resets++ == 0) { | |||
| 421 | /* Power on reset */ | |||
| 422 | env->pc = s->prom_addr + 0x20ULL; | |||
| 423 | } else { | |||
| 424 | env->pc = s->prom_addr + 0x40ULL; | |||
| 425 | } | |||
| 426 | env->npc = env->pc + 4; | |||
| 427 | } | |||
| 428 | ||||
| 429 | static void tick_irq(void *opaque) | |||
| 430 | { | |||
| 431 | SPARCCPU *cpu = opaque; | |||
| 432 | CPUSPARCState *env = &cpu->env; | |||
| 433 | ||||
| 434 | CPUTimer* timer = env->tick; | |||
| 435 | ||||
| 436 | if (timer->disabled) { | |||
| 437 | CPUIRQ_DPRINTF("tick_irq: softint disabled\n"); | |||
| 438 | return; | |||
| 439 | } else { | |||
| 440 | CPUIRQ_DPRINTF("tick: fire\n"); | |||
| 441 | } | |||
| 442 | ||||
| 443 | env->softint |= SOFTINT_TIMER1; | |||
| 444 | cpu_kick_irq(cpu); | |||
| 445 | } | |||
| 446 | ||||
| 447 | static void stick_irq(void *opaque) | |||
| 448 | { | |||
| 449 | SPARCCPU *cpu = opaque; | |||
| 450 | CPUSPARCState *env = &cpu->env; | |||
| 451 | ||||
| 452 | CPUTimer* timer = env->stick; | |||
| 453 | ||||
| 454 | if (timer->disabled) { | |||
| 455 | CPUIRQ_DPRINTF("stick_irq: softint disabled\n"); | |||
| 456 | return; | |||
| 457 | } else { | |||
| 458 | CPUIRQ_DPRINTF("stick: fire\n"); | |||
| 459 | } | |||
| 460 | ||||
| 461 | env->softint |= SOFTINT_STIMER(1 << 16); | |||
| 462 | cpu_kick_irq(cpu); | |||
| 463 | } | |||
| 464 | ||||
| 465 | static void hstick_irq(void *opaque) | |||
| 466 | { | |||
| 467 | SPARCCPU *cpu = opaque; | |||
| 468 | CPUSPARCState *env = &cpu->env; | |||
| 469 | ||||
| 470 | CPUTimer* timer = env->hstick; | |||
| 471 | ||||
| 472 | if (timer->disabled) { | |||
| 473 | CPUIRQ_DPRINTF("hstick_irq: softint disabled\n"); | |||
| 474 | return; | |||
| 475 | } else { | |||
| 476 | CPUIRQ_DPRINTF("hstick: fire\n"); | |||
| 477 | } | |||
| 478 | ||||
| 479 | env->softint |= SOFTINT_STIMER(1 << 16); | |||
| 480 | cpu_kick_irq(cpu); | |||
| 481 | } | |||
| 482 | ||||
| 483 | static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) | |||
| 484 | { | |||
| 485 | return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency); | |||
| 486 | } | |||
| 487 | ||||
| 488 | static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency) | |||
| 489 | { | |||
| 490 | return muldiv64(timer_ticks, frequency, get_ticks_per_sec()); | |||
| 491 | } | |||
| 492 | ||||
| 493 | void cpu_tick_set_count(CPUTimer *timer, uint64_t count) | |||
| 494 | { | |||
| 495 | uint64_t real_count = count & ~timer->disabled_mask; | |||
| 496 | uint64_t disabled_bit = count & timer->disabled_mask; | |||
| 497 | ||||
| 498 | int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - | |||
| 499 | cpu_to_timer_ticks(real_count, timer->frequency); | |||
| 500 | ||||
| 501 | TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n", | |||
| 502 | timer->name, real_count, | |||
| 503 | timer->disabled?"disabled":"enabled", timer); | |||
| 504 | ||||
| 505 | timer->disabled = disabled_bit ? 1 : 0; | |||
| 506 | timer->clock_offset = vm_clock_offset; | |||
| 507 | } | |||
| 508 | ||||
| 509 | uint64_t cpu_tick_get_count(CPUTimer *timer) | |||
| 510 | { | |||
| 511 | uint64_t real_count = timer_to_cpu_ticks( | |||
| 512 | qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset, | |||
| 513 | timer->frequency); | |||
| 514 | ||||
| 515 | TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n", | |||
| 516 | timer->name, real_count, | |||
| 517 | timer->disabled?"disabled":"enabled", timer); | |||
| 518 | ||||
| 519 | if (timer->disabled) | |||
| 520 | real_count |= timer->disabled_mask; | |||
| 521 | ||||
| 522 | return real_count; | |||
| 523 | } | |||
| 524 | ||||
| 525 | void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) | |||
| 526 | { | |||
| 527 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |||
| 528 | ||||
| 529 | uint64_t real_limit = limit & ~timer->disabled_mask; | |||
| 530 | timer->disabled = (limit & timer->disabled_mask) ? 1 : 0; | |||
| 531 | ||||
| 532 | int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) + | |||
| 533 | timer->clock_offset; | |||
| 534 | ||||
| 535 | if (expires < now) { | |||
| 536 | expires = now + 1; | |||
| 537 | } | |||
| 538 | ||||
| 539 | TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p " | |||
| 540 | "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n", | |||
| 541 | timer->name, real_limit, | |||
| 542 | timer->disabled?"disabled":"enabled", | |||
| 543 | timer, limit, | |||
| 544 | timer_to_cpu_ticks(now - timer->clock_offset, | |||
| 545 | timer->frequency), | |||
| 546 | timer_to_cpu_ticks(expires - now, timer->frequency)); | |||
| 547 | ||||
| 548 | if (!real_limit) { | |||
| 549 | TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n", | |||
| 550 | timer->name); | |||
| 551 | timer_del(timer->qtimer); | |||
| 552 | } else if (timer->disabled) { | |||
| 553 | timer_del(timer->qtimer); | |||
| 554 | } else { | |||
| 555 | timer_mod(timer->qtimer, expires); | |||
| 556 | } | |||
| 557 | } | |||
| 558 | ||||
| 559 | static void isa_irq_handler(void *opaque, int n, int level) | |||
| 560 | { | |||
| 561 | static const int isa_irq_to_ivec[16] = { | |||
| 562 | [1] = 0x29, /* keyboard */ | |||
| 563 | [4] = 0x2b, /* serial */ | |||
| 564 | [6] = 0x27, /* floppy */ | |||
| 565 | [7] = 0x22, /* parallel */ | |||
| 566 | [12] = 0x2a, /* mouse */ | |||
| 567 | }; | |||
| 568 | qemu_irq *irqs = opaque; | |||
| 569 | int ivec; | |||
| 570 | ||||
| 571 | assert(n < 16)((n < 16) ? (void) (0) : __assert_fail ("n < 16", "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 571, __PRETTY_FUNCTION__)); | |||
| 572 | ivec = isa_irq_to_ivec[n]; | |||
| 573 | EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec); | |||
| 574 | if (ivec) { | |||
| 575 | qemu_set_irq(irqs[ivec], level); | |||
| 576 | } | |||
| 577 | } | |||
| 578 | ||||
| 579 | /* EBUS (Eight bit bus) bridge */ | |||
| 580 | static ISABus * | |||
| 581 | pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs) | |||
| 582 | { | |||
| 583 | qemu_irq *isa_irq; | |||
| 584 | PCIDevice *pci_dev; | |||
| 585 | ISABus *isa_bus; | |||
| 586 | ||||
| 587 | pci_dev = pci_create_simple(bus, devfn, "ebus"); | |||
| 588 | isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0"))((ISABus *)object_dynamic_cast_assert(((Object *)((qdev_get_child_bus (((DeviceState *)object_dynamic_cast_assert(((Object *)((pci_dev ))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 588, __func__)), "isa.0")))), ("ISA"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 588, __func__)); | |||
| 589 | isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); | |||
| 590 | isa_bus_irqs(isa_bus, isa_irq); | |||
| 591 | return isa_bus; | |||
| 592 | } | |||
| 593 | ||||
| 594 | static int | |||
| 595 | pci_ebus_init1(PCIDevice *pci_dev) | |||
| 596 | { | |||
| 597 | EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(EbusState, pci_dev)]; ({ const typeof(( (EbusState *) 0)->pci_dev) *__mptr = (pci_dev); (EbusState *) ((char *) __mptr - __builtin_offsetof(EbusState, pci_dev) );});})); | |||
| 598 | ||||
| 599 | isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev)); | |||
| 600 | ||||
| 601 | pci_dev->config[0x04] = 0x06; // command = bus master, pci mem | |||
| 602 | pci_dev->config[0x05] = 0x00; | |||
| 603 | pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error | |||
| 604 | pci_dev->config[0x07] = 0x03; // status = medium devsel | |||
| 605 | pci_dev->config[0x09] = 0x00; // programming i/f | |||
| 606 | pci_dev->config[0x0D] = 0x0a; // latency_timer | |||
| 607 | ||||
| 608 | memory_region_init_alias(&s->bar0, OBJECT(s)((Object *)(s)), "bar0", get_system_io(), | |||
| 609 | 0, 0x1000000); | |||
| 610 | pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY0x00, &s->bar0); | |||
| 611 | memory_region_init_alias(&s->bar1, OBJECT(s)((Object *)(s)), "bar1", get_system_io(), | |||
| 612 | 0, 0x800000); | |||
| 613 | pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY0x00, &s->bar1); | |||
| 614 | return 0; | |||
| 615 | } | |||
| 616 | ||||
| 617 | static void ebus_class_init(ObjectClass *klass, void *data) | |||
| 618 | { | |||
| 619 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass)((PCIDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("pci-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 619, __func__)); | |||
| 620 | ||||
| 621 | k->init = pci_ebus_init1; | |||
| 622 | k->vendor_id = PCI_VENDOR_ID_SUN0x108e; | |||
| 623 | k->device_id = PCI_DEVICE_ID_SUN_EBUS0x1000; | |||
| 624 | k->revision = 0x01; | |||
| 625 | k->class_id = PCI_CLASS_BRIDGE_OTHER0x0680; | |||
| 626 | } | |||
| 627 | ||||
| 628 | static const TypeInfo ebus_info = { | |||
| 629 | .name = "ebus", | |||
| 630 | .parent = TYPE_PCI_DEVICE"pci-device", | |||
| 631 | .instance_size = sizeof(EbusState), | |||
| 632 | .class_init = ebus_class_init, | |||
| 633 | }; | |||
| 634 | ||||
| 635 | #define TYPE_OPENPROM"openprom" "openprom" | |||
| 636 | #define OPENPROM(obj)((PROMState *)object_dynamic_cast_assert(((Object *)((obj))), ("openprom"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 636, __func__)) OBJECT_CHECK(PROMState, (obj), TYPE_OPENPROM)((PROMState *)object_dynamic_cast_assert(((Object *)((obj))), ("openprom"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 636, __func__)) | |||
| 637 | ||||
| 638 | typedef struct PROMState { | |||
| 639 | SysBusDevice parent_obj; | |||
| 640 | ||||
| 641 | MemoryRegion prom; | |||
| 642 | } PROMState; | |||
| 643 | ||||
| 644 | static uint64_t translate_prom_address(void *opaque, uint64_t addr) | |||
| 645 | { | |||
| 646 | hwaddr *base_addr = (hwaddr *)opaque; | |||
| 647 | return addr + *base_addr - PROM_VADDR0x000ffd00000ULL; | |||
| 648 | } | |||
| 649 | ||||
| 650 | /* Boot PROM (OpenBIOS) */ | |||
| 651 | static void prom_init(hwaddr addr, const char *bios_name) | |||
| 652 | { | |||
| 653 | DeviceState *dev; | |||
| 654 | SysBusDevice *s; | |||
| 655 | char *filename; | |||
| 656 | int ret; | |||
| 657 | ||||
| 658 | dev = qdev_create(NULL((void*)0), TYPE_OPENPROM"openprom"); | |||
| 659 | qdev_init_nofail(dev); | |||
| 660 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 660, __func__)); | |||
| 661 | ||||
| 662 | sysbus_mmio_map(s, 0, addr); | |||
| 663 | ||||
| 664 | /* load boot prom */ | |||
| 665 | if (bios_name == NULL((void*)0)) { | |||
| 666 | bios_name = PROM_FILENAME"openbios-sparc64"; | |||
| 667 | } | |||
| 668 | filename = qemu_find_file(QEMU_FILE_TYPE_BIOS0, bios_name); | |||
| 669 | if (filename) { | |||
| 670 | ret = load_elf(filename, translate_prom_address, &addr, | |||
| 671 | NULL((void*)0), NULL((void*)0), NULL((void*)0), 1, ELF_MACHINE43, 0); | |||
| 672 | if (ret < 0 || ret > PROM_SIZE_MAX(4 * 1024 * 1024)) { | |||
| 673 | ret = load_image_targphys(filename, addr, PROM_SIZE_MAX(4 * 1024 * 1024)); | |||
| 674 | } | |||
| 675 | g_free(filename); | |||
| 676 | } else { | |||
| 677 | ret = -1; | |||
| 678 | } | |||
| 679 | if (ret < 0 || ret > PROM_SIZE_MAX(4 * 1024 * 1024)) { | |||
| 680 | fprintf(stderrstderr, "qemu: could not load prom '%s'\n", bios_name); | |||
| 681 | exit(1); | |||
| 682 | } | |||
| 683 | } | |||
| 684 | ||||
| 685 | static int prom_init1(SysBusDevice *dev) | |||
| 686 | { | |||
| 687 | PROMState *s = OPENPROM(dev)((PROMState *)object_dynamic_cast_assert(((Object *)((dev))), ("openprom"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 687, __func__)); | |||
| 688 | ||||
| 689 | memory_region_init_ram(&s->prom, OBJECT(s)((Object *)(s)), "sun4u.prom", PROM_SIZE_MAX(4 * 1024 * 1024)); | |||
| 690 | vmstate_register_ram_global(&s->prom); | |||
| 691 | memory_region_set_readonly(&s->prom, true1); | |||
| 692 | sysbus_init_mmio(dev, &s->prom); | |||
| 693 | return 0; | |||
| 694 | } | |||
| 695 | ||||
| 696 | static Property prom_properties[] = { | |||
| 697 | {/* end of property list */}, | |||
| 698 | }; | |||
| 699 | ||||
| 700 | static void prom_class_init(ObjectClass *klass, void *data) | |||
| 701 | { | |||
| 702 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 702, __func__)); | |||
| 703 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass)((SysBusDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 703, __func__)); | |||
| 704 | ||||
| 705 | k->init = prom_init1; | |||
| 706 | dc->props = prom_properties; | |||
| 707 | } | |||
| 708 | ||||
| 709 | static const TypeInfo prom_info = { | |||
| 710 | .name = TYPE_OPENPROM"openprom", | |||
| 711 | .parent = TYPE_SYS_BUS_DEVICE"sys-bus-device", | |||
| 712 | .instance_size = sizeof(PROMState), | |||
| 713 | .class_init = prom_class_init, | |||
| 714 | }; | |||
| 715 | ||||
| 716 | ||||
| 717 | #define TYPE_SUN4U_MEMORY"memory" "memory" | |||
| 718 | #define SUN4U_RAM(obj)((RamDevice *)object_dynamic_cast_assert(((Object *)((obj))), ("memory"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 718, __func__)) OBJECT_CHECK(RamDevice, (obj), TYPE_SUN4U_MEMORY)((RamDevice *)object_dynamic_cast_assert(((Object *)((obj))), ("memory"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 718, __func__)) | |||
| 719 | ||||
| 720 | typedef struct RamDevice { | |||
| 721 | SysBusDevice parent_obj; | |||
| 722 | ||||
| 723 | MemoryRegion ram; | |||
| 724 | uint64_t size; | |||
| 725 | } RamDevice; | |||
| 726 | ||||
| 727 | /* System RAM */ | |||
| 728 | static int ram_init1(SysBusDevice *dev) | |||
| 729 | { | |||
| 730 | RamDevice *d = SUN4U_RAM(dev)((RamDevice *)object_dynamic_cast_assert(((Object *)((dev))), ("memory"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 730, __func__)); | |||
| 731 | ||||
| 732 | memory_region_init_ram(&d->ram, OBJECT(d)((Object *)(d)), "sun4u.ram", d->size); | |||
| 733 | vmstate_register_ram_global(&d->ram); | |||
| 734 | sysbus_init_mmio(dev, &d->ram); | |||
| 735 | return 0; | |||
| 736 | } | |||
| 737 | ||||
| 738 | static void ram_init(hwaddr addr, ram_addr_t RAM_size) | |||
| 739 | { | |||
| 740 | DeviceState *dev; | |||
| 741 | SysBusDevice *s; | |||
| 742 | RamDevice *d; | |||
| 743 | ||||
| 744 | /* allocate RAM */ | |||
| 745 | dev = qdev_create(NULL((void*)0), TYPE_SUN4U_MEMORY"memory"); | |||
| 746 | s = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 746, __func__)); | |||
| 747 | ||||
| 748 | d = SUN4U_RAM(dev)((RamDevice *)object_dynamic_cast_assert(((Object *)((dev))), ("memory"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 748, __func__)); | |||
| 749 | d->size = RAM_size; | |||
| 750 | qdev_init_nofail(dev); | |||
| 751 | ||||
| 752 | sysbus_mmio_map(s, 0, addr); | |||
| 753 | } | |||
| 754 | ||||
| 755 | static Property ram_properties[] = { | |||
| 756 | DEFINE_PROP_UINT64("size", RamDevice, size, 0){ .name = ("size"), .info = &(qdev_prop_uint64), .offset = __builtin_offsetof(RamDevice, size) + ((uint64_t*)0 - (typeof (((RamDevice *)0)->size)*)0), .qtype = QTYPE_QINT, .defval = (uint64_t)0, }, | |||
| 757 | DEFINE_PROP_END_OF_LIST(){}, | |||
| 758 | }; | |||
| 759 | ||||
| 760 | static void ram_class_init(ObjectClass *klass, void *data) | |||
| 761 | { | |||
| 762 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 762, __func__)); | |||
| 763 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass)((SysBusDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/sparc64/sun4u.c" , 763, __func__)); | |||
| 764 | ||||
| 765 | k->init = ram_init1; | |||
| 766 | dc->props = ram_properties; | |||
| 767 | } | |||
| 768 | ||||
| 769 | static const TypeInfo ram_info = { | |||
| 770 | .name = TYPE_SUN4U_MEMORY"memory", | |||
| 771 | .parent = TYPE_SYS_BUS_DEVICE"sys-bus-device", | |||
| 772 | .instance_size = sizeof(RamDevice), | |||
| 773 | .class_init = ram_class_init, | |||
| 774 | }; | |||
| 775 | ||||
| 776 | static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) | |||
| 777 | { | |||
| 778 | SPARCCPU *cpu; | |||
| 779 | CPUSPARCState *env; | |||
| 780 | ResetData *reset_info; | |||
| 781 | ||||
| 782 | uint32_t tick_frequency = 100*1000000; | |||
| 783 | uint32_t stick_frequency = 100*1000000; | |||
| 784 | uint32_t hstick_frequency = 100*1000000; | |||
| 785 | ||||
| 786 | if (cpu_model == NULL((void*)0)) { | |||
| 787 | cpu_model = hwdef->default_cpu_model; | |||
| 788 | } | |||
| 789 | cpu = cpu_sparc_init(cpu_model); | |||
| 790 | if (cpu == NULL((void*)0)) { | |||
| 791 | fprintf(stderrstderr, "Unable to find Sparc CPU definition\n"); | |||
| 792 | exit(1); | |||
| 793 | } | |||
| 794 | env = &cpu->env; | |||
| 795 | ||||
| 796 | env->tick = cpu_timer_create("tick", cpu, tick_irq, | |||
| 797 | tick_frequency, TICK_NPT_MASK0x8000000000000000ULL); | |||
| 798 | ||||
| 799 | env->stick = cpu_timer_create("stick", cpu, stick_irq, | |||
| 800 | stick_frequency, TICK_INT_DIS0x8000000000000000ULL); | |||
| 801 | ||||
| 802 | env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, | |||
| 803 | hstick_frequency, TICK_INT_DIS0x8000000000000000ULL); | |||
| 804 | ||||
| 805 | reset_info = g_malloc0(sizeof(ResetData)); | |||
| 806 | reset_info->cpu = cpu; | |||
| 807 | reset_info->prom_addr = hwdef->prom_addr; | |||
| 808 | qemu_register_reset(main_cpu_reset, reset_info); | |||
| 809 | ||||
| 810 | return cpu; | |||
| 811 | } | |||
| 812 | ||||
| 813 | static void sun4uv_init(MemoryRegion *address_space_mem, | |||
| 814 | QEMUMachineInitArgs *args, | |||
| 815 | const struct hwdef *hwdef) | |||
| 816 | { | |||
| 817 | SPARCCPU *cpu; | |||
| 818 | M48t59State *nvram; | |||
| 819 | unsigned int i; | |||
| 820 | uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; | |||
| 821 | PCIBus *pci_bus, *pci_bus2, *pci_bus3; | |||
| 822 | ISABus *isa_bus; | |||
| 823 | qemu_irq *ivec_irqs, *pbm_irqs; | |||
| 824 | DriveInfo *hd[MAX_IDE_BUS2 * MAX_IDE_DEVS2]; | |||
| 825 | DriveInfo *fd[MAX_FD2]; | |||
| 826 | FWCfgState *fw_cfg; | |||
| 827 | ||||
| 828 | /* init CPUs */ | |||
| 829 | cpu = cpu_devinit(args->cpu_model, hwdef); | |||
| 830 | ||||
| 831 | /* set up devices */ | |||
| 832 | ram_init(0, args->ram_size); | |||
| 833 | ||||
| 834 | prom_init(hwdef->prom_addr, bios_name); | |||
| 835 | ||||
| 836 | ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX0x40); | |||
| 837 | pci_bus = pci_apb_init(APB_SPECIAL_BASE0x1fe00000000ULL, APB_MEM_BASE0x1ff00000000ULL, ivec_irqs, &pci_bus2, | |||
| 838 | &pci_bus3, &pbm_irqs); | |||
| 839 | pci_vga_init(pci_bus); | |||
| 840 | ||||
| 841 | // XXX Should be pci_bus3 | |||
| 842 | isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); | |||
| 843 | ||||
| 844 | i = 0; | |||
| 845 | if (hwdef->console_serial_base) { | |||
| 846 | serial_mm_init(address_space_mem, hwdef->console_serial_base, 0, | |||
| 847 | NULL((void*)0), 115200, serial_hds[i], DEVICE_BIG_ENDIAN); | |||
| 848 | i++; | |||
| 849 | } | |||
| 850 | for(; i < MAX_SERIAL_PORTS4; i++) { | |||
| 851 | if (serial_hds[i]) { | |||
| 852 | serial_isa_init(isa_bus, i, serial_hds[i]); | |||
| 853 | } | |||
| 854 | } | |||
| 855 | ||||
| 856 | for(i = 0; i < MAX_PARALLEL_PORTS3; i++) { | |||
| 857 | if (parallel_hds[i]) { | |||
| 858 | parallel_init(isa_bus, i, parallel_hds[i]); | |||
| 859 | } | |||
| 860 | } | |||
| 861 | ||||
| 862 | for(i = 0; i < nb_nics; i++) | |||
| 863 | pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL((void*)0)); | |||
| 864 | ||||
| 865 | ide_drive_get(hd, MAX_IDE_BUS2); | |||
| 866 | ||||
| 867 | pci_cmd646_ide_init(pci_bus, hd, 1); | |||
| 868 | ||||
| 869 | isa_create_simple(isa_bus, "i8042"); | |||
| 870 | for(i = 0; i < MAX_FD2; i++) { | |||
| 871 | fd[i] = drive_get(IF_FLOPPY, 0, i); | |||
| 872 | } | |||
| 873 | fdctrl_init_isa(isa_bus, fd); | |||
| 874 | nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE0x2000, 59); | |||
| 875 | ||||
| 876 | initrd_size = 0; | |||
| 877 | initrd_addr = 0; | |||
| 878 | kernel_size = sun4u_load_kernel(args->kernel_filename, | |||
| 879 | args->initrd_filename, | |||
| 880 | ram_size, &initrd_size, &initrd_addr, | |||
| 881 | &kernel_addr, &kernel_entry); | |||
| 882 | ||||
| 883 | sun4u_NVRAM_set_params(nvram, NVRAM_SIZE0x2000, "Sun4u", args->ram_size, | |||
| ||||
| 884 | args->boot_order, | |||
| 885 | kernel_addr, kernel_size, | |||
| 886 | args->kernel_cmdline, | |||
| 887 | initrd_addr, initrd_size, | |||
| 888 | /* XXX: need an option to load a NVRAM image */ | |||
| 889 | 0, | |||
| 890 | graphic_width, graphic_height, graphic_depth, | |||
| 891 | (uint8_t *)&nd_table[0].macaddr); | |||
| 892 | ||||
| 893 | fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT0x510, BIOS_CFG_IOPORT0x510 + 1, 0, 0); | |||
| 894 | fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS0x0f, (uint16_t)max_cpus); | |||
| 895 | fw_cfg_add_i32(fw_cfg, FW_CFG_ID0x01, 1); | |||
| 896 | fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE0x03, (uint64_t)ram_size); | |||
| 897 | fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID0x06, hwdef->machine_id); | |||
| 898 | fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR0x07, kernel_entry); | |||
| 899 | fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE0x08, kernel_size); | |||
| 900 | if (args->kernel_cmdline) { | |||
| 901 | fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE0x14, | |||
| 902 | strlen(args->kernel_cmdline) + 1); | |||
| 903 | fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA0x15, args->kernel_cmdline); | |||
| 904 | } else { | |||
| 905 | fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE0x14, 0); | |||
| 906 | } | |||
| 907 | fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR0x0a, initrd_addr); | |||
| 908 | fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE0x0b, initrd_size); | |||
| 909 | fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE0x0c, args->boot_order[0]); | |||
| 910 | ||||
| 911 | fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH(0x8000 + 0x00), graphic_width); | |||
| 912 | fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT(0x8000 + 0x01), graphic_height); | |||
| 913 | fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH(0x8000 + 0x02), graphic_depth); | |||
| 914 | ||||
| 915 | qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); | |||
| 916 | } | |||
| 917 | ||||
| 918 | enum { | |||
| 919 | sun4u_id = 0, | |||
| 920 | sun4v_id = 64, | |||
| 921 | niagara_id, | |||
| 922 | }; | |||
| 923 | ||||
| 924 | static const struct hwdef hwdefs[] = { | |||
| 925 | /* Sun4u generic PC-like machine */ | |||
| 926 | { | |||
| 927 | .default_cpu_model = "TI UltraSparc IIi", | |||
| 928 | .machine_id = sun4u_id, | |||
| 929 | .prom_addr = 0x1fff0000000ULL, | |||
| 930 | .console_serial_base = 0, | |||
| 931 | }, | |||
| 932 | /* Sun4v generic PC-like machine */ | |||
| 933 | { | |||
| 934 | .default_cpu_model = "Sun UltraSparc T1", | |||
| 935 | .machine_id = sun4v_id, | |||
| 936 | .prom_addr = 0x1fff0000000ULL, | |||
| 937 | .console_serial_base = 0, | |||
| 938 | }, | |||
| 939 | /* Sun4v generic Niagara machine */ | |||
| 940 | { | |||
| 941 | .default_cpu_model = "Sun UltraSparc T1", | |||
| 942 | .machine_id = niagara_id, | |||
| 943 | .prom_addr = 0xfff0000000ULL, | |||
| 944 | .console_serial_base = 0xfff0c2c000ULL, | |||
| 945 | }, | |||
| 946 | }; | |||
| 947 | ||||
| 948 | /* Sun4u hardware initialisation */ | |||
| 949 | static void sun4u_init(QEMUMachineInitArgs *args) | |||
| 950 | { | |||
| 951 | sun4uv_init(get_system_memory(), args, &hwdefs[0]); | |||
| 952 | } | |||
| 953 | ||||
| 954 | /* Sun4v hardware initialisation */ | |||
| 955 | static void sun4v_init(QEMUMachineInitArgs *args) | |||
| 956 | { | |||
| 957 | sun4uv_init(get_system_memory(), args, &hwdefs[1]); | |||
| 958 | } | |||
| 959 | ||||
| 960 | /* Niagara hardware initialisation */ | |||
| 961 | static void niagara_init(QEMUMachineInitArgs *args) | |||
| 962 | { | |||
| 963 | sun4uv_init(get_system_memory(), args, &hwdefs[2]); | |||
| ||||
| 964 | } | |||
| 965 | ||||
| 966 | static QEMUMachine sun4u_machine = { | |||
| 967 | .name = "sun4u", | |||
| 968 | .desc = "Sun4u platform", | |||
| 969 | .init = sun4u_init, | |||
| 970 | .max_cpus = 1, // XXX for now | |||
| 971 | .is_default = 1, | |||
| 972 | .default_boot_order = "c", | |||
| 973 | }; | |||
| 974 | ||||
| 975 | static QEMUMachine sun4v_machine = { | |||
| 976 | .name = "sun4v", | |||
| 977 | .desc = "Sun4v platform", | |||
| 978 | .init = sun4v_init, | |||
| 979 | .max_cpus = 1, // XXX for now | |||
| 980 | .default_boot_order = "c", | |||
| 981 | }; | |||
| 982 | ||||
| 983 | static QEMUMachine niagara_machine = { | |||
| 984 | .name = "Niagara", | |||
| 985 | .desc = "Sun4v platform, Niagara", | |||
| 986 | .init = niagara_init, | |||
| 987 | .max_cpus = 1, // XXX for now | |||
| 988 | .default_boot_order = "c", | |||
| 989 | }; | |||
| 990 | ||||
| 991 | static void sun4u_register_types(void) | |||
| 992 | { | |||
| 993 | type_register_static(&ebus_info); | |||
| 994 | type_register_static(&prom_info); | |||
| 995 | type_register_static(&ram_info); | |||
| 996 | } | |||
| 997 | ||||
| 998 | static void sun4u_machine_init(void) | |||
| 999 | { | |||
| 1000 | qemu_register_machine(&sun4u_machine); | |||
| 1001 | qemu_register_machine(&sun4v_machine); | |||
| 1002 | qemu_register_machine(&niagara_machine); | |||
| 1003 | } | |||
| 1004 | ||||
| 1005 | type_init(sun4u_register_types)static void __attribute__((constructor)) do_qemu_init_sun4u_register_types (void) { register_module_init(sun4u_register_types, MODULE_INIT_QOM ); } | |||
| 1006 | machine_init(sun4u_machine_init)static void __attribute__((constructor)) do_qemu_init_sun4u_machine_init (void) { register_module_init(sun4u_machine_init, MODULE_INIT_MACHINE ); }; |