1
2
/*
* QEMU Sun4u 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
24
* 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 .
*/
# include "vl.h"
25
# include "m48t59.h"
26
# include "firmware_abi.h"
27
28
29
30
# define KERNEL_LOAD_ADDR 0x00404000
# define CMDLINE_ADDR 0x003ff000
# define INITRD_LOAD_ADDR 0x00300000
31
# define PROM_SIZE_MAX ( 512 * 1024 )
32
33
# define PROM_ADDR 0x1fff0000000ULL
# define PROM_VADDR 0x000ffd00000ULL
34
# define APB_SPECIAL_BASE 0x1fe00000000ULL
35
36
37
# define APB_MEM_BASE 0x1ff00000000ULL
# define VGA_BASE ( APB_MEM_BASE + 0x400000ULL )
# define PROM_FILENAME "openbios-sparc64"
38
# define NVRAM_SIZE 0x2000
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* TSC handling */
uint64_t cpu_get_tsc ()
{
return qemu_get_clock ( vm_clock );
}
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 )
{
}
extern int nographic ;
72
73
74
75
76
77
78
79
static int sun4u_NVRAM_set_params ( m48t59_t * nvram , uint16_t NVRAM_size ,
const unsigned char * arch ,
uint32_t RAM_size , const char * boot_devices ,
uint32_t kernel_image , uint32_t kernel_size ,
const char * cmdline ,
uint32_t initrd_image , uint32_t initrd_size ,
uint32_t NVRAM_image ,
int width , int height , int depth )
80
{
81
82
unsigned int i ;
uint32_t start , end ;
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
strcpy ( header -> struct_ident , "QEMU_BIOS" );
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 ));
strcpy ( header -> arch , arch );
header -> nb_cpus = smp_cpus & 0xff ;
header -> RAM0_base = 0 ;
header -> RAM0_size = cpu_to_be64 (( uint64_t ) RAM_size );
strcpy ( header -> boot_devices , boot_devices );
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 );
105
if ( cmdline ) {
106
strcpy ( phys_ram_base + CMDLINE_ADDR , cmdline );
107
108
header -> cmdline = cpu_to_be64 (( uint64_t ) CMDLINE_ADDR );
header -> cmdline_size = cpu_to_be64 (( uint64_t ) strlen ( cmdline ));
109
}
110
111
112
113
114
115
116
117
118
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 );
119
120
121
122
123
124
125
126
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 );
127
128
129
// OpenBIOS nvram variables
// Variable partition
130
131
132
part_header = ( struct OpenBIOS_nvpart_v1 * ) & image [ start ];
part_header -> signature = OPENBIOS_PART_SYSTEM ;
strcpy ( part_header -> name , "system" );
133
134
end = start + sizeof ( struct OpenBIOS_nvpart_v1 );
135
for ( i = 0 ; i < nb_prom_envs ; i ++ )
136
137
138
139
end = OpenBIOS_set_var ( image , end , prom_envs [ i ]);
// End marker
image [ end ++ ] = '\0' ;
140
141
end = start + (( end - start + 15 ) & ~ 15 );
142
OpenBIOS_finish_partition ( part_header , end - start );
143
144
145
// free partition
start = end ;
146
147
148
part_header = ( struct OpenBIOS_nvpart_v1 * ) & image [ start ];
part_header -> signature = OPENBIOS_PART_FREE ;
strcpy ( part_header -> name , "free" );
149
150
end = 0x1fd0 ;
151
152
153
154
OpenBIOS_finish_partition ( part_header , end - start );
for ( i = 0 ; i < sizeof ( image ); i ++ )
m48t59_write ( nvram , i , image [ i ]);
155
156
return 0 ;
157
158
159
160
161
162
163
164
165
166
}
void pic_info ()
{
}
void irq_info ()
{
}
167
void qemu_system_powerdown ( void )
168
169
170
{
}
171
172
173
static void main_cpu_reset ( void * opaque )
{
CPUState * env = opaque ;
174
175
cpu_reset ( env );
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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 );
}
void tick_irq ( void * opaque )
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
}
void stick_irq ( void * opaque )
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
}
void hstick_irq ( void * opaque )
{
CPUState * env = opaque ;
cpu_interrupt ( env , CPU_INTERRUPT_TIMER );
203
204
}
205
206
207
208
static void dummy_cpu_set_irq ( void * opaque , int irq , int level )
{
}
209
210
211
static const int ide_iobase [ 2 ] = { 0x1f0 , 0x170 };
static const int ide_iobase2 [ 2 ] = { 0x3f6 , 0x376 };
static const int ide_irq [ 2 ] = { 14 , 15 };
212
213
214
215
216
217
218
219
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 ;
220
221
/* Sun4u hardware initialisation */
222
static void sun4u_init ( int ram_size , int vga_ram_size , const char * boot_devices ,
223
224
DisplayState * ds , const char ** fd_filename , int snapshot ,
const char * kernel_filename , const char * kernel_cmdline ,
225
const char * initrd_filename , const char * cpu_model )
226
{
227
CPUState * env ;
228
char buf [ 1024 ];
229
m48t59_t * nvram ;
230
231
int ret , linux_boot ;
unsigned int i ;
232
233
long prom_offset , initrd_size , kernel_size ;
PCIBus * pci_bus ;
234
QEMUBH * bh ;
235
qemu_irq * irq ;
236
237
238
linux_boot = ( kernel_filename != NULL );
239
240
241
/* init CPUs */
if ( cpu_model == NULL )
cpu_model = "TI UltraSparc II" ;
242
243
env = cpu_init ( cpu_model );
if ( ! env ) {
244
245
246
fprintf ( stderr , "Unable to find Sparc CPU definition \n " );
exit ( 1 );
}
247
248
249
250
251
252
253
254
255
256
257
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 );
258
259
register_savevm ( "cpu" , 0 , 3 , cpu_save , cpu_load , env );
qemu_register_reset ( main_cpu_reset , env );
260
main_cpu_reset ( env );
261
262
263
264
/* allocate RAM */
cpu_register_physical_memory ( 0 , ram_size , 0 );
265
prom_offset = ram_size + vga_ram_size ;
ths
authored
18 years ago
266
267
cpu_register_physical_memory ( PROM_ADDR ,
( PROM_SIZE_MAX + TARGET_PAGE_SIZE ) & TARGET_PAGE_MASK ,
268
prom_offset | IO_MEM_ROM );
269
270
271
272
if ( bios_name == NULL )
bios_name = PROM_FILENAME ;
snprintf ( buf , sizeof ( buf ), "%s/%s" , bios_dir , bios_name );
273
ret = load_elf ( buf , PROM_ADDR - PROM_VADDR , NULL , NULL , NULL );
274
if ( ret < 0 ) {
275
276
277
fprintf ( stderr , "qemu: could not load prom '%s' \n " ,
buf );
exit ( 1 );
278
279
280
}
kernel_size = 0 ;
281
initrd_size = 0 ;
282
if ( linux_boot ) {
283
/* XXX: put correct offset */
ths
authored
18 years ago
284
kernel_size = load_elf ( kernel_filename , 0 , NULL , NULL , NULL );
285
if ( kernel_size < 0 )
286
287
288
kernel_size = load_aout ( kernel_filename , phys_ram_base + KERNEL_LOAD_ADDR );
if ( kernel_size < 0 )
kernel_size = load_image ( kernel_filename , phys_ram_base + KERNEL_LOAD_ADDR );
289
if ( kernel_size < 0 ) {
ths
authored
18 years ago
290
fprintf ( stderr , "qemu: could not load kernel '%s' \n " ,
291
kernel_filename );
292
exit ( 1 );
293
294
295
296
297
298
}
/* load initrd */
if ( initrd_filename ) {
initrd_size = load_image ( initrd_filename , phys_ram_base + INITRD_LOAD_ADDR );
if ( initrd_size < 0 ) {
ths
authored
18 years ago
299
fprintf ( stderr , "qemu: could not load initial ram disk '%s' \n " ,
300
301
302
303
304
initrd_filename );
exit ( 1 );
}
}
if ( initrd_size > 0 ) {
305
306
307
308
309
310
311
312
for ( i = 0 ; i < 64 * TARGET_PAGE_SIZE ; i += TARGET_PAGE_SIZE ) {
if ( ldl_raw ( phys_ram_base + KERNEL_LOAD_ADDR + i )
== 0x48647253 ) { // HdrS
stl_raw ( phys_ram_base + KERNEL_LOAD_ADDR + i + 16 , INITRD_LOAD_ADDR );
stl_raw ( phys_ram_base + KERNEL_LOAD_ADDR + i + 20 , initrd_size );
break ;
}
}
313
314
}
}
315
pci_bus = pci_apb_init ( APB_SPECIAL_BASE , APB_MEM_BASE , NULL );
316
isa_mem_base = VGA_BASE ;
317
pci_cirrus_vga_init ( pci_bus , ds , phys_ram_base + ram_size , ram_size , vga_ram_size );
318
319
320
for ( i = 0 ; i < MAX_SERIAL_PORTS ; i ++ ) {
if ( serial_hds [ i ]) {
321
serial_init ( serial_io [ i ], NULL /*serial_irq[i]*/ , serial_hds [ i ]);
322
323
324
325
326
}
}
for ( i = 0 ; i < MAX_PARALLEL_PORTS ; i ++ ) {
if ( parallel_hds [ i ]) {
327
parallel_init ( parallel_io [ i ], NULL /*parallel_irq[i]*/ , parallel_hds [ i ]);
328
329
330
331
}
}
for ( i = 0 ; i < nb_nics ; i ++ ) {
332
333
if ( ! nd_table [ i ]. model )
nd_table [ i ]. model = "ne2k_pci" ;
334
pci_nic_init ( pci_bus , & nd_table [ i ], - 1 );
335
336
}
337
338
339
irq = qemu_allocate_irqs ( dummy_cpu_set_irq , NULL , 32 );
// XXX pci_cmd646_ide_init ( pci_bus , bs_table , 1 );
pci_piix3_ide_init ( pci_bus , bs_table , - 1 , irq );
340
341
342
343
/* FIXME: wire up interrupts. */
i8042_init ( NULL /*1*/ , NULL /*12*/ , 0x60 );
floppy_controller = fdctrl_init ( NULL /*6*/ , 2 , 0 , 0x3f0 , fd_table );
nvram = m48t59_init ( NULL /*8*/ , 0 , 0x0074 , NVRAM_SIZE , 59 );
344
sun4u_NVRAM_set_params ( nvram , NVRAM_SIZE , "Sun4u" , ram_size , boot_devices ,
345
346
347
348
349
350
351
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 );
352
353
354
355
356
357
358
}
QEMUMachine sun4u_machine = {
"sun4u" ,
"Sun4u platform" ,
sun4u_init ,
};