Revision 7d85892b hw/sun4m.c
b/hw/sun4m.c | ||
---|---|---|
1 | 1 |
/* |
2 |
* QEMU Sun4m System Emulator |
|
2 |
* QEMU Sun4m & Sun4d System Emulator
|
|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2003-2005 Fabrice Bellard |
5 | 5 |
* |
... | ... | |
46 | 46 |
* SPARCstation 20/xx, SPARCserver 20 |
47 | 47 |
* SPARCstation 4 |
48 | 48 |
* |
49 |
* Sun4d architecture was used in the following machines: |
|
50 |
* |
|
51 |
* SPARCcenter 2000 |
|
52 |
* SPARCserver 1000 |
|
53 |
* |
|
49 | 54 |
* See for example: http://www.sunhelp.org/faq/sunref1.html |
50 | 55 |
*/ |
51 | 56 |
|
... | ... | |
86 | 91 |
const char * const default_cpu_model; |
87 | 92 |
}; |
88 | 93 |
|
94 |
#define MAX_IOUNITS 5 |
|
95 |
|
|
96 |
struct sun4d_hwdef { |
|
97 |
target_phys_addr_t iounit_bases[MAX_IOUNITS], slavio_base; |
|
98 |
target_phys_addr_t counter_base, nvram_base, ms_kb_base; |
|
99 |
target_phys_addr_t serial_base; |
|
100 |
target_phys_addr_t espdma_base, esp_base; |
|
101 |
target_phys_addr_t ledma_base, le_base; |
|
102 |
target_phys_addr_t tcx_base; |
|
103 |
target_phys_addr_t sbi_base; |
|
104 |
unsigned long vram_size, nvram_size; |
|
105 |
// IRQ numbers are not PIL ones, but SBI register bit numbers |
|
106 |
int esp_irq, le_irq, clock_irq, clock1_irq; |
|
107 |
int ser_irq, ms_kb_irq, me_irq; |
|
108 |
int machine_id; // For NVRAM |
|
109 |
uint32_t iounit_version; |
|
110 |
uint64_t max_mem; |
|
111 |
const char * const default_cpu_model; |
|
112 |
}; |
|
113 |
|
|
89 | 114 |
/* TSC handling */ |
90 | 115 |
|
91 | 116 |
uint64_t cpu_get_tsc() |
... | ... | |
122 | 147 |
const char *boot_devices, uint32_t RAM_size, |
123 | 148 |
uint32_t kernel_size, |
124 | 149 |
int width, int height, int depth, |
125 |
int machine_id) |
|
150 |
int machine_id, const char *arch)
|
|
126 | 151 |
{ |
127 | 152 |
unsigned int i; |
128 | 153 |
uint32_t start, end; |
... | ... | |
140 | 165 |
header->nvram_size = cpu_to_be16(0x2000); |
141 | 166 |
header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t)); |
142 | 167 |
header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg)); |
143 |
strcpy(header->arch, "sun4m");
|
|
168 |
strcpy(header->arch, arch);
|
|
144 | 169 |
header->nb_cpus = smp_cpus & 0xff; |
145 | 170 |
header->RAM0_base = 0; |
146 | 171 |
header->RAM0_size = cpu_to_be64((uint64_t)RAM_size); |
... | ... | |
203 | 228 |
|
204 | 229 |
void pic_info() |
205 | 230 |
{ |
206 |
slavio_pic_info(slavio_intctl); |
|
231 |
if (slavio_intctl) |
|
232 |
slavio_pic_info(slavio_intctl); |
|
207 | 233 |
} |
208 | 234 |
|
209 | 235 |
void irq_info() |
210 | 236 |
{ |
211 |
slavio_irq_info(slavio_intctl); |
|
237 |
if (slavio_intctl) |
|
238 |
slavio_irq_info(slavio_intctl); |
|
212 | 239 |
} |
213 | 240 |
|
214 | 241 |
void cpu_check_irqs(CPUState *env) |
... | ... | |
488 | 515 |
|
489 | 516 |
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, |
490 | 517 |
boot_device, RAM_size, kernel_size, graphic_width, |
491 |
graphic_height, graphic_depth, hwdef->machine_id); |
|
518 |
graphic_height, graphic_depth, hwdef->machine_id, "Sun4m");
|
|
492 | 519 |
|
493 | 520 |
if (hwdef->ecc_base != (target_phys_addr_t)-1) |
494 | 521 |
ecc_init(hwdef->ecc_base, hwdef->ecc_version); |
... | ... | |
716 | 743 |
ss20_init, |
717 | 744 |
}; |
718 | 745 |
|
746 |
|
|
747 |
static const struct sun4d_hwdef sun4d_hwdefs[] = { |
|
748 |
/* SS-1000 */ |
|
749 |
{ |
|
750 |
.iounit_bases = { |
|
751 |
0xfe0200000ULL, |
|
752 |
0xfe1200000ULL, |
|
753 |
0xfe2200000ULL, |
|
754 |
0xfe3200000ULL, |
|
755 |
-1, |
|
756 |
}, |
|
757 |
.tcx_base = 0x820000000ULL, |
|
758 |
.slavio_base = 0xf00000000ULL, |
|
759 |
.ms_kb_base = 0xf00240000ULL, |
|
760 |
.serial_base = 0xf00200000ULL, |
|
761 |
.nvram_base = 0xf00280000ULL, |
|
762 |
.counter_base = 0xf00300000ULL, |
|
763 |
.espdma_base = 0x800081000ULL, |
|
764 |
.esp_base = 0x800080000ULL, |
|
765 |
.ledma_base = 0x800040000ULL, |
|
766 |
.le_base = 0x800060000ULL, |
|
767 |
.sbi_base = 0xf02800000ULL, |
|
768 |
.vram_size = 0x00100000, |
|
769 |
.nvram_size = 0x2000, |
|
770 |
.esp_irq = 3, |
|
771 |
.le_irq = 4, |
|
772 |
.clock_irq = 14, |
|
773 |
.clock1_irq = 10, |
|
774 |
.ms_kb_irq = 12, |
|
775 |
.ser_irq = 12, |
|
776 |
.machine_id = 0x80, |
|
777 |
.iounit_version = 0x03000000, |
|
778 |
.max_mem = 0xffffffff, // XXX actually first 62GB ok |
|
779 |
.default_cpu_model = "TI SuperSparc II", |
|
780 |
}, |
|
781 |
/* SS-2000 */ |
|
782 |
{ |
|
783 |
.iounit_bases = { |
|
784 |
0xfe0200000ULL, |
|
785 |
0xfe1200000ULL, |
|
786 |
0xfe2200000ULL, |
|
787 |
0xfe3200000ULL, |
|
788 |
0xfe4200000ULL, |
|
789 |
}, |
|
790 |
.tcx_base = 0x820000000ULL, |
|
791 |
.slavio_base = 0xf00000000ULL, |
|
792 |
.ms_kb_base = 0xf00240000ULL, |
|
793 |
.serial_base = 0xf00200000ULL, |
|
794 |
.nvram_base = 0xf00280000ULL, |
|
795 |
.counter_base = 0xf00300000ULL, |
|
796 |
.espdma_base = 0x800081000ULL, |
|
797 |
.esp_base = 0x800080000ULL, |
|
798 |
.ledma_base = 0x800040000ULL, |
|
799 |
.le_base = 0x800060000ULL, |
|
800 |
.sbi_base = 0xf02800000ULL, |
|
801 |
.vram_size = 0x00100000, |
|
802 |
.nvram_size = 0x2000, |
|
803 |
.esp_irq = 3, |
|
804 |
.le_irq = 4, |
|
805 |
.clock_irq = 14, |
|
806 |
.clock1_irq = 10, |
|
807 |
.ms_kb_irq = 12, |
|
808 |
.ser_irq = 12, |
|
809 |
.machine_id = 0x80, |
|
810 |
.iounit_version = 0x03000000, |
|
811 |
.max_mem = 0xffffffff, // XXX actually first 62GB ok |
|
812 |
.default_cpu_model = "TI SuperSparc II", |
|
813 |
}, |
|
814 |
}; |
|
815 |
|
|
816 |
static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, int RAM_size, |
|
817 |
const char *boot_device, |
|
818 |
DisplayState *ds, const char *kernel_filename, |
|
819 |
const char *kernel_cmdline, |
|
820 |
const char *initrd_filename, const char *cpu_model) |
|
821 |
{ |
|
822 |
CPUState *env, *envs[MAX_CPUS]; |
|
823 |
unsigned int i; |
|
824 |
void *iounits[MAX_IOUNITS], *espdma, *ledma, *main_esp, *nvram, *sbi; |
|
825 |
qemu_irq *cpu_irqs[MAX_CPUS], *sbi_irq, *sbi_cpu_irq, |
|
826 |
*espdma_irq, *ledma_irq; |
|
827 |
qemu_irq *esp_reset, *le_reset; |
|
828 |
unsigned long prom_offset, kernel_size; |
|
829 |
int ret; |
|
830 |
char buf[1024]; |
|
831 |
int index; |
|
832 |
|
|
833 |
/* init CPUs */ |
|
834 |
if (!cpu_model) |
|
835 |
cpu_model = hwdef->default_cpu_model; |
|
836 |
|
|
837 |
for (i = 0; i < smp_cpus; i++) { |
|
838 |
env = cpu_init(cpu_model); |
|
839 |
if (!env) { |
|
840 |
fprintf(stderr, "Unable to find Sparc CPU definition\n"); |
|
841 |
exit(1); |
|
842 |
} |
|
843 |
cpu_sparc_set_id(env, i); |
|
844 |
envs[i] = env; |
|
845 |
if (i == 0) { |
|
846 |
qemu_register_reset(main_cpu_reset, env); |
|
847 |
} else { |
|
848 |
qemu_register_reset(secondary_cpu_reset, env); |
|
849 |
env->halted = 1; |
|
850 |
} |
|
851 |
register_savevm("cpu", i, 3, cpu_save, cpu_load, env); |
|
852 |
cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); |
|
853 |
env->prom_addr = hwdef->slavio_base; |
|
854 |
} |
|
855 |
|
|
856 |
for (i = smp_cpus; i < MAX_CPUS; i++) |
|
857 |
cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); |
|
858 |
|
|
859 |
/* allocate RAM */ |
|
860 |
if ((uint64_t)RAM_size > hwdef->max_mem) { |
|
861 |
fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", |
|
862 |
(unsigned int)RAM_size / (1024 * 1024), |
|
863 |
(unsigned int)(hwdef->max_mem / (1024 * 1024))); |
|
864 |
exit(1); |
|
865 |
} |
|
866 |
cpu_register_physical_memory(0, RAM_size, 0); |
|
867 |
|
|
868 |
/* load boot prom */ |
|
869 |
prom_offset = RAM_size + hwdef->vram_size; |
|
870 |
cpu_register_physical_memory(hwdef->slavio_base, |
|
871 |
(PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & |
|
872 |
TARGET_PAGE_MASK, |
|
873 |
prom_offset | IO_MEM_ROM); |
|
874 |
|
|
875 |
if (bios_name == NULL) |
|
876 |
bios_name = PROM_FILENAME; |
|
877 |
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); |
|
878 |
ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); |
|
879 |
if (ret < 0 || ret > PROM_SIZE_MAX) |
|
880 |
ret = load_image(buf, phys_ram_base + prom_offset); |
|
881 |
if (ret < 0 || ret > PROM_SIZE_MAX) { |
|
882 |
fprintf(stderr, "qemu: could not load prom '%s'\n", |
|
883 |
buf); |
|
884 |
exit(1); |
|
885 |
} |
|
886 |
|
|
887 |
/* set up devices */ |
|
888 |
sbi = sbi_init(hwdef->sbi_base, &sbi_irq, &sbi_cpu_irq, cpu_irqs); |
|
889 |
|
|
890 |
for (i = 0; i < MAX_IOUNITS; i++) |
|
891 |
if (hwdef->iounit_bases[i] != (target_phys_addr_t)-1) |
|
892 |
iounits[i] = iommu_init(hwdef->iounit_bases[i], hwdef->iounit_version); |
|
893 |
|
|
894 |
espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[hwdef->esp_irq], |
|
895 |
iounits[0], &espdma_irq, &esp_reset); |
|
896 |
|
|
897 |
ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[hwdef->le_irq], |
|
898 |
iounits[0], &ledma_irq, &le_reset); |
|
899 |
|
|
900 |
if (graphic_depth != 8 && graphic_depth != 24) { |
|
901 |
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); |
|
902 |
exit (1); |
|
903 |
} |
|
904 |
tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, |
|
905 |
hwdef->vram_size, graphic_width, graphic_height, graphic_depth); |
|
906 |
|
|
907 |
if (nd_table[0].model == NULL |
|
908 |
|| strcmp(nd_table[0].model, "lance") == 0) { |
|
909 |
lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); |
|
910 |
} else if (strcmp(nd_table[0].model, "?") == 0) { |
|
911 |
fprintf(stderr, "qemu: Supported NICs: lance\n"); |
|
912 |
exit (1); |
|
913 |
} else { |
|
914 |
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); |
|
915 |
exit (1); |
|
916 |
} |
|
917 |
|
|
918 |
nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, |
|
919 |
hwdef->nvram_size, 8); |
|
920 |
|
|
921 |
slavio_timer_init_all(hwdef->counter_base, sbi_irq[hwdef->clock1_irq], |
|
922 |
sbi_cpu_irq, smp_cpus); |
|
923 |
|
|
924 |
slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[hwdef->ms_kb_irq], |
|
925 |
nographic); |
|
926 |
// Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device |
|
927 |
// Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device |
|
928 |
slavio_serial_init(hwdef->serial_base, sbi_irq[hwdef->ser_irq], |
|
929 |
serial_hds[1], serial_hds[0]); |
|
930 |
|
|
931 |
if (drive_get_max_bus(IF_SCSI) > 0) { |
|
932 |
fprintf(stderr, "qemu: too many SCSI bus\n"); |
|
933 |
exit(1); |
|
934 |
} |
|
935 |
|
|
936 |
main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, |
|
937 |
esp_reset); |
|
938 |
|
|
939 |
for (i = 0; i < ESP_MAX_DEVS; i++) { |
|
940 |
index = drive_get_index(IF_SCSI, 0, i); |
|
941 |
if (index == -1) |
|
942 |
continue; |
|
943 |
esp_scsi_attach(main_esp, drives_table[index].bdrv, i); |
|
944 |
} |
|
945 |
|
|
946 |
kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, |
|
947 |
initrd_filename); |
|
948 |
|
|
949 |
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, |
|
950 |
boot_device, RAM_size, kernel_size, graphic_width, |
|
951 |
graphic_height, graphic_depth, hwdef->machine_id, "Sun4d"); |
|
952 |
} |
|
953 |
|
|
954 |
/* SPARCserver 1000 hardware initialisation */ |
|
955 |
static void ss1000_init(int RAM_size, int vga_ram_size, |
|
956 |
const char *boot_device, DisplayState *ds, |
|
957 |
const char *kernel_filename, const char *kernel_cmdline, |
|
958 |
const char *initrd_filename, const char *cpu_model) |
|
959 |
{ |
|
960 |
sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, ds, kernel_filename, |
|
961 |
kernel_cmdline, initrd_filename, cpu_model); |
|
962 |
} |
|
963 |
|
|
964 |
/* SPARCcenter 2000 hardware initialisation */ |
|
965 |
static void ss2000_init(int RAM_size, int vga_ram_size, |
|
966 |
const char *boot_device, DisplayState *ds, |
|
967 |
const char *kernel_filename, const char *kernel_cmdline, |
|
968 |
const char *initrd_filename, const char *cpu_model) |
|
969 |
{ |
|
970 |
sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, ds, kernel_filename, |
|
971 |
kernel_cmdline, initrd_filename, cpu_model); |
|
972 |
} |
|
973 |
|
|
974 |
QEMUMachine ss1000_machine = { |
|
975 |
"SS-1000", |
|
976 |
"Sun4d platform, SPARCserver 1000", |
|
977 |
ss1000_init, |
|
978 |
}; |
|
979 |
|
|
980 |
QEMUMachine ss2000_machine = { |
|
981 |
"SS-2000", |
|
982 |
"Sun4d platform, SPARCcenter 2000", |
|
983 |
ss2000_init, |
|
984 |
}; |
Also available in: Unified diff