blob: 47bcf9382dd530dd9499d3dbd21b279394af905b [file] [log] [blame]
bellard34751872005-07-02 14:31:34 +00001/*
blueswir1c7ba2182008-07-22 07:07:34 +00002 * QEMU Sun4u/Sun4v System Emulator
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard34751872005-07-02 14:31:34 +00004 * Copyright (c) 2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellard34751872005-07-02 14:31:34 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "hw.h"
Michael S. Tsirkina2cb15b2012-12-12 14:24:50 +020025#include "pci/pci.h"
Michael S. Tsirkin18e08a52009-11-11 14:59:56 +020026#include "apb_pci.h"
pbrook87ecb682007-11-17 17:14:51 +000027#include "pc.h"
Gerd Hoffmann488cb992012-10-17 09:54:19 +020028#include "serial.h"
pbrook87ecb682007-11-17 17:14:51 +000029#include "nvram.h"
30#include "fdc.h"
31#include "net.h"
32#include "qemu-timer.h"
33#include "sysemu.h"
34#include "boards.h"
blueswir1d2c63fc2007-11-14 19:35:16 +000035#include "firmware_abi.h"
blueswir13cce6242008-09-18 18:27:29 +000036#include "fw_cfg.h"
Blue Swirl1baffa42009-07-21 09:58:02 +000037#include "sysbus.h"
Gerd Hoffmann977e1242009-08-20 15:22:20 +020038#include "ide.h"
Blue Swirlca20cf32009-09-20 14:58:02 +000039#include "loader.h"
40#include "elf.h"
Blue Swirl24463332010-08-24 15:22:24 +000041#include "blockdev.h"
Richard Henderson39186d82011-08-11 16:07:16 -070042#include "exec-memory.h"
bellard34751872005-07-02 14:31:34 +000043
blueswir19d926592008-09-22 19:50:28 +000044//#define DEBUG_IRQ
Blue Swirlb430a222009-12-30 12:27:17 +000045//#define DEBUG_EBUS
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +030046//#define DEBUG_TIMER
blueswir19d926592008-09-22 19:50:28 +000047
48#ifdef DEBUG_IRQ
Blue Swirlb430a222009-12-30 12:27:17 +000049#define CPUIRQ_DPRINTF(fmt, ...) \
Blue Swirl001faf32009-05-13 17:53:17 +000050 do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
blueswir19d926592008-09-22 19:50:28 +000051#else
Blue Swirlb430a222009-12-30 12:27:17 +000052#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, ...)
blueswir19d926592008-09-22 19:50:28 +000060#endif
61
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +030062#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
bellard83469012005-07-23 14:27:54 +000069#define KERNEL_LOAD_ADDR 0x00404000
70#define CMDLINE_ADDR 0x003ff000
blueswir1ac2e9d62008-04-27 15:29:18 +000071#define PROM_SIZE_MAX (4 * 1024 * 1024)
blueswir1f930d072007-10-06 11:28:21 +000072#define PROM_VADDR 0x000ffd00000ULL
bellard83469012005-07-23 14:27:54 +000073#define APB_SPECIAL_BASE 0x1fe00000000ULL
blueswir1f930d072007-10-06 11:28:21 +000074#define APB_MEM_BASE 0x1ff00000000ULL
Igor V. Kovalenkod63baf92010-05-25 16:09:03 +040075#define APB_PCI_IO_BASE (APB_SPECIAL_BASE + 0x02000000ULL)
blueswir1f930d072007-10-06 11:28:21 +000076#define PROM_FILENAME "openbios-sparc64"
bellard83469012005-07-23 14:27:54 +000077#define NVRAM_SIZE 0x2000
thse4bcb142007-12-02 04:51:10 +000078#define MAX_IDE_BUS 2
blueswir13cce6242008-09-18 18:27:29 +000079#define BIOS_CFG_IOPORT 0x510
Blue Swirl75896902009-08-08 10:44:56 +000080#define FW_CFG_SPARC64_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
81#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
82#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
bellard34751872005-07-02 14:31:34 +000083
Blue Swirl361dea42012-03-10 20:37:00 +000084#define IVEC_MAX 0x30
blueswir19d926592008-09-22 19:50:28 +000085
blueswir18fa211e2008-12-23 08:47:26 +000086#define TICK_MAX 0x7fffffffffffffffULL
87
blueswir1c7ba2182008-07-22 07:07:34 +000088struct hwdef {
89 const char * const default_cpu_model;
blueswir1905fdcb2008-09-18 18:33:18 +000090 uint16_t machine_id;
blueswir1e87231d2008-09-26 19:48:58 +000091 uint64_t prom_addr;
92 uint64_t console_serial_base;
blueswir1c7ba2182008-07-22 07:07:34 +000093};
94
Avi Kivityc5e6fb72011-08-08 16:09:22 +030095typedef struct EbusState {
96 PCIDevice pci_dev;
97 MemoryRegion bar0;
98 MemoryRegion bar1;
99} EbusState;
100
bellard34751872005-07-02 14:31:34 +0000101int DMA_get_channel_mode (int nchan)
102{
103 return 0;
104}
105int DMA_read_memory (int nchan, void *buf, int pos, int size)
106{
107 return 0;
108}
109int DMA_write_memory (int nchan, void *buf, int pos, int size)
110{
111 return 0;
112}
113void DMA_hold_DREQ (int nchan) {}
114void DMA_release_DREQ (int nchan) {}
115void DMA_schedule(int nchan) {}
Blue Swirl4556bd82010-05-22 08:00:52 +0000116
117void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
118{
119}
120
bellard34751872005-07-02 14:31:34 +0000121void DMA_register_channel (int nchan,
122 DMA_transfer_handler transfer_handler,
123 void *opaque)
124{
125}
126
blueswir1513f7892009-03-08 09:51:29 +0000127static int fw_cfg_boot_set(void *opaque, const char *boot_device)
blueswir181864572008-06-20 16:25:56 +0000128{
blueswir1513f7892009-03-08 09:51:29 +0000129 fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
blueswir181864572008-06-20 16:25:56 +0000130 return 0;
131}
132
Blue Swirl43a34702010-02-07 08:05:03 +0000133static 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)
bellard34751872005-07-02 14:31:34 +0000142{
blueswir166508602007-05-01 14:16:52 +0000143 unsigned int i;
144 uint32_t start, end;
blueswir1d2c63fc2007-11-14 19:35:16 +0000145 uint8_t image[0x1ff0];
blueswir1d2c63fc2007-11-14 19:35:16 +0000146 struct OpenBIOS_nvpart_v1 *part_header;
bellard34751872005-07-02 14:31:34 +0000147
blueswir1d2c63fc2007-11-14 19:35:16 +0000148 memset(image, '\0', sizeof(image));
149
blueswir1513f7892009-03-08 09:51:29 +0000150 start = 0;
bellard34751872005-07-02 14:31:34 +0000151
blueswir166508602007-05-01 14:16:52 +0000152 // OpenBIOS nvram variables
153 // Variable partition
blueswir1d2c63fc2007-11-14 19:35:16 +0000154 part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
155 part_header->signature = OPENBIOS_PART_SYSTEM;
blueswir1363a37d2008-08-21 17:58:08 +0000156 pstrcpy(part_header->name, sizeof(part_header->name), "system");
blueswir166508602007-05-01 14:16:52 +0000157
blueswir1d2c63fc2007-11-14 19:35:16 +0000158 end = start + sizeof(struct OpenBIOS_nvpart_v1);
blueswir166508602007-05-01 14:16:52 +0000159 for (i = 0; i < nb_prom_envs; i++)
blueswir1d2c63fc2007-11-14 19:35:16 +0000160 end = OpenBIOS_set_var(image, end, prom_envs[i]);
blueswir166508602007-05-01 14:16:52 +0000161
blueswir1d2c63fc2007-11-14 19:35:16 +0000162 // End marker
163 image[end++] = '\0';
164
blueswir166508602007-05-01 14:16:52 +0000165 end = start + ((end - start + 15) & ~15);
blueswir1d2c63fc2007-11-14 19:35:16 +0000166 OpenBIOS_finish_partition(part_header, end - start);
blueswir166508602007-05-01 14:16:52 +0000167
168 // free partition
169 start = end;
blueswir1d2c63fc2007-11-14 19:35:16 +0000170 part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
171 part_header->signature = OPENBIOS_PART_FREE;
blueswir1363a37d2008-08-21 17:58:08 +0000172 pstrcpy(part_header->name, sizeof(part_header->name), "free");
blueswir166508602007-05-01 14:16:52 +0000173
174 end = 0x1fd0;
blueswir1d2c63fc2007-11-14 19:35:16 +0000175 OpenBIOS_finish_partition(part_header, end - start);
176
blueswir10d31cb92008-07-15 14:54:01 +0000177 Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
178
blueswir1d2c63fc2007-11-14 19:35:16 +0000179 for (i = 0; i < sizeof(image); i++)
180 m48t59_write(nvram, i, image[i]);
blueswir166508602007-05-01 14:16:52 +0000181
bellard83469012005-07-23 14:27:54 +0000182 return 0;
bellard34751872005-07-02 14:31:34 +0000183}
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000184
185static 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)
Blue Swirl636aa702009-07-21 10:49:47 +0000190{
191 int linux_boot;
192 unsigned int i;
193 long kernel_size;
Blue Swirl6908d9c2010-01-24 21:18:00 +0000194 uint8_t *ptr;
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000195 uint64_t kernel_top;
Blue Swirl636aa702009-07-21 10:49:47 +0000196
197 linux_boot = (kernel_filename != NULL);
198
199 kernel_size = 0;
200 if (linux_boot) {
Blue Swirlca20cf32009-09-20 14:58:02 +0000201 int bswap_needed;
202
203#ifdef BSWAP_NEEDED
204 bswap_needed = 1;
205#else
206 bswap_needed = 0;
207#endif
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000208 kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
209 kernel_addr, &kernel_top, 1, ELF_MACHINE, 0);
210 if (kernel_size < 0) {
211 *kernel_addr = KERNEL_LOAD_ADDR;
212 *kernel_entry = KERNEL_LOAD_ADDR;
Blue Swirl636aa702009-07-21 10:49:47 +0000213 kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
Blue Swirlca20cf32009-09-20 14:58:02 +0000214 RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
215 TARGET_PAGE_SIZE);
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000216 }
217 if (kernel_size < 0) {
Blue Swirl636aa702009-07-21 10:49:47 +0000218 kernel_size = load_image_targphys(kernel_filename,
219 KERNEL_LOAD_ADDR,
220 RAM_size - KERNEL_LOAD_ADDR);
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000221 }
Blue Swirl636aa702009-07-21 10:49:47 +0000222 if (kernel_size < 0) {
223 fprintf(stderr, "qemu: could not load kernel '%s'\n",
224 kernel_filename);
225 exit(1);
226 }
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000227 /* load initrd above kernel */
Blue Swirl636aa702009-07-21 10:49:47 +0000228 *initrd_size = 0;
229 if (initrd_filename) {
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000230 *initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
231
Blue Swirl636aa702009-07-21 10:49:47 +0000232 *initrd_size = load_image_targphys(initrd_filename,
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000233 *initrd_addr,
234 RAM_size - *initrd_addr);
235 if ((int)*initrd_size < 0) {
Blue Swirl636aa702009-07-21 10:49:47 +0000236 fprintf(stderr, "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; i += TARGET_PAGE_SIZE) {
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000243 ptr = rom_ptr(*kernel_addr + i);
Blue Swirl6908d9c2010-01-24 21:18:00 +0000244 if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000245 stl_p(ptr + 24, *initrd_addr + *kernel_addr);
Blue Swirl6908d9c2010-01-24 21:18:00 +0000246 stl_p(ptr + 28, *initrd_size);
Blue Swirl636aa702009-07-21 10:49:47 +0000247 break;
248 }
249 }
250 }
251 }
252 return kernel_size;
253}
bellard34751872005-07-02 14:31:34 +0000254
Andreas Färber98cec4a2012-03-14 01:38:24 +0100255void cpu_check_irqs(CPUSPARCState *env)
blueswir19d926592008-09-22 19:50:28 +0000256{
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300257 uint32_t pil = env->pil_in |
258 (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
blueswir19d926592008-09-22 19:50:28 +0000259
Artyom Tarasenkoa7be9ba2012-04-03 17:49:05 +0200260 /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
261 if (env->ivec_status & 0x20) {
262 return;
263 }
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300264 /* check if TM or SM in SOFTINT are set
265 setting these also causes interrupt 14 */
266 if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
267 pil |= 1 << 14;
268 }
269
Artyom Tarasenko9f947782011-07-25 19:22:38 +0200270 /* The bit corresponding to psrpil is (1<< psrpil), the next bit
271 is (2 << psrpil). */
272 if (pil < (2 << env->psrpil)){
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300273 if (env->interrupt_request & CPU_INTERRUPT_HARD) {
274 CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
275 env->interrupt_index);
276 env->interrupt_index = 0;
277 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
278 }
279 return;
280 }
281
282 if (cpu_interrupts_enabled(env)) {
283
blueswir19d926592008-09-22 19:50:28 +0000284 unsigned int i;
285
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300286 for (i = 15; i > env->psrpil; i--) {
blueswir19d926592008-09-22 19:50:28 +0000287 if (pil & (1 << i)) {
288 int old_interrupt = env->interrupt_index;
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300289 int new_interrupt = TT_EXTINT | i;
blueswir19d926592008-09-22 19:50:28 +0000290
Artyom Tarasenkoa7be9ba2012-04-03 17:49:05 +0200291 if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
292 && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300293 CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
294 "current %x >= pending %x\n",
295 env->tl, cpu_tsptr(env)->tt, new_interrupt);
296 } else if (old_interrupt != new_interrupt) {
297 env->interrupt_index = new_interrupt;
298 CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
299 old_interrupt, new_interrupt);
blueswir19d926592008-09-22 19:50:28 +0000300 cpu_interrupt(env, CPU_INTERRUPT_HARD);
301 }
302 break;
303 }
304 }
Artyom Tarasenko9f947782011-07-25 19:22:38 +0200305 } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300306 CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
307 "current interrupt %x\n",
308 pil, env->pil_in, env->softint, env->interrupt_index);
Artyom Tarasenko9f947782011-07-25 19:22:38 +0200309 env->interrupt_index = 0;
310 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
blueswir19d926592008-09-22 19:50:28 +0000311 }
312}
313
Andreas Färberce18c552012-10-12 04:23:07 +0200314static void cpu_kick_irq(SPARCCPU *cpu)
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300315{
Andreas Färberce18c552012-10-12 04:23:07 +0200316 CPUSPARCState *env = &cpu->env;
317
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300318 env->halted = 0;
319 cpu_check_irqs(env);
Andreas Färberc08d7422012-05-03 04:34:15 +0200320 qemu_cpu_kick(CPU(cpu));
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300321}
322
Blue Swirl361dea42012-03-10 20:37:00 +0000323static void cpu_set_ivec_irq(void *opaque, int irq, int level)
blueswir19d926592008-09-22 19:50:28 +0000324{
Andreas Färberb64ba4b2012-10-12 04:23:08 +0200325 SPARCCPU *cpu = opaque;
326 CPUSPARCState *env = &cpu->env;
blueswir19d926592008-09-22 19:50:28 +0000327
328 if (level) {
Artyom Tarasenko23cf96e2012-04-03 17:49:04 +0200329 if (!(env->ivec_status & 0x20)) {
330 CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
331 env->halted = 0;
332 env->interrupt_index = TT_IVEC;
333 env->ivec_status |= 0x20;
334 env->ivec_data[0] = (0x1f << 6) | irq;
335 env->ivec_data[1] = 0;
336 env->ivec_data[2] = 0;
337 cpu_interrupt(env, CPU_INTERRUPT_HARD);
338 }
339 } else {
340 if (env->ivec_status & 0x20) {
341 CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
342 env->ivec_status &= ~0x20;
343 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
344 }
blueswir19d926592008-09-22 19:50:28 +0000345 }
346}
347
blueswir1e87231d2008-09-26 19:48:58 +0000348typedef struct ResetData {
Andreas Färber403d7a22012-05-03 03:41:16 +0200349 SPARCCPU *cpu;
Blue Swirl44a99352009-11-07 10:05:03 +0000350 uint64_t prom_addr;
blueswir1e87231d2008-09-26 19:48:58 +0000351} ResetData;
352
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300353void cpu_put_timer(QEMUFile *f, CPUTimer *s)
354{
355 qemu_put_be32s(f, &s->frequency);
356 qemu_put_be32s(f, &s->disabled);
357 qemu_put_be64s(f, &s->disabled_mask);
358 qemu_put_sbe64s(f, &s->clock_offset);
359
360 qemu_put_timer(f, s->qtimer);
361}
362
363void cpu_get_timer(QEMUFile *f, CPUTimer *s)
364{
365 qemu_get_be32s(f, &s->frequency);
366 qemu_get_be32s(f, &s->disabled);
367 qemu_get_be64s(f, &s->disabled_mask);
368 qemu_get_sbe64s(f, &s->clock_offset);
369
370 qemu_get_timer(f, s->qtimer);
371}
372
Andreas Färber6b678e12012-10-12 04:23:06 +0200373static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300374 QEMUBHFunc *cb, uint32_t frequency,
375 uint64_t disabled_mask)
376{
Anthony Liguori7267c092011-08-20 22:09:37 -0500377 CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300378
379 timer->name = name;
380 timer->frequency = frequency;
381 timer->disabled_mask = disabled_mask;
382
383 timer->disabled = 1;
Paolo Bonzini74475452011-03-11 16:47:48 +0100384 timer->clock_offset = qemu_get_clock_ns(vm_clock);
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300385
Andreas Färber6b678e12012-10-12 04:23:06 +0200386 timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu);
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300387
388 return timer;
389}
390
391static void cpu_timer_reset(CPUTimer *timer)
392{
393 timer->disabled = 1;
Paolo Bonzini74475452011-03-11 16:47:48 +0100394 timer->clock_offset = qemu_get_clock_ns(vm_clock);
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300395
396 qemu_del_timer(timer->qtimer);
397}
398
bellardc68ea702005-11-21 23:33:12 +0000399static void main_cpu_reset(void *opaque)
400{
blueswir1e87231d2008-09-26 19:48:58 +0000401 ResetData *s = (ResetData *)opaque;
Andreas Färber403d7a22012-05-03 03:41:16 +0200402 CPUSPARCState *env = &s->cpu->env;
Blue Swirl44a99352009-11-07 10:05:03 +0000403 static unsigned int nr_resets;
blueswir120c9f092007-05-25 18:50:28 +0000404
Andreas Färber403d7a22012-05-03 03:41:16 +0200405 cpu_reset(CPU(s->cpu));
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300406
407 cpu_timer_reset(env->tick);
408 cpu_timer_reset(env->stick);
409 cpu_timer_reset(env->hstick);
410
blueswir1e87231d2008-09-26 19:48:58 +0000411 env->gregs[1] = 0; // Memory start
412 env->gregs[2] = ram_size; // Memory size
413 env->gregs[3] = 0; // Machine description XXX
Blue Swirl44a99352009-11-07 10:05:03 +0000414 if (nr_resets++ == 0) {
415 /* Power on reset */
416 env->pc = s->prom_addr + 0x20ULL;
417 } else {
418 env->pc = s->prom_addr + 0x40ULL;
419 }
blueswir1e87231d2008-09-26 19:48:58 +0000420 env->npc = env->pc + 4;
blueswir120c9f092007-05-25 18:50:28 +0000421}
422
blueswir122548762008-05-10 10:12:00 +0000423static void tick_irq(void *opaque)
blueswir120c9f092007-05-25 18:50:28 +0000424{
Andreas Färber6b678e12012-10-12 04:23:06 +0200425 SPARCCPU *cpu = opaque;
426 CPUSPARCState *env = &cpu->env;
blueswir120c9f092007-05-25 18:50:28 +0000427
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300428 CPUTimer* timer = env->tick;
429
430 if (timer->disabled) {
431 CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
432 return;
433 } else {
434 CPUIRQ_DPRINTF("tick: fire\n");
blueswir18fa211e2008-12-23 08:47:26 +0000435 }
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300436
437 env->softint |= SOFTINT_TIMER;
Andreas Färberce18c552012-10-12 04:23:07 +0200438 cpu_kick_irq(cpu);
blueswir120c9f092007-05-25 18:50:28 +0000439}
440
blueswir122548762008-05-10 10:12:00 +0000441static void stick_irq(void *opaque)
blueswir120c9f092007-05-25 18:50:28 +0000442{
Andreas Färber6b678e12012-10-12 04:23:06 +0200443 SPARCCPU *cpu = opaque;
444 CPUSPARCState *env = &cpu->env;
blueswir120c9f092007-05-25 18:50:28 +0000445
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300446 CPUTimer* timer = env->stick;
447
448 if (timer->disabled) {
449 CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
450 return;
451 } else {
452 CPUIRQ_DPRINTF("stick: fire\n");
blueswir18fa211e2008-12-23 08:47:26 +0000453 }
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300454
455 env->softint |= SOFTINT_STIMER;
Andreas Färberce18c552012-10-12 04:23:07 +0200456 cpu_kick_irq(cpu);
blueswir120c9f092007-05-25 18:50:28 +0000457}
458
blueswir122548762008-05-10 10:12:00 +0000459static void hstick_irq(void *opaque)
blueswir120c9f092007-05-25 18:50:28 +0000460{
Andreas Färber6b678e12012-10-12 04:23:06 +0200461 SPARCCPU *cpu = opaque;
462 CPUSPARCState *env = &cpu->env;
blueswir120c9f092007-05-25 18:50:28 +0000463
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300464 CPUTimer* timer = env->hstick;
465
466 if (timer->disabled) {
467 CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
468 return;
469 } else {
470 CPUIRQ_DPRINTF("hstick: fire\n");
blueswir18fa211e2008-12-23 08:47:26 +0000471 }
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300472
473 env->softint |= SOFTINT_STIMER;
Andreas Färberce18c552012-10-12 04:23:07 +0200474 cpu_kick_irq(cpu);
bellardc68ea702005-11-21 23:33:12 +0000475}
476
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300477static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
blueswir1f4b1a842008-10-03 19:04:42 +0000478{
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300479 return muldiv64(cpu_ticks, get_ticks_per_sec(), frequency);
blueswir1f4b1a842008-10-03 19:04:42 +0000480}
481
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300482static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
blueswir1f4b1a842008-10-03 19:04:42 +0000483{
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300484 return muldiv64(timer_ticks, frequency, get_ticks_per_sec());
blueswir1f4b1a842008-10-03 19:04:42 +0000485}
486
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300487void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
blueswir1f4b1a842008-10-03 19:04:42 +0000488{
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300489 uint64_t real_count = count & ~timer->disabled_mask;
490 uint64_t disabled_bit = count & timer->disabled_mask;
491
Paolo Bonzini74475452011-03-11 16:47:48 +0100492 int64_t vm_clock_offset = qemu_get_clock_ns(vm_clock) -
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300493 cpu_to_timer_ticks(real_count, timer->frequency);
494
495 TIMER_DPRINTF("%s set_count count=0x%016lx (%s) p=%p\n",
496 timer->name, real_count,
497 timer->disabled?"disabled":"enabled", timer);
498
499 timer->disabled = disabled_bit ? 1 : 0;
500 timer->clock_offset = vm_clock_offset;
501}
502
503uint64_t cpu_tick_get_count(CPUTimer *timer)
504{
505 uint64_t real_count = timer_to_cpu_ticks(
Paolo Bonzini74475452011-03-11 16:47:48 +0100506 qemu_get_clock_ns(vm_clock) - timer->clock_offset,
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300507 timer->frequency);
508
509 TIMER_DPRINTF("%s get_count count=0x%016lx (%s) p=%p\n",
510 timer->name, real_count,
511 timer->disabled?"disabled":"enabled", timer);
512
513 if (timer->disabled)
514 real_count |= timer->disabled_mask;
515
516 return real_count;
517}
518
519void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
520{
Paolo Bonzini74475452011-03-11 16:47:48 +0100521 int64_t now = qemu_get_clock_ns(vm_clock);
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300522
523 uint64_t real_limit = limit & ~timer->disabled_mask;
524 timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
525
526 int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
527 timer->clock_offset;
528
529 if (expires < now) {
530 expires = now + 1;
531 }
532
533 TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
534 "called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
535 timer->name, real_limit,
536 timer->disabled?"disabled":"enabled",
537 timer, limit,
538 timer_to_cpu_ticks(now - timer->clock_offset,
539 timer->frequency),
540 timer_to_cpu_ticks(expires - now, timer->frequency));
541
542 if (!real_limit) {
543 TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
544 timer->name);
545 qemu_del_timer(timer->qtimer);
546 } else if (timer->disabled) {
547 qemu_del_timer(timer->qtimer);
548 } else {
549 qemu_mod_timer(timer->qtimer, expires);
550 }
blueswir1f4b1a842008-10-03 19:04:42 +0000551}
552
Blue Swirl361dea42012-03-10 20:37:00 +0000553static void isa_irq_handler(void *opaque, int n, int level)
Blue Swirl1387fe42009-08-28 19:04:13 +0000554{
Blue Swirl361dea42012-03-10 20:37:00 +0000555 static const int isa_irq_to_ivec[16] = {
556 [1] = 0x29, /* keyboard */
557 [4] = 0x2b, /* serial */
558 [6] = 0x27, /* floppy */
559 [7] = 0x22, /* parallel */
560 [12] = 0x2a, /* mouse */
561 };
562 qemu_irq *irqs = opaque;
563 int ivec;
564
565 assert(n < 16);
566 ivec = isa_irq_to_ivec[n];
567 EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
568 if (ivec) {
569 qemu_set_irq(irqs[ivec], level);
570 }
Blue Swirl1387fe42009-08-28 19:04:13 +0000571}
572
blueswir1c190ea02009-01-10 11:33:32 +0000573/* EBUS (Eight bit bus) bridge */
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100574static ISABus *
Blue Swirl361dea42012-03-10 20:37:00 +0000575pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
blueswir1c190ea02009-01-10 11:33:32 +0000576{
Blue Swirl1387fe42009-08-28 19:04:13 +0000577 qemu_irq *isa_irq;
Hervé Poussineauab953e22011-12-15 22:09:56 +0100578 PCIDevice *pci_dev;
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100579 ISABus *isa_bus;
Blue Swirl1387fe42009-08-28 19:04:13 +0000580
Hervé Poussineauab953e22011-12-15 22:09:56 +0100581 pci_dev = pci_create_simple(bus, devfn, "ebus");
582 isa_bus = DO_UPCAST(ISABus, qbus,
583 qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
Blue Swirl361dea42012-03-10 20:37:00 +0000584 isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100585 isa_bus_irqs(isa_bus, isa_irq);
586 return isa_bus;
Blue Swirl53e3c4f2009-07-12 08:54:49 +0000587}
blueswir1c190ea02009-01-10 11:33:32 +0000588
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200589static int
Avi Kivityc5e6fb72011-08-08 16:09:22 +0300590pci_ebus_init1(PCIDevice *pci_dev)
Blue Swirl53e3c4f2009-07-12 08:54:49 +0000591{
Avi Kivityc5e6fb72011-08-08 16:09:22 +0300592 EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
Blue Swirl0c5b8d82009-08-13 17:51:46 +0000593
Richard Hendersonc2d0d012011-08-10 15:28:11 -0700594 isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev));
blueswir1c190ea02009-01-10 11:33:32 +0000595
Avi Kivityc5e6fb72011-08-08 16:09:22 +0300596 pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
597 pci_dev->config[0x05] = 0x00;
598 pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
599 pci_dev->config[0x07] = 0x03; // status = medium devsel
600 pci_dev->config[0x09] = 0x00; // programming i/f
601 pci_dev->config[0x0D] = 0x0a; // latency_timer
602
603 isa_mmio_setup(&s->bar0, 0x1000000);
Avi Kivitye824b2c2011-08-08 16:09:31 +0300604 pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
Avi Kivityc5e6fb72011-08-08 16:09:22 +0300605 isa_mmio_setup(&s->bar1, 0x800000);
Avi Kivitye824b2c2011-08-08 16:09:31 +0300606 pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200607 return 0;
blueswir1c190ea02009-01-10 11:33:32 +0000608}
609
Anthony Liguori40021f02011-12-04 12:22:06 -0600610static void ebus_class_init(ObjectClass *klass, void *data)
611{
612 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
613
614 k->init = pci_ebus_init1;
615 k->vendor_id = PCI_VENDOR_ID_SUN;
616 k->device_id = PCI_DEVICE_ID_SUN_EBUS;
617 k->revision = 0x01;
618 k->class_id = PCI_CLASS_BRIDGE_OTHER;
619}
620
Anthony Liguori39bffca2011-12-07 21:34:16 -0600621static TypeInfo ebus_info = {
622 .name = "ebus",
623 .parent = TYPE_PCI_DEVICE,
624 .instance_size = sizeof(EbusState),
625 .class_init = ebus_class_init,
Blue Swirl53e3c4f2009-07-12 08:54:49 +0000626};
627
Avi Kivityd4edce32011-10-03 14:31:12 +0200628typedef struct PROMState {
629 SysBusDevice busdev;
630 MemoryRegion prom;
631} PROMState;
632
Aurelien Jarno409dbce2010-03-14 21:20:59 +0100633static uint64_t translate_prom_address(void *opaque, uint64_t addr)
634{
Avi Kivitya8170e52012-10-23 12:30:10 +0200635 hwaddr *base_addr = (hwaddr *)opaque;
Aurelien Jarno409dbce2010-03-14 21:20:59 +0100636 return addr + *base_addr - PROM_VADDR;
637}
638
Blue Swirl1baffa42009-07-21 09:58:02 +0000639/* Boot PROM (OpenBIOS) */
Avi Kivitya8170e52012-10-23 12:30:10 +0200640static void prom_init(hwaddr addr, const char *bios_name)
Blue Swirl1baffa42009-07-21 09:58:02 +0000641{
642 DeviceState *dev;
643 SysBusDevice *s;
644 char *filename;
645 int ret;
646
647 dev = qdev_create(NULL, "openprom");
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200648 qdev_init_nofail(dev);
Blue Swirl1baffa42009-07-21 09:58:02 +0000649 s = sysbus_from_qdev(dev);
650
651 sysbus_mmio_map(s, 0, addr);
652
653 /* load boot prom */
654 if (bios_name == NULL) {
655 bios_name = PROM_FILENAME;
656 }
657 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
658 if (filename) {
Aurelien Jarno409dbce2010-03-14 21:20:59 +0100659 ret = load_elf(filename, translate_prom_address, &addr,
660 NULL, NULL, NULL, 1, ELF_MACHINE, 0);
Blue Swirl1baffa42009-07-21 09:58:02 +0000661 if (ret < 0 || ret > PROM_SIZE_MAX) {
662 ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
663 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500664 g_free(filename);
Blue Swirl1baffa42009-07-21 09:58:02 +0000665 } else {
666 ret = -1;
667 }
668 if (ret < 0 || ret > PROM_SIZE_MAX) {
669 fprintf(stderr, "qemu: could not load prom '%s'\n", bios_name);
670 exit(1);
671 }
672}
673
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200674static int prom_init1(SysBusDevice *dev)
Blue Swirl1baffa42009-07-21 09:58:02 +0000675{
Avi Kivityd4edce32011-10-03 14:31:12 +0200676 PROMState *s = FROM_SYSBUS(PROMState, dev);
Blue Swirl1baffa42009-07-21 09:58:02 +0000677
Avi Kivityc5705a72011-12-20 15:59:12 +0200678 memory_region_init_ram(&s->prom, "sun4u.prom", PROM_SIZE_MAX);
679 vmstate_register_ram_global(&s->prom);
Avi Kivityd4edce32011-10-03 14:31:12 +0200680 memory_region_set_readonly(&s->prom, true);
Avi Kivity750ecd42011-11-27 11:38:10 +0200681 sysbus_init_mmio(dev, &s->prom);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200682 return 0;
Blue Swirl1baffa42009-07-21 09:58:02 +0000683}
684
Anthony Liguori999e12b2012-01-24 13:12:29 -0600685static Property prom_properties[] = {
686 {/* end of property list */},
687};
688
689static void prom_class_init(ObjectClass *klass, void *data)
690{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600691 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600692 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
693
694 k->init = prom_init1;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600695 dc->props = prom_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600696}
697
Anthony Liguori39bffca2011-12-07 21:34:16 -0600698static TypeInfo prom_info = {
699 .name = "openprom",
700 .parent = TYPE_SYS_BUS_DEVICE,
701 .instance_size = sizeof(PROMState),
702 .class_init = prom_class_init,
Blue Swirl1baffa42009-07-21 09:58:02 +0000703};
704
Blue Swirlbda42032009-07-21 10:04:47 +0000705
706typedef struct RamDevice
707{
708 SysBusDevice busdev;
Avi Kivityd4edce32011-10-03 14:31:12 +0200709 MemoryRegion ram;
Blue Swirl04843622009-07-21 11:20:11 +0000710 uint64_t size;
Blue Swirlbda42032009-07-21 10:04:47 +0000711} RamDevice;
712
713/* System RAM */
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200714static int ram_init1(SysBusDevice *dev)
Blue Swirlbda42032009-07-21 10:04:47 +0000715{
Blue Swirlbda42032009-07-21 10:04:47 +0000716 RamDevice *d = FROM_SYSBUS(RamDevice, dev);
717
Avi Kivityc5705a72011-12-20 15:59:12 +0200718 memory_region_init_ram(&d->ram, "sun4u.ram", d->size);
719 vmstate_register_ram_global(&d->ram);
Avi Kivity750ecd42011-11-27 11:38:10 +0200720 sysbus_init_mmio(dev, &d->ram);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200721 return 0;
Blue Swirlbda42032009-07-21 10:04:47 +0000722}
723
Avi Kivitya8170e52012-10-23 12:30:10 +0200724static void ram_init(hwaddr addr, ram_addr_t RAM_size)
Blue Swirlbda42032009-07-21 10:04:47 +0000725{
726 DeviceState *dev;
727 SysBusDevice *s;
728 RamDevice *d;
729
730 /* allocate RAM */
731 dev = qdev_create(NULL, "memory");
732 s = sysbus_from_qdev(dev);
733
734 d = FROM_SYSBUS(RamDevice, s);
735 d->size = RAM_size;
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200736 qdev_init_nofail(dev);
Blue Swirlbda42032009-07-21 10:04:47 +0000737
738 sysbus_mmio_map(s, 0, addr);
739}
740
Anthony Liguori999e12b2012-01-24 13:12:29 -0600741static Property ram_properties[] = {
742 DEFINE_PROP_UINT64("size", RamDevice, size, 0),
743 DEFINE_PROP_END_OF_LIST(),
744};
745
746static void ram_class_init(ObjectClass *klass, void *data)
747{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600748 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600749 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
750
751 k->init = ram_init1;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600752 dc->props = ram_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600753}
754
Anthony Liguori39bffca2011-12-07 21:34:16 -0600755static TypeInfo ram_info = {
756 .name = "memory",
757 .parent = TYPE_SYS_BUS_DEVICE,
758 .instance_size = sizeof(RamDevice),
759 .class_init = ram_class_init,
Blue Swirlbda42032009-07-21 10:04:47 +0000760};
761
Andreas Färberf9d14652012-05-03 03:33:52 +0200762static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
bellard34751872005-07-02 14:31:34 +0000763{
Andreas Färber8ebdf9d2012-05-03 03:29:49 +0200764 SPARCCPU *cpu;
Andreas Färber98cec4a2012-03-14 01:38:24 +0100765 CPUSPARCState *env;
blueswir1e87231d2008-09-26 19:48:58 +0000766 ResetData *reset_info;
bellard34751872005-07-02 14:31:34 +0000767
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300768 uint32_t tick_frequency = 100*1000000;
769 uint32_t stick_frequency = 100*1000000;
770 uint32_t hstick_frequency = 100*1000000;
771
Andreas Färber8ebdf9d2012-05-03 03:29:49 +0200772 if (cpu_model == NULL) {
blueswir1c7ba2182008-07-22 07:07:34 +0000773 cpu_model = hwdef->default_cpu_model;
Andreas Färber8ebdf9d2012-05-03 03:29:49 +0200774 }
775 cpu = cpu_sparc_init(cpu_model);
776 if (cpu == NULL) {
blueswir162724a32007-03-25 07:55:52 +0000777 fprintf(stderr, "Unable to find Sparc CPU definition\n");
778 exit(1);
779 }
Andreas Färber8ebdf9d2012-05-03 03:29:49 +0200780 env = &cpu->env;
blueswir120c9f092007-05-25 18:50:28 +0000781
Andreas Färber6b678e12012-10-12 04:23:06 +0200782 env->tick = cpu_timer_create("tick", cpu, tick_irq,
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300783 tick_frequency, TICK_NPT_MASK);
blueswir120c9f092007-05-25 18:50:28 +0000784
Andreas Färber6b678e12012-10-12 04:23:06 +0200785 env->stick = cpu_timer_create("stick", cpu, stick_irq,
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300786 stick_frequency, TICK_INT_DIS);
787
Andreas Färber6b678e12012-10-12 04:23:06 +0200788 env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
Igor V. Kovalenko8f4efc52010-01-28 00:00:53 +0300789 hstick_frequency, TICK_INT_DIS);
blueswir1e87231d2008-09-26 19:48:58 +0000790
Anthony Liguori7267c092011-08-20 22:09:37 -0500791 reset_info = g_malloc0(sizeof(ResetData));
Andreas Färber403d7a22012-05-03 03:41:16 +0200792 reset_info->cpu = cpu;
Blue Swirl44a99352009-11-07 10:05:03 +0000793 reset_info->prom_addr = hwdef->prom_addr;
Jan Kiszkaa08d4362009-06-27 09:25:07 +0200794 qemu_register_reset(main_cpu_reset, reset_info);
bellardc68ea702005-11-21 23:33:12 +0000795
Andreas Färberf9d14652012-05-03 03:33:52 +0200796 return cpu;
Blue Swirl7b833f52009-07-21 10:46:23 +0000797}
798
Richard Henderson38bc50f2011-08-11 16:07:21 -0700799static void sun4uv_init(MemoryRegion *address_space_mem,
800 ram_addr_t RAM_size,
Blue Swirl7b833f52009-07-21 10:46:23 +0000801 const char *boot_devices,
802 const char *kernel_filename, const char *kernel_cmdline,
803 const char *initrd_filename, const char *cpu_model,
804 const struct hwdef *hwdef)
805{
Andreas Färberf9d14652012-05-03 03:33:52 +0200806 SPARCCPU *cpu;
Blue Swirl43a34702010-02-07 08:05:03 +0000807 M48t59State *nvram;
Blue Swirl7b833f52009-07-21 10:46:23 +0000808 unsigned int i;
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000809 uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
Blue Swirl7b833f52009-07-21 10:46:23 +0000810 PCIBus *pci_bus, *pci_bus2, *pci_bus3;
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100811 ISABus *isa_bus;
Blue Swirl361dea42012-03-10 20:37:00 +0000812 qemu_irq *ivec_irqs, *pbm_irqs;
Gerd Hoffmannf455e982009-08-28 15:47:03 +0200813 DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
Gerd Hoffmannfd8014e2009-09-22 13:53:18 +0200814 DriveInfo *fd[MAX_FD];
Blue Swirl7b833f52009-07-21 10:46:23 +0000815 void *fw_cfg;
816
Blue Swirl7b833f52009-07-21 10:46:23 +0000817 /* init CPUs */
Andreas Färberf9d14652012-05-03 03:33:52 +0200818 cpu = cpu_devinit(cpu_model, hwdef);
Blue Swirl7b833f52009-07-21 10:46:23 +0000819
Blue Swirlbda42032009-07-21 10:04:47 +0000820 /* set up devices */
821 ram_init(0, RAM_size);
bellard34751872005-07-02 14:31:34 +0000822
Blue Swirl1baffa42009-07-21 09:58:02 +0000823 prom_init(hwdef->prom_addr, bios_name);
bellard34751872005-07-02 14:31:34 +0000824
Andreas Färberb64ba4b2012-10-12 04:23:08 +0200825 ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX);
Blue Swirl361dea42012-03-10 20:37:00 +0000826 pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
827 &pci_bus3, &pbm_irqs);
Aurelien Jarnof2898772012-09-08 12:23:54 +0200828 pci_vga_init(pci_bus);
bellard83469012005-07-23 14:27:54 +0000829
blueswir1c190ea02009-01-10 11:33:32 +0000830 // XXX Should be pci_bus3
Blue Swirl361dea42012-03-10 20:37:00 +0000831 isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
blueswir1c190ea02009-01-10 11:33:32 +0000832
blueswir1e87231d2008-09-26 19:48:58 +0000833 i = 0;
834 if (hwdef->console_serial_base) {
Richard Henderson38bc50f2011-08-11 16:07:21 -0700835 serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
Richard Henderson39186d82011-08-11 16:07:16 -0700836 NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
blueswir1e87231d2008-09-26 19:48:58 +0000837 i++;
838 }
839 for(; i < MAX_SERIAL_PORTS; i++) {
bellard83469012005-07-23 14:27:54 +0000840 if (serial_hds[i]) {
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100841 serial_isa_init(isa_bus, i, serial_hds[i]);
bellard83469012005-07-23 14:27:54 +0000842 }
843 }
844
845 for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
846 if (parallel_hds[i]) {
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100847 parallel_init(isa_bus, i, parallel_hds[i]);
bellard83469012005-07-23 14:27:54 +0000848 }
849 }
850
aliguoricb457d72009-01-13 19:47:10 +0000851 for(i = 0; i < nb_nics; i++)
Markus Armbruster07caea32009-09-25 03:53:51 +0200852 pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
bellard83469012005-07-23 14:27:54 +0000853
Isaku Yamahata75717902011-04-03 20:32:46 +0900854 ide_drive_get(hd, MAX_IDE_BUS);
thse4bcb142007-12-02 04:51:10 +0000855
blueswir13b898dd2009-01-17 18:41:53 +0000856 pci_cmd646_ide_init(pci_bus, hd, 1);
857
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100858 isa_create_simple(isa_bus, "i8042");
thse4bcb142007-12-02 04:51:10 +0000859 for(i = 0; i < MAX_FD; i++) {
Gerd Hoffmannfd8014e2009-09-22 13:53:18 +0200860 fd[i] = drive_get(IF_FLOPPY, 0, i);
thse4bcb142007-12-02 04:51:10 +0000861 }
Hervé Poussineau48a18b32011-12-15 22:09:51 +0100862 fdctrl_init_isa(isa_bus, fd);
863 nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
Blue Swirl636aa702009-07-21 10:49:47 +0000864
865 initrd_size = 0;
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000866 initrd_addr = 0;
Blue Swirl636aa702009-07-21 10:49:47 +0000867 kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000868 ram_size, &initrd_size, &initrd_addr,
869 &kernel_addr, &kernel_entry);
Blue Swirl636aa702009-07-21 10:49:47 +0000870
blueswir122548762008-05-10 10:12:00 +0000871 sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000872 kernel_addr, kernel_size,
blueswir10d31cb92008-07-15 14:54:01 +0000873 kernel_cmdline,
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000874 initrd_addr, initrd_size,
blueswir10d31cb92008-07-15 14:54:01 +0000875 /* XXX: need an option to load a NVRAM image */
876 0,
877 graphic_width, graphic_height, graphic_depth,
878 (uint8_t *)&nd_table[0].macaddr);
bellard83469012005-07-23 14:27:54 +0000879
blueswir13cce6242008-09-18 18:27:29 +0000880 fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
881 fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
blueswir1905fdcb2008-09-18 18:33:18 +0000882 fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
883 fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000884 fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
885 fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
blueswir1513f7892009-03-08 09:51:29 +0000886 if (kernel_cmdline) {
Blue Swirl9c9b0512010-01-09 21:27:04 +0000887 fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
888 strlen(kernel_cmdline) + 1);
Blue Swirl6bb4ca52009-12-27 18:25:49 +0000889 fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
890 (uint8_t*)strdup(kernel_cmdline),
891 strlen(kernel_cmdline) + 1);
blueswir1513f7892009-03-08 09:51:29 +0000892 } else {
Blue Swirl9c9b0512010-01-09 21:27:04 +0000893 fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
blueswir1513f7892009-03-08 09:51:29 +0000894 }
Blue Swirl5f2bf0f2012-05-12 17:20:52 +0000895 fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
896 fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
blueswir1513f7892009-03-08 09:51:29 +0000897 fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
Blue Swirl75896902009-08-08 10:44:56 +0000898
899 fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
900 fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
901 fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_DEPTH, graphic_depth);
902
blueswir1513f7892009-03-08 09:51:29 +0000903 qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
bellard34751872005-07-02 14:31:34 +0000904}
905
blueswir1905fdcb2008-09-18 18:33:18 +0000906enum {
907 sun4u_id = 0,
908 sun4v_id = 64,
blueswir1e87231d2008-09-26 19:48:58 +0000909 niagara_id,
blueswir1905fdcb2008-09-18 18:33:18 +0000910};
911
blueswir1c7ba2182008-07-22 07:07:34 +0000912static const struct hwdef hwdefs[] = {
913 /* Sun4u generic PC-like machine */
914 {
Igor V. Kovalenko5910b042010-05-25 16:08:57 +0400915 .default_cpu_model = "TI UltraSparc IIi",
blueswir1905fdcb2008-09-18 18:33:18 +0000916 .machine_id = sun4u_id,
blueswir1e87231d2008-09-26 19:48:58 +0000917 .prom_addr = 0x1fff0000000ULL,
918 .console_serial_base = 0,
blueswir1c7ba2182008-07-22 07:07:34 +0000919 },
920 /* Sun4v generic PC-like machine */
921 {
922 .default_cpu_model = "Sun UltraSparc T1",
blueswir1905fdcb2008-09-18 18:33:18 +0000923 .machine_id = sun4v_id,
blueswir1e87231d2008-09-26 19:48:58 +0000924 .prom_addr = 0x1fff0000000ULL,
925 .console_serial_base = 0,
926 },
927 /* Sun4v generic Niagara machine */
928 {
929 .default_cpu_model = "Sun UltraSparc T1",
930 .machine_id = niagara_id,
931 .prom_addr = 0xfff0000000ULL,
932 .console_serial_base = 0xfff0c2c000ULL,
blueswir1c7ba2182008-07-22 07:07:34 +0000933 },
934};
935
936/* Sun4u hardware initialisation */
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300937static void sun4u_init(QEMUMachineInitArgs *args)
blueswir1c7ba2182008-07-22 07:07:34 +0000938{
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300939 ram_addr_t RAM_size = args->ram_size;
940 const char *cpu_model = args->cpu_model;
941 const char *kernel_filename = args->kernel_filename;
942 const char *kernel_cmdline = args->kernel_cmdline;
943 const char *initrd_filename = args->initrd_filename;
944 const char *boot_devices = args->boot_device;
Richard Henderson38bc50f2011-08-11 16:07:21 -0700945 sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
blueswir1c7ba2182008-07-22 07:07:34 +0000946 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
947}
948
949/* Sun4v hardware initialisation */
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300950static void sun4v_init(QEMUMachineInitArgs *args)
blueswir1c7ba2182008-07-22 07:07:34 +0000951{
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300952 ram_addr_t RAM_size = args->ram_size;
953 const char *cpu_model = args->cpu_model;
954 const char *kernel_filename = args->kernel_filename;
955 const char *kernel_cmdline = args->kernel_cmdline;
956 const char *initrd_filename = args->initrd_filename;
957 const char *boot_devices = args->boot_device;
Richard Henderson38bc50f2011-08-11 16:07:21 -0700958 sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
blueswir1c7ba2182008-07-22 07:07:34 +0000959 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
960}
961
blueswir1e87231d2008-09-26 19:48:58 +0000962/* Niagara hardware initialisation */
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300963static void niagara_init(QEMUMachineInitArgs *args)
blueswir1e87231d2008-09-26 19:48:58 +0000964{
Eduardo Habkost5f072e12012-10-15 17:22:02 -0300965 ram_addr_t RAM_size = args->ram_size;
966 const char *cpu_model = args->cpu_model;
967 const char *kernel_filename = args->kernel_filename;
968 const char *kernel_cmdline = args->kernel_cmdline;
969 const char *initrd_filename = args->initrd_filename;
970 const char *boot_devices = args->boot_device;
Richard Henderson38bc50f2011-08-11 16:07:21 -0700971 sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
blueswir1e87231d2008-09-26 19:48:58 +0000972 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
973}
974
Anthony Liguorif80f9ec2009-05-20 18:38:09 -0500975static QEMUMachine sun4u_machine = {
blueswir166de7332008-08-12 15:51:09 +0000976 .name = "sun4u",
977 .desc = "Sun4u platform",
978 .init = sun4u_init,
blueswir11bcee012008-11-02 16:51:02 +0000979 .max_cpus = 1, // XXX for now
Anthony Liguori0c257432009-05-21 20:41:01 -0500980 .is_default = 1,
bellard34751872005-07-02 14:31:34 +0000981};
blueswir1c7ba2182008-07-22 07:07:34 +0000982
Anthony Liguorif80f9ec2009-05-20 18:38:09 -0500983static QEMUMachine sun4v_machine = {
blueswir166de7332008-08-12 15:51:09 +0000984 .name = "sun4v",
985 .desc = "Sun4v platform",
986 .init = sun4v_init,
blueswir11bcee012008-11-02 16:51:02 +0000987 .max_cpus = 1, // XXX for now
blueswir1c7ba2182008-07-22 07:07:34 +0000988};
blueswir1e87231d2008-09-26 19:48:58 +0000989
Anthony Liguorif80f9ec2009-05-20 18:38:09 -0500990static QEMUMachine niagara_machine = {
blueswir1e87231d2008-09-26 19:48:58 +0000991 .name = "Niagara",
992 .desc = "Sun4v platform, Niagara",
993 .init = niagara_init,
blueswir11bcee012008-11-02 16:51:02 +0000994 .max_cpus = 1, // XXX for now
blueswir1e87231d2008-09-26 19:48:58 +0000995};
Anthony Liguorif80f9ec2009-05-20 18:38:09 -0500996
Andreas Färber83f7d432012-02-09 15:20:55 +0100997static void sun4u_register_types(void)
998{
999 type_register_static(&ebus_info);
1000 type_register_static(&prom_info);
1001 type_register_static(&ram_info);
1002}
1003
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001004static void sun4u_machine_init(void)
1005{
1006 qemu_register_machine(&sun4u_machine);
1007 qemu_register_machine(&sun4v_machine);
1008 qemu_register_machine(&niagara_machine);
1009}
1010
Andreas Färber83f7d432012-02-09 15:20:55 +01001011type_init(sun4u_register_types)
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001012machine_init(sun4u_machine_init);