1
/*
2
* QEMU Sun4u / Sun4v System Emulator
ths
authored
18 years ago
3
*
4
* Copyright ( c ) 2005 Fabrice Bellard
ths
authored
18 years ago
5
*
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the "Software" ), to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
24
25
26
27
28
29
30
31
32
# include "hw.h"
# include "pci.h"
# include "pc.h"
# include "nvram.h"
# include "fdc.h"
# include "net.h"
# include "qemu-timer.h"
# include "sysemu.h"
# include "boards.h"
33
# include "firmware_abi.h"
34
# include "fw_cfg.h"
35
36
37
38
# define KERNEL_LOAD_ADDR 0x00404000
# define CMDLINE_ADDR 0x003ff000
# define INITRD_LOAD_ADDR 0x00300000
39
# define PROM_SIZE_MAX ( 4 * 1024 * 1024 )
40
41
# define PROM_ADDR 0x1fff0000000ULL
# define PROM_VADDR 0x000ffd00000ULL
42
# define APB_SPECIAL_BASE 0x1fe00000000ULL
43
44
45
# define APB_MEM_BASE 0x1ff00000000ULL
# define VGA_BASE ( APB_MEM_BASE + 0x400000ULL )
# define PROM_FILENAME "openbios-sparc64"
46
# define NVRAM_SIZE 0x2000
ths
authored
17 years ago
47
# define MAX_IDE_BUS 2
48
# define BIOS_CFG_IOPORT 0x510
49
50
51
struct hwdef {
const char * const default_cpu_model ;
52
uint16_t machine_id ;
53
54
};
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
int DMA_get_channel_mode ( int nchan )
{
return 0 ;
}
int DMA_read_memory ( int nchan , void * buf , int pos , int size )
{
return 0 ;
}
int DMA_write_memory ( int nchan , void * buf , int pos , int size )
{
return 0 ;
}
void DMA_hold_DREQ ( int nchan ) {}
void DMA_release_DREQ ( int nchan ) {}
void DMA_schedule ( int nchan ) {}
void DMA_run ( void ) {}
void DMA_init ( int high_page_enable ) {}
void DMA_register_channel ( int nchan ,
DMA_transfer_handler transfer_handler ,
void * opaque )
{
}
78
79
80
81
82
83
84
85
86
87
static int nvram_boot_set ( void * opaque , const char * boot_device )
{
unsigned int i ;
uint8_t image [ sizeof ( ohwcfg_v3_t )];
ohwcfg_v3_t * header = ( ohwcfg_v3_t * ) & image ;
m48t59_t * nvram = ( m48t59_t * ) opaque ;
for ( i = 0 ; i < sizeof ( image ); i ++ )
image [ i ] = m48t59_read ( nvram , i ) & 0xff ;
88
89
pstrcpy (( char * ) header -> boot_devices , sizeof ( header -> boot_devices ),
boot_device );
90
91
92
93
94
95
96
97
98
header -> nboot_devices = strlen ( boot_device ) & 0xff ;
header -> crc = cpu_to_be16 ( OHW_compute_crc ( header , 0x00 , 0xF8 ));
for ( i = 0 ; i < sizeof ( image ); i ++ )
m48t59_write ( nvram , i , image [ i ]);
return 0 ;
}
99
100
extern int nographic ;
101
static int sun4u_NVRAM_set_params ( m48t59_t * nvram , uint16_t NVRAM_size ,
102
const char * arch ,
103
104
ram_addr_t RAM_size ,
const char * boot_devices ,
105
106
107
108
uint32_t kernel_image , uint32_t kernel_size ,
const char * cmdline ,
uint32_t initrd_image , uint32_t initrd_size ,
uint32_t NVRAM_image ,
109
110
int width , int height , int depth ,
const uint8_t * macaddr )
111
{
112
113
unsigned int i ;
uint32_t start , end ;
114
115
116
117
118
119
120
121
uint8_t image [ 0x1ff0 ];
ohwcfg_v3_t * header = ( ohwcfg_v3_t * ) & image ;
struct sparc_arch_cfg * sparc_header ;
struct OpenBIOS_nvpart_v1 * part_header ;
memset ( image , '\0' , sizeof ( image ));
// Try to match PPC NVRAM
122
123
pstrcpy (( char * ) header -> struct_ident , sizeof ( header -> struct_ident ),
"QEMU_BIOS" );
124
125
126
127
128
header -> struct_version = cpu_to_be32 ( 3 ); /* structure v3 */
header -> nvram_size = cpu_to_be16 ( NVRAM_size );
header -> nvram_arch_ptr = cpu_to_be16 ( sizeof ( ohwcfg_v3_t ));
header -> nvram_arch_size = cpu_to_be16 ( sizeof ( struct sparc_arch_cfg ));
129
pstrcpy (( char * ) header -> arch , sizeof ( header -> arch ), arch );
130
131
132
header -> nb_cpus = smp_cpus & 0xff ;
header -> RAM0_base = 0 ;
header -> RAM0_size = cpu_to_be64 (( uint64_t ) RAM_size );
133
134
pstrcpy (( char * ) header -> boot_devices , sizeof ( header -> boot_devices ),
boot_devices );
135
136
137
header -> nboot_devices = strlen ( boot_devices ) & 0xff ;
header -> kernel_image = cpu_to_be64 (( uint64_t ) kernel_image );
header -> kernel_size = cpu_to_be64 (( uint64_t ) kernel_size );
138
if ( cmdline ) {
139
pstrcpy_targphys ( CMDLINE_ADDR , TARGET_PAGE_SIZE , cmdline );
140
141
header -> cmdline = cpu_to_be64 (( uint64_t ) CMDLINE_ADDR );
header -> cmdline_size = cpu_to_be64 (( uint64_t ) strlen ( cmdline ));
142
}
143
144
145
146
147
148
149
150
151
header -> initrd_image = cpu_to_be64 (( uint64_t ) initrd_image );
header -> initrd_size = cpu_to_be64 (( uint64_t ) initrd_size );
header -> NVRAM_image = cpu_to_be64 (( uint64_t ) NVRAM_image );
header -> width = cpu_to_be16 ( width );
header -> height = cpu_to_be16 ( height );
header -> depth = cpu_to_be16 ( depth );
if ( nographic )
header -> graphic_flags = cpu_to_be16 ( OHW_GF_NOGRAPHICS );
152
153
154
155
156
157
158
159
header -> crc = cpu_to_be16 ( OHW_compute_crc ( header , 0x00 , 0xF8 ));
// Architecture specific header
start = sizeof ( ohwcfg_v3_t );
sparc_header = ( struct sparc_arch_cfg * ) & image [ start ];
sparc_header -> valid = 0 ;
start += sizeof ( struct sparc_arch_cfg );
160
161
162
// OpenBIOS nvram variables
// Variable partition
163
164
part_header = ( struct OpenBIOS_nvpart_v1 * ) & image [ start ];
part_header -> signature = OPENBIOS_PART_SYSTEM ;
165
pstrcpy ( part_header -> name , sizeof ( part_header -> name ), "system" );
166
167
end = start + sizeof ( struct OpenBIOS_nvpart_v1 );
168
for ( i = 0 ; i < nb_prom_envs ; i ++ )
169
170
171
172
end = OpenBIOS_set_var ( image , end , prom_envs [ i ]);
// End marker
image [ end ++ ] = '\0' ;
173
174
end = start + (( end - start + 15 ) & ~ 15 );
175
OpenBIOS_finish_partition ( part_header , end - start );
176
177
178
// free partition
start = end ;
179
180
part_header = ( struct OpenBIOS_nvpart_v1 * ) & image [ start ];
part_header -> signature = OPENBIOS_PART_FREE ;
181
pstrcpy ( part_header -> name , sizeof ( part_header -> name ), "free" );
182
183
end = 0x1fd0 ;
184
185
OpenBIOS_finish_partition ( part_header , end - start );
186
187
Sun_init_header (( struct Sun_nvram * ) & image [ 0x1fd8 ], macaddr , 0x80 );
188
189
for ( i = 0 ; i < sizeof ( image ); i ++ )
m48t59_write ( nvram , i , image [ i ]);
190
191
192
qemu_register_boot_set ( nvram_boot_set , nvram );
193
return 0 ;
194
195
}
196
void pic_info ( void )
197
198
199
{
}
200
void irq_info ( void )
201
202
203
{
}
204
void qemu_system_powerdown ( void )
205
206
207
{
}
208
209
210
static void main_cpu_reset ( void * opaque )
{
CPUState * env = opaque ;
211
212
cpu_reset ( env );
213
214
215
216
217
218
219
220
ptimer_set_limit ( env -> tick , 0x7fffffffffffffffULL , 1 );
ptimer_run ( env -> tick , 0 );
ptimer_set_limit ( env -> stick , 0x7fffffffffffffffULL , 1 );
ptimer_run ( env -> stick , 0 );
ptimer_set_limit ( env -> hstick , 0x7fffffffffffffffULL , 1 );
ptimer_run ( env -> hstick , 0 );
}
221
static void tick_irq ( void * opaque )
222
223
224
225
226
227
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
}
228
static void stick_irq ( void * opaque )
229
230
231
232
233
234
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
}
235
static void hstick_irq ( void * opaque )
236
237
238
239
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
240
241
}
242
243
244
245
static void dummy_cpu_set_irq ( void * opaque , int irq , int level )
{
}
246
247
248
static const int ide_iobase [ 2 ] = { 0x1f0 , 0x170 };
static const int ide_iobase2 [ 2 ] = { 0x3f6 , 0x376 };
static const int ide_irq [ 2 ] = { 14 , 15 };
249
250
251
252
253
254
255
256
static const int serial_io [ MAX_SERIAL_PORTS ] = { 0x3f8 , 0x2f8 , 0x3e8 , 0x2e8 };
static const int serial_irq [ MAX_SERIAL_PORTS ] = { 4 , 3 , 4 , 3 };
static const int parallel_io [ MAX_PARALLEL_PORTS ] = { 0x378 , 0x278 , 0x3bc };
static const int parallel_irq [ MAX_PARALLEL_PORTS ] = { 7 , 7 , 7 };
static fdctrl_t * floppy_controller ;
257
258
259
260
261
262
static void sun4uv_init ( ram_addr_t RAM_size , int vga_ram_size ,
const char * boot_devices , DisplayState * ds ,
const char * kernel_filename , const char * kernel_cmdline ,
const char * initrd_filename , const char * cpu_model ,
const struct hwdef * hwdef )
263
{
264
CPUState * env ;
265
char buf [ 1024 ];
266
m48t59_t * nvram ;
267
268
int ret , linux_boot ;
unsigned int i ;
269
270
long prom_offset , initrd_size , kernel_size ;
PCIBus * pci_bus ;
271
QEMUBH * bh ;
272
qemu_irq * irq ;
273
int drive_index ;
ths
authored
17 years ago
274
275
BlockDriverState * hd [ MAX_IDE_BUS * MAX_IDE_DEVS ];
BlockDriverState * fd [ MAX_FD ];
276
void * fw_cfg ;
277
278
279
linux_boot = ( kernel_filename != NULL );
280
/* init CPUs */
281
282
283
if ( ! cpu_model )
cpu_model = hwdef -> default_cpu_model ;
284
285
env = cpu_init ( cpu_model );
if ( ! env ) {
286
287
288
fprintf ( stderr , "Unable to find Sparc CPU definition \n " );
exit ( 1 );
}
289
290
291
292
293
294
295
296
297
298
299
bh = qemu_bh_new ( tick_irq , env );
env -> tick = ptimer_init ( bh );
ptimer_set_period ( env -> tick , 1ULL );
bh = qemu_bh_new ( stick_irq , env );
env -> stick = ptimer_init ( bh );
ptimer_set_period ( env -> stick , 1ULL );
bh = qemu_bh_new ( hstick_irq , env );
env -> hstick = ptimer_init ( bh );
ptimer_set_period ( env -> hstick , 1ULL );
300
qemu_register_reset ( main_cpu_reset , env );
301
main_cpu_reset ( env );
302
303
/* allocate RAM */
304
cpu_register_physical_memory ( 0 , RAM_size , 0 );
305
306
prom_offset = RAM_size + vga_ram_size ;
ths
authored
18 years ago
307
cpu_register_physical_memory ( PROM_ADDR ,
308
309
( PROM_SIZE_MAX + TARGET_PAGE_SIZE ) &
TARGET_PAGE_MASK ,
310
prom_offset | IO_MEM_ROM );
311
312
313
314
if ( bios_name == NULL )
bios_name = PROM_FILENAME ;
snprintf ( buf , sizeof ( buf ), "%s/%s" , bios_dir , bios_name );
315
ret = load_elf ( buf , PROM_ADDR - PROM_VADDR , NULL , NULL , NULL );
316
if ( ret < 0 ) {
317
318
319
fprintf ( stderr , "qemu: could not load prom '%s' \n " ,
buf );
exit ( 1 );
320
321
322
}
kernel_size = 0 ;
323
initrd_size = 0 ;
324
if ( linux_boot ) {
325
/* XXX: put correct offset */
ths
authored
18 years ago
326
kernel_size = load_elf ( kernel_filename , 0 , NULL , NULL , NULL );
327
if ( kernel_size < 0 )
328
329
kernel_size = load_aout ( kernel_filename , KERNEL_LOAD_ADDR ,
ram_size - KERNEL_LOAD_ADDR );
330
if ( kernel_size < 0 )
331
332
333
kernel_size = load_image_targphys ( kernel_filename ,
KERNEL_LOAD_ADDR ,
ram_size - KERNEL_LOAD_ADDR );
334
if ( kernel_size < 0 ) {
ths
authored
18 years ago
335
fprintf ( stderr , "qemu: could not load kernel '%s' \n " ,
336
kernel_filename );
337
exit ( 1 );
338
339
340
341
}
/* load initrd */
if ( initrd_filename ) {
342
343
344
initrd_size = load_image_targphys ( initrd_filename ,
INITRD_LOAD_ADDR ,
ram_size - INITRD_LOAD_ADDR );
345
if ( initrd_size < 0 ) {
ths
authored
18 years ago
346
fprintf ( stderr , "qemu: could not load initial ram disk '%s' \n " ,
347
348
349
350
351
initrd_filename );
exit ( 1 );
}
}
if ( initrd_size > 0 ) {
352
for ( i = 0 ; i < 64 * TARGET_PAGE_SIZE ; i += TARGET_PAGE_SIZE ) {
353
354
355
if ( ldl_phys ( KERNEL_LOAD_ADDR + i ) == 0x48647253 ) { // HdrS
stl_phys ( KERNEL_LOAD_ADDR + i + 16 , INITRD_LOAD_ADDR );
stl_phys ( KERNEL_LOAD_ADDR + i + 20 , initrd_size );
356
357
358
break ;
}
}
359
360
}
}
361
pci_bus = pci_apb_init ( APB_SPECIAL_BASE , APB_MEM_BASE , NULL );
362
isa_mem_base = VGA_BASE ;
363
364
pci_cirrus_vga_init ( pci_bus , ds , phys_ram_base + RAM_size , RAM_size ,
vga_ram_size );
365
366
367
for ( i = 0 ; i < MAX_SERIAL_PORTS ; i ++ ) {
if ( serial_hds [ i ]) {
368
369
serial_init ( serial_io [ i ], NULL /*serial_irq[i]*/ , 115200 ,
serial_hds [ i ]);
370
371
372
373
374
}
}
for ( i = 0 ; i < MAX_PARALLEL_PORTS ; i ++ ) {
if ( parallel_hds [ i ]) {
375
376
parallel_init ( parallel_io [ i ], NULL /*parallel_irq[i]*/ ,
parallel_hds [ i ]);
377
378
379
380
}
}
for ( i = 0 ; i < nb_nics ; i ++ ) {
381
382
if ( ! nd_table [ i ]. model )
nd_table [ i ]. model = "ne2k_pci" ;
383
pci_nic_init ( pci_bus , & nd_table [ i ], - 1 );
384
385
}
386
irq = qemu_allocate_irqs ( dummy_cpu_set_irq , NULL , 32 );
ths
authored
17 years ago
387
388
389
390
391
if ( drive_get_max_bus ( IF_IDE ) >= MAX_IDE_BUS ) {
fprintf ( stderr , "qemu: too many IDE bus \n " );
exit ( 1 );
}
for ( i = 0 ; i < MAX_IDE_BUS * MAX_IDE_DEVS ; i ++ ) {
392
393
394
395
drive_index = drive_get_index ( IF_IDE , i / MAX_IDE_DEVS ,
i % MAX_IDE_DEVS );
if ( drive_index != - 1 )
hd [ i ] = drives_table [ drive_index ]. bdrv ;
ths
authored
17 years ago
396
397
398
399
400
401
else
hd [ i ] = NULL ;
}
// XXX pci_cmd646_ide_init ( pci_bus , hd , 1 );
pci_piix3_ide_init ( pci_bus , hd , - 1 , irq );
402
403
/* FIXME: wire up interrupts. */
i8042_init ( NULL /*1*/ , NULL /*12*/ , 0x60 );
ths
authored
17 years ago
404
for ( i = 0 ; i < MAX_FD ; i ++ ) {
405
406
407
drive_index = drive_get_index ( IF_FLOPPY , 0 , i );
if ( drive_index != - 1 )
fd [ i ] = drives_table [ drive_index ]. bdrv ;
ths
authored
17 years ago
408
409
410
411
else
fd [ i ] = NULL ;
}
floppy_controller = fdctrl_init ( NULL /*6*/ , 2 , 0 , 0x3f0 , fd );
412
nvram = m48t59_init ( NULL /*8*/ , 0 , 0x0074 , NVRAM_SIZE , 59 );
413
sun4u_NVRAM_set_params ( nvram , NVRAM_SIZE , "Sun4u" , RAM_size , boot_devices ,
414
415
416
417
418
419
420
KERNEL_LOAD_ADDR , kernel_size ,
kernel_cmdline ,
INITRD_LOAD_ADDR , initrd_size ,
/* XXX: need an option to load a NVRAM image */
0 ,
graphic_width , graphic_height , graphic_depth ,
( uint8_t * ) & nd_table [ 0 ]. macaddr );
421
422
423
fw_cfg = fw_cfg_init ( BIOS_CFG_IOPORT , BIOS_CFG_IOPORT + 1 , 0 , 0 );
fw_cfg_add_i32 ( fw_cfg , FW_CFG_ID , 1 );
424
425
fw_cfg_add_i64 ( fw_cfg , FW_CFG_RAM_SIZE , ( uint64_t ) ram_size );
fw_cfg_add_i16 ( fw_cfg , FW_CFG_MACHINE_ID , hwdef -> machine_id );
426
427
}
428
429
430
431
432
enum {
sun4u_id = 0 ,
sun4v_id = 64 ,
};
433
434
435
436
static const struct hwdef hwdefs [] = {
/* Sun4u generic PC-like machine */
{
. default_cpu_model = "TI UltraSparc II" ,
437
. machine_id = sun4u_id ,
438
439
440
441
},
/* Sun4v generic PC-like machine */
{
. default_cpu_model = "Sun UltraSparc T1" ,
442
. machine_id = sun4v_id ,
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
},
};
/* Sun4u hardware initialisation */
static void sun4u_init ( ram_addr_t RAM_size , int vga_ram_size ,
const char * boot_devices , DisplayState * ds ,
const char * kernel_filename , const char * kernel_cmdline ,
const char * initrd_filename , const char * cpu_model )
{
sun4uv_init ( RAM_size , vga_ram_size , boot_devices , ds , kernel_filename ,
kernel_cmdline , initrd_filename , cpu_model , & hwdefs [ 0 ]);
}
/* Sun4v hardware initialisation */
static void sun4v_init ( ram_addr_t RAM_size , int vga_ram_size ,
const char * boot_devices , DisplayState * ds ,
const char * kernel_filename , const char * kernel_cmdline ,
const char * initrd_filename , const char * cpu_model )
{
sun4uv_init ( RAM_size , vga_ram_size , boot_devices , ds , kernel_filename ,
kernel_cmdline , initrd_filename , cpu_model , & hwdefs [ 1 ]);
}
466
QEMUMachine sun4u_machine = {
467
468
469
470
. name = "sun4u" ,
. desc = "Sun4u platform" ,
. init = sun4u_init ,
. ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE ,
471
. nodisk_ok = 1 ,
472
};
473
474
QEMUMachine sun4v_machine = {
475
476
477
478
. name = "sun4v" ,
. desc = "Sun4v platform" ,
. init = sun4v_init ,
. ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE ,
479
. nodisk_ok = 1 ,
480
};