Compare commits
115
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1909e1ca09 | ||
|
|
f5a8510c7c | ||
|
|
93856aac7b | ||
|
|
5cedb46460 | ||
|
|
0f4c64157f | ||
|
|
90cb949352 | ||
|
|
db6e6ed77e | ||
|
|
57e4c06ed7 | ||
|
|
09d459a1db | ||
|
|
108c49b8a2 | ||
|
|
90f18422d9 | ||
|
|
9529397248 | ||
|
|
a2458627f9 | ||
|
|
b1fc0348b1 | ||
|
|
45bbbb466c | ||
|
|
d592d3033d | ||
|
|
1ff5c1a68e | ||
|
|
e5d80f94c5 | ||
|
|
8f091a5960 | ||
|
|
2efbe911d3 | ||
|
|
667f38b167 | ||
|
|
8346901560 | ||
|
|
b7c7b18129 | ||
|
|
9835236910 | ||
|
|
e573335624 | ||
|
|
4e588a4d0e | ||
|
|
a368741bf2 | ||
|
|
61271e5c2d | ||
|
|
aefce9af41 | ||
|
|
ee5bbe38b1 | ||
|
|
e37e863f5e | ||
|
|
fdabc366bd | ||
|
|
2157fa0682 | ||
|
|
d24b15a8d8 | ||
|
|
9d0a8e6f8f | ||
|
|
51a36cb2cb | ||
|
|
33d084399c | ||
|
|
e0727e17f3 | ||
|
|
97067eb5bc | ||
|
|
4157a66212 | ||
|
|
0289b2c1df | ||
|
|
d5295253b0 | ||
|
|
fb3444b86c | ||
|
|
2be0071f22 | ||
|
|
f68c781c2d | ||
|
|
fa296b0fb4 | ||
|
|
3fc6c082e3 | ||
|
|
2f636b458f | ||
|
|
3de388f676 | ||
|
|
73133662c6 | ||
|
|
bf82d81801 | ||
|
|
b195775fef | ||
|
|
1b351e5291 | ||
|
|
d325856010 | ||
|
|
0d8aca8c67 | ||
|
|
8549850891 | ||
|
|
7a962d3087 | ||
|
|
e1d9a50836 | ||
|
|
568b600d85 | ||
|
|
bc2c390907 | ||
|
|
9827e95c78 | ||
|
|
51e11d9e6c | ||
|
|
90b37806ba | ||
|
|
0699b54839 | ||
|
|
9d1d106a3d | ||
|
|
ae022501f2 | ||
|
|
899abcf513 | ||
|
|
dfae6487c0 | ||
|
|
de12d6369b | ||
|
|
bc9ed47b12 | ||
|
|
9fb63ac281 | ||
|
|
6af0bf9c7c | ||
|
|
6643d27ea0 | ||
|
|
3475187dd8 | ||
|
|
8979b2277d | ||
|
|
97ccc689e6 | ||
|
|
c98baaac2f | ||
|
|
101c593562 | ||
|
|
b685369795 | ||
|
|
3f1a88f450 | ||
|
|
a84eaf0c9b | ||
|
|
6e20a45f53 | ||
|
|
cadae95f33 | ||
|
|
e68b9b2b10 | ||
|
|
c0e564d53b | ||
|
|
384d887691 | ||
|
|
5457c8ceeb | ||
|
|
0aa6a4a250 | ||
|
|
938828a263 | ||
|
|
b5ff2d6e2d | ||
|
|
54fa5af546 | ||
|
|
cc1daa40f1 | ||
|
|
2d61879305 | ||
|
|
7c48011b45 | ||
|
|
8dd4983c4e | ||
|
|
71be0fc3eb | ||
|
|
30aec8768f | ||
|
|
8993433789 | ||
|
|
d094807b9b | ||
|
|
6d506e6dc2 | ||
|
|
43ef9eb267 | ||
|
|
e4cf1adc80 | ||
|
|
72cc6cfeef | ||
|
|
bc380d1719 | ||
|
|
ff8263a951 | ||
|
|
04d81be884 | ||
|
|
2d5262f991 | ||
|
|
a09db21f71 | ||
|
|
b671f9ed2d | ||
|
|
de167e416f | ||
|
|
712e78744e | ||
|
|
7c35359cbf | ||
|
|
d37282add1 | ||
|
|
a343df1659 | ||
|
|
98ff7d30f2 |
No files matched your search
@@ -6,6 +6,7 @@ i386
|
||||
i386-softmmu
|
||||
i386-user
|
||||
ppc-softmmu
|
||||
ppc64-softmmu
|
||||
ppc-user
|
||||
qemu-doc.html
|
||||
qemu-tech.html
|
||||
@@ -19,3 +20,4 @@ sparc-softmmu
|
||||
x86_64-softmmu
|
||||
sparc64-user
|
||||
sparc64-softmmu
|
||||
mips-softmmu
|
||||
@@ -1,3 +1,14 @@
|
||||
version 0.7.1:
|
||||
|
||||
- read-only Virtual FAT support (Johannes Schindelin)
|
||||
- Windows 2000 install disk full hack (original idea from Vladimir
|
||||
N. Oleynik)
|
||||
- VMDK disk image creation (Filip Navara)
|
||||
- SPARC64 progress (Blue Swirl)
|
||||
- initial MIPS support (Jocelyn mayer)
|
||||
- MIPS improvements (Ralf Baechle)
|
||||
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
|
||||
|
||||
version 0.7.0:
|
||||
|
||||
- better BIOS translation and HDD geometry auto-detection
|
||||
|
||||
@@ -25,7 +25,7 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
|
||||
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
|
||||
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
|
||||
|
||||
dyngen$(EXESUF): dyngen.c
|
||||
@@ -59,7 +59,7 @@ install: all
|
||||
mkdir -p "$(datadir)"
|
||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
|
||||
pc-bios/vgabios-cirrus.bin \
|
||||
pc-bios/ppc_rom.bin \
|
||||
pc-bios/ppc_rom.bin pc-bios/video.x \
|
||||
pc-bios/proll.elf \
|
||||
pc-bios/linux_boot.bin "$(datadir)"
|
||||
mkdir -p "$(docdir)"
|
||||
@@ -112,6 +112,7 @@ tarbin:
|
||||
$(bindir)/qemu-system-ppc \
|
||||
$(bindir)/qemu-system-sparc \
|
||||
$(bindir)/qemu-system-x86_64 \
|
||||
$(bindir)/qemu-system-mips \
|
||||
$(bindir)/qemu-i386 \
|
||||
$(bindir)/qemu-arm \
|
||||
$(bindir)/qemu-sparc \
|
||||
@@ -121,6 +122,7 @@ tarbin:
|
||||
$(datadir)/vgabios.bin \
|
||||
$(datadir)/vgabios-cirrus.bin \
|
||||
$(datadir)/ppc_rom.bin \
|
||||
$(datadir)/video.x \
|
||||
$(datadir)/proll.elf \
|
||||
$(datadir)/linux_boot.bin \
|
||||
$(docdir)/qemu-doc.html \
|
||||
|
||||
+36
-72
@@ -4,6 +4,9 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH)
|
||||
ifeq ($(TARGET_ARCH), x86_64)
|
||||
TARGET_BASE_ARCH:=i386
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), ppc64)
|
||||
TARGET_BASE_ARCH:=ppc
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
TARGET_BASE_ARCH:=sparc
|
||||
endif
|
||||
@@ -44,74 +47,10 @@ endif
|
||||
ifdef CONFIG_USER_ONLY
|
||||
PROGS=$(QEMU_USER)
|
||||
else
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
ifndef CONFIG_SOFTMMU
|
||||
CONFIG_STATIC=y
|
||||
endif
|
||||
else
|
||||
# the system emulator using soft mmu is portable
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH != i386
|
||||
|
||||
endif # TARGET_ARCH = i386
|
||||
|
||||
ifeq ($(TARGET_ARCH), x86_64)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # TARGET_ARCH = x86_64
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
|
||||
ifeq ($(ARCH), ppc)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = i386
|
||||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = x86_64
|
||||
|
||||
endif # TARGET_ARCH = ppc
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc)
|
||||
|
||||
ifeq ($(ARCH), ppc)
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH), i386)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = i386
|
||||
|
||||
ifeq ($(ARCH), x86_64)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # ARCH = x86_64
|
||||
|
||||
endif # TARGET_ARCH = sparc
|
||||
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
ifdef CONFIG_SOFTMMU
|
||||
PROGS+=$(QEMU_SYSTEM)
|
||||
endif
|
||||
endif # TARGET_ARCH = sparc64
|
||||
|
||||
endif # !CONFIG_USER_ONLY
|
||||
|
||||
ifdef CONFIG_STATIC
|
||||
@@ -259,7 +198,11 @@ ifeq ($(TARGET_ARCH), x86_64)
|
||||
LIBOBJS+=helper.o helper2.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
LIBOBJS+= op_helper.o helper.o
|
||||
endif
|
||||
|
||||
@@ -285,9 +228,12 @@ endif
|
||||
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
|
||||
LIBOBJS+=alpha-dis.o
|
||||
endif
|
||||
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
|
||||
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
|
||||
LIBOBJS+=ppc-dis.o
|
||||
endif
|
||||
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
|
||||
LIBOBJS+=mips-dis.o
|
||||
endif
|
||||
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
|
||||
LIBOBJS+=sparc-dis.o
|
||||
endif
|
||||
@@ -314,7 +260,7 @@ endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
|
||||
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o
|
||||
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
|
||||
|
||||
SOUND_HW = sb16.o
|
||||
AUDIODRV = audio.o noaudio.o wavaudio.o
|
||||
@@ -343,13 +289,24 @@ VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
|
||||
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
|
||||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
|
||||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o
|
||||
#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o
|
||||
ifeq ($(TARGET_ARCH), sparc64)
|
||||
VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
|
||||
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
|
||||
VL_OBJS+= cirrus_vga.o parallel.o
|
||||
VL_OBJS+= magic-load.o
|
||||
else
|
||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_GDBSTUB
|
||||
VL_OBJS+=gdbstub.o
|
||||
@@ -442,12 +399,19 @@ op.o: op.c op_template.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), sparc)
|
||||
op.o: op.c op_template.h op_mem.h
|
||||
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
|
||||
magic_load.o: elf_op.h
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), ppc)
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
op.o: op.c op_template.h op_mem.h
|
||||
op_helper.o: op_helper_mem.h
|
||||
translate.o: translate.c translate_init.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
op.o: op.c op_template.c op_mem.c
|
||||
op_helper.o: op_helper_mem.c
|
||||
endif
|
||||
|
||||
mixeng.o: mixeng.c mixeng.h mixeng_template.h
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
|
||||
int fmt, freq, nchannels;
|
||||
const char *dspname = conf.dspname;
|
||||
|
||||
fd = open (dspname, O_RDWR | O_NONBLOCK);
|
||||
fd = open (dspname, O_WRONLY | O_NONBLOCK);
|
||||
if (-1 == fd) {
|
||||
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
|
||||
"Reason:%s\n",
|
||||
|
||||
+2
-1
@@ -54,7 +54,8 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const struct cow_header_v2 *cow_header = (const void *)buf;
|
||||
|
||||
if (be32_to_cpu(cow_header->magic) == COW_MAGIC &&
|
||||
if (buf_size >= sizeof(struct cow_header_v2) &&
|
||||
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
|
||||
be32_to_cpu(cow_header->version) == COW_VERSION)
|
||||
return 100;
|
||||
else
|
||||
|
||||
+3
-1
@@ -91,7 +91,9 @@ static int dmg_open(BlockDriverState *bs, const char *filename)
|
||||
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
|
||||
dmg_close:
|
||||
close(s->fd);
|
||||
return -1;
|
||||
/* open raw instead */
|
||||
bs->drv=&bdrv_raw;
|
||||
return bs->drv->bdrv_open(bs,filename);
|
||||
}
|
||||
info_begin=read_off(s->fd);
|
||||
if(info_begin==0)
|
||||
|
||||
+16
-5
@@ -80,8 +80,9 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
|
||||
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
const QCowHeader *cow_header = (const void *)buf;
|
||||
|
||||
if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
||||
|
||||
if (buf_size >= sizeof(QCowHeader) &&
|
||||
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
||||
be32_to_cpu(cow_header->version) == QCOW_VERSION)
|
||||
return 100;
|
||||
else
|
||||
@@ -551,9 +552,19 @@ static int qcow_create(const char *filename, int64_t total_size,
|
||||
header_size = sizeof(header);
|
||||
backing_filename_len = 0;
|
||||
if (backing_file) {
|
||||
realpath(backing_file, backing_filename);
|
||||
if (stat(backing_filename, &st) != 0) {
|
||||
return -1;
|
||||
const char *p;
|
||||
/* XXX: this is a hack: we do not attempt to check for URL
|
||||
like syntax */
|
||||
p = strchr(backing_file, ':');
|
||||
if (p && (p - backing_file) >= 2) {
|
||||
/* URL like but exclude "c:" like filenames */
|
||||
pstrcpy(backing_filename, sizeof(backing_filename),
|
||||
backing_file);
|
||||
} else {
|
||||
realpath(backing_file, backing_filename);
|
||||
if (stat(backing_filename, &st) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
header.mtime = cpu_to_be32(st.st_mtime);
|
||||
header.backing_file_offset = cpu_to_be64(header_size);
|
||||
|
||||
+104
-1
@@ -315,6 +315,109 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmdk_create(const char *filename, int64_t total_size,
|
||||
const char *backing_file, int flags)
|
||||
{
|
||||
int fd, i;
|
||||
VMDK4Header header;
|
||||
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
|
||||
char *desc_template =
|
||||
"# Disk DescriptorFile\n"
|
||||
"version=1\n"
|
||||
"CID=%x\n"
|
||||
"parentCID=ffffffff\n"
|
||||
"createType=\"monolithicSparse\"\n"
|
||||
"\n"
|
||||
"# Extent description\n"
|
||||
"RW %lu SPARSE \"%s\"\n"
|
||||
"\n"
|
||||
"# The Disk Data Base \n"
|
||||
"#DDB\n"
|
||||
"\n"
|
||||
"ddb.virtualHWVersion = \"3\"\n"
|
||||
"ddb.geometry.cylinders = \"%lu\"\n"
|
||||
"ddb.geometry.heads = \"16\"\n"
|
||||
"ddb.geometry.sectors = \"63\"\n"
|
||||
"ddb.adapterType = \"ide\"\n";
|
||||
char desc[1024];
|
||||
const char *real_filename, *temp_str;
|
||||
|
||||
/* XXX: add support for backing file */
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
magic = cpu_to_be32(VMDK4_MAGIC);
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.version = cpu_to_le32(1);
|
||||
header.flags = cpu_to_le32(3); /* ?? */
|
||||
header.capacity = cpu_to_le64(total_size);
|
||||
header.granularity = cpu_to_le64(128);
|
||||
header.num_gtes_per_gte = cpu_to_le32(512);
|
||||
|
||||
grains = (total_size + header.granularity - 1) / header.granularity;
|
||||
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
|
||||
gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
|
||||
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
|
||||
|
||||
header.desc_offset = 1;
|
||||
header.desc_size = 20;
|
||||
header.rgd_offset = header.desc_offset + header.desc_size;
|
||||
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
|
||||
header.grain_offset =
|
||||
((header.gd_offset + gd_size + (gt_size * gt_count) +
|
||||
header.granularity - 1) / header.granularity) *
|
||||
header.granularity;
|
||||
|
||||
header.desc_offset = cpu_to_le64(header.desc_offset);
|
||||
header.desc_size = cpu_to_le64(header.desc_size);
|
||||
header.rgd_offset = cpu_to_le64(header.rgd_offset);
|
||||
header.gd_offset = cpu_to_le64(header.gd_offset);
|
||||
header.grain_offset = cpu_to_le64(header.grain_offset);
|
||||
|
||||
header.check_bytes[0] = 0xa;
|
||||
header.check_bytes[1] = 0x20;
|
||||
header.check_bytes[2] = 0xd;
|
||||
header.check_bytes[3] = 0xa;
|
||||
|
||||
/* write all the data */
|
||||
write(fd, &magic, sizeof(magic));
|
||||
write(fd, &header, sizeof(header));
|
||||
|
||||
ftruncate(fd, header.grain_offset << 9);
|
||||
|
||||
/* write grain directory */
|
||||
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
|
||||
for (i = 0, tmp = header.rgd_offset + gd_size;
|
||||
i < gt_count; i++, tmp += gt_size)
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
|
||||
/* write backup grain directory */
|
||||
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
|
||||
for (i = 0, tmp = header.gd_offset + gd_size;
|
||||
i < gt_count; i++, tmp += gt_size)
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
|
||||
/* compose the descriptor */
|
||||
real_filename = filename;
|
||||
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
if ((temp_str = strrchr(real_filename, '/')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
if ((temp_str = strrchr(real_filename, ':')) != NULL)
|
||||
real_filename = temp_str + 1;
|
||||
sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
|
||||
real_filename, total_size / (63 * 16));
|
||||
|
||||
/* write the descriptor */
|
||||
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
|
||||
write(fd, desc, strlen(desc));
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmdk_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
@@ -331,6 +434,6 @@ BlockDriver bdrv_vmdk = {
|
||||
vmdk_read,
|
||||
vmdk_write,
|
||||
vmdk_close,
|
||||
NULL, /* no create yet */
|
||||
vmdk_create,
|
||||
vmdk_is_allocated,
|
||||
};
|
||||
+1
-2
@@ -81,9 +81,8 @@ typedef struct BDRVVPCState {
|
||||
|
||||
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
if (!strncmp(buf, "conectix", 8))
|
||||
if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
|
||||
return 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1742
File diff suppressed because it is too large.
Load diff
@@ -106,26 +106,29 @@ static BlockDriver *find_image_format(const char *filename)
|
||||
size_t bufsize = 1024;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
if (fd < 0) {
|
||||
buf = NULL;
|
||||
ret = 0;
|
||||
} else {
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
{
|
||||
unsigned int sectorsize = 512;
|
||||
if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
|
||||
sectorsize > bufsize)
|
||||
bufsize = sectorsize;
|
||||
}
|
||||
{
|
||||
unsigned int sectorsize = 512;
|
||||
if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) &&
|
||||
sectorsize > bufsize)
|
||||
bufsize = sectorsize;
|
||||
}
|
||||
#endif
|
||||
buf = malloc(bufsize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
ret = read(fd, buf, bufsize);
|
||||
if (ret < 0) {
|
||||
buf = qemu_malloc(bufsize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
ret = read(fd, buf, bufsize);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
qemu_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
drv = NULL;
|
||||
score_max = 0;
|
||||
@@ -136,7 +139,7 @@ static BlockDriver *find_image_format(const char *filename)
|
||||
drv = drv1;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
qemu_free(buf);
|
||||
return drv;
|
||||
}
|
||||
|
||||
@@ -154,7 +157,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
|
||||
bs->read_only = 0;
|
||||
bs->is_temporary = 0;
|
||||
bs->encrypted = 0;
|
||||
|
||||
|
||||
if (snapshot) {
|
||||
BlockDriverState *bs1;
|
||||
int64_t total_size;
|
||||
@@ -183,7 +186,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
|
||||
filename = tmp_filename;
|
||||
bs->is_temporary = 1;
|
||||
}
|
||||
|
||||
|
||||
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
||||
if (!drv) {
|
||||
drv = find_image_format(filename);
|
||||
@@ -653,4 +656,5 @@ void bdrv_init(void)
|
||||
bdrv_register(&bdrv_dmg);
|
||||
bdrv_register(&bdrv_bochs);
|
||||
bdrv_register(&bdrv_vpc);
|
||||
bdrv_register(&bdrv_vvfat);
|
||||
}
|
||||
@@ -84,6 +84,7 @@ linux="no"
|
||||
kqemu="no"
|
||||
kernel_path=""
|
||||
cocoa="no"
|
||||
check_gfx="yes"
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
@@ -152,6 +153,8 @@ for opt do
|
||||
;;
|
||||
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--make=*) make=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
|
||||
@@ -186,6 +189,8 @@ for opt do
|
||||
;;
|
||||
--enable-cocoa) cocoa="yes" ; sdl="no"
|
||||
;;
|
||||
--disable-gfx-check) check_gfx="no"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -210,11 +215,13 @@ fi
|
||||
|
||||
if test -z "$target_list" ; then
|
||||
# these targets are portable
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu"
|
||||
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
|
||||
# the following are Linux specific
|
||||
if [ "$linux" = "yes" ] ; then
|
||||
target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
|
||||
fi
|
||||
else
|
||||
target_list=$(echo "$target_list" | sed -e 's/,/ /g')
|
||||
fi
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
@@ -244,6 +251,12 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
# host long bits test
|
||||
hostlongbits="32"
|
||||
if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then
|
||||
hostlongbits="64"
|
||||
fi
|
||||
|
||||
# check gcc options support
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
@@ -328,9 +341,11 @@ echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc."
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --static enable static build [$static]"
|
||||
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
|
||||
echo " --enable-adlib enable Adlib emulation"
|
||||
echo " --enable-fmod enable FMOD audio output driver"
|
||||
echo " --fmod-lib path to FMOD library"
|
||||
echo " --fmod-inc path to FMOD includes"
|
||||
@@ -408,6 +423,7 @@ echo "ELF interp prefix $interp_prefix"
|
||||
fi
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "Host C compiler $host_cc"
|
||||
echo "make $make"
|
||||
echo "host CPU $cpu"
|
||||
echo "host big endian $bigendian"
|
||||
@@ -517,6 +533,7 @@ if test "$bigendian" = "yes" ; then
|
||||
echo "WORDS_BIGENDIAN=yes" >> $config_mak
|
||||
echo "#define WORDS_BIGENDIAN 1" >> $config_h
|
||||
fi
|
||||
echo "#define HOST_LONG_BITS $hostlongbits" >> $config_h
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> $config_mak
|
||||
echo "#define CONFIG_WIN32 1" >> $config_h
|
||||
@@ -594,6 +611,8 @@ target_bigendian="no"
|
||||
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
|
||||
[ "$target_cpu" = "mips" ] && target_bigendian=yes
|
||||
target_softmmu="no"
|
||||
if expr $target : '.*-softmmu' > /dev/null ; then
|
||||
target_softmmu="yes"
|
||||
@@ -603,6 +622,14 @@ if expr $target : '.*-user' > /dev/null ; then
|
||||
target_user_only="yes"
|
||||
fi
|
||||
|
||||
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
|
||||
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
|
||||
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
|
||||
echo "To build QEMU with graphical output configure with --disable-gfx-check"
|
||||
echo "Note that this will disable all output from the virtual graphics card."
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
|
||||
|
||||
mkdir -p $target_dir
|
||||
@@ -650,6 +677,11 @@ elif test "$target_cpu" = "ppc" ; then
|
||||
echo "TARGET_ARCH=ppc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
|
||||
echo "#define TARGET_PPC 1" >> $config_h
|
||||
elif test "$target_cpu" = "ppc64" ; then
|
||||
echo "TARGET_ARCH=ppc64" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
|
||||
echo "#define TARGET_PPC 1" >> $config_h
|
||||
echo "#define TARGET_PPC64 1" >> $config_h
|
||||
elif test "$target_cpu" = "x86_64" ; then
|
||||
echo "TARGET_ARCH=x86_64" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
|
||||
@@ -658,6 +690,10 @@ elif test "$target_cpu" = "x86_64" ; then
|
||||
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then
|
||||
echo "#define USE_KQEMU 1" >> $config_h
|
||||
fi
|
||||
elif test "$target_cpu" = "mips" ; then
|
||||
echo "TARGET_ARCH=mips" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"mips\"" >> $config_h
|
||||
echo "#define TARGET_MIPS 1" >> $config_h
|
||||
else
|
||||
echo "Unsupported target CPU"
|
||||
exit 1
|
||||
|
||||
@@ -617,6 +617,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
#define cpu_gen_code cpu_ppc_gen_code
|
||||
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||
|
||||
#elif defined(TARGET_MIPS)
|
||||
#define CPUState CPUMIPSState
|
||||
#define cpu_init cpu_mips_init
|
||||
#define cpu_exec cpu_mips_exec
|
||||
#define cpu_gen_code cpu_mips_gen_code
|
||||
#define cpu_signal_handler cpu_mips_signal_handler
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported target CPU
|
||||
|
||||
+3
-9
@@ -29,12 +29,6 @@
|
||||
#error TARGET_LONG_BITS must be defined before including this header
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
|
||||
#define HOST_LONG_BITS 64
|
||||
#else
|
||||
#define HOST_LONG_BITS 32
|
||||
#endif
|
||||
|
||||
#ifndef TARGET_PHYS_ADDR_BITS
|
||||
#if TARGET_LONG_BITS >= HOST_LONG_BITS
|
||||
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
|
||||
@@ -74,9 +68,9 @@ typedef uint64_t target_phys_addr_t;
|
||||
|
||||
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
|
||||
|
||||
#define EXCP_INTERRUPT 256 /* async interruption */
|
||||
#define EXCP_HLT 257 /* hlt instruction reached */
|
||||
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
|
||||
#define EXCP_INTERRUPT 0x10000 /* async interruption */
|
||||
#define EXCP_HLT 0x10001 /* hlt instruction reached */
|
||||
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
|
||||
|
||||
#define MAX_BREAKPOINTS 32
|
||||
|
||||
|
||||
+122
-3
@@ -47,6 +47,9 @@ void cpu_loop_exit(void)
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
#endif
|
||||
#ifndef TARGET_SPARC
|
||||
#define reg_T2
|
||||
#endif
|
||||
|
||||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
@@ -74,8 +77,12 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
|
||||
|
||||
int cpu_exec(CPUState *env1)
|
||||
{
|
||||
int saved_T0, saved_T1, saved_T2;
|
||||
int saved_T0, saved_T1;
|
||||
#if defined(reg_T2)
|
||||
int saved_T2;
|
||||
#endif
|
||||
CPUState *saved_env;
|
||||
#if defined(TARGET_I386)
|
||||
#ifdef reg_EAX
|
||||
int saved_EAX;
|
||||
#endif
|
||||
@@ -100,6 +107,11 @@ int cpu_exec(CPUState *env1)
|
||||
#ifdef reg_EDI
|
||||
int saved_EDI;
|
||||
#endif
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
uint32_t *saved_regwptr;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
@@ -115,7 +127,9 @@ int cpu_exec(CPUState *env1)
|
||||
env = env1;
|
||||
saved_T0 = T0;
|
||||
saved_T1 = T1;
|
||||
#if defined(reg_T2)
|
||||
saved_T2 = T2;
|
||||
#endif
|
||||
#ifdef __sparc__
|
||||
/* we also save i7 because longjmp may not restore it */
|
||||
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
|
||||
@@ -164,7 +178,11 @@ int cpu_exec(CPUState *env1)
|
||||
env->cpsr = psr & ~CACHED_CPSR_BITS;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
saved_regwptr = REGWPTR;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#elif defined(TARGET_MIPS)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -203,6 +221,8 @@ int cpu_exec(CPUState *env1)
|
||||
env->exception_next_eip, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_MIPS)
|
||||
do_interrupt(env);
|
||||
#elif defined(TARGET_SPARC)
|
||||
do_interrupt(env->exception_index);
|
||||
#endif
|
||||
@@ -284,6 +304,19 @@ int cpu_exec(CPUState *env1)
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_MIPS)
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->CP0_Status & (1 << CP0St_IE)) &&
|
||||
(env->CP0_Cause & 0x0000FF00) &&
|
||||
!(env->hflags & MIPS_HFLAG_EXL) &&
|
||||
!(env->hflags & MIPS_HFLAG_ERL) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
/* Raise it */
|
||||
env->exception_index = EXCP_EXT_INTERRUPT;
|
||||
env->error_code = 0;
|
||||
do_interrupt(env);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->psret != 0)) {
|
||||
@@ -354,9 +387,13 @@ int cpu_exec(CPUState *env1)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
env->cpsr &= ~CACHED_CPSR_BITS;
|
||||
#elif defined(TARGET_SPARC)
|
||||
cpu_dump_state (env, logfile, fprintf, 0);
|
||||
REGWPTR = env->regbase + (env->cwp * 16);
|
||||
env->regwptr = REGWPTR;
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_PPC)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#elif defined(TARGET_MIPS)
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -376,7 +413,11 @@ int cpu_exec(CPUState *env1)
|
||||
cs_base = 0;
|
||||
pc = env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
flags = 0;
|
||||
#ifdef TARGET_SPARC64
|
||||
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
|
||||
#else
|
||||
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
|
||||
#endif
|
||||
cs_base = env->npc;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_PPC)
|
||||
@@ -384,6 +425,10 @@ int cpu_exec(CPUState *env1)
|
||||
(msr_se << MSR_SE) | (msr_le << MSR_LE);
|
||||
cs_base = 0;
|
||||
pc = env->nip;
|
||||
#elif defined(TARGET_MIPS)
|
||||
flags = env->hflags & MIPS_HFLAGS_TMASK;
|
||||
cs_base = NULL;
|
||||
pc = env->PC;
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
@@ -657,7 +702,11 @@ int cpu_exec(CPUState *env1)
|
||||
env->cpsr = compute_cpsr();
|
||||
/* XXX: Save/restore host fpu exception state?. */
|
||||
#elif defined(TARGET_SPARC)
|
||||
#if defined(reg_REGWPTR)
|
||||
REGWPTR = saved_regwptr;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#elif defined(TARGET_MIPS)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -666,7 +715,9 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
T0 = saved_T0;
|
||||
T1 = saved_T1;
|
||||
#if defined(reg_T2)
|
||||
T2 = saved_T2;
|
||||
#endif
|
||||
env = saved_env;
|
||||
return ret;
|
||||
}
|
||||
@@ -907,6 +958,57 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined (TARGET_MIPS)
|
||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
int is_write, sigset_t *old_set,
|
||||
void *puc)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
if (is_write && page_unprotect(address, pc, puc)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* see if it is an MMU fault */
|
||||
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
|
||||
if (ret < 0)
|
||||
return 0; /* not an MMU fault */
|
||||
if (ret == 0)
|
||||
return 1; /* the MMU fault was handled without causing real CPU fault */
|
||||
|
||||
/* now we have a real cpu fault */
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, puc);
|
||||
}
|
||||
if (ret == 1) {
|
||||
#if 0
|
||||
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
|
||||
env->nip, env->error_code, tb);
|
||||
#endif
|
||||
/* we restore the process signal mask as the sigreturn should
|
||||
do it (XXX: use sigsetjmp) */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
} else {
|
||||
/* activate soft MMU for this block */
|
||||
cpu_resume_from_signal(env, puc);
|
||||
}
|
||||
/* never comes here */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
@@ -1178,6 +1280,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, struct siginfo *info,
|
||||
void *puc)
|
||||
{
|
||||
struct ucontext *uc = puc;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = uc->uc_mcontext.psw.addr;
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
|
||||
is_write,
|
||||
&uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error host CPU specific signal handler needed
|
||||
|
||||
@@ -126,6 +126,24 @@ enum bfd_architecture
|
||||
#define bfd_mach_h8300h 2
|
||||
#define bfd_mach_h8300s 3
|
||||
bfd_arch_powerpc, /* PowerPC */
|
||||
#define bfd_mach_ppc 0
|
||||
#define bfd_mach_ppc64 1
|
||||
#define bfd_mach_ppc_403 403
|
||||
#define bfd_mach_ppc_403gc 4030
|
||||
#define bfd_mach_ppc_505 505
|
||||
#define bfd_mach_ppc_601 601
|
||||
#define bfd_mach_ppc_602 602
|
||||
#define bfd_mach_ppc_603 603
|
||||
#define bfd_mach_ppc_ec603e 6031
|
||||
#define bfd_mach_ppc_604 604
|
||||
#define bfd_mach_ppc_620 620
|
||||
#define bfd_mach_ppc_630 630
|
||||
#define bfd_mach_ppc_750 750
|
||||
#define bfd_mach_ppc_860 860
|
||||
#define bfd_mach_ppc_a35 35
|
||||
#define bfd_mach_ppc_rs64ii 642
|
||||
#define bfd_mach_ppc_rs64iii 643
|
||||
#define bfd_mach_ppc_7400 7400
|
||||
bfd_arch_rs6000, /* IBM RS/6000 */
|
||||
bfd_arch_hppa, /* HP PA RISC */
|
||||
bfd_arch_d10v, /* Mitsubishi D10V */
|
||||
@@ -404,6 +422,8 @@ extern int generic_symbol_at_address
|
||||
|
||||
bfd_vma bfd_getl32 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getb32 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getl16 (const bfd_byte *addr);
|
||||
bfd_vma bfd_getb16 (const bfd_byte *addr);
|
||||
typedef enum bfd_boolean {false, true} boolean;
|
||||
|
||||
#endif /* ! defined (DIS_ASM_H) */
|
||||
@@ -108,6 +108,24 @@ bfd_vma bfd_getb32 (const bfd_byte *addr)
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getl16 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0];
|
||||
v |= (unsigned long) addr[1] << 8;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
bfd_vma bfd_getb16 (const bfd_byte *addr)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
v = (unsigned long) addr[0] << 24;
|
||||
v |= (unsigned long) addr[1] << 16;
|
||||
return (bfd_vma) v;
|
||||
}
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
static int
|
||||
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
||||
@@ -155,10 +173,20 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
if (cpu_single_env->msr[MSR_LE])
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(TARGET_MIPS)
|
||||
print_insn = print_insn_big_mips;
|
||||
#else
|
||||
fprintf(out, "0x" TARGET_FMT_lx
|
||||
": Asm output not supported on this arch\n", code);
|
||||
@@ -219,6 +247,10 @@ void disas(FILE *out, void *code, unsigned long size)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(__MIPSEB__)
|
||||
print_insn = print_insn_big_mips;
|
||||
#elif defined(__MIPSEL__)
|
||||
print_insn = print_insn_little_mips;
|
||||
#else
|
||||
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
|
||||
(long) code);
|
||||
@@ -328,7 +360,14 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#elif defined(TARGET_PPC)
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(TARGET_MIPS)
|
||||
print_insn = print_insn_big_mips;
|
||||
#else
|
||||
term_printf("0x" TARGET_FMT_lx
|
||||
": Asm output not supported on this arch\n", pc);
|
||||
|
||||
@@ -218,6 +218,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
#endif
|
||||
#ifdef __s390__
|
||||
#define EXIT_TB() asm volatile ("br %r14")
|
||||
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
|
||||
#endif
|
||||
#ifdef __alpha__
|
||||
#define EXIT_TB() asm volatile ("ret")
|
||||
|
||||
@@ -31,11 +31,29 @@ typedef int64_t Elf64_Sxword;
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7fffffff
|
||||
#define PT_MIPS_REGINFO 0x70000000
|
||||
#define PT_MIPS_OPTIONS 0x70000001
|
||||
|
||||
/* Flags in the e_flags field of the header */
|
||||
/* MIPS architecture level. */
|
||||
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
|
||||
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
|
||||
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
|
||||
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
|
||||
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
|
||||
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
|
||||
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
|
||||
|
||||
/* The ABI of a file. */
|
||||
#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */
|
||||
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
|
||||
|
||||
#define EF_MIPS_NOREORDER 0x00000001
|
||||
#define EF_MIPS_PIC 0x00000002
|
||||
#define EF_MIPS_CPIC 0x00000004
|
||||
#define EF_MIPS_ABI2 0x00000020
|
||||
#define EF_MIPS_OPTIONS_FIRST 0x00000080
|
||||
#define EF_MIPS_32BITMODE 0x00000100
|
||||
#define EF_MIPS_ABI 0x0000f000
|
||||
#define EF_MIPS_ARCH 0xf0000000
|
||||
|
||||
/* These constants define the different elf file types */
|
||||
|
||||
+6
-3
@@ -28,7 +28,7 @@
|
||||
#define tostring(s) #s
|
||||
#endif
|
||||
|
||||
#if GCC_MAJOR < 3
|
||||
#if __GNUC__ < 3
|
||||
#define __builtin_expect(x, n) (x)
|
||||
#endif
|
||||
|
||||
@@ -131,7 +131,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
#elif defined(__powerpc__)
|
||||
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
|
||||
#else
|
||||
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
|
||||
#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
|
||||
@@ -582,6 +582,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
|
||||
is_user = ((env->hflags & HF_CPL_MASK) == 3);
|
||||
#elif defined (TARGET_PPC)
|
||||
is_user = msr_pr;
|
||||
#elif defined (TARGET_MIPS)
|
||||
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
|
||||
#elif defined (TARGET_SPARC)
|
||||
is_user = (env->psrs == 0);
|
||||
#else
|
||||
@@ -613,7 +615,8 @@ static inline int kqemu_is_ok(CPUState *env)
|
||||
(env->eflags & IOPL_MASK) != IOPL_MASK &&
|
||||
(env->cr[0] & CR0_PE_MASK) &&
|
||||
(env->eflags & IF_MASK) &&
|
||||
!(env->eflags & VM_MASK));
|
||||
!(env->eflags & VM_MASK) &&
|
||||
(env->ldt.limit == 0 || env->ldt.limit == 0x27));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,6 +51,15 @@
|
||||
#define MMAP_AREA_START 0x00000000
|
||||
#define MMAP_AREA_END 0xa8000000
|
||||
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 41
|
||||
#elif defined(TARGET_PPC64)
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 42
|
||||
#else
|
||||
/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#endif
|
||||
|
||||
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
|
||||
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
|
||||
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
|
||||
@@ -83,6 +92,8 @@ typedef struct PhysPageDesc {
|
||||
uint32_t phys_offset;
|
||||
} PhysPageDesc;
|
||||
|
||||
/* Note: the VirtPage handling is absolete and will be suppressed
|
||||
ASAP */
|
||||
typedef struct VirtPageDesc {
|
||||
/* physical address of code page. It is valid only if 'valid_tag'
|
||||
matches 'virt_valid_tag' */
|
||||
@@ -113,7 +124,13 @@ static PageDesc *l1_map[L1_SIZE];
|
||||
PhysPageDesc **l1_phys_map;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if TARGET_LONG_BITS > 32
|
||||
#define VIRT_L_BITS 9
|
||||
#define VIRT_L_SIZE (1 << VIRT_L_BITS)
|
||||
static void *l1_virt_map[VIRT_L_SIZE];
|
||||
#else
|
||||
static VirtPageDesc *l1_virt_map[L1_SIZE];
|
||||
#endif
|
||||
static unsigned int virt_valid_tag;
|
||||
#endif
|
||||
|
||||
@@ -176,8 +193,8 @@ static void page_init(void)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
virt_valid_tag = 1;
|
||||
#endif
|
||||
l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
|
||||
memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
|
||||
l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
|
||||
memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
|
||||
}
|
||||
|
||||
static inline PageDesc *page_find_alloc(unsigned int index)
|
||||
@@ -205,80 +222,156 @@ static inline PageDesc *page_find(unsigned int index)
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
}
|
||||
|
||||
static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
|
||||
static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
|
||||
{
|
||||
PhysPageDesc **lp, *p;
|
||||
void **lp, **p;
|
||||
|
||||
lp = &l1_phys_map[index >> L2_BITS];
|
||||
p = (void **)l1_phys_map;
|
||||
#if TARGET_PHYS_ADDR_SPACE_BITS > 32
|
||||
|
||||
#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
|
||||
#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
|
||||
#endif
|
||||
lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
/* allocate if not found */
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
|
||||
memset(p, 0, sizeof(void *) * L1_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
#endif
|
||||
lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
/* allocate if not found */
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
|
||||
memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
|
||||
}
|
||||
|
||||
static inline PhysPageDesc *phys_page_find(unsigned int index)
|
||||
static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
|
||||
{
|
||||
PhysPageDesc *p;
|
||||
|
||||
p = l1_phys_map[index >> L2_BITS];
|
||||
if (!p)
|
||||
return 0;
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
return phys_page_find_alloc(index, 0);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static void tlb_protect_code(CPUState *env, target_ulong addr);
|
||||
static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
|
||||
|
||||
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
|
||||
static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
|
||||
{
|
||||
VirtPageDesc **lp, *p;
|
||||
|
||||
/* XXX: should not truncate for 64 bit addresses */
|
||||
#if TARGET_LONG_BITS > 32
|
||||
index &= (L1_SIZE - 1);
|
||||
#endif
|
||||
void **p, **lp;
|
||||
|
||||
p = l1_virt_map;
|
||||
lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
|
||||
#else
|
||||
VirtPageDesc *p, **lp;
|
||||
|
||||
lp = &l1_virt_map[index >> L2_BITS];
|
||||
p = *lp;
|
||||
if (!p) {
|
||||
/* allocate if not found */
|
||||
p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
|
||||
memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
|
||||
if (!alloc)
|
||||
return NULL;
|
||||
p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline VirtPageDesc *virt_page_find(unsigned int index)
|
||||
static inline VirtPageDesc *virt_page_find(target_ulong index)
|
||||
{
|
||||
VirtPageDesc *p;
|
||||
|
||||
p = l1_virt_map[index >> L2_BITS];
|
||||
if (!p)
|
||||
return 0;
|
||||
return p + (index & (L2_SIZE - 1));
|
||||
return virt_page_find_alloc(index, 0);
|
||||
}
|
||||
|
||||
#if TARGET_LONG_BITS > 32
|
||||
static void virt_page_flush_internal(void **p, int level)
|
||||
{
|
||||
int i;
|
||||
if (level == 0) {
|
||||
VirtPageDesc *q = (VirtPageDesc *)p;
|
||||
for(i = 0; i < VIRT_L_SIZE; i++)
|
||||
q[i].valid_tag = 0;
|
||||
} else {
|
||||
level--;
|
||||
for(i = 0; i < VIRT_L_SIZE; i++) {
|
||||
if (p[i])
|
||||
virt_page_flush_internal(p[i], level);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void virt_page_flush(void)
|
||||
{
|
||||
int i, j;
|
||||
VirtPageDesc *p;
|
||||
|
||||
virt_valid_tag++;
|
||||
|
||||
if (virt_valid_tag == 0) {
|
||||
virt_valid_tag = 1;
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
p = l1_virt_map[i];
|
||||
if (p) {
|
||||
for(j = 0; j < L2_SIZE; j++)
|
||||
p[j].valid_tag = 0;
|
||||
#if TARGET_LONG_BITS > 32
|
||||
virt_page_flush_internal(l1_virt_map, 5);
|
||||
#else
|
||||
{
|
||||
int i, j;
|
||||
VirtPageDesc *p;
|
||||
for(i = 0; i < L1_SIZE; i++) {
|
||||
p = l1_virt_map[i];
|
||||
if (p) {
|
||||
for(j = 0; j < L2_SIZE; j++)
|
||||
p[j].valid_tag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -945,7 +1038,7 @@ void tb_link(TranslationBlock *tb)
|
||||
|
||||
/* save the code memory mappings (needed to invalidate the code) */
|
||||
addr = tb->pc & TARGET_PAGE_MASK;
|
||||
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
|
||||
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
|
||||
#ifdef DEBUG_TLB_CHECK
|
||||
if (vp->valid_tag == virt_valid_tag &&
|
||||
vp->phys_addr != tb->page_addr[0]) {
|
||||
@@ -963,7 +1056,7 @@ void tb_link(TranslationBlock *tb)
|
||||
|
||||
if (tb->page_addr[1] != -1) {
|
||||
addr += TARGET_PAGE_SIZE;
|
||||
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
|
||||
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
|
||||
#ifdef DEBUG_TLB_CHECK
|
||||
if (vp->valid_tag == virt_valid_tag &&
|
||||
vp->phys_addr != tb->page_addr[1]) {
|
||||
@@ -1330,7 +1423,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
|
||||
TranslationBlock *tb;
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_flush_page: 0x%08x\n", addr);
|
||||
printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
|
||||
#endif
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
@@ -1497,7 +1590,7 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
|
||||
}
|
||||
|
||||
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
|
||||
unsigned long start)
|
||||
unsigned long start)
|
||||
{
|
||||
unsigned long addr;
|
||||
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
|
||||
@@ -1536,7 +1629,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
TranslationBlock *first_tb;
|
||||
unsigned int index;
|
||||
target_ulong address;
|
||||
unsigned long addend;
|
||||
target_phys_addr_t addend;
|
||||
int ret;
|
||||
|
||||
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
|
||||
@@ -1553,7 +1646,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
}
|
||||
}
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
|
||||
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
|
||||
vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
|
||||
#endif
|
||||
|
||||
@@ -1572,7 +1665,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
|
||||
}
|
||||
|
||||
index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
|
||||
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
addend -= vaddr;
|
||||
if (prot & PAGE_READ) {
|
||||
env->tlb_read[is_user][index].address = address;
|
||||
@@ -1635,7 +1728,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
original mapping */
|
||||
VirtPageDesc *vp;
|
||||
|
||||
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
|
||||
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
|
||||
vp->phys_addr = pd;
|
||||
vp->prot = prot;
|
||||
vp->valid_tag = virt_valid_tag;
|
||||
@@ -1859,13 +1952,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
unsigned long size,
|
||||
unsigned long phys_offset)
|
||||
{
|
||||
unsigned long addr, end_addr;
|
||||
target_phys_addr_t addr, end_addr;
|
||||
PhysPageDesc *p;
|
||||
|
||||
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
|
||||
end_addr = start_addr + size;
|
||||
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
|
||||
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
|
||||
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
|
||||
p->phys_offset = phys_offset;
|
||||
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
|
||||
phys_offset += TARGET_PAGE_SIZE;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -253,14 +253,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
}
|
||||
/* nip, msr, ccr, lnk, ctr, xer, mq */
|
||||
registers[96] = tswapl(env->nip);
|
||||
registers[97] = tswapl(_load_msr(env));
|
||||
registers[97] = tswapl(do_load_msr(env));
|
||||
tmp = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||
registers[98] = tswapl(tmp);
|
||||
registers[99] = tswapl(env->lr);
|
||||
registers[100] = tswapl(env->ctr);
|
||||
registers[101] = tswapl(_load_xer(env));
|
||||
registers[101] = tswapl(do_load_xer(env));
|
||||
registers[102] = 0;
|
||||
|
||||
return 103 * 4;
|
||||
@@ -282,18 +282,18 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
}
|
||||
/* nip, msr, ccr, lnk, ctr, xer, mq */
|
||||
env->nip = tswapl(registers[96]);
|
||||
_store_msr(env, tswapl(registers[97]));
|
||||
do_store_msr(env, tswapl(registers[97]));
|
||||
registers[98] = tswapl(registers[98]);
|
||||
for (i = 0; i < 8; i++)
|
||||
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
|
||||
env->lr = tswapl(registers[99]);
|
||||
env->ctr = tswapl(registers[100]);
|
||||
_store_xer(env, tswapl(registers[101]));
|
||||
do_store_xer(env, tswapl(registers[101]));
|
||||
}
|
||||
#elif defined (TARGET_SPARC)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf, tmp;
|
||||
target_ulong *registers = (target_ulong *)mem_buf;
|
||||
int i;
|
||||
|
||||
/* fill in g0..g7 */
|
||||
@@ -308,10 +308,15 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
for (i = 0; i < 32; i++) {
|
||||
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
registers[64] = tswapl(env->y);
|
||||
tmp = GET_PSR(env);
|
||||
registers[65] = tswapl(tmp);
|
||||
{
|
||||
target_ulong tmp;
|
||||
|
||||
tmp = GET_PSR(env);
|
||||
registers[65] = tswapl(tmp);
|
||||
}
|
||||
registers[66] = tswapl(env->wim);
|
||||
registers[67] = tswapl(env->tbr);
|
||||
registers[68] = tswapl(env->pc);
|
||||
@@ -319,13 +324,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
registers[70] = tswapl(env->fsr);
|
||||
registers[71] = 0; /* csr */
|
||||
registers[72] = 0;
|
||||
|
||||
return 73 * 4;
|
||||
return 73 * sizeof(target_ulong);
|
||||
#else
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
|
||||
}
|
||||
registers[81] = tswapl(env->pc);
|
||||
registers[82] = tswapl(env->npc);
|
||||
registers[83] = tswapl(env->tstate[env->tl]);
|
||||
registers[84] = tswapl(env->fsr);
|
||||
registers[85] = tswapl(env->fprs);
|
||||
registers[86] = tswapl(env->y);
|
||||
return 87 * sizeof(target_ulong);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
uint32_t *registers = (uint32_t *)mem_buf;
|
||||
target_ulong *registers = (target_ulong *)mem_buf;
|
||||
int i;
|
||||
|
||||
/* fill in g0..g7 */
|
||||
@@ -334,12 +350,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
}
|
||||
/* fill in register window */
|
||||
for(i = 0; i < 24; i++) {
|
||||
env->regwptr[i] = tswapl(registers[i]);
|
||||
env->regwptr[i] = tswapl(registers[i + 8]);
|
||||
}
|
||||
/* fill in fprs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
env->y = tswapl(registers[64]);
|
||||
PUT_PSR(env, tswapl(registers[65]));
|
||||
@@ -348,6 +365,20 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
env->pc = tswapl(registers[68]);
|
||||
env->npc = tswapl(registers[69]);
|
||||
env->fsr = tswapl(registers[70]);
|
||||
#else
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
uint64_t tmp;
|
||||
tmp = tswapl(registers[i/2 + 64]) << 32;
|
||||
tmp |= tswapl(registers[i/2 + 64 + 1]);
|
||||
*((uint64_t *)&env->fpr[i]) = tmp;
|
||||
}
|
||||
env->pc = tswapl(registers[81]);
|
||||
env->npc = tswapl(registers[82]);
|
||||
env->tstate[env->tl] = tswapl(registers[83]);
|
||||
env->fsr = tswapl(registers[84]);
|
||||
env->fprs = tswapl(registers[85]);
|
||||
env->y = tswapl(registers[86]);
|
||||
#endif
|
||||
}
|
||||
#elif defined (TARGET_ARM)
|
||||
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "vl.h"
|
||||
|
||||
//#define DEBUG_APIC
|
||||
//#define DEBUG_IOAPIC
|
||||
|
||||
/* APIC Local Vector Table */
|
||||
#define APIC_LVT_TIMER 0
|
||||
@@ -39,6 +40,10 @@
|
||||
#define APIC_DM_SIPI 6
|
||||
#define APIC_DM_EXTINT 7
|
||||
|
||||
/* APIC destination mode */
|
||||
#define APIC_DESTMODE_FLAT 0xf
|
||||
#define APIC_DESTMODE_CLUSTER 1
|
||||
|
||||
#define APIC_TRIGGER_EDGE 0
|
||||
#define APIC_TRIGGER_LEVEL 1
|
||||
|
||||
@@ -49,6 +54,8 @@
|
||||
#define APIC_INPUT_POLARITY (1<<13)
|
||||
#define APIC_SEND_PENDING (1<<12)
|
||||
|
||||
#define IOAPIC_NUM_PINS 0x18
|
||||
|
||||
#define ESR_ILLEGAL_ADDRESS (1 << 7)
|
||||
|
||||
#define APIC_SV_ENABLE (1 << 8)
|
||||
@@ -57,8 +64,11 @@ typedef struct APICState {
|
||||
CPUState *cpu_env;
|
||||
uint32_t apicbase;
|
||||
uint8_t id;
|
||||
uint8_t arb_id;
|
||||
uint8_t tpr;
|
||||
uint32_t spurious_vec;
|
||||
uint8_t log_dest;
|
||||
uint8_t dest_mode;
|
||||
uint32_t isr[8]; /* in service register */
|
||||
uint32_t tmr[8]; /* trigger mode register */
|
||||
uint32_t irr[8]; /* interrupt request register */
|
||||
@@ -71,9 +81,64 @@ typedef struct APICState {
|
||||
uint32_t initial_count;
|
||||
int64_t initial_count_load_time, next_time;
|
||||
QEMUTimer *timer;
|
||||
|
||||
struct APICState *next_apic;
|
||||
} APICState;
|
||||
|
||||
struct IOAPICState {
|
||||
uint8_t id;
|
||||
uint8_t ioregsel;
|
||||
|
||||
uint32_t irr;
|
||||
uint64_t ioredtbl[IOAPIC_NUM_PINS];
|
||||
};
|
||||
|
||||
static int apic_io_memory;
|
||||
static APICState *first_local_apic = NULL;
|
||||
static int last_apic_id = 0;
|
||||
|
||||
static void apic_init_ipi(APICState *s);
|
||||
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
|
||||
static void apic_update_irq(APICState *s);
|
||||
|
||||
static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
|
||||
uint8_t vector_num, uint8_t polarity,
|
||||
uint8_t trigger_mode)
|
||||
{
|
||||
APICState *apic_iter;
|
||||
|
||||
switch (delivery_mode) {
|
||||
case APIC_DM_LOWPRI:
|
||||
case APIC_DM_FIXED:
|
||||
/* XXX: arbitration */
|
||||
break;
|
||||
|
||||
case APIC_DM_SMI:
|
||||
case APIC_DM_NMI:
|
||||
break;
|
||||
|
||||
case APIC_DM_INIT:
|
||||
/* normal INIT IPI sent to processors */
|
||||
for (apic_iter = first_local_apic; apic_iter != NULL;
|
||||
apic_iter = apic_iter->next_apic) {
|
||||
apic_init_ipi(apic_iter);
|
||||
}
|
||||
return;
|
||||
|
||||
case APIC_DM_EXTINT:
|
||||
/* handled in I/O APIC code */
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (apic_iter = first_local_apic; apic_iter != NULL;
|
||||
apic_iter = apic_iter->next_apic) {
|
||||
if (deliver_bitmask & (1 << apic_iter->id))
|
||||
apic_set_irq(apic_iter, vector_num, trigger_mode);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_set_apic_base(CPUState *env, uint64_t val)
|
||||
{
|
||||
@@ -104,6 +169,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
s->tpr = (val & 0x0f) << 4;
|
||||
apic_update_irq(s);
|
||||
}
|
||||
|
||||
uint8_t cpu_get_apic_tpr(CPUX86State *env)
|
||||
@@ -112,16 +178,24 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env)
|
||||
return s->tpr >> 4;
|
||||
}
|
||||
|
||||
/* return -1 if no bit is set */
|
||||
static int get_highest_priority_int(uint32_t *tab)
|
||||
static int fls_bit(int value)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i < 8; i++) {
|
||||
if (tab[i] != 0) {
|
||||
return i * 32 + ffs(tab[i]) - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
unsigned int ret = 0;
|
||||
|
||||
#ifdef HOST_I386
|
||||
__asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
|
||||
return ret;
|
||||
#else
|
||||
if (value > 0xffff)
|
||||
value >>= 16, ret = 16;
|
||||
if (value > 0xff)
|
||||
value >>= 8, ret += 8;
|
||||
if (value > 0xf)
|
||||
value >>= 4, ret += 4;
|
||||
if (value > 0x3)
|
||||
value >>= 2, ret += 2;
|
||||
return ret + (value >> 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void set_bit(uint32_t *tab, int index)
|
||||
@@ -140,6 +214,18 @@ static inline void reset_bit(uint32_t *tab, int index)
|
||||
tab[i] &= ~mask;
|
||||
}
|
||||
|
||||
/* return -1 if no bit is set */
|
||||
static int get_highest_priority_int(uint32_t *tab)
|
||||
{
|
||||
int i;
|
||||
for(i = 7; i >= 0; i--) {
|
||||
if (tab[i] != 0) {
|
||||
return i * 32 + fls_bit(tab[i]);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int apic_get_ppr(APICState *s)
|
||||
{
|
||||
int tpr, isrv, ppr;
|
||||
@@ -156,16 +242,23 @@ static int apic_get_ppr(APICState *s)
|
||||
return ppr;
|
||||
}
|
||||
|
||||
static int apic_get_arb_pri(APICState *s)
|
||||
{
|
||||
/* XXX: arbitration */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* signal the CPU if an irq is pending */
|
||||
static void apic_update_irq(APICState *s)
|
||||
{
|
||||
int irrv, isrv;
|
||||
int irrv, ppr;
|
||||
if (!(s->spurious_vec & APIC_SV_ENABLE))
|
||||
return;
|
||||
irrv = get_highest_priority_int(s->irr);
|
||||
if (irrv < 0)
|
||||
return;
|
||||
isrv = get_highest_priority_int(s->isr);
|
||||
/* if the pending irq has less priority, we do not make a new request */
|
||||
if (isrv >= 0 && irrv >= isrv)
|
||||
ppr = apic_get_ppr(s);
|
||||
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
|
||||
return;
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
@@ -187,9 +280,116 @@ static void apic_eoi(APICState *s)
|
||||
if (isrv < 0)
|
||||
return;
|
||||
reset_bit(s->isr, isrv);
|
||||
/* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
|
||||
set the remote IRR bit for level triggered interrupts. */
|
||||
apic_update_irq(s);
|
||||
}
|
||||
|
||||
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
|
||||
{
|
||||
uint32_t mask = 0;
|
||||
APICState *apic_iter;
|
||||
|
||||
if (dest_mode == 0) {
|
||||
if (dest == 0xff)
|
||||
mask = 0xff;
|
||||
else
|
||||
mask = 1 << dest;
|
||||
} else {
|
||||
/* XXX: cluster mode */
|
||||
for (apic_iter = first_local_apic; apic_iter != NULL;
|
||||
apic_iter = apic_iter->next_apic) {
|
||||
if (dest & apic_iter->log_dest)
|
||||
mask |= (1 << apic_iter->id);
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
static void apic_init_ipi(APICState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < APIC_LVT_NB; i++)
|
||||
s->lvt[i] = 1 << 16; /* mask LVT */
|
||||
s->tpr = 0;
|
||||
s->spurious_vec = 0xff;
|
||||
s->log_dest = 0;
|
||||
s->dest_mode = 0;
|
||||
memset(s->isr, 0, sizeof(s->isr));
|
||||
memset(s->tmr, 0, sizeof(s->tmr));
|
||||
memset(s->irr, 0, sizeof(s->irr));
|
||||
memset(s->lvt, 0, sizeof(s->lvt));
|
||||
s->esr = 0;
|
||||
memset(s->icr, 0, sizeof(s->icr));
|
||||
s->divide_conf = 0;
|
||||
s->count_shift = 0;
|
||||
s->initial_count = 0;
|
||||
s->initial_count_load_time = 0;
|
||||
s->next_time = 0;
|
||||
}
|
||||
|
||||
static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
|
||||
uint8_t delivery_mode, uint8_t vector_num,
|
||||
uint8_t polarity, uint8_t trigger_mode)
|
||||
{
|
||||
uint32_t deliver_bitmask = 0;
|
||||
int dest_shorthand = (s->icr[0] >> 18) & 3;
|
||||
APICState *apic_iter;
|
||||
|
||||
switch (delivery_mode) {
|
||||
case APIC_DM_LOWPRI:
|
||||
/* XXX: serch for focus processor, arbitration */
|
||||
dest = s->id;
|
||||
|
||||
case APIC_DM_INIT:
|
||||
{
|
||||
int trig_mode = (s->icr[0] >> 15) & 1;
|
||||
int level = (s->icr[0] >> 14) & 1;
|
||||
if (level == 0 && trig_mode == 1) {
|
||||
for (apic_iter = first_local_apic; apic_iter != NULL;
|
||||
apic_iter = apic_iter->next_apic) {
|
||||
if (deliver_bitmask & (1 << apic_iter->id)) {
|
||||
apic_iter->arb_id = apic_iter->id;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APIC_DM_SIPI:
|
||||
for (apic_iter = first_local_apic; apic_iter != NULL;
|
||||
apic_iter = apic_iter->next_apic) {
|
||||
if (deliver_bitmask & (1 << apic_iter->id)) {
|
||||
/* XXX: SMP support */
|
||||
/* apic_startup(apic_iter); */
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dest_shorthand) {
|
||||
case 0:
|
||||
deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
|
||||
break;
|
||||
case 1:
|
||||
deliver_bitmask = (1 << s->id);
|
||||
break;
|
||||
case 2:
|
||||
deliver_bitmask = 0xffffffff;
|
||||
break;
|
||||
case 3:
|
||||
deliver_bitmask = 0xffffffff & ~(1 << s->id);
|
||||
break;
|
||||
}
|
||||
|
||||
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
|
||||
trigger_mode);
|
||||
}
|
||||
|
||||
int apic_get_interrupt(CPUState *env)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
@@ -207,6 +407,8 @@ int apic_get_interrupt(CPUState *env)
|
||||
if (intno < 0)
|
||||
return -1;
|
||||
reset_bit(s->irr, intno);
|
||||
if (s->tpr && intno <= s->tpr)
|
||||
return s->spurious_vec & 0xff;
|
||||
set_bit(s->isr, intno);
|
||||
apic_update_irq(s);
|
||||
return intno;
|
||||
@@ -220,7 +422,7 @@ static uint32_t apic_get_current_count(APICState *s)
|
||||
s->count_shift;
|
||||
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
|
||||
/* periodic */
|
||||
val = s->initial_count - (d % (s->initial_count + 1));
|
||||
val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
|
||||
} else {
|
||||
if (d >= s->initial_count)
|
||||
val = 0;
|
||||
@@ -238,11 +440,11 @@ static void apic_timer_update(APICState *s, int64_t current_time)
|
||||
d = (current_time - s->initial_count_load_time) >>
|
||||
s->count_shift;
|
||||
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
|
||||
d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);
|
||||
d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
|
||||
} else {
|
||||
if (d >= s->initial_count)
|
||||
goto no_timer;
|
||||
d = s->initial_count + 1;
|
||||
d = (uint64_t)s->initial_count + 1;
|
||||
}
|
||||
next_time = s->initial_count_load_time + (d << s->count_shift);
|
||||
qemu_mod_timer(s->timer, next_time);
|
||||
@@ -304,10 +506,19 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
case 0x08:
|
||||
val = s->tpr;
|
||||
break;
|
||||
case 0x09:
|
||||
val = apic_get_arb_pri(s);
|
||||
break;
|
||||
case 0x0a:
|
||||
/* ppr */
|
||||
val = apic_get_ppr(s);
|
||||
break;
|
||||
case 0x0d:
|
||||
val = s->log_dest << 24;
|
||||
break;
|
||||
case 0x0e:
|
||||
val = s->dest_mode << 28;
|
||||
break;
|
||||
case 0x0f:
|
||||
val = s->spurious_vec;
|
||||
break;
|
||||
@@ -372,16 +583,29 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
break;
|
||||
case 0x08:
|
||||
s->tpr = val;
|
||||
apic_update_irq(s);
|
||||
break;
|
||||
case 0x0b: /* EOI */
|
||||
apic_eoi(s);
|
||||
break;
|
||||
case 0x0d:
|
||||
s->log_dest = val >> 24;
|
||||
break;
|
||||
case 0x0e:
|
||||
s->dest_mode = val >> 28;
|
||||
break;
|
||||
case 0x0f:
|
||||
s->spurious_vec = val & 0x1ff;
|
||||
apic_update_irq(s);
|
||||
break;
|
||||
case 0x30:
|
||||
s->icr[0] = val;
|
||||
apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
|
||||
(s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
|
||||
(s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
|
||||
break;
|
||||
case 0x31:
|
||||
s->icr[index & 1] = val;
|
||||
s->icr[1] = val;
|
||||
break;
|
||||
case 0x32 ... 0x37:
|
||||
{
|
||||
@@ -410,7 +634,76 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static void apic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
APICState *s = opaque;
|
||||
int i;
|
||||
|
||||
qemu_put_be32s(f, &s->apicbase);
|
||||
qemu_put_8s(f, &s->id);
|
||||
qemu_put_8s(f, &s->arb_id);
|
||||
qemu_put_8s(f, &s->tpr);
|
||||
qemu_put_be32s(f, &s->spurious_vec);
|
||||
qemu_put_8s(f, &s->log_dest);
|
||||
qemu_put_8s(f, &s->dest_mode);
|
||||
for (i = 0; i < 8; i++) {
|
||||
qemu_put_be32s(f, &s->isr[i]);
|
||||
qemu_put_be32s(f, &s->tmr[i]);
|
||||
qemu_put_be32s(f, &s->irr[i]);
|
||||
}
|
||||
for (i = 0; i < APIC_LVT_NB; i++) {
|
||||
qemu_put_be32s(f, &s->lvt[i]);
|
||||
}
|
||||
qemu_put_be32s(f, &s->esr);
|
||||
qemu_put_be32s(f, &s->icr[0]);
|
||||
qemu_put_be32s(f, &s->icr[1]);
|
||||
qemu_put_be32s(f, &s->divide_conf);
|
||||
qemu_put_be32s(f, &s->count_shift);
|
||||
qemu_put_be32s(f, &s->initial_count);
|
||||
qemu_put_be64s(f, &s->initial_count_load_time);
|
||||
qemu_put_be64s(f, &s->next_time);
|
||||
}
|
||||
|
||||
static int apic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
APICState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* XXX: what if the base changes? (registered memory regions) */
|
||||
qemu_get_be32s(f, &s->apicbase);
|
||||
qemu_get_8s(f, &s->id);
|
||||
qemu_get_8s(f, &s->arb_id);
|
||||
qemu_get_8s(f, &s->tpr);
|
||||
qemu_get_be32s(f, &s->spurious_vec);
|
||||
qemu_get_8s(f, &s->log_dest);
|
||||
qemu_get_8s(f, &s->dest_mode);
|
||||
for (i = 0; i < 8; i++) {
|
||||
qemu_get_be32s(f, &s->isr[i]);
|
||||
qemu_get_be32s(f, &s->tmr[i]);
|
||||
qemu_get_be32s(f, &s->irr[i]);
|
||||
}
|
||||
for (i = 0; i < APIC_LVT_NB; i++) {
|
||||
qemu_get_be32s(f, &s->lvt[i]);
|
||||
}
|
||||
qemu_get_be32s(f, &s->esr);
|
||||
qemu_get_be32s(f, &s->icr[0]);
|
||||
qemu_get_be32s(f, &s->icr[1]);
|
||||
qemu_get_be32s(f, &s->divide_conf);
|
||||
qemu_get_be32s(f, &s->count_shift);
|
||||
qemu_get_be32s(f, &s->initial_count);
|
||||
qemu_get_be64s(f, &s->initial_count_load_time);
|
||||
qemu_get_be64s(f, &s->next_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void apic_reset(void *opaque)
|
||||
{
|
||||
APICState *s = opaque;
|
||||
apic_init_ipi(s);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *apic_mem_read[3] = {
|
||||
apic_mem_readb,
|
||||
@@ -427,27 +720,237 @@ static CPUWriteMemoryFunc *apic_mem_write[3] = {
|
||||
int apic_init(CPUState *env)
|
||||
{
|
||||
APICState *s;
|
||||
int i;
|
||||
|
||||
s = malloc(sizeof(APICState));
|
||||
s = qemu_mallocz(sizeof(APICState));
|
||||
if (!s)
|
||||
return -1;
|
||||
memset(s, 0, sizeof(*s));
|
||||
env->apic_state = s;
|
||||
apic_init_ipi(s);
|
||||
s->id = last_apic_id++;
|
||||
s->cpu_env = env;
|
||||
s->apicbase = 0xfee00000 |
|
||||
MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
|
||||
for(i = 0; i < APIC_LVT_NB; i++)
|
||||
s->lvt[i] = 1 << 16; /* mask LVT */
|
||||
s->spurious_vec = 0xff;
|
||||
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
|
||||
|
||||
/* XXX: mapping more APICs at the same memory location */
|
||||
if (apic_io_memory == 0) {
|
||||
/* NOTE: the APIC is directly connected to the CPU - it is not
|
||||
on the global memory bus. */
|
||||
apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
|
||||
apic_mem_write, NULL);
|
||||
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);
|
||||
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
|
||||
apic_io_memory);
|
||||
}
|
||||
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
|
||||
|
||||
register_savevm("apic", 0, 1, apic_save, apic_load, s);
|
||||
qemu_register_reset(apic_reset, s);
|
||||
|
||||
s->next_apic = first_local_apic;
|
||||
first_local_apic = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioapic_service(IOAPICState *s)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t trig_mode;
|
||||
uint8_t vector;
|
||||
uint8_t delivery_mode;
|
||||
uint32_t mask;
|
||||
uint64_t entry;
|
||||
uint8_t dest;
|
||||
uint8_t dest_mode;
|
||||
uint8_t polarity;
|
||||
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
mask = 1 << i;
|
||||
if (s->irr & mask) {
|
||||
entry = s->ioredtbl[i];
|
||||
if (!(entry & APIC_LVT_MASKED)) {
|
||||
trig_mode = ((entry >> 15) & 1);
|
||||
dest = entry >> 56;
|
||||
dest_mode = (entry >> 11) & 1;
|
||||
delivery_mode = (entry >> 8) & 7;
|
||||
polarity = (entry >> 13) & 1;
|
||||
if (trig_mode == APIC_TRIGGER_EDGE)
|
||||
s->irr &= ~mask;
|
||||
if (delivery_mode == APIC_DM_EXTINT)
|
||||
vector = pic_read_irq(isa_pic);
|
||||
else
|
||||
vector = entry & 0xff;
|
||||
apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
|
||||
delivery_mode, vector, polarity, trig_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ioapic_set_irq(void *opaque, int vector, int level)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
|
||||
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
|
||||
uint32_t mask = 1 << vector;
|
||||
uint64_t entry = s->ioredtbl[vector];
|
||||
|
||||
if ((entry >> 15) & 1) {
|
||||
/* level triggered */
|
||||
if (level) {
|
||||
s->irr |= mask;
|
||||
ioapic_service(s);
|
||||
} else {
|
||||
s->irr &= ~mask;
|
||||
}
|
||||
} else {
|
||||
/* edge triggered */
|
||||
if (level) {
|
||||
s->irr |= mask;
|
||||
ioapic_service(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
int index;
|
||||
uint32_t val = 0;
|
||||
|
||||
addr &= 0xff;
|
||||
if (addr == 0x00) {
|
||||
val = s->ioregsel;
|
||||
} else if (addr == 0x10) {
|
||||
switch (s->ioregsel) {
|
||||
case 0x00:
|
||||
val = s->id << 24;
|
||||
break;
|
||||
case 0x01:
|
||||
val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
|
||||
break;
|
||||
case 0x02:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
index = (s->ioregsel - 0x10) >> 1;
|
||||
if (index >= 0 && index < IOAPIC_NUM_PINS) {
|
||||
if (s->ioregsel & 1)
|
||||
val = s->ioredtbl[index] >> 32;
|
||||
else
|
||||
val = s->ioredtbl[index] & 0xffffffff;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_IOAPIC
|
||||
printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
int index;
|
||||
|
||||
addr &= 0xff;
|
||||
if (addr == 0x00) {
|
||||
s->ioregsel = val;
|
||||
return;
|
||||
} else if (addr == 0x10) {
|
||||
#ifdef DEBUG_IOAPIC
|
||||
printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
|
||||
#endif
|
||||
switch (s->ioregsel) {
|
||||
case 0x00:
|
||||
s->id = (val >> 24) & 0xff;
|
||||
return;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
return;
|
||||
default:
|
||||
index = (s->ioregsel - 0x10) >> 1;
|
||||
if (index >= 0 && index < IOAPIC_NUM_PINS) {
|
||||
if (s->ioregsel & 1) {
|
||||
s->ioredtbl[index] &= 0xffffffff;
|
||||
s->ioredtbl[index] |= (uint64_t)val << 32;
|
||||
} else {
|
||||
s->ioredtbl[index] &= ~0xffffffffULL;
|
||||
s->ioredtbl[index] |= val;
|
||||
}
|
||||
ioapic_service(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ioapic_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
int i;
|
||||
|
||||
qemu_put_8s(f, &s->id);
|
||||
qemu_put_8s(f, &s->ioregsel);
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
qemu_put_be64s(f, &s->ioredtbl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
int i;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
qemu_get_8s(f, &s->id);
|
||||
qemu_get_8s(f, &s->ioregsel);
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
qemu_get_be64s(f, &s->ioredtbl[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioapic_reset(void *opaque)
|
||||
{
|
||||
IOAPICState *s = opaque;
|
||||
int i;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
for(i = 0; i < IOAPIC_NUM_PINS; i++)
|
||||
s->ioredtbl[i] = 1 << 16; /* mask LVT */
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *ioapic_mem_read[3] = {
|
||||
ioapic_mem_readl,
|
||||
ioapic_mem_readl,
|
||||
ioapic_mem_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
|
||||
ioapic_mem_writel,
|
||||
ioapic_mem_writel,
|
||||
ioapic_mem_writel,
|
||||
};
|
||||
|
||||
IOAPICState *ioapic_init(void)
|
||||
{
|
||||
IOAPICState *s;
|
||||
int io_memory;
|
||||
|
||||
s = qemu_mallocz(sizeof(IOAPICState));
|
||||
if (!s)
|
||||
return NULL;
|
||||
ioapic_reset(s);
|
||||
s->id = last_apic_id++;
|
||||
|
||||
io_memory = cpu_register_io_memory(0, ioapic_mem_read,
|
||||
ioapic_mem_write, s);
|
||||
cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
|
||||
|
||||
register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
|
||||
qemu_register_reset(ioapic_reset, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -61,8 +61,8 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||
pattern_pitch = 32;
|
||||
#endif
|
||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||
pattern_x = skipleft;
|
||||
for(y = 0; y < bltheight; y++) {
|
||||
pattern_x = skipleft;
|
||||
d = dst + skipleft;
|
||||
src1 = src + pattern_y * pattern_pitch;
|
||||
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
/* XXX: implement all timer modes */
|
||||
|
||||
//#define DEBUG_CUDA
|
||||
//#define DEBUG_CUDA_PACKET
|
||||
|
||||
@@ -41,6 +43,7 @@
|
||||
#define IER_CLR 0 /* clear bits in IER */
|
||||
#define SR_INT 0x04 /* Shift register full/empty */
|
||||
#define T1_INT 0x40 /* Timer 1 interrupt */
|
||||
#define T2_INT 0x20 /* Timer 2 interrupt */
|
||||
|
||||
/* Bits in ACR */
|
||||
#define T1MODE 0xc0 /* Timer 1 mode */
|
||||
@@ -91,7 +94,8 @@
|
||||
#define RTC_OFFSET 2082844800
|
||||
|
||||
typedef struct CUDATimer {
|
||||
unsigned int latch;
|
||||
int index;
|
||||
uint16_t latch;
|
||||
uint16_t counter_value; /* counter value at load time */
|
||||
int64_t load_time;
|
||||
int64_t next_irq_time;
|
||||
@@ -120,8 +124,9 @@ typedef struct CUDAState {
|
||||
int data_in_index;
|
||||
int data_out_index;
|
||||
|
||||
SetIRQFunc *set_irq;
|
||||
int irq;
|
||||
openpic_t *openpic;
|
||||
void *irq_opaque;
|
||||
uint8_t autopoll;
|
||||
uint8_t data_in[128];
|
||||
uint8_t data_out[16];
|
||||
@@ -140,9 +145,9 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
|
||||
static void cuda_update_irq(CUDAState *s)
|
||||
{
|
||||
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
|
||||
openpic_set_irq(s->openpic, s->irq, 1);
|
||||
s->set_irq(s->irq_opaque, s->irq, 1);
|
||||
} else {
|
||||
openpic_set_irq(s->openpic, s->irq, 0);
|
||||
s->set_irq(s->irq_opaque, s->irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s)
|
||||
|
||||
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
|
||||
CUDA_TIMER_FREQ, ticks_per_sec);
|
||||
if (d <= s->counter_value) {
|
||||
counter = d;
|
||||
if (s->index == 0) {
|
||||
/* the timer goes down from latch to -1 (period of latch + 2) */
|
||||
if (d <= (s->counter_value + 1)) {
|
||||
counter = (s->counter_value - d) & 0xffff;
|
||||
} else {
|
||||
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
|
||||
counter = (s->latch - counter) & 0xffff;
|
||||
}
|
||||
} else {
|
||||
counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
|
||||
counter = (s->counter_value - d) & 0xffff;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
@@ -174,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
|
||||
|
||||
static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
|
||||
{
|
||||
int64_t d, next_time, base;
|
||||
int64_t d, next_time;
|
||||
unsigned int counter;
|
||||
|
||||
/* current counter value */
|
||||
d = muldiv64(current_time - s->load_time,
|
||||
CUDA_TIMER_FREQ, ticks_per_sec);
|
||||
if (d < s->counter_value) {
|
||||
next_time = s->counter_value + 1;
|
||||
} else
|
||||
{
|
||||
base = ((d - s->counter_value + 1) / s->latch);
|
||||
base = (base * s->latch) + s->counter_value;
|
||||
next_time = base + s->latch;
|
||||
/* the timer goes down from latch to -1 (period of latch + 2) */
|
||||
if (d <= (s->counter_value + 1)) {
|
||||
counter = (s->counter_value - d) & 0xffff;
|
||||
} else {
|
||||
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
|
||||
counter = (s->latch - counter) & 0xffff;
|
||||
}
|
||||
|
||||
/* Note: we consider the irq is raised on 0 */
|
||||
if (counter == 0xffff) {
|
||||
next_time = d + s->latch + 1;
|
||||
} else if (counter == 0) {
|
||||
next_time = d + s->latch + 2;
|
||||
} else {
|
||||
next_time = d + counter;
|
||||
}
|
||||
#if 0
|
||||
#ifdef DEBUG_CUDA
|
||||
@@ -248,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
|
||||
break;
|
||||
case 5:
|
||||
val = get_counter(&s->timers[0]) >> 8;
|
||||
s->ifr &= ~T1_INT;
|
||||
cuda_update_irq(s);
|
||||
break;
|
||||
case 6:
|
||||
val = s->timers[0].latch & 0xff;
|
||||
break;
|
||||
case 7:
|
||||
/* XXX: check this */
|
||||
val = (s->timers[0].latch >> 8) & 0xff;
|
||||
break;
|
||||
case 8:
|
||||
val = get_counter(&s->timers[1]) & 0xff;
|
||||
s->ifr &= ~T2_INT;
|
||||
break;
|
||||
case 9:
|
||||
val = get_counter(&s->timers[1]) >> 8;
|
||||
@@ -276,9 +298,11 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
|
||||
break;
|
||||
case 13:
|
||||
val = s->ifr;
|
||||
if (s->ifr & s->ier)
|
||||
val |= 0x80;
|
||||
break;
|
||||
case 14:
|
||||
val = s->ier;
|
||||
val = s->ier | 0x80;
|
||||
break;
|
||||
default:
|
||||
case 15:
|
||||
@@ -316,12 +340,13 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
s->dira = val;
|
||||
break;
|
||||
case 4:
|
||||
val = val | (get_counter(&s->timers[0]) & 0xff00);
|
||||
set_counter(s, &s->timers[0], val);
|
||||
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
|
||||
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
|
||||
break;
|
||||
case 5:
|
||||
val = (val << 8) | (get_counter(&s->timers[0]) & 0xff);
|
||||
set_counter(s, &s->timers[0], val);
|
||||
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
|
||||
s->ifr &= ~T1_INT;
|
||||
set_counter(s, &s->timers[0], s->timers[0].latch);
|
||||
break;
|
||||
case 6:
|
||||
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
|
||||
@@ -329,15 +354,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
break;
|
||||
case 7:
|
||||
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
|
||||
s->ifr &= ~T1_INT;
|
||||
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
|
||||
break;
|
||||
case 8:
|
||||
val = val | (get_counter(&s->timers[1]) & 0xff00);
|
||||
s->timers[1].latch = val;
|
||||
set_counter(s, &s->timers[1], val);
|
||||
break;
|
||||
case 9:
|
||||
val = (val << 8) | (get_counter(&s->timers[1]) & 0xff);
|
||||
set_counter(s, &s->timers[1], val);
|
||||
set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
|
||||
break;
|
||||
case 10:
|
||||
s->sr = val;
|
||||
@@ -545,7 +570,7 @@ static void cuda_receive_packet_from_host(CUDAState *s,
|
||||
#ifdef DEBUG_CUDA_PACKET
|
||||
{
|
||||
int i;
|
||||
printf("cuda_receive_packet_to_host:\n");
|
||||
printf("cuda_receive_packet_from_host:\n");
|
||||
for(i = 0; i < len; i++)
|
||||
printf(" %02x", data[i]);
|
||||
printf("\n");
|
||||
@@ -605,19 +630,24 @@ static CPUReadMemoryFunc *cuda_read[] = {
|
||||
&cuda_readl,
|
||||
};
|
||||
|
||||
int cuda_init(openpic_t *openpic, int irq)
|
||||
int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
|
||||
{
|
||||
CUDAState *s = &cuda_state;
|
||||
int cuda_mem_index;
|
||||
|
||||
s->openpic = openpic;
|
||||
s->set_irq = set_irq;
|
||||
s->irq_opaque = irq_opaque;
|
||||
s->irq = irq;
|
||||
|
||||
s->timers[0].index = 0;
|
||||
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
|
||||
s->timers[0].latch = 0x10000;
|
||||
s->timers[0].latch = 0xffff;
|
||||
set_counter(s, &s->timers[0], 0xffff);
|
||||
s->timers[1].latch = 0x10000;
|
||||
s->ier = T1_INT | SR_INT;
|
||||
|
||||
s->timers[1].index = 1;
|
||||
s->timers[1].latch = 0;
|
||||
// s->ier = T1_INT | SR_INT;
|
||||
s->ier = 0;
|
||||
set_counter(s, &s->timers[1], 0xffff);
|
||||
|
||||
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
|
||||
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
#ifdef BSWAP_NEEDED
|
||||
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
|
||||
{
|
||||
bswap16s(&ehdr->e_type); /* Object file type */
|
||||
bswap16s(&ehdr->e_machine); /* Architecture */
|
||||
bswap32s(&ehdr->e_version); /* Object file version */
|
||||
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
|
||||
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
|
||||
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
|
||||
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
|
||||
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
|
||||
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
|
||||
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
|
||||
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
|
||||
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
|
||||
{
|
||||
bswap32s(&phdr->p_type); /* Segment type */
|
||||
bswapSZs(&phdr->p_offset); /* Segment file offset */
|
||||
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
|
||||
bswapSZs(&phdr->p_paddr); /* Segment physical address */
|
||||
bswapSZs(&phdr->p_filesz); /* Segment size in file */
|
||||
bswapSZs(&phdr->p_memsz); /* Segment size in memory */
|
||||
bswap32s(&phdr->p_flags); /* Segment flags */
|
||||
bswapSZs(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
|
||||
{
|
||||
bswap32s(&shdr->sh_name);
|
||||
bswap32s(&shdr->sh_type);
|
||||
bswapSZs(&shdr->sh_flags);
|
||||
bswapSZs(&shdr->sh_addr);
|
||||
bswapSZs(&shdr->sh_offset);
|
||||
bswapSZs(&shdr->sh_size);
|
||||
bswap32s(&shdr->sh_link);
|
||||
bswap32s(&shdr->sh_info);
|
||||
bswapSZs(&shdr->sh_addralign);
|
||||
bswapSZs(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void glue(bswap_sym, SZ)(struct elf_sym *sym)
|
||||
{
|
||||
bswap32s(&sym->st_name);
|
||||
bswapSZs(&sym->st_value);
|
||||
bswapSZs(&sym->st_size);
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
retval = read(fd, phdr, sizeof(*phdr));
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
glue(bswap_phdr, SZ)(phdr);
|
||||
if (phdr->p_type == type)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
glue(bswap_shdr, SZ)(shdr);
|
||||
if (shdr->sh_type == type)
|
||||
return qemu_malloc(shdr->sh_size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
glue(bswap_shdr, SZ)(shdr);
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
return qemu_malloc(shdr->sh_size);;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
|
||||
{
|
||||
int retval;
|
||||
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return read(fd, dst, phdr->p_filesz);
|
||||
}
|
||||
|
||||
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, s->sh_offset, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
retval = read(fd, dst, s->sh_size);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (glue(read_section, SZ)(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (glue(read_section, SZ)(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd)
|
||||
{
|
||||
struct elf_shdr symtab, strtab;
|
||||
struct elf_sym *syms;
|
||||
#if (SZ == 64)
|
||||
struct elf32_sym *syms32;
|
||||
#endif
|
||||
struct syminfo *s;
|
||||
int nsyms, i;
|
||||
char *str;
|
||||
|
||||
/* Symbol table */
|
||||
syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB);
|
||||
if (!syms)
|
||||
return;
|
||||
|
||||
nsyms = symtab.sh_size / sizeof(struct elf_sym);
|
||||
#if (SZ == 64)
|
||||
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
|
||||
#endif
|
||||
for (i = 0; i < nsyms; i++) {
|
||||
glue(bswap_sym, SZ)(&syms[i]);
|
||||
#if (SZ == 64)
|
||||
syms32[i].st_name = syms[i].st_name;
|
||||
syms32[i].st_info = syms[i].st_info;
|
||||
syms32[i].st_other = syms[i].st_other;
|
||||
syms32[i].st_shndx = syms[i].st_shndx;
|
||||
syms32[i].st_value = syms[i].st_value & 0xffffffff;
|
||||
syms32[i].st_size = syms[i].st_size & 0xffffffff;
|
||||
#endif
|
||||
}
|
||||
/* String table */
|
||||
str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab);
|
||||
if (!str)
|
||||
goto error_freesyms;
|
||||
|
||||
/* Commit */
|
||||
s = qemu_mallocz(sizeof(*s));
|
||||
#if (SZ == 64)
|
||||
s->disas_symtab = syms32;
|
||||
qemu_free(syms);
|
||||
#else
|
||||
s->disas_symtab = syms;
|
||||
#endif
|
||||
s->disas_num_syms = nsyms;
|
||||
s->disas_strtab = str;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
return;
|
||||
error_freesyms:
|
||||
#if (SZ == 64)
|
||||
qemu_free(syms32);
|
||||
#endif
|
||||
qemu_free(syms);
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Heathrow PIC support (standard PowerMac PIC)
|
||||
*
|
||||
* Copyright (c) 2005 Fabrice Bellard
|
||||
*
|
||||
* 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"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
typedef struct HeathrowPIC {
|
||||
uint32_t events;
|
||||
uint32_t mask;
|
||||
uint32_t levels;
|
||||
uint32_t level_triggered;
|
||||
} HeathrowPIC;
|
||||
|
||||
struct HeathrowPICS {
|
||||
HeathrowPIC pics[2];
|
||||
};
|
||||
|
||||
static inline int check_irq(HeathrowPIC *pic)
|
||||
{
|
||||
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
|
||||
}
|
||||
|
||||
/* update the CPU irq state */
|
||||
static void heathrow_pic_update(HeathrowPICS *s)
|
||||
{
|
||||
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
HeathrowPICS *s = opaque;
|
||||
HeathrowPIC *pic;
|
||||
unsigned int n;
|
||||
|
||||
value = bswap32(value);
|
||||
#ifdef DEBUG
|
||||
printf("pic_writel: %08x: %08x\n",
|
||||
addr, value);
|
||||
#endif
|
||||
n = ((addr & 0xfff) - 0x10) >> 4;
|
||||
if (n >= 2)
|
||||
return;
|
||||
pic = &s->pics[n];
|
||||
switch(addr & 0xf) {
|
||||
case 0x04:
|
||||
pic->mask = value;
|
||||
heathrow_pic_update(s);
|
||||
break;
|
||||
case 0x08:
|
||||
/* do not reset level triggered IRQs */
|
||||
value &= ~pic->level_triggered;
|
||||
pic->events &= ~value;
|
||||
heathrow_pic_update(s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
HeathrowPICS *s = opaque;
|
||||
HeathrowPIC *pic;
|
||||
unsigned int n;
|
||||
uint32_t value;
|
||||
|
||||
n = ((addr & 0xfff) - 0x10) >> 4;
|
||||
if (n >= 2) {
|
||||
value = 0;
|
||||
} else {
|
||||
pic = &s->pics[n];
|
||||
switch(addr & 0xf) {
|
||||
case 0x0:
|
||||
value = pic->events;
|
||||
break;
|
||||
case 0x4:
|
||||
value = pic->mask;
|
||||
break;
|
||||
case 0xc:
|
||||
value = pic->levels;
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("pic_readl: %08x: %08x\n",
|
||||
addr, value);
|
||||
#endif
|
||||
value = bswap32(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pic_write[] = {
|
||||
&pic_writel,
|
||||
&pic_writel,
|
||||
&pic_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pic_read[] = {
|
||||
&pic_readl,
|
||||
&pic_readl,
|
||||
&pic_readl,
|
||||
};
|
||||
|
||||
|
||||
void heathrow_pic_set_irq(void *opaque, int num, int level)
|
||||
{
|
||||
HeathrowPICS *s = opaque;
|
||||
HeathrowPIC *pic;
|
||||
unsigned int irq_bit;
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
static int last_level[64];
|
||||
if (last_level[num] != level) {
|
||||
printf("set_irq: num=0x%02x level=%d\n", num, level);
|
||||
last_level[num] = level;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pic = &s->pics[1 - (num >> 5)];
|
||||
irq_bit = 1 << (num & 0x1f);
|
||||
if (level) {
|
||||
pic->events |= irq_bit & ~pic->level_triggered;
|
||||
pic->levels |= irq_bit;
|
||||
} else {
|
||||
pic->levels &= ~irq_bit;
|
||||
}
|
||||
heathrow_pic_update(s);
|
||||
}
|
||||
|
||||
HeathrowPICS *heathrow_pic_init(int *pmem_index)
|
||||
{
|
||||
HeathrowPICS *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(HeathrowPICS));
|
||||
s->pics[0].level_triggered = 0;
|
||||
s->pics[1].level_triggered = 0x1ff00000;
|
||||
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
|
||||
return s;
|
||||
}
|
||||
+98
-58
@@ -46,10 +46,19 @@ typedef struct PicState {
|
||||
uint8_t init4; /* true if 4 byte init */
|
||||
uint8_t elcr; /* PIIX edge/trigger selection*/
|
||||
uint8_t elcr_mask;
|
||||
PicState2 *pics_state;
|
||||
} PicState;
|
||||
|
||||
/* 0 is master pic, 1 is slave pic */
|
||||
static PicState pics[2];
|
||||
struct PicState2 {
|
||||
/* 0 is master pic, 1 is slave pic */
|
||||
/* XXX: better separation between the two pics */
|
||||
PicState pics[2];
|
||||
IRQRequestFunc *irq_request;
|
||||
void *irq_request_opaque;
|
||||
/* IOAPIC callback support */
|
||||
SetIRQFunc *alt_irq_func;
|
||||
void *alt_irq_opaque;
|
||||
};
|
||||
|
||||
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
|
||||
static int irq_level[16];
|
||||
@@ -110,7 +119,7 @@ static int pic_get_irq(PicState *s)
|
||||
master, the IRQ coming from the slave is not taken into account
|
||||
for the priority computation. */
|
||||
mask = s->isr;
|
||||
if (s->special_fully_nested_mode && s == &pics[0])
|
||||
if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
|
||||
mask &= ~(1 << 2);
|
||||
cur_priority = get_priority(s, mask);
|
||||
if (priority < cur_priority) {
|
||||
@@ -123,32 +132,34 @@ static int pic_get_irq(PicState *s)
|
||||
|
||||
/* raise irq to CPU if necessary. must be called every time the active
|
||||
irq may change */
|
||||
static void pic_update_irq(void)
|
||||
/* XXX: should not export it, but it is needed for an APIC kludge */
|
||||
void pic_update_irq(PicState2 *s)
|
||||
{
|
||||
int irq2, irq;
|
||||
|
||||
/* first look at slave pic */
|
||||
irq2 = pic_get_irq(&pics[1]);
|
||||
irq2 = pic_get_irq(&s->pics[1]);
|
||||
if (irq2 >= 0) {
|
||||
/* if irq request by slave pic, signal master PIC */
|
||||
pic_set_irq1(&pics[0], 2, 1);
|
||||
pic_set_irq1(&pics[0], 2, 0);
|
||||
pic_set_irq1(&s->pics[0], 2, 1);
|
||||
pic_set_irq1(&s->pics[0], 2, 0);
|
||||
}
|
||||
/* look at requested irq */
|
||||
irq = pic_get_irq(&pics[0]);
|
||||
irq = pic_get_irq(&s->pics[0]);
|
||||
if (irq >= 0) {
|
||||
#if defined(DEBUG_PIC)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 2; i++) {
|
||||
printf("pic%d: imr=%x irr=%x padd=%d\n",
|
||||
i, pics[i].imr, pics[i].irr, pics[i].priority_add);
|
||||
i, s->pics[i].imr, s->pics[i].irr,
|
||||
s->pics[i].priority_add);
|
||||
|
||||
}
|
||||
}
|
||||
printf("pic: cpu_interrupt\n");
|
||||
#endif
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
s->irq_request(s->irq_request_opaque, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +167,10 @@ static void pic_update_irq(void)
|
||||
int64_t irq_time[16];
|
||||
#endif
|
||||
|
||||
void pic_set_irq(int irq, int level)
|
||||
void pic_set_irq_new(void *opaque, int irq, int level)
|
||||
{
|
||||
PicState2 *s = opaque;
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
|
||||
if (level != irq_level[irq]) {
|
||||
#if defined(DEBUG_PIC)
|
||||
@@ -175,8 +188,17 @@ void pic_set_irq(int irq, int level)
|
||||
irq_time[irq] = qemu_get_clock(vm_clock);
|
||||
}
|
||||
#endif
|
||||
pic_set_irq1(&pics[irq >> 3], irq & 7, level);
|
||||
pic_update_irq();
|
||||
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
|
||||
/* used for IOAPIC irqs */
|
||||
if (s->alt_irq_func)
|
||||
s->alt_irq_func(s->alt_irq_opaque, irq, level);
|
||||
pic_update_irq(s);
|
||||
}
|
||||
|
||||
/* obsolete function */
|
||||
void pic_set_irq(int irq, int level)
|
||||
{
|
||||
pic_set_irq_new(isa_pic, irq, level);
|
||||
}
|
||||
|
||||
/* acknowledge interrupt 'irq' */
|
||||
@@ -193,43 +215,32 @@ static inline void pic_intack(PicState *s, int irq)
|
||||
s->irr &= ~(1 << irq);
|
||||
}
|
||||
|
||||
int cpu_get_pic_interrupt(CPUState *env)
|
||||
int pic_read_irq(PicState2 *s)
|
||||
{
|
||||
int irq, irq2, intno;
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
intno = apic_get_interrupt(env);
|
||||
if (intno >= 0) {
|
||||
/* set irq request if a PIC irq is still pending */
|
||||
/* XXX: improve that */
|
||||
pic_update_irq();
|
||||
return intno;
|
||||
}
|
||||
#endif
|
||||
/* read the irq from the PIC */
|
||||
|
||||
irq = pic_get_irq(&pics[0]);
|
||||
irq = pic_get_irq(&s->pics[0]);
|
||||
if (irq >= 0) {
|
||||
pic_intack(&pics[0], irq);
|
||||
pic_intack(&s->pics[0], irq);
|
||||
if (irq == 2) {
|
||||
irq2 = pic_get_irq(&pics[1]);
|
||||
irq2 = pic_get_irq(&s->pics[1]);
|
||||
if (irq2 >= 0) {
|
||||
pic_intack(&pics[1], irq2);
|
||||
pic_intack(&s->pics[1], irq2);
|
||||
} else {
|
||||
/* spurious IRQ on slave controller */
|
||||
irq2 = 7;
|
||||
}
|
||||
intno = pics[1].irq_base + irq2;
|
||||
intno = s->pics[1].irq_base + irq2;
|
||||
irq = irq2 + 8;
|
||||
} else {
|
||||
intno = pics[0].irq_base + irq;
|
||||
intno = s->pics[0].irq_base + irq;
|
||||
}
|
||||
} else {
|
||||
/* spurious IRQ on host controller */
|
||||
irq = 7;
|
||||
intno = pics[0].irq_base + irq;
|
||||
intno = s->pics[0].irq_base + irq;
|
||||
}
|
||||
pic_update_irq();
|
||||
pic_update_irq(s);
|
||||
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
printf("IRQ%d latency=%0.3fus\n",
|
||||
@@ -245,11 +256,22 @@ int cpu_get_pic_interrupt(CPUState *env)
|
||||
static void pic_reset(void *opaque)
|
||||
{
|
||||
PicState *s = opaque;
|
||||
int tmp;
|
||||
|
||||
tmp = s->elcr_mask;
|
||||
memset(s, 0, sizeof(PicState));
|
||||
s->elcr_mask = tmp;
|
||||
s->last_irr = 0;
|
||||
s->irr = 0;
|
||||
s->imr = 0;
|
||||
s->isr = 0;
|
||||
s->priority_add = 0;
|
||||
s->irq_base = 0;
|
||||
s->read_reg_select = 0;
|
||||
s->poll = 0;
|
||||
s->special_mask = 0;
|
||||
s->init_state = 0;
|
||||
s->auto_eoi = 0;
|
||||
s->rotate_on_auto_eoi = 0;
|
||||
s->special_fully_nested_mode = 0;
|
||||
s->init4 = 0;
|
||||
s->elcr = 0;
|
||||
}
|
||||
|
||||
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
@@ -266,8 +288,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
/* init */
|
||||
pic_reset(s);
|
||||
/* deassert a pending interrupt */
|
||||
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
|
||||
s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
|
||||
s->init_state = 1;
|
||||
s->init4 = val & 1;
|
||||
if (val & 0x02)
|
||||
@@ -296,23 +317,23 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
s->isr &= ~(1 << irq);
|
||||
if (cmd == 5)
|
||||
s->priority_add = (irq + 1) & 7;
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
irq = val & 7;
|
||||
s->isr &= ~(1 << irq);
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
break;
|
||||
case 6:
|
||||
s->priority_add = (val + 1) & 7;
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
break;
|
||||
case 7:
|
||||
irq = val & 7;
|
||||
s->isr &= ~(1 << irq);
|
||||
s->priority_add = (irq + 1) & 7;
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
break;
|
||||
default:
|
||||
/* no operation */
|
||||
@@ -324,7 +345,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
case 0:
|
||||
/* normal mode */
|
||||
s->imr = val;
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
break;
|
||||
case 1:
|
||||
s->irq_base = val & 0xf8;
|
||||
@@ -353,16 +374,16 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
|
||||
ret = pic_get_irq(s);
|
||||
if (ret >= 0) {
|
||||
if (addr1 >> 7) {
|
||||
pics[0].isr &= ~(1 << 2);
|
||||
pics[0].irr &= ~(1 << 2);
|
||||
s->pics_state->pics[0].isr &= ~(1 << 2);
|
||||
s->pics_state->pics[0].irr &= ~(1 << 2);
|
||||
}
|
||||
s->irr &= ~(1 << ret);
|
||||
s->isr &= ~(1 << ret);
|
||||
if (addr1 >> 7 || ret != 2)
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
} else {
|
||||
ret = 0x07;
|
||||
pic_update_irq();
|
||||
pic_update_irq(s->pics_state);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -396,15 +417,16 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
|
||||
}
|
||||
|
||||
/* memory mapped interrupt status */
|
||||
uint32_t pic_intack_read(CPUState *env)
|
||||
/* XXX: may be the same than pic_read_irq() */
|
||||
uint32_t pic_intack_read(PicState2 *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pic_poll_read(&pics[0], 0x00);
|
||||
ret = pic_poll_read(&s->pics[0], 0x00);
|
||||
if (ret == 2)
|
||||
ret = pic_poll_read(&pics[1], 0x80) + 8;
|
||||
ret = pic_poll_read(&s->pics[1], 0x80) + 8;
|
||||
/* Prepare for ISR read */
|
||||
pics[0].read_reg_select = 1;
|
||||
s->pics[0].read_reg_select = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -484,9 +506,12 @@ void pic_info(void)
|
||||
{
|
||||
int i;
|
||||
PicState *s;
|
||||
|
||||
if (!isa_pic)
|
||||
return;
|
||||
|
||||
for(i=0;i<2;i++) {
|
||||
s = &pics[i];
|
||||
s = &isa_pic->pics[i];
|
||||
term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||
i, s->irr, s->imr, s->isr, s->priority_add,
|
||||
s->irq_base, s->read_reg_select, s->elcr,
|
||||
@@ -511,11 +536,26 @@ void irq_info(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void pic_init(void)
|
||||
PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
|
||||
{
|
||||
pic_init1(0x20, 0x4d0, &pics[0]);
|
||||
pic_init1(0xa0, 0x4d1, &pics[1]);
|
||||
pics[0].elcr_mask = 0xf8;
|
||||
pics[1].elcr_mask = 0xde;
|
||||
PicState2 *s;
|
||||
s = qemu_mallocz(sizeof(PicState2));
|
||||
if (!s)
|
||||
return NULL;
|
||||
pic_init1(0x20, 0x4d0, &s->pics[0]);
|
||||
pic_init1(0xa0, 0x4d1, &s->pics[1]);
|
||||
s->pics[0].elcr_mask = 0xf8;
|
||||
s->pics[1].elcr_mask = 0xde;
|
||||
s->irq_request = irq_request;
|
||||
s->irq_request_opaque = irq_request_opaque;
|
||||
s->pics[0].pics_state = s;
|
||||
s->pics[1].pics_state = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
|
||||
void *alt_irq_opaque)
|
||||
{
|
||||
s->alt_irq_func = alt_irq_func;
|
||||
s->alt_irq_opaque = alt_irq_opaque;
|
||||
}
|
||||
@@ -296,8 +296,9 @@ typedef struct IDEState {
|
||||
int cylinders, heads, sectors;
|
||||
int64_t nb_sectors;
|
||||
int mult_sectors;
|
||||
SetIRQFunc *set_irq;
|
||||
void *irq_opaque;
|
||||
int irq;
|
||||
openpic_t *openpic;
|
||||
PCIDevice *pci_dev;
|
||||
struct BMDMAState *bmdma;
|
||||
int drive_serial;
|
||||
@@ -332,6 +333,7 @@ typedef struct IDEState {
|
||||
uint8_t *data_ptr;
|
||||
uint8_t *data_end;
|
||||
uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
|
||||
QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
|
||||
} IDEState;
|
||||
|
||||
#define BM_STATUS_DMAING 0x01
|
||||
@@ -341,6 +343,18 @@ typedef struct IDEState {
|
||||
#define BM_CMD_START 0x01
|
||||
#define BM_CMD_READ 0x08
|
||||
|
||||
#define IDE_TYPE_PIIX3 0
|
||||
#define IDE_TYPE_CMD646 1
|
||||
|
||||
/* CMD646 specific */
|
||||
#define MRDMODE 0x71
|
||||
#define MRDMODE_INTR_CH0 0x04
|
||||
#define MRDMODE_INTR_CH1 0x08
|
||||
#define MRDMODE_BLK_CH0 0x10
|
||||
#define MRDMODE_BLK_CH1 0x20
|
||||
#define UDIDETCR0 0x73
|
||||
#define UDIDETCR1 0x7B
|
||||
|
||||
typedef int IDEDMAFunc(IDEState *s,
|
||||
target_phys_addr_t phys_addr,
|
||||
int transfer_size1);
|
||||
@@ -349,6 +363,8 @@ typedef struct BMDMAState {
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint32_t addr;
|
||||
|
||||
struct PCIIDEState *pci_dev;
|
||||
/* current transfer state */
|
||||
IDEState *ide_if;
|
||||
IDEDMAFunc *dma_cb;
|
||||
@@ -358,6 +374,7 @@ typedef struct PCIIDEState {
|
||||
PCIDevice dev;
|
||||
IDEState ide_if[4];
|
||||
BMDMAState bmdma[2];
|
||||
int type; /* see IDE_TYPE_xxx */
|
||||
} PCIIDEState;
|
||||
|
||||
static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
|
||||
@@ -499,16 +516,12 @@ static inline void ide_abort_command(IDEState *s)
|
||||
|
||||
static inline void ide_set_irq(IDEState *s)
|
||||
{
|
||||
BMDMAState *bm = s->bmdma;
|
||||
if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
|
||||
#ifdef TARGET_PPC
|
||||
if (s->openpic)
|
||||
openpic_set_irq(s->openpic, s->irq, 1);
|
||||
else
|
||||
#endif
|
||||
if (s->irq == 16)
|
||||
pci_set_irq(s->pci_dev, 0, 1);
|
||||
else
|
||||
pic_set_irq(s->irq, 1);
|
||||
if (bm) {
|
||||
bm->status |= BM_STATUS_INT;
|
||||
}
|
||||
s->set_irq(s->irq_opaque, s->irq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,6 +655,12 @@ static void ide_sector_read_dma(IDEState *s)
|
||||
ide_dma_start(s, ide_read_dma_cb);
|
||||
}
|
||||
|
||||
static void ide_sector_write_timer_cb(void *opaque)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
ide_set_irq(s);
|
||||
}
|
||||
|
||||
static void ide_sector_write(IDEState *s)
|
||||
{
|
||||
int64_t sector_num;
|
||||
@@ -667,7 +686,22 @@ static void ide_sector_write(IDEState *s)
|
||||
ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
|
||||
}
|
||||
ide_set_sector(s, sector_num + n);
|
||||
ide_set_irq(s);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
if (win2k_install_hack) {
|
||||
/* It seems there is a bug in the Windows 2000 installer HDD
|
||||
IDE driver which fills the disk with empty logs when the
|
||||
IDE write IRQ comes too early. This hack tries to correct
|
||||
that at the expense of slower write performances. Use this
|
||||
option _only_ to install Windows 2000. You must disable it
|
||||
for normal use. */
|
||||
qemu_mod_timer(s->sector_write_timer,
|
||||
qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ide_set_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int ide_write_dma_cb(IDEState *s,
|
||||
@@ -789,7 +823,8 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
||||
case 2352:
|
||||
/* sync bytes */
|
||||
buf[0] = 0x00;
|
||||
memset(buf + 1, 0xff, 11);
|
||||
memset(buf + 1, 0xff, 10);
|
||||
buf[11] = 0x00;
|
||||
buf += 12;
|
||||
/* MSF */
|
||||
lba_to_msf(buf, lba);
|
||||
@@ -917,6 +952,9 @@ static int ide_atapi_cmd_read_dma_cb(IDEState *s,
|
||||
|
||||
transfer_size = transfer_size1;
|
||||
while (transfer_size > 0) {
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);
|
||||
#endif
|
||||
if (s->packet_transfer_size <= 0)
|
||||
break;
|
||||
len = s->cd_sector_size - s->io_buffer_index;
|
||||
@@ -994,9 +1032,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
|
||||
*q++ = 0; /* reserved */
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
*q++ = 0; /* minute */
|
||||
*q++ = 2; /* second */
|
||||
*q++ = 0; /* frame */
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
/* sector 0 */
|
||||
cpu_to_ube32(q, 0);
|
||||
@@ -1081,10 +1118,16 @@ static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
if (msf) {
|
||||
*q++ = 0;
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
}
|
||||
|
||||
len = q - buf;
|
||||
cpu_to_ube16(buf, len - 2);
|
||||
@@ -1571,6 +1614,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
break;
|
||||
case WIN_STANDBYNOW1:
|
||||
case WIN_IDLEIMMEDIATE:
|
||||
case WIN_FLUSH_CACHE:
|
||||
s->status = READY_STAT;
|
||||
ide_set_irq(s);
|
||||
break;
|
||||
@@ -1672,15 +1716,7 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = 0;
|
||||
else
|
||||
ret = s->status;
|
||||
#ifdef TARGET_PPC
|
||||
if (s->openpic)
|
||||
openpic_set_irq(s->openpic, s->irq, 0);
|
||||
else
|
||||
#endif
|
||||
if (s->irq == 16)
|
||||
pci_set_irq(s->pci_dev, 0, 0);
|
||||
else
|
||||
pic_set_irq(s->irq, 0);
|
||||
s->set_irq(s->irq_opaque, s->irq, 0);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
@@ -1873,8 +1909,9 @@ static int guess_disk_lchs(IDEState *s,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ide_init2(IDEState *ide_state, int irq,
|
||||
BlockDriverState *hd0, BlockDriverState *hd1)
|
||||
static void ide_init2(IDEState *ide_state,
|
||||
BlockDriverState *hd0, BlockDriverState *hd1,
|
||||
SetIRQFunc *set_irq, void *irq_opaque, int irq)
|
||||
{
|
||||
IDEState *s;
|
||||
static int drive_serial = 1;
|
||||
@@ -1935,7 +1972,11 @@ static void ide_init2(IDEState *ide_state, int irq,
|
||||
}
|
||||
}
|
||||
s->drive_serial = drive_serial++;
|
||||
s->set_irq = set_irq;
|
||||
s->irq_opaque = irq_opaque;
|
||||
s->irq = irq;
|
||||
s->sector_write_timer = qemu_new_timer(vm_clock,
|
||||
ide_sector_write_timer_cb, s);
|
||||
ide_reset(s);
|
||||
}
|
||||
}
|
||||
@@ -1968,13 +2009,15 @@ void isa_ide_init(int iobase, int iobase2, int irq,
|
||||
if (!ide_state)
|
||||
return;
|
||||
|
||||
ide_init2(ide_state, irq, hd0, hd1);
|
||||
ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
|
||||
ide_init_ioport(ide_state, iobase, iobase2);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* PCI IDE definitions */
|
||||
|
||||
static void cmd646_update_irq(PCIIDEState *d);
|
||||
|
||||
static void ide_map(PCIDevice *pci_dev, int region_num,
|
||||
uint32_t addr, uint32_t size, int type)
|
||||
{
|
||||
@@ -2055,17 +2098,6 @@ static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
BMDMAState *bm = opaque;
|
||||
uint32_t val;
|
||||
val = bm->cmd;
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
BMDMAState *bm = opaque;
|
||||
@@ -2085,24 +2117,77 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t bmdma_status_readb(void *opaque, uint32_t addr)
|
||||
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
BMDMAState *bm = opaque;
|
||||
PCIIDEState *pci_dev;
|
||||
uint32_t val;
|
||||
val = bm->status;
|
||||
|
||||
switch(addr & 3) {
|
||||
case 0:
|
||||
val = bm->cmd;
|
||||
break;
|
||||
case 1:
|
||||
pci_dev = bm->pci_dev;
|
||||
if (pci_dev->type == IDE_TYPE_CMD646) {
|
||||
val = pci_dev->dev.config[MRDMODE];
|
||||
} else {
|
||||
val = 0xff;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
val = bm->status;
|
||||
break;
|
||||
case 3:
|
||||
pci_dev = bm->pci_dev;
|
||||
if (pci_dev->type == IDE_TYPE_CMD646) {
|
||||
if (bm == &pci_dev->bmdma[0])
|
||||
val = pci_dev->dev.config[UDIDETCR0];
|
||||
else
|
||||
val = pci_dev->dev.config[UDIDETCR1];
|
||||
} else {
|
||||
val = 0xff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = 0xff;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
BMDMAState *bm = opaque;
|
||||
PCIIDEState *pci_dev;
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
|
||||
#endif
|
||||
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
|
||||
switch(addr & 3) {
|
||||
case 1:
|
||||
pci_dev = bm->pci_dev;
|
||||
if (pci_dev->type == IDE_TYPE_CMD646) {
|
||||
pci_dev->dev.config[MRDMODE] =
|
||||
(pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
|
||||
cmd646_update_irq(pci_dev);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
|
||||
break;
|
||||
case 3:
|
||||
pci_dev = bm->pci_dev;
|
||||
if (pci_dev->type == IDE_TYPE_CMD646) {
|
||||
if (bm == &pci_dev->bmdma[0])
|
||||
pci_dev->dev.config[UDIDETCR0] = val;
|
||||
else
|
||||
pci_dev->dev.config[UDIDETCR1] = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
|
||||
@@ -2135,12 +2220,12 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
||||
BMDMAState *bm = &d->bmdma[i];
|
||||
d->ide_if[2 * i].bmdma = bm;
|
||||
d->ide_if[2 * i + 1].bmdma = bm;
|
||||
|
||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||
register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm);
|
||||
bm->pci_dev = (PCIIDEState *)pci_dev;
|
||||
|
||||
register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm);
|
||||
register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm);
|
||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||
|
||||
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
|
||||
register_ioport_read(addr, 4, 1, bmdma_readb, bm);
|
||||
|
||||
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
|
||||
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
|
||||
@@ -2148,29 +2233,62 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
||||
}
|
||||
}
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
/* XXX: call it also when the MRDMODE is changed from the PCI config
|
||||
registers */
|
||||
static void cmd646_update_irq(PCIIDEState *d)
|
||||
{
|
||||
int pci_level;
|
||||
pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
|
||||
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
|
||||
((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
|
||||
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
|
||||
pci_set_irq((PCIDevice *)d, 0, pci_level);
|
||||
}
|
||||
|
||||
/* the PCI irq level is the logical OR of the two channels */
|
||||
static void cmd646_set_irq(void *opaque, int channel, int level)
|
||||
{
|
||||
PCIIDEState *d = opaque;
|
||||
int irq_mask;
|
||||
|
||||
irq_mask = MRDMODE_INTR_CH0 << channel;
|
||||
if (level)
|
||||
d->dev.config[MRDMODE] |= irq_mask;
|
||||
else
|
||||
d->dev.config[MRDMODE] &= ~irq_mask;
|
||||
cmd646_update_irq(d);
|
||||
}
|
||||
|
||||
/* CMD646 PCI IDE controller */
|
||||
void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
|
||||
int secondary_ide_enabled)
|
||||
{
|
||||
PCIIDEState *d;
|
||||
uint8_t *pci_conf;
|
||||
int i;
|
||||
|
||||
d = (PCIIDEState *)pci_register_device(bus, "IDE", sizeof(PCIIDEState),
|
||||
d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
|
||||
sizeof(PCIIDEState),
|
||||
-1,
|
||||
NULL, NULL);
|
||||
d->type = IDE_TYPE_CMD646;
|
||||
pci_conf = d->dev.config;
|
||||
pci_conf[0x00] = 0x86; // Intel
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x00; // fake
|
||||
pci_conf[0x03] = 0x01; // fake
|
||||
pci_conf[0x00] = 0x95; // CMD646
|
||||
pci_conf[0x01] = 0x10;
|
||||
pci_conf[0x02] = 0x46;
|
||||
pci_conf[0x03] = 0x06;
|
||||
|
||||
pci_conf[0x08] = 0x07; // IDE controller revision
|
||||
pci_conf[0x09] = 0x8f;
|
||||
|
||||
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
|
||||
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
|
||||
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
|
||||
|
||||
pci_conf[0x2c] = 0x86; // subsys vendor
|
||||
pci_conf[0x2d] = 0x80; // subsys vendor
|
||||
pci_conf[0x2e] = 0x00; // fake
|
||||
pci_conf[0x2f] = 0x01; // fake
|
||||
pci_conf[0x0e] = 0x00; // header_type
|
||||
|
||||
if (secondary_ide_enabled) {
|
||||
/* XXX: if not enabled, really disable the seconday IDE controller */
|
||||
pci_conf[0x51] = 0x80; /* enable IDE1 */
|
||||
}
|
||||
|
||||
pci_register_io_region((PCIDevice *)d, 0, 0x8,
|
||||
PCI_ADDRESS_SPACE_IO, ide_map);
|
||||
@@ -2184,11 +2302,13 @@ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
PCI_ADDRESS_SPACE_IO, bmdma_map);
|
||||
|
||||
pci_conf[0x3d] = 0x01; // interrupt on pin 1
|
||||
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
d->ide_if[i].pci_dev = (PCIDevice *)d;
|
||||
ide_init2(&d->ide_if[0], 16, hd_table[0], hd_table[1]);
|
||||
ide_init2(&d->ide_if[2], 16, hd_table[2], hd_table[3]);
|
||||
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
|
||||
cmd646_set_irq, d, 0);
|
||||
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
|
||||
cmd646_set_irq, d, 1);
|
||||
}
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
@@ -2203,6 +2323,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
sizeof(PCIIDEState),
|
||||
((PCIDevice *)piix3_state)->devfn + 1,
|
||||
NULL, NULL);
|
||||
d->type = IDE_TYPE_PIIX3;
|
||||
|
||||
pci_conf = d->dev.config;
|
||||
pci_conf[0x00] = 0x86; // Intel
|
||||
pci_conf[0x01] = 0x80;
|
||||
@@ -2215,8 +2337,10 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
pci_register_io_region((PCIDevice *)d, 4, 0x10,
|
||||
PCI_ADDRESS_SPACE_IO, bmdma_map);
|
||||
|
||||
ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]);
|
||||
ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]);
|
||||
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
|
||||
pic_set_irq_new, isa_pic, 14);
|
||||
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
|
||||
pic_set_irq_new, isa_pic, 15);
|
||||
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
|
||||
ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
|
||||
}
|
||||
@@ -2334,15 +2458,14 @@ static CPUReadMemoryFunc *pmac_ide_read[] = {
|
||||
/* PowerMac uses memory mapped registers, not I/O. Return the memory
|
||||
I/O index to access the ide. */
|
||||
int pmac_ide_init (BlockDriverState **hd_table,
|
||||
openpic_t *openpic, int irq)
|
||||
SetIRQFunc *set_irq, void *irq_opaque, int irq)
|
||||
{
|
||||
IDEState *ide_if;
|
||||
int pmac_ide_memory;
|
||||
|
||||
ide_if = qemu_mallocz(sizeof(IDEState) * 2);
|
||||
ide_init2(&ide_if[0], irq, hd_table[0], hd_table[1]);
|
||||
ide_if[0].openpic = openpic;
|
||||
ide_if[1].openpic = openpic;
|
||||
ide_init2(&ide_if[0], hd_table[0], hd_table[1],
|
||||
set_irq, irq_opaque, irq);
|
||||
|
||||
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
|
||||
pmac_ide_write, &ide_if[0]);
|
||||
|
||||
+69
-211
@@ -56,213 +56,49 @@ static void bswap_ahdr(struct exec *e)
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
#ifdef BSWAP_NEEDED
|
||||
static void bswap_ehdr(Elf32_Ehdr *ehdr)
|
||||
{
|
||||
bswap16s(&ehdr->e_type); /* Object file type */
|
||||
bswap16s(&ehdr->e_machine); /* Architecture */
|
||||
bswap32s(&ehdr->e_version); /* Object file version */
|
||||
bswap32s(&ehdr->e_entry); /* Entry point virtual address */
|
||||
bswap32s(&ehdr->e_phoff); /* Program header table file offset */
|
||||
bswap32s(&ehdr->e_shoff); /* Section header table file offset */
|
||||
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
|
||||
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
|
||||
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
|
||||
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
|
||||
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
|
||||
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
|
||||
}
|
||||
|
||||
static void bswap_phdr(Elf32_Phdr *phdr)
|
||||
{
|
||||
bswap32s(&phdr->p_type); /* Segment type */
|
||||
bswap32s(&phdr->p_offset); /* Segment file offset */
|
||||
bswap32s(&phdr->p_vaddr); /* Segment virtual address */
|
||||
bswap32s(&phdr->p_paddr); /* Segment physical address */
|
||||
bswap32s(&phdr->p_filesz); /* Segment size in file */
|
||||
bswap32s(&phdr->p_memsz); /* Segment size in memory */
|
||||
bswap32s(&phdr->p_flags); /* Segment flags */
|
||||
bswap32s(&phdr->p_align); /* Segment alignment */
|
||||
}
|
||||
|
||||
static void bswap_shdr(Elf32_Shdr *shdr)
|
||||
{
|
||||
bswap32s(&shdr->sh_name);
|
||||
bswap32s(&shdr->sh_type);
|
||||
bswap32s(&shdr->sh_flags);
|
||||
bswap32s(&shdr->sh_addr);
|
||||
bswap32s(&shdr->sh_offset);
|
||||
bswap32s(&shdr->sh_size);
|
||||
bswap32s(&shdr->sh_link);
|
||||
bswap32s(&shdr->sh_info);
|
||||
bswap32s(&shdr->sh_addralign);
|
||||
bswap32s(&shdr->sh_entsize);
|
||||
}
|
||||
|
||||
static void bswap_sym(Elf32_Sym *sym)
|
||||
{
|
||||
bswap32s(&sym->st_name);
|
||||
bswap32s(&sym->st_value);
|
||||
bswap32s(&sym->st_size);
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
#else
|
||||
#define bswap_ehdr(e) do { } while (0)
|
||||
#define bswap_phdr(e) do { } while (0)
|
||||
#define bswap_shdr(e) do { } while (0)
|
||||
#define bswap_sym(e) do { } while (0)
|
||||
#ifndef BSWAP_NEEDED
|
||||
#define bswap_ehdr32(e) do { } while (0)
|
||||
#define bswap_phdr32(e) do { } while (0)
|
||||
#define bswap_shdr32(e) do { } while (0)
|
||||
#define bswap_sym32(e) do { } while (0)
|
||||
#ifdef TARGET_SPARC64
|
||||
#define bswap_ehdr64(e) do { } while (0)
|
||||
#define bswap_phdr64(e) do { } while (0)
|
||||
#define bswap_shdr64(e) do { } while (0)
|
||||
#define bswap_sym64(e) do { } while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
|
||||
{
|
||||
int i, retval;
|
||||
#define SZ 32
|
||||
#define elf_word uint32_t
|
||||
#define bswapSZs bswap32s
|
||||
#include "elf_ops.h"
|
||||
|
||||
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
retval = read(fd, phdr, sizeof(*phdr));
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
bswap_phdr(phdr);
|
||||
if (phdr->p_type == type)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
|
||||
{
|
||||
int i, retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
bswap_shdr(shdr);
|
||||
if (shdr->sh_type == type)
|
||||
return qemu_malloc(shdr->sh_size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
|
||||
retval = read(fd, shdr, sizeof(*shdr));
|
||||
if (retval < 0)
|
||||
return NULL;
|
||||
bswap_shdr(shdr);
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
return qemu_malloc(shdr->sh_size);;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
|
||||
{
|
||||
int retval;
|
||||
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return read(fd, dst, phdr->p_filesz);
|
||||
}
|
||||
|
||||
static int read_section(int fd, struct elf_shdr *s, void *dst)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = lseek(fd, s->sh_offset, SEEK_SET);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
retval = read(fd, dst, s->sh_size);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = find_shdr(ehdr, fd, shdr, type);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (read_section(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = find_strtab(ehdr, fd, shdr, symtab);
|
||||
if (!dst)
|
||||
goto error;
|
||||
|
||||
if (read_section(fd, shdr, dst))
|
||||
goto error;
|
||||
return dst;
|
||||
error:
|
||||
qemu_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void load_symbols(struct elfhdr *ehdr, int fd)
|
||||
{
|
||||
struct elf_shdr symtab, strtab;
|
||||
struct elf_sym *syms;
|
||||
struct syminfo *s;
|
||||
int nsyms, i;
|
||||
char *str;
|
||||
|
||||
/* Symbol table */
|
||||
syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB);
|
||||
if (!syms)
|
||||
return;
|
||||
|
||||
nsyms = symtab.sh_size / sizeof(struct elf_sym);
|
||||
for (i = 0; i < nsyms; i++)
|
||||
bswap_sym(&syms[i]);
|
||||
|
||||
/* String table */
|
||||
str = process_strtab(ehdr, fd, &strtab, &symtab);
|
||||
if (!str)
|
||||
goto error_freesyms;
|
||||
|
||||
/* Commit */
|
||||
s = qemu_mallocz(sizeof(*s));
|
||||
s->disas_symtab = syms;
|
||||
s->disas_num_syms = nsyms;
|
||||
s->disas_strtab = str;
|
||||
s->next = syminfos;
|
||||
syminfos = s;
|
||||
return;
|
||||
error_freesyms:
|
||||
qemu_free(syms);
|
||||
return;
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
#undef elfhdr
|
||||
#undef elf_phdr
|
||||
#undef elf_shdr
|
||||
#undef elf_sym
|
||||
#undef elf_note
|
||||
#undef elf_word
|
||||
#undef bswapSZs
|
||||
#undef SZ
|
||||
#define elfhdr elf64_hdr
|
||||
#define elf_phdr elf64_phdr
|
||||
#define elf_note elf64_note
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_word uint64_t
|
||||
#define bswapSZs bswap64s
|
||||
#define SZ 64
|
||||
#include "elf_ops.h"
|
||||
#endif
|
||||
|
||||
int load_elf(const char *filename, uint8_t *addr)
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
struct elf_phdr phdr;
|
||||
struct elf32_hdr ehdr;
|
||||
int retval, fd;
|
||||
Elf32_Half machine;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
@@ -272,21 +108,43 @@ int load_elf(const char *filename, uint8_t *addr)
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
bswap_ehdr(&ehdr);
|
||||
|
||||
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|
||||
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|
||||
|| (ehdr.e_machine != EM_SPARC
|
||||
&& ehdr.e_machine != EM_SPARC32PLUS))
|
||||
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
|
||||
goto error;
|
||||
machine = tswap16(ehdr.e_machine);
|
||||
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
|
||||
struct elf32_phdr phdr;
|
||||
|
||||
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program(fd, &phdr, addr, ehdr.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
bswap_ehdr32(&ehdr);
|
||||
|
||||
load_symbols(&ehdr, fd);
|
||||
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
load_symbols32(&ehdr, fd);
|
||||
}
|
||||
#ifdef TARGET_SPARC64
|
||||
else if (machine == EM_SPARCV9) {
|
||||
struct elf64_hdr ehdr64;
|
||||
struct elf64_phdr phdr;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
retval = read(fd, &ehdr64, sizeof(ehdr64));
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
bswap_ehdr64(&ehdr64);
|
||||
|
||||
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
|
||||
goto error;
|
||||
retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
load_symbols64(&ehdr64, fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
return retval;
|
||||
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
#include "vl.h"
|
||||
|
||||
#define BIOS_FILENAME "mips_bios.bin"
|
||||
//#define BIOS_FILENAME "system.bin"
|
||||
#define KERNEL_LOAD_ADDR 0x80010000
|
||||
#define INITRD_LOAD_ADDR 0x80800000
|
||||
|
||||
extern FILE *logfile;
|
||||
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
if (level) {
|
||||
cpu_single_env->CP0_Cause |= 0x00000400;
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_single_env->CP0_Cause &= ~0x00000400;
|
||||
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_irqctrl_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t cpu_mips_get_random (CPUState *env)
|
||||
{
|
||||
uint32_t now = qemu_get_clock(vm_clock);
|
||||
|
||||
return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
|
||||
}
|
||||
|
||||
/* MIPS R4K timer */
|
||||
uint32_t cpu_mips_get_count (CPUState *env)
|
||||
{
|
||||
return env->CP0_Count +
|
||||
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
|
||||
100 * 1000 * 1000, ticks_per_sec);
|
||||
}
|
||||
|
||||
static void cpu_mips_update_count (CPUState *env, uint32_t count,
|
||||
uint32_t compare)
|
||||
{
|
||||
uint64_t now, next;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = count;
|
||||
if (count == compare)
|
||||
tmp++;
|
||||
now = qemu_get_clock(vm_clock);
|
||||
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
|
||||
if (next == now)
|
||||
next++;
|
||||
#if 1
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
|
||||
__func__, now, count, compare, next - now);
|
||||
}
|
||||
#endif
|
||||
/* Store new count and compare registers */
|
||||
env->CP0_Compare = compare;
|
||||
env->CP0_Count =
|
||||
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
|
||||
/* Adjust timer */
|
||||
qemu_mod_timer(env->timer, next);
|
||||
}
|
||||
|
||||
void cpu_mips_store_count (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, value, env->CP0_Compare);
|
||||
}
|
||||
|
||||
void cpu_mips_store_compare (CPUState *env, uint32_t value)
|
||||
{
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
|
||||
pic_set_irq(5, 0);
|
||||
}
|
||||
|
||||
static void mips_timer_cb (void *opaque)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
env = opaque;
|
||||
#if 1
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s\n", __func__);
|
||||
}
|
||||
#endif
|
||||
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
|
||||
pic_set_irq(5, 1);
|
||||
}
|
||||
|
||||
void cpu_mips_clock_init (CPUState *env)
|
||||
{
|
||||
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
|
||||
env->CP0_Compare = 0;
|
||||
cpu_mips_update_count(env, 1, 0);
|
||||
}
|
||||
|
||||
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
cpu_outb(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap16(value);
|
||||
#endif
|
||||
cpu_outw(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap16(ret);
|
||||
#endif
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
value = bswap32(value);
|
||||
#endif
|
||||
cpu_outl(NULL, addr & 0xffff, value);
|
||||
}
|
||||
|
||||
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
ret = bswap32(ret);
|
||||
#endif
|
||||
if (logfile)
|
||||
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CPUWriteMemoryFunc *io_write[] = {
|
||||
&io_writeb,
|
||||
&io_writew,
|
||||
&io_writel,
|
||||
};
|
||||
|
||||
CPUReadMemoryFunc *io_read[] = {
|
||||
&io_readb,
|
||||
&io_readw,
|
||||
&io_readl,
|
||||
};
|
||||
|
||||
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
|
||||
unsigned long bios_offset;
|
||||
int io_memory;
|
||||
int linux_boot;
|
||||
int ret;
|
||||
|
||||
printf("%s: start\n", __func__);
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
/* allocate RAM */
|
||||
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
|
||||
bios_offset = ram_size + vga_ram_size;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
|
||||
ret = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (ret != BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory((uint32_t)(0x1fc00000),
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
#if 0
|
||||
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
|
||||
cpu_single_env->PC = 0x80010004;
|
||||
#else
|
||||
cpu_single_env->PC = 0xBFC00004;
|
||||
#endif
|
||||
if (linux_boot) {
|
||||
kernel_base = KERNEL_LOAD_ADDR;
|
||||
/* now we can load the kernel */
|
||||
kernel_size = load_image(kernel_filename,
|
||||
phys_ram_base + (kernel_base - 0x80000000));
|
||||
if (kernel_size == (target_ulong) -1) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_base = INITRD_LOAD_ADDR;
|
||||
initrd_size = load_image(initrd_filename,
|
||||
phys_ram_base + initrd_base);
|
||||
if (initrd_size == (target_ulong) -1) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
}
|
||||
cpu_single_env->PC = KERNEL_LOAD_ADDR;
|
||||
} else {
|
||||
kernel_base = 0;
|
||||
kernel_size = 0;
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
}
|
||||
|
||||
/* Init internal devices */
|
||||
cpu_mips_clock_init(cpu_single_env);
|
||||
cpu_mips_irqctrl_init();
|
||||
|
||||
/* Register 64 KB of ISA IO space at 0x14000000 */
|
||||
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
|
||||
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
|
||||
isa_mem_base = 0x10000000;
|
||||
|
||||
isa_pic = pic_init(pic_irq_request, cpu_single_env);
|
||||
serial_init(0x3f8, 4, serial_hds[0]);
|
||||
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
|
||||
isa_ne2000_init(0x300, 9, &nd_table[0]);
|
||||
}
|
||||
|
||||
QEMUMachine mips_machine = {
|
||||
"mips",
|
||||
"mips r4k platform",
|
||||
mips_r4k_init,
|
||||
};
|
||||
+11
-2
@@ -61,6 +61,9 @@
|
||||
#define EN1_CURPAG 0x17
|
||||
#define EN1_MULT 0x18
|
||||
|
||||
#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
|
||||
#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
|
||||
|
||||
/* Register accessed at EN_CMD, the 8390 base addr. */
|
||||
#define E8390_STOP 0x01 /* Stop and reset the chip */
|
||||
#define E8390_START 0x02 /* Start the chip, clear reset */
|
||||
@@ -150,7 +153,7 @@ static void ne2000_reset(NE2000State *s)
|
||||
static void ne2000_update_irq(NE2000State *s)
|
||||
{
|
||||
int isr;
|
||||
isr = s->isr & s->imr;
|
||||
isr = (s->isr & s->imr) & 0x7f;
|
||||
#if defined(DEBUG_NE2000)
|
||||
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
|
||||
s->irq, isr ? 1 : 0, s->isr, s->imr);
|
||||
@@ -255,7 +258,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
if (addr == E8390_CMD) {
|
||||
/* control register */
|
||||
s->cmd = val;
|
||||
if (val & E8390_START) {
|
||||
if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
|
||||
s->isr &= ~ENISR_RESET;
|
||||
/* test specific case: zero length transfert */
|
||||
if ((val & (E8390_RREAD | E8390_RWRITE)) &&
|
||||
@@ -376,6 +379,12 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
|
||||
case EN0_RSR:
|
||||
ret = s->rsr;
|
||||
break;
|
||||
case EN2_STARTPG:
|
||||
ret = s->start >> 8;
|
||||
break;
|
||||
case EN2_STOPPG:
|
||||
ret = s->stop >> 8;
|
||||
break;
|
||||
default:
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
+2
-1
@@ -320,8 +320,9 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ)
|
||||
}
|
||||
}
|
||||
|
||||
void openpic_set_irq(openpic_t *opp, int n_IRQ, int level)
|
||||
void openpic_set_irq(void *opaque, int n_IRQ, int level)
|
||||
{
|
||||
openpic_t *opp = opaque;
|
||||
IRQ_src_t *src;
|
||||
|
||||
src = &opp->src[n_IRQ];
|
||||
|
||||
@@ -41,6 +41,7 @@ int dummy_refresh_clock;
|
||||
static fdctrl_t *floppy_controller;
|
||||
static RTCState *rtc_state;
|
||||
static PITState *pit;
|
||||
static IOAPICState *ioapic;
|
||||
|
||||
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
|
||||
{
|
||||
@@ -65,6 +66,31 @@ uint64_t cpu_get_tsc(CPUX86State *env)
|
||||
return qemu_get_clock(vm_clock);
|
||||
}
|
||||
|
||||
/* IRQ handling */
|
||||
int cpu_get_pic_interrupt(CPUState *env)
|
||||
{
|
||||
int intno;
|
||||
|
||||
intno = apic_get_interrupt(env);
|
||||
if (intno >= 0) {
|
||||
/* set irq request if a PIC irq is still pending */
|
||||
/* XXX: improve that */
|
||||
pic_update_irq(isa_pic);
|
||||
return intno;
|
||||
}
|
||||
/* read the irq from the PIC */
|
||||
intno = pic_read_irq(isa_pic);
|
||||
return intno;
|
||||
}
|
||||
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
if (level)
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
else
|
||||
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
|
||||
/* PC cmos mappings */
|
||||
|
||||
#define REG_EQUIPMENT_BYTE 0x14
|
||||
@@ -380,17 +406,17 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
|
||||
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
|
||||
|
||||
/* PC hardware initialisation */
|
||||
void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
int ret, linux_boot, initrd_size, i, nb_nics1;
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
int bios_size, isa_bios_size;
|
||||
PCIBus *pci_bus;
|
||||
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
/* allocate RAM */
|
||||
@@ -520,7 +546,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
} else {
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size);
|
||||
vga_ram_size, 0, 0);
|
||||
}
|
||||
|
||||
rtc_state = rtc_init(0x70, 8);
|
||||
@@ -530,10 +556,15 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
|
||||
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
|
||||
|
||||
if (pci_enabled)
|
||||
if (pci_enabled) {
|
||||
apic_init(cpu_single_env);
|
||||
pic_init();
|
||||
ioapic = ioapic_init();
|
||||
}
|
||||
isa_pic = pic_init(pic_irq_request, cpu_single_env);
|
||||
pit = pit_init(0x40, 0);
|
||||
if (pci_enabled) {
|
||||
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
|
||||
}
|
||||
|
||||
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
@@ -595,3 +626,9 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
pci_bios_init();
|
||||
}
|
||||
}
|
||||
|
||||
QEMUMachine pc_machine = {
|
||||
"pc",
|
||||
"Standard PC",
|
||||
pc_init1,
|
||||
};
|
||||
@@ -45,7 +45,9 @@ struct PCIBus {
|
||||
int devfn_min;
|
||||
void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
|
||||
uint32_t config_reg; /* XXX: suppress */
|
||||
openpic_t *openpic; /* XXX: suppress */
|
||||
/* low level pic */
|
||||
SetIRQFunc *low_set_irq;
|
||||
void *irq_opaque;
|
||||
PCIDevice *devices[256];
|
||||
};
|
||||
|
||||
@@ -498,6 +500,27 @@ static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
return (irq_num + slot_addend) & 3;
|
||||
}
|
||||
|
||||
static inline int get_pci_irq_level(int irq_num)
|
||||
{
|
||||
int pic_level;
|
||||
#if (PCI_IRQ_WORDS == 2)
|
||||
pic_level = ((pci_irq_levels[irq_num][0] |
|
||||
pci_irq_levels[irq_num][1]) != 0);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
pic_level = 0;
|
||||
for(i = 0; i < PCI_IRQ_WORDS; i++) {
|
||||
if (pci_irq_levels[irq_num][i]) {
|
||||
pic_level = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return pic_level;
|
||||
}
|
||||
|
||||
static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
|
||||
{
|
||||
int irq_index, shift, pic_irq, pic_level;
|
||||
@@ -510,26 +533,20 @@ static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
|
||||
*p = (*p & ~(1 << shift)) | (level << shift);
|
||||
|
||||
/* now we change the pic irq level according to the piix irq mappings */
|
||||
/* XXX: optimize */
|
||||
pic_irq = piix3_state->dev.config[0x60 + irq_num];
|
||||
if (pic_irq < 16) {
|
||||
/* the pic level is the logical OR of all the PCI irqs mapped
|
||||
to it */
|
||||
pic_level = 0;
|
||||
#if (PCI_IRQ_WORDS == 2)
|
||||
pic_level = ((pci_irq_levels[irq_num][0] |
|
||||
pci_irq_levels[irq_num][1]) != 0);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
pic_level = 0;
|
||||
for(i = 0; i < PCI_IRQ_WORDS; i++) {
|
||||
if (pci_irq_levels[irq_num][i]) {
|
||||
pic_level = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pic_irq == piix3_state->dev.config[0x60])
|
||||
pic_level |= get_pci_irq_level(0);
|
||||
if (pic_irq == piix3_state->dev.config[0x61])
|
||||
pic_level |= get_pci_irq_level(1);
|
||||
if (pic_irq == piix3_state->dev.config[0x62])
|
||||
pic_level |= get_pci_irq_level(2);
|
||||
if (pic_irq == piix3_state->dev.config[0x63])
|
||||
pic_level |= get_pci_irq_level(3);
|
||||
pic_set_irq(pic_irq, pic_level);
|
||||
}
|
||||
}
|
||||
@@ -708,25 +725,25 @@ PCIBus *pci_prep_init(void)
|
||||
PPC_PCIIO_write, s);
|
||||
cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
|
||||
|
||||
d = pci_register_device(s, "PREP PCI Bridge", sizeof(PCIDevice), 0,
|
||||
NULL, NULL);
|
||||
|
||||
/* XXX: put correct IDs */
|
||||
d->config[0x00] = 0x11; // vendor_id
|
||||
/* PCI host bridge */
|
||||
d = pci_register_device(s, "PREP Host Bridge - Motorola Raven",
|
||||
sizeof(PCIDevice), 0, NULL, NULL);
|
||||
d->config[0x00] = 0x57; // vendor_id : Motorola
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x26; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x02; // revision
|
||||
d->config[0x0a] = 0x04; // class_sub = pci2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x01; // header_type
|
||||
d->config[0x02] = 0x01; // device_id : Raven
|
||||
d->config[0x03] = 0x48;
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x0A] = 0x00; // class_sub = pci host
|
||||
d->config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0C] = 0x08; // cache_line_size
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
d->config[0x34] = 0x00; // capabilities_pointer
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* pmac pci init */
|
||||
|
||||
#if 0
|
||||
/* Grackle PCI host */
|
||||
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
@@ -831,7 +848,93 @@ static CPUReadMemoryFunc *pci_grackle_read[] = {
|
||||
&pci_grackle_readw,
|
||||
&pci_grackle_readl,
|
||||
};
|
||||
|
||||
void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
|
||||
{
|
||||
bus->low_set_irq = set_irq;
|
||||
bus->irq_opaque = irq_opaque;
|
||||
}
|
||||
|
||||
/* XXX: we do not simulate the hardware - we rely on the BIOS to
|
||||
set correctly for irq line field */
|
||||
static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
|
||||
}
|
||||
|
||||
PCIBus *pci_grackle_init(uint32_t base)
|
||||
{
|
||||
PCIBus *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data;
|
||||
|
||||
s = pci_register_bus();
|
||||
s->set_irq = pci_set_irq_simple;
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
|
||||
pci_grackle_config_write, s);
|
||||
pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
|
||||
pci_grackle_write, s);
|
||||
cpu_register_physical_memory(base, 0x1000, pci_mem_config);
|
||||
cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
|
||||
d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice),
|
||||
0, NULL, NULL);
|
||||
d->config[0x00] = 0x57; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x02; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x01;
|
||||
d->config[0x0a] = 0x00; // class_sub = host
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x00; // header_type
|
||||
|
||||
d->config[0x18] = 0x00; // primary_bus
|
||||
d->config[0x19] = 0x01; // secondary_bus
|
||||
d->config[0x1a] = 0x00; // subordinate_bus
|
||||
d->config[0x1c] = 0x00;
|
||||
d->config[0x1d] = 0x00;
|
||||
|
||||
d->config[0x20] = 0x00; // memory_base
|
||||
d->config[0x21] = 0x00;
|
||||
d->config[0x22] = 0x01; // memory_limit
|
||||
d->config[0x23] = 0x00;
|
||||
|
||||
d->config[0x24] = 0x00; // prefetchable_memory_base
|
||||
d->config[0x25] = 0x00;
|
||||
d->config[0x26] = 0x00; // prefetchable_memory_limit
|
||||
d->config[0x27] = 0x00;
|
||||
|
||||
#if 0
|
||||
/* PCI2PCI bridge same values as PearPC - check this */
|
||||
d->config[0x00] = 0x11; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x26; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x02; // revision
|
||||
d->config[0x0a] = 0x04; // class_sub = pci2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x01; // header_type
|
||||
|
||||
d->config[0x18] = 0x0; // primary_bus
|
||||
d->config[0x19] = 0x1; // secondary_bus
|
||||
d->config[0x1a] = 0x1; // subordinate_bus
|
||||
d->config[0x1c] = 0x10; // io_base
|
||||
d->config[0x1d] = 0x20; // io_limit
|
||||
|
||||
d->config[0x20] = 0x80; // memory_base
|
||||
d->config[0x21] = 0x80;
|
||||
d->config[0x22] = 0x90; // memory_limit
|
||||
d->config[0x23] = 0x80;
|
||||
|
||||
d->config[0x24] = 0x00; // prefetchable_memory_base
|
||||
d->config[0x25] = 0x84;
|
||||
d->config[0x26] = 0x00; // prefetchable_memory_limit
|
||||
d->config[0x27] = 0x85;
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Uninorth PCI host (for all Mac99 and newer machines */
|
||||
static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
@@ -1073,23 +1176,6 @@ static CPUReadMemoryFunc *pci_unin_read[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static void pmac_set_irq(PCIDevice *d, int irq_num, int level)
|
||||
{
|
||||
openpic_t *openpic;
|
||||
/* XXX: we do not simulate the hardware - we rely on the BIOS to
|
||||
set correctly for irq line field */
|
||||
openpic = d->bus->openpic;
|
||||
#ifdef TARGET_PPC
|
||||
if (openpic)
|
||||
openpic_set_irq(openpic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pci_pmac_set_openpic(PCIBus *bus, openpic_t *openpic)
|
||||
{
|
||||
bus->openpic = openpic;
|
||||
}
|
||||
|
||||
PCIBus *pci_pmac_init(void)
|
||||
{
|
||||
PCIBus *s;
|
||||
@@ -1099,7 +1185,7 @@ PCIBus *pci_pmac_init(void)
|
||||
/* Use values found on a real PowerMac */
|
||||
/* Uninorth main bus */
|
||||
s = pci_register_bus();
|
||||
s->set_irq = pmac_set_irq;
|
||||
s->set_irq = pci_set_irq_simple;
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
|
||||
pci_unin_main_config_write, s);
|
||||
@@ -1202,34 +1288,253 @@ PCIBus *pci_pmac_init(void)
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
d->config[0x34] = 0x00; // capabilities_pointer
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
#if 0 // Grackle ?
|
||||
/* same values as PearPC - check this */
|
||||
d->config[0x00] = 0x11; // vendor_id
|
||||
/* Ultrasparc APB PCI host */
|
||||
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 11; i < 32; i++) {
|
||||
if ((val & (1 << i)) != 0)
|
||||
break;
|
||||
}
|
||||
s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
int devfn;
|
||||
|
||||
devfn = (s->config_reg >> 8) & 0xFF;
|
||||
val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_config_read[] = {
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
};
|
||||
|
||||
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *apb_config_write[] = {
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *apb_config_read[] = {
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
};
|
||||
|
||||
static void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
|
||||
pci_data_write(s, addr & 7, val, 1);
|
||||
}
|
||||
|
||||
static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
|
||||
pci_data_write(s, addr & 7, val, 2);
|
||||
}
|
||||
|
||||
static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
|
||||
pci_data_write(s, addr & 7, val, 4);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
val = pci_data_read(s, addr & 7, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
val = pci_data_read(s, addr & 7, 2);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
val = pci_data_read(s, addr, 4);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_write[] = {
|
||||
&pci_apb_writeb,
|
||||
&pci_apb_writew,
|
||||
&pci_apb_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_read[] = {
|
||||
&pci_apb_readb,
|
||||
&pci_apb_readw,
|
||||
&pci_apb_readl,
|
||||
};
|
||||
|
||||
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outb(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outw(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outl(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inb(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inw(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inl(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
|
||||
&pci_apb_iowriteb,
|
||||
&pci_apb_iowritew,
|
||||
&pci_apb_iowritel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_ioread[] = {
|
||||
&pci_apb_ioreadb,
|
||||
&pci_apb_ioreadw,
|
||||
&pci_apb_ioreadl,
|
||||
};
|
||||
|
||||
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
|
||||
{
|
||||
PCIBus *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
|
||||
|
||||
/* Ultrasparc APB main bus */
|
||||
s = pci_register_bus();
|
||||
s->set_irq = pci_set_irq_simple;
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
|
||||
pci_apb_config_write, s);
|
||||
apb_config = cpu_register_io_memory(0, apb_config_read,
|
||||
apb_config_write, s);
|
||||
pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
|
||||
pci_apb_write, s);
|
||||
pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
|
||||
pci_apb_iowrite, s);
|
||||
|
||||
cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
|
||||
cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
|
||||
cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
|
||||
cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
|
||||
|
||||
d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
d->config[0x00] = 0x8e; // vendor_id : Sun
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x26; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x02; // revision
|
||||
d->config[0x0a] = 0x04; // class_sub = pci2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x01; // header_type
|
||||
|
||||
d->config[0x18] = 0x0; // primary_bus
|
||||
d->config[0x19] = 0x1; // secondary_bus
|
||||
d->config[0x1a] = 0x1; // subordinate_bus
|
||||
d->config[0x1c] = 0x10; // io_base
|
||||
d->config[0x1d] = 0x20; // io_limit
|
||||
|
||||
d->config[0x20] = 0x80; // memory_base
|
||||
d->config[0x21] = 0x80;
|
||||
d->config[0x22] = 0x90; // memory_limit
|
||||
d->config[0x23] = 0x80;
|
||||
|
||||
d->config[0x24] = 0x00; // prefetchable_memory_base
|
||||
d->config[0x25] = 0x84;
|
||||
d->config[0x26] = 0x00; // prefetchable_memory_limit
|
||||
d->config[0x27] = 0x85;
|
||||
#endif
|
||||
d->config[0x02] = 0x00; // device_id
|
||||
d->config[0x03] = 0xa0;
|
||||
d->config[0x04] = 0x06; // command = bus master, pci mem
|
||||
d->config[0x05] = 0x00;
|
||||
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
|
||||
d->config[0x07] = 0x03; // status = medium devsel
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x00; // programming i/f
|
||||
d->config[0x0A] = 0x00; // class_sub = pci host
|
||||
d->config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,13 +107,16 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
uint32_t decr;
|
||||
int64_t diff;
|
||||
|
||||
decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
|
||||
tb_env->tb_freq, ticks_per_sec);
|
||||
diff = tb_env->decr_next - qemu_get_clock(vm_clock);
|
||||
if (diff >= 0)
|
||||
decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
|
||||
else
|
||||
decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
|
||||
#if defined(DEBUG_TB)
|
||||
printf("%s: 0x%08x\n", __func__, decr);
|
||||
#endif
|
||||
|
||||
return decr;
|
||||
}
|
||||
|
||||
@@ -440,23 +443,4 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
|
||||
NVRAM_set_word(nvram, 0xFC, crc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
if (prep_enabled) {
|
||||
ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
|
||||
snapshot, kernel_filename, kernel_cmdline,
|
||||
initrd_filename);
|
||||
} else {
|
||||
ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
|
||||
snapshot, kernel_filename, kernel_cmdline,
|
||||
initrd_filename);
|
||||
}
|
||||
/* Special port to get debug messages from Open-Firmware */
|
||||
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
|
||||
}
|
||||
+381
-58
@@ -24,19 +24,22 @@
|
||||
#include "vl.h"
|
||||
|
||||
#define BIOS_FILENAME "ppc_rom.bin"
|
||||
#define VGABIOS_FILENAME "video.x"
|
||||
#define NVRAM_SIZE 0x2000
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x01000000
|
||||
#define INITRD_LOAD_ADDR 0x01800000
|
||||
|
||||
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
|
||||
NVRAM (not implemented). */
|
||||
NVRAM */
|
||||
|
||||
static int dbdma_mem_index;
|
||||
static int cuda_mem_index;
|
||||
static int ide0_mem_index;
|
||||
static int ide1_mem_index;
|
||||
static int openpic_mem_index;
|
||||
static int ide0_mem_index = -1;
|
||||
static int ide1_mem_index = -1;
|
||||
static int openpic_mem_index = -1;
|
||||
static int heathrow_pic_mem_index = -1;
|
||||
static int macio_nvram_mem_index = -1;
|
||||
|
||||
/* DBDMA: currently no op - should suffice right now */
|
||||
|
||||
@@ -81,17 +84,75 @@ static CPUReadMemoryFunc *dbdma_read[] = {
|
||||
&dbdma_readl,
|
||||
};
|
||||
|
||||
/* macio style NVRAM device */
|
||||
typedef struct MacIONVRAMState {
|
||||
uint8_t data[0x2000];
|
||||
} MacIONVRAMState;
|
||||
|
||||
static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
MacIONVRAMState *s = opaque;
|
||||
addr = (addr >> 4) & 0x1fff;
|
||||
s->data[addr] = value;
|
||||
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
|
||||
}
|
||||
|
||||
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
MacIONVRAMState *s = opaque;
|
||||
uint32_t value;
|
||||
|
||||
addr = (addr >> 4) & 0x1fff;
|
||||
value = s->data[addr];
|
||||
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *macio_nvram_write[] = {
|
||||
&macio_nvram_writeb,
|
||||
&macio_nvram_writeb,
|
||||
&macio_nvram_writeb,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *macio_nvram_read[] = {
|
||||
&macio_nvram_readb,
|
||||
&macio_nvram_readb,
|
||||
&macio_nvram_readb,
|
||||
};
|
||||
|
||||
static MacIONVRAMState *macio_nvram_init(void)
|
||||
{
|
||||
MacIONVRAMState *s;
|
||||
s = qemu_mallocz(sizeof(MacIONVRAMState));
|
||||
if (!s)
|
||||
return NULL;
|
||||
macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
|
||||
macio_nvram_write, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void macio_map(PCIDevice *pci_dev, int region_num,
|
||||
uint32_t addr, uint32_t size, int type)
|
||||
{
|
||||
if (heathrow_pic_mem_index >= 0) {
|
||||
cpu_register_physical_memory(addr + 0x00000, 0x1000,
|
||||
heathrow_pic_mem_index);
|
||||
}
|
||||
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
|
||||
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
|
||||
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
|
||||
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
|
||||
cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index);
|
||||
if (ide0_mem_index >= 0)
|
||||
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
|
||||
if (ide1_mem_index >= 0)
|
||||
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
|
||||
if (openpic_mem_index >= 0) {
|
||||
cpu_register_physical_memory(addr + 0x40000, 0x40000,
|
||||
openpic_mem_index);
|
||||
}
|
||||
if (macio_nvram_mem_index >= 0)
|
||||
cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
|
||||
}
|
||||
|
||||
static void macio_init(PCIBus *bus)
|
||||
static void macio_init(PCIBus *bus, int device_id)
|
||||
{
|
||||
PCIDevice *d;
|
||||
|
||||
@@ -101,8 +162,8 @@ static void macio_init(PCIBus *bus)
|
||||
in PearPC */
|
||||
d->config[0x00] = 0x6b; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x22;
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x02] = device_id;
|
||||
d->config[0x03] = device_id >> 8;
|
||||
|
||||
d->config[0x0a] = 0x00; // class_sub = pci2pci
|
||||
d->config[0x0b] = 0xff; // class_base = bridge
|
||||
@@ -116,20 +177,141 @@ static void macio_init(PCIBus *bus)
|
||||
PCI_ADDRESS_SPACE_MEM, macio_map);
|
||||
}
|
||||
|
||||
/* PowerPC PREP hardware initialisation */
|
||||
void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
/* UniN device */
|
||||
static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
{
|
||||
}
|
||||
|
||||
static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *unin_write[] = {
|
||||
&unin_writel,
|
||||
&unin_writel,
|
||||
&unin_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *unin_read[] = {
|
||||
&unin_readl,
|
||||
&unin_readl,
|
||||
&unin_readl,
|
||||
};
|
||||
|
||||
/* temporary frame buffer OSI calls for the video.x driver. The right
|
||||
solution is to modify the driver to use VGA PCI I/Os */
|
||||
static int vga_osi_call(CPUState *env)
|
||||
{
|
||||
static int vga_vbl_enabled;
|
||||
int linesize;
|
||||
|
||||
// printf("osi_call R5=%d\n", env->gpr[5]);
|
||||
|
||||
/* same handler as PearPC, coming from the original MOL video
|
||||
driver. */
|
||||
switch(env->gpr[5]) {
|
||||
case 4:
|
||||
break;
|
||||
case 28: /* set_vmode */
|
||||
if (env->gpr[6] != 1 || env->gpr[7] != 0)
|
||||
env->gpr[3] = 1;
|
||||
else
|
||||
env->gpr[3] = 0;
|
||||
break;
|
||||
case 29: /* get_vmode_info */
|
||||
if (env->gpr[6] != 0) {
|
||||
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
|
||||
env->gpr[3] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->gpr[3] = 0;
|
||||
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
|
||||
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
|
||||
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
|
||||
env->gpr[7] = 85 << 16; /* refresh rate */
|
||||
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
|
||||
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
|
||||
linesize = (linesize + 3) & ~3;
|
||||
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
|
||||
break;
|
||||
case 31: /* set_video power */
|
||||
env->gpr[3] = 0;
|
||||
break;
|
||||
case 39: /* video_ctrl */
|
||||
if (env->gpr[6] == 0 || env->gpr[6] == 1)
|
||||
vga_vbl_enabled = env->gpr[6];
|
||||
env->gpr[3] = 0;
|
||||
break;
|
||||
case 47:
|
||||
break;
|
||||
case 59: /* set_color */
|
||||
/* R6 = index, R7 = RGB */
|
||||
env->gpr[3] = 0;
|
||||
break;
|
||||
case 64: /* get color */
|
||||
/* R6 = index */
|
||||
env->gpr[3] = 0;
|
||||
break;
|
||||
case 116: /* set hwcursor */
|
||||
/* R6 = x, R7 = y, R8 = visible, R9 = data */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
|
||||
break;
|
||||
}
|
||||
return 1; /* osi_call handled */
|
||||
}
|
||||
|
||||
/* XXX: suppress that */
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t nvram_chksum(const uint8_t *buf, int n)
|
||||
{
|
||||
int sum, i;
|
||||
sum = 0;
|
||||
for(i = 0; i < n; i++)
|
||||
sum += buf[i];
|
||||
return (sum & 0xff) + (sum >> 8);
|
||||
}
|
||||
|
||||
/* set a free Mac OS NVRAM partition */
|
||||
void pmac_format_nvram_partition(uint8_t *buf, int len)
|
||||
{
|
||||
char partition_name[12] = "wwwwwwwwwwww";
|
||||
|
||||
buf[0] = 0x7f; /* free partition magic */
|
||||
buf[1] = 0; /* checksum */
|
||||
buf[2] = len >> 8;
|
||||
buf[3] = len;
|
||||
memcpy(buf + 4, partition_name, 12);
|
||||
buf[1] = nvram_chksum(buf, 16);
|
||||
}
|
||||
|
||||
/* PowerPC CHRP hardware initialisation */
|
||||
static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename,
|
||||
int snapshot,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
int is_heathrow)
|
||||
{
|
||||
char buf[1024];
|
||||
openpic_t *openpic;
|
||||
SetIRQFunc *set_irq;
|
||||
void *pic;
|
||||
m48t59_t *nvram;
|
||||
int PPC_io_memory;
|
||||
int ret, linux_boot, i;
|
||||
unsigned long bios_offset;
|
||||
int PPC_io_memory, unin_memory;
|
||||
int linux_boot, i;
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
|
||||
ppc_def_t *def;
|
||||
PCIBus *pci_bus;
|
||||
const char *arch_name;
|
||||
int vga_bios_size, bios_size;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
@@ -139,15 +321,36 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
/* allocate and load BIOS */
|
||||
bios_offset = ram_size + vga_ram_size;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (ret != BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
|
||||
bios_size = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (bios_size < 0 || bios_size > BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
cpu_single_env->nip = 0xfffffffc;
|
||||
|
||||
bios_size = (bios_size + 0xfff) & ~0xfff;
|
||||
cpu_register_physical_memory((uint32_t)(-bios_size),
|
||||
bios_size, bios_offset | IO_MEM_ROM);
|
||||
|
||||
/* allocate and load VGA BIOS */
|
||||
vga_bios_offset = bios_offset + bios_size;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
|
||||
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
|
||||
if (vga_bios_size < 0) {
|
||||
/* if no bios is present, we can still work */
|
||||
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
|
||||
vga_bios_size = 0;
|
||||
} else {
|
||||
/* set a specific header (XXX: find real Apple format for NDRV
|
||||
drivers) */
|
||||
phys_ram_base[vga_bios_offset] = 'N';
|
||||
phys_ram_base[vga_bios_offset + 1] = 'D';
|
||||
phys_ram_base[vga_bios_offset + 2] = 'R';
|
||||
phys_ram_base[vga_bios_offset + 3] = 'V';
|
||||
cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
|
||||
vga_bios_size);
|
||||
vga_bios_size += 8;
|
||||
}
|
||||
vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
|
||||
|
||||
if (linux_boot) {
|
||||
kernel_base = KERNEL_LOAD_ADDR;
|
||||
/* now we can load the kernel */
|
||||
@@ -179,50 +382,129 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
initrd_size = 0;
|
||||
}
|
||||
/* Register CPU as a 74x/75x */
|
||||
cpu_ppc_register(cpu_single_env, 0x00080000);
|
||||
/* XXX: CPU model (or PVR) should be provided on command line */
|
||||
// ppc_find_by_name("750gx", &def); // Linux boot OK
|
||||
// ppc_find_by_name("750fx", &def); // Linux boot OK
|
||||
/* Linux does not boot on 750cxe (and probably other 750cx based)
|
||||
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
|
||||
*/
|
||||
// ppc_find_by_name("750cxe", &def);
|
||||
// ppc_find_by_name("750p", &def);
|
||||
// ppc_find_by_name("740p", &def);
|
||||
ppc_find_by_name("750", &def);
|
||||
// ppc_find_by_name("740", &def);
|
||||
// ppc_find_by_name("G3", &def);
|
||||
// ppc_find_by_name("604r", &def);
|
||||
// ppc_find_by_name("604e", &def);
|
||||
// ppc_find_by_name("604", &def);
|
||||
if (def == NULL) {
|
||||
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
|
||||
}
|
||||
cpu_ppc_register(cpu_single_env, def);
|
||||
|
||||
/* Set time-base frequency to 100 Mhz */
|
||||
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
|
||||
|
||||
isa_mem_base = 0x80000000;
|
||||
pci_bus = pci_pmac_init();
|
||||
cpu_single_env->osi_call = vga_osi_call;
|
||||
|
||||
/* Register 8 MB of ISA IO space */
|
||||
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
|
||||
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
|
||||
if (is_heathrow) {
|
||||
isa_mem_base = 0x80000000;
|
||||
pci_bus = pci_grackle_init(0xfec00000);
|
||||
|
||||
/* Register 2 MB of ISA IO space */
|
||||
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
|
||||
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
|
||||
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
pic = heathrow_pic_init(&heathrow_pic_mem_index);
|
||||
set_irq = heathrow_pic_set_irq;
|
||||
pci_set_pic(pci_bus, set_irq, pic);
|
||||
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size);
|
||||
openpic = openpic_init(NULL, &openpic_mem_index, 1);
|
||||
pci_pmac_set_openpic(pci_bus, openpic);
|
||||
|
||||
/* XXX: suppress that */
|
||||
pic_init();
|
||||
/* XXX: suppress that */
|
||||
isa_pic = pic_init(pic_irq_request, NULL);
|
||||
|
||||
/* XXX: use Mac Serial port */
|
||||
serial_init(0x3f8, 4, serial_hds[0]);
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
pci_ne2000_init(pci_bus, &nd_table[i]);
|
||||
}
|
||||
|
||||
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
|
||||
|
||||
/* XXX: use Mac Serial port */
|
||||
serial_init(0x3f8, 4, serial_hds[0]);
|
||||
/* cuda also initialize ADB */
|
||||
cuda_mem_index = cuda_init(set_irq, pic, 0x12);
|
||||
|
||||
adb_kbd_init(&adb_bus);
|
||||
adb_mouse_init(&adb_bus);
|
||||
|
||||
{
|
||||
MacIONVRAMState *nvr;
|
||||
nvr = macio_nvram_init();
|
||||
pmac_format_nvram_partition(nvr->data, 0x2000);
|
||||
}
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
pci_ne2000_init(pci_bus, &nd_table[i]);
|
||||
macio_init(pci_bus, 0x0017);
|
||||
|
||||
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
|
||||
|
||||
arch_name = "HEATHROW";
|
||||
} else {
|
||||
isa_mem_base = 0x80000000;
|
||||
pci_bus = pci_pmac_init();
|
||||
|
||||
/* Register 8 MB of ISA IO space */
|
||||
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
|
||||
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
|
||||
|
||||
/* UniN init */
|
||||
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
|
||||
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
|
||||
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
|
||||
ram_size, vga_ram_size,
|
||||
vga_bios_offset, vga_bios_size);
|
||||
pic = openpic_init(NULL, &openpic_mem_index, 1);
|
||||
set_irq = openpic_set_irq;
|
||||
pci_set_pic(pci_bus, set_irq, pic);
|
||||
|
||||
/* XXX: suppress that */
|
||||
isa_pic = pic_init(pic_irq_request, NULL);
|
||||
|
||||
/* XXX: use Mac Serial port */
|
||||
serial_init(0x3f8, 4, serial_hds[0]);
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
pci_ne2000_init(pci_bus, &nd_table[i]);
|
||||
}
|
||||
|
||||
#if 1
|
||||
ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
|
||||
ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
|
||||
#else
|
||||
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
|
||||
#endif
|
||||
/* cuda also initialize ADB */
|
||||
cuda_mem_index = cuda_init(set_irq, pic, 0x19);
|
||||
|
||||
adb_kbd_init(&adb_bus);
|
||||
adb_mouse_init(&adb_bus);
|
||||
|
||||
macio_init(pci_bus, 0x0022);
|
||||
|
||||
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
|
||||
|
||||
arch_name = "MAC99";
|
||||
}
|
||||
|
||||
ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13);
|
||||
ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x14);
|
||||
|
||||
/* cuda also initialize ADB */
|
||||
cuda_mem_index = cuda_init(openpic, 0x19);
|
||||
|
||||
adb_kbd_init(&adb_bus);
|
||||
adb_mouse_init(&adb_bus);
|
||||
|
||||
macio_init(pci_bus);
|
||||
|
||||
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
|
||||
|
||||
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
|
||||
graphic_depth = 15;
|
||||
|
||||
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device,
|
||||
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
|
||||
kernel_base, kernel_size,
|
||||
kernel_cmdline,
|
||||
initrd_base, initrd_size,
|
||||
@@ -230,4 +512,45 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
0,
|
||||
graphic_width, graphic_height, graphic_depth);
|
||||
/* No PCI init: the BIOS will do it */
|
||||
|
||||
/* Special port to get debug messages from Open-Firmware */
|
||||
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
|
||||
}
|
||||
|
||||
static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename,
|
||||
int snapshot,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
|
||||
ds, fd_filename, snapshot,
|
||||
kernel_filename, kernel_cmdline,
|
||||
initrd_filename, 0);
|
||||
}
|
||||
|
||||
static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename,
|
||||
int snapshot,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
|
||||
ds, fd_filename, snapshot,
|
||||
kernel_filename, kernel_cmdline,
|
||||
initrd_filename, 1);
|
||||
}
|
||||
|
||||
QEMUMachine core99_machine = {
|
||||
"mac99",
|
||||
"Mac99 based PowerMAC",
|
||||
ppc_core99_init,
|
||||
};
|
||||
|
||||
QEMUMachine heathrow_machine = {
|
||||
"g3bw",
|
||||
"Heathrow based PowerMAC",
|
||||
ppc_heathrow_init,
|
||||
};
|
||||
+43
-19
@@ -96,6 +96,14 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pic_irq_request(void *opaque, int level)
|
||||
{
|
||||
if (level)
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
else
|
||||
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
|
||||
/* PCI intack register */
|
||||
/* Read-only register (?) */
|
||||
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
@@ -108,7 +116,7 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
|
||||
uint32_t retval = 0;
|
||||
|
||||
if (addr == 0xBFFFFFF0)
|
||||
retval = pic_intack_read(NULL);
|
||||
retval = pic_intack_read(isa_pic);
|
||||
// printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
|
||||
|
||||
return retval;
|
||||
@@ -250,6 +258,7 @@ typedef struct sysctrl_t {
|
||||
uint8_t syscontrol;
|
||||
uint8_t fake_io[2];
|
||||
int contiguous_map;
|
||||
int endian;
|
||||
} sysctrl_t;
|
||||
|
||||
enum {
|
||||
@@ -289,8 +298,9 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
/* Check LE mode */
|
||||
if (val & 0x02) {
|
||||
printf("Little Endian mode isn't supported (yet ?)\n");
|
||||
abort();
|
||||
sysctrl->endian = 1;
|
||||
} else {
|
||||
sysctrl->endian = 0;
|
||||
}
|
||||
break;
|
||||
case 0x0800:
|
||||
@@ -505,22 +515,21 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = {
|
||||
&PPC_prep_io_readl,
|
||||
};
|
||||
|
||||
extern CPUPPCState *global_env;
|
||||
|
||||
#define NVRAM_SIZE 0x2000
|
||||
|
||||
/* PowerPC PREP hardware initialisation */
|
||||
void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
m48t59_t *nvram;
|
||||
int PPC_io_memory;
|
||||
int ret, linux_boot, i, nb_nics1;
|
||||
int linux_boot, i, nb_nics1, bios_size;
|
||||
unsigned long bios_offset;
|
||||
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
|
||||
ppc_def_t *def;
|
||||
PCIBus *pci_bus;
|
||||
|
||||
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
|
||||
@@ -535,14 +544,14 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
/* allocate and load BIOS */
|
||||
bios_offset = ram_size + vga_ram_size;
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
|
||||
ret = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (ret != BIOS_SIZE) {
|
||||
bios_size = load_image(buf, phys_ram_base + bios_offset);
|
||||
if (bios_size < 0 || bios_size > BIOS_SIZE) {
|
||||
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
|
||||
BIOS_SIZE, bios_offset | IO_MEM_ROM);
|
||||
cpu_single_env->nip = 0xfffffffc;
|
||||
bios_size = (bios_size + 0xfff) & ~0xfff;
|
||||
cpu_register_physical_memory((uint32_t)(-bios_size),
|
||||
bios_size, bios_offset | IO_MEM_ROM);
|
||||
|
||||
if (linux_boot) {
|
||||
kernel_base = KERNEL_LOAD_ADDR;
|
||||
@@ -576,7 +585,14 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
|
||||
/* Register CPU as a 604 */
|
||||
cpu_ppc_register(cpu_single_env, 0x00040000);
|
||||
/* XXX: CPU model (or PVR) should be provided on command line */
|
||||
// ppc_find_by_name("604r", &def);
|
||||
// ppc_find_by_name("604e", &def);
|
||||
ppc_find_by_name("604", &def);
|
||||
if (def == NULL) {
|
||||
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
|
||||
}
|
||||
cpu_ppc_register(cpu_single_env, def);
|
||||
/* Set time-base frequency to 100 Mhz */
|
||||
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
|
||||
|
||||
@@ -590,11 +606,10 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
|
||||
/* init basic PC hardware */
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size);
|
||||
vga_ram_size, 0, 0);
|
||||
rtc_init(0x70, 8);
|
||||
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
|
||||
// pic_init(openpic);
|
||||
pic_init();
|
||||
isa_pic = pic_init(pic_irq_request, cpu_single_env);
|
||||
// pit = pit_init(0x40, 0);
|
||||
|
||||
serial_init(0x3f8, 4, serial_hds[0]);
|
||||
@@ -650,4 +665,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
/* XXX: need an option to load a NVRAM image */
|
||||
0,
|
||||
graphic_width, graphic_height, graphic_depth);
|
||||
|
||||
/* Special port to get debug messages from Open-Firmware */
|
||||
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
|
||||
}
|
||||
|
||||
QEMUMachine prep_machine = {
|
||||
"prep",
|
||||
"PowerPC PREP platform",
|
||||
ppc_prep_init,
|
||||
};
|
||||
+3
-3
@@ -144,14 +144,14 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin
|
||||
switch (saddr) {
|
||||
case 2: // clear (enable)
|
||||
// Force clear unused bits
|
||||
val &= ~0x7fb2007f;
|
||||
val &= ~0x4fb2007f;
|
||||
s->intregm_disabled &= ~val;
|
||||
DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
|
||||
slavio_check_interrupts(s);
|
||||
break;
|
||||
case 3: // set (disable, clear pending)
|
||||
// Force clear unused bits
|
||||
val &= ~0x7fb2007f;
|
||||
val &= ~0x4fb2007f;
|
||||
s->intregm_disabled |= val;
|
||||
s->intregm_pending &= ~val;
|
||||
DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
|
||||
@@ -208,7 +208,7 @@ void slavio_irq_info(void *opaque)
|
||||
|
||||
static const uint32_t intbit_to_level[32] = {
|
||||
2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
|
||||
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0,
|
||||
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
|
||||
};
|
||||
|
||||
static void slavio_check_interrupts(void *opaque)
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* QEMU Sparc SLAVIO aux io port emulation
|
||||
*
|
||||
* Copyright (c) 2005 Fabrice Bellard
|
||||
*
|
||||
* 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"
|
||||
/* debug misc */
|
||||
//#define DEBUG_MISC
|
||||
|
||||
/*
|
||||
* This is the auxio port, chip control and system control part of
|
||||
* chip STP2001 (Slave I/O), also produced as NCR89C105. See
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
||||
*
|
||||
* This also includes the PMC CPU idle controller.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_MISC
|
||||
#define MISC_DPRINTF(fmt, args...) \
|
||||
do { printf("MISC: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define MISC_DPRINTF(fmt, args...)
|
||||
#endif
|
||||
|
||||
typedef struct MiscState {
|
||||
int irq;
|
||||
uint8_t config;
|
||||
uint8_t aux1, aux2;
|
||||
uint8_t diag, mctrl;
|
||||
} MiscState;
|
||||
|
||||
#define MISC_MAXADDR 1
|
||||
|
||||
static void slavio_misc_update_irq(void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
if ((s->aux2 & 0x4) && (s->config & 0x8)) {
|
||||
pic_set_irq(s->irq, 1);
|
||||
} else {
|
||||
pic_set_irq(s->irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void slavio_misc_reset(void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
// Diagnostic register not cleared in reset
|
||||
s->config = s->aux1 = s->aux2 = s->mctrl = 0;
|
||||
}
|
||||
|
||||
void slavio_set_power_fail(void *opaque, int power_failing)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
|
||||
if (power_failing && (s->config & 0x8)) {
|
||||
s->aux2 |= 0x4;
|
||||
} else {
|
||||
s->aux2 &= ~0x4;
|
||||
}
|
||||
slavio_misc_update_irq(s);
|
||||
}
|
||||
|
||||
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
switch (addr & 0xfff0000) {
|
||||
case 0x1800000:
|
||||
MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
|
||||
s->config = val & 0xff;
|
||||
slavio_misc_update_irq(s);
|
||||
break;
|
||||
case 0x1900000:
|
||||
MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
|
||||
s->aux1 = val & 0xff;
|
||||
break;
|
||||
case 0x1910000:
|
||||
val &= 0x3;
|
||||
MISC_DPRINTF("Write aux2 %2.2x\n", val);
|
||||
val |= s->aux2 & 0x4;
|
||||
if (val & 0x2) // Clear Power Fail int
|
||||
val &= 0x1;
|
||||
s->aux2 = val;
|
||||
if (val & 1)
|
||||
qemu_system_shutdown_request();
|
||||
slavio_misc_update_irq(s);
|
||||
break;
|
||||
case 0x1a00000:
|
||||
MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
|
||||
s->diag = val & 0xff;
|
||||
break;
|
||||
case 0x1b00000:
|
||||
MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
|
||||
s->mctrl = val & 0xff;
|
||||
break;
|
||||
case 0x1f00000:
|
||||
MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
|
||||
if (val & 1)
|
||||
qemu_system_reset_request();
|
||||
break;
|
||||
case 0xa000000:
|
||||
MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
|
||||
#if 0
|
||||
// XXX: halting CPU does not work
|
||||
raise_exception(EXCP_HLT);
|
||||
cpu_loop_exit();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
uint32_t ret = 0;
|
||||
|
||||
switch (addr & 0xfff0000) {
|
||||
case 0x1800000:
|
||||
ret = s->config;
|
||||
MISC_DPRINTF("Read config %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1900000:
|
||||
ret = s->aux1;
|
||||
MISC_DPRINTF("Read aux1 %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1910000:
|
||||
ret = s->aux2;
|
||||
MISC_DPRINTF("Read aux2 %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1a00000:
|
||||
ret = s->diag;
|
||||
MISC_DPRINTF("Read diag %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1b00000:
|
||||
ret = s->mctrl;
|
||||
MISC_DPRINTF("Read modem control %2.2x\n", ret);
|
||||
break;
|
||||
case 0x1f00000:
|
||||
MISC_DPRINTF("Read system control %2.2x\n", ret);
|
||||
break;
|
||||
case 0xa000000:
|
||||
MISC_DPRINTF("Read power management %2.2x\n", ret);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
|
||||
slavio_misc_mem_readb,
|
||||
slavio_misc_mem_readb,
|
||||
slavio_misc_mem_readb,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
|
||||
slavio_misc_mem_writeb,
|
||||
slavio_misc_mem_writeb,
|
||||
slavio_misc_mem_writeb,
|
||||
};
|
||||
|
||||
static void slavio_misc_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
qemu_put_be32s(f, &s->irq);
|
||||
qemu_put_8s(f, &s->config);
|
||||
qemu_put_8s(f, &s->aux1);
|
||||
qemu_put_8s(f, &s->aux2);
|
||||
qemu_put_8s(f, &s->diag);
|
||||
qemu_put_8s(f, &s->mctrl);
|
||||
}
|
||||
|
||||
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
MiscState *s = opaque;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
qemu_get_be32s(f, &s->irq);
|
||||
qemu_get_8s(f, &s->config);
|
||||
qemu_get_8s(f, &s->aux1);
|
||||
qemu_get_8s(f, &s->aux2);
|
||||
qemu_get_8s(f, &s->diag);
|
||||
qemu_get_8s(f, &s->mctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *slavio_misc_init(uint32_t base, int irq)
|
||||
{
|
||||
int slavio_misc_io_memory;
|
||||
MiscState *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(MiscState));
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
|
||||
// Slavio control
|
||||
cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// AUX 1
|
||||
cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// AUX 2
|
||||
cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Diagnostics
|
||||
cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Modem control
|
||||
cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// System control
|
||||
cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
// Power management
|
||||
cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
|
||||
|
||||
s->irq = irq;
|
||||
|
||||
register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
|
||||
qemu_register_reset(slavio_misc_reset, s);
|
||||
slavio_misc_reset(s);
|
||||
return s;
|
||||
}
|
||||
+20
-4
@@ -37,6 +37,7 @@
|
||||
// bits
|
||||
#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
|
||||
#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */
|
||||
#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */
|
||||
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
|
||||
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
|
||||
#define PHYS_JJ_ESP_IRQ 18
|
||||
@@ -55,6 +56,7 @@
|
||||
#define PHYS_JJ_SER_IRQ 15
|
||||
#define PHYS_JJ_FDC 0x71400000 /* Floppy */
|
||||
#define PHYS_JJ_FLOPPY_IRQ 22
|
||||
#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */
|
||||
|
||||
/* TSC handling */
|
||||
|
||||
@@ -202,11 +204,18 @@ uint32_t iommu_translate(uint32_t addr)
|
||||
return iommu_translate_local(iommu, addr);
|
||||
}
|
||||
|
||||
static void *slavio_misc;
|
||||
|
||||
void qemu_system_powerdown(void)
|
||||
{
|
||||
slavio_set_power_fail(slavio_misc, 1);
|
||||
}
|
||||
|
||||
/* Sun4m hardware initialisation */
|
||||
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
int ret, linux_boot;
|
||||
@@ -230,6 +239,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
|
||||
fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
|
||||
esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
|
||||
slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
|
||||
|
||||
prom_offset = ram_size + vram_size;
|
||||
|
||||
@@ -283,3 +293,9 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
|
||||
}
|
||||
|
||||
QEMUMachine sun4m_machine = {
|
||||
"sun4m",
|
||||
"Sun4m platform",
|
||||
sun4m_init,
|
||||
};
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* QEMU Sun4u System Emulator
|
||||
*
|
||||
* Copyright (c) 2005 Fabrice Bellard
|
||||
*
|
||||
* 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"
|
||||
#include "m48t59.h"
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x00404000
|
||||
#define CMDLINE_ADDR 0x003ff000
|
||||
#define INITRD_LOAD_ADDR 0x00300000
|
||||
#define PROM_ADDR 0x1fff0000000ULL
|
||||
#define APB_SPECIAL_BASE 0x1fe00000000ULL
|
||||
#define APB_MEM_BASE 0x1ff00000000ULL
|
||||
#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
|
||||
#define PROM_FILENAMEB "proll-sparc64.bin"
|
||||
#define PROM_FILENAMEE "proll-sparc64.elf"
|
||||
#define NVRAM_SIZE 0x2000
|
||||
|
||||
/* 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)
|
||||
{
|
||||
}
|
||||
|
||||
/* NVRAM helpers */
|
||||
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
|
||||
{
|
||||
m48t59_set_addr(nvram, addr);
|
||||
m48t59_write(nvram, value);
|
||||
}
|
||||
|
||||
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
|
||||
{
|
||||
m48t59_set_addr(nvram, addr);
|
||||
return m48t59_read(nvram);
|
||||
}
|
||||
|
||||
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
|
||||
{
|
||||
m48t59_set_addr(nvram, addr);
|
||||
m48t59_write(nvram, value >> 8);
|
||||
m48t59_set_addr(nvram, addr + 1);
|
||||
m48t59_write(nvram, value & 0xFF);
|
||||
}
|
||||
|
||||
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
|
||||
{
|
||||
uint16_t tmp;
|
||||
|
||||
m48t59_set_addr(nvram, addr);
|
||||
tmp = m48t59_read(nvram) << 8;
|
||||
m48t59_set_addr(nvram, addr + 1);
|
||||
tmp |= m48t59_read(nvram);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
|
||||
{
|
||||
m48t59_set_addr(nvram, addr);
|
||||
m48t59_write(nvram, value >> 24);
|
||||
m48t59_set_addr(nvram, addr + 1);
|
||||
m48t59_write(nvram, (value >> 16) & 0xFF);
|
||||
m48t59_set_addr(nvram, addr + 2);
|
||||
m48t59_write(nvram, (value >> 8) & 0xFF);
|
||||
m48t59_set_addr(nvram, addr + 3);
|
||||
m48t59_write(nvram, value & 0xFF);
|
||||
}
|
||||
|
||||
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
m48t59_set_addr(nvram, addr);
|
||||
tmp = m48t59_read(nvram) << 24;
|
||||
m48t59_set_addr(nvram, addr + 1);
|
||||
tmp |= m48t59_read(nvram) << 16;
|
||||
m48t59_set_addr(nvram, addr + 2);
|
||||
tmp |= m48t59_read(nvram) << 8;
|
||||
m48t59_set_addr(nvram, addr + 3);
|
||||
tmp |= m48t59_read(nvram);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
|
||||
const unsigned char *str, uint32_t max)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max && str[i] != '\0'; i++) {
|
||||
m48t59_set_addr(nvram, addr + i);
|
||||
m48t59_write(nvram, str[i]);
|
||||
}
|
||||
m48t59_set_addr(nvram, addr + max - 1);
|
||||
m48t59_write(nvram, '\0');
|
||||
}
|
||||
|
||||
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(dst, 0, max);
|
||||
for (i = 0; i < max; i++) {
|
||||
dst[i] = NVRAM_get_byte(nvram, addr + i);
|
||||
if (dst[i] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
|
||||
{
|
||||
uint16_t tmp;
|
||||
uint16_t pd, pd1, pd2;
|
||||
|
||||
tmp = prev >> 8;
|
||||
pd = prev ^ value;
|
||||
pd1 = pd & 0x000F;
|
||||
pd2 = ((pd >> 4) & 0x000F) ^ pd1;
|
||||
tmp ^= (pd1 << 3) | (pd1 << 8);
|
||||
tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
uint16_t crc = 0xFFFF;
|
||||
int odd;
|
||||
|
||||
odd = count & 1;
|
||||
count &= ~1;
|
||||
for (i = 0; i != count; i++) {
|
||||
crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
|
||||
}
|
||||
if (odd) {
|
||||
crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
extern int nographic;
|
||||
|
||||
int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
|
||||
const unsigned char *arch,
|
||||
uint32_t RAM_size, int boot_device,
|
||||
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)
|
||||
{
|
||||
uint16_t crc;
|
||||
|
||||
/* Set parameters for Open Hack'Ware BIOS */
|
||||
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
|
||||
NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
|
||||
NVRAM_set_word(nvram, 0x14, NVRAM_size);
|
||||
NVRAM_set_string(nvram, 0x20, arch, 16);
|
||||
NVRAM_set_byte(nvram, 0x2f, nographic & 0xff);
|
||||
NVRAM_set_lword(nvram, 0x30, RAM_size);
|
||||
NVRAM_set_byte(nvram, 0x34, boot_device);
|
||||
NVRAM_set_lword(nvram, 0x38, kernel_image);
|
||||
NVRAM_set_lword(nvram, 0x3C, kernel_size);
|
||||
if (cmdline) {
|
||||
/* XXX: put the cmdline in NVRAM too ? */
|
||||
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
|
||||
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
|
||||
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
|
||||
} else {
|
||||
NVRAM_set_lword(nvram, 0x40, 0);
|
||||
NVRAM_set_lword(nvram, 0x44, 0);
|
||||
}
|
||||
NVRAM_set_lword(nvram, 0x48, initrd_image);
|
||||
NVRAM_set_lword(nvram, 0x4C, initrd_size);
|
||||
NVRAM_set_lword(nvram, 0x50, NVRAM_image);
|
||||
|
||||
NVRAM_set_word(nvram, 0x54, width);
|
||||
NVRAM_set_word(nvram, 0x56, height);
|
||||
NVRAM_set_word(nvram, 0x58, depth);
|
||||
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
|
||||
NVRAM_set_word(nvram, 0xFC, crc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pic_info()
|
||||
{
|
||||
}
|
||||
|
||||
void irq_info()
|
||||
{
|
||||
}
|
||||
|
||||
void pic_set_irq(int irq, int level)
|
||||
{
|
||||
}
|
||||
|
||||
void pic_set_irq_new(void *opaque, int irq, int level)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_system_powerdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
static const int ide_iobase[2] = { 0x1f0, 0x170 };
|
||||
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
|
||||
static const int ide_irq[2] = { 14, 15 };
|
||||
|
||||
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;
|
||||
|
||||
/* Sun4u hardware initialisation */
|
||||
static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename)
|
||||
{
|
||||
char buf[1024];
|
||||
m48t59_t *nvram;
|
||||
int ret, linux_boot;
|
||||
unsigned int i;
|
||||
long prom_offset, initrd_size, kernel_size;
|
||||
PCIBus *pci_bus;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
/* allocate RAM */
|
||||
cpu_register_physical_memory(0, ram_size, 0);
|
||||
|
||||
prom_offset = ram_size + vga_ram_size;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
|
||||
ret = load_elf(buf, phys_ram_base + prom_offset);
|
||||
if (ret < 0) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
|
||||
ret = load_image(buf, phys_ram_base + prom_offset);
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "qemu: could not load prom '%s'\n",
|
||||
buf);
|
||||
exit(1);
|
||||
}
|
||||
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
|
||||
prom_offset | IO_MEM_ROM);
|
||||
|
||||
kernel_size = 0;
|
||||
initrd_size = 0;
|
||||
if (linux_boot) {
|
||||
kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||
if (kernel_size < 0)
|
||||
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);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (initrd_size > 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
|
||||
isa_mem_base = VGA_BASE;
|
||||
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
|
||||
vga_ram_size, 0, 0);
|
||||
cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size);
|
||||
//pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
|
||||
|
||||
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
|
||||
if (parallel_hds[i]) {
|
||||
parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < nb_nics; i++) {
|
||||
pci_ne2000_init(pci_bus, &nd_table[i]);
|
||||
}
|
||||
|
||||
pci_cmd646_ide_init(pci_bus, bs_table, 1);
|
||||
kbd_init();
|
||||
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
|
||||
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
|
||||
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
QEMUMachine sun4u_machine = {
|
||||
"sun4u",
|
||||
"Sun4u platform",
|
||||
sun4u_init,
|
||||
};
|
||||
@@ -1654,8 +1654,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
|
||||
uint32_t addr, uint32_t size, int type)
|
||||
{
|
||||
VGAState *s = vga_state;
|
||||
|
||||
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
|
||||
if (region_num == PCI_ROM_SLOT) {
|
||||
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
|
||||
} else {
|
||||
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
@@ -1701,7 +1704,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
|
||||
|
||||
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
unsigned long vga_ram_offset, int vga_ram_size)
|
||||
unsigned long vga_ram_offset, int vga_ram_size,
|
||||
unsigned long vga_bios_offset, int vga_bios_size)
|
||||
{
|
||||
VGAState *s;
|
||||
|
||||
@@ -1776,6 +1780,17 @@ int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
|
||||
/* XXX: vga_ram_size must be a power of two */
|
||||
pci_register_io_region(d, 0, vga_ram_size,
|
||||
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
|
||||
if (vga_bios_size != 0) {
|
||||
unsigned int bios_total_size;
|
||||
s->bios_offset = vga_bios_offset;
|
||||
s->bios_size = vga_bios_size;
|
||||
/* must be a power of two */
|
||||
bios_total_size = 1;
|
||||
while (bios_total_size < vga_bios_size)
|
||||
bios_total_size <<= 1;
|
||||
pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size,
|
||||
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_BOCHS_VBE
|
||||
/* XXX: use optimized standard vga accesses */
|
||||
|
||||
@@ -78,6 +78,8 @@
|
||||
uint8_t *vram_ptr; \
|
||||
unsigned long vram_offset; \
|
||||
unsigned int vram_size; \
|
||||
unsigned long bios_offset; \
|
||||
unsigned int bios_size; \
|
||||
uint32_t latch; \
|
||||
uint8_t sr_index; \
|
||||
uint8_t sr[256]; \
|
||||
|
||||
@@ -99,7 +99,7 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
else
|
||||
return STDOUT_FILENO;
|
||||
}
|
||||
return set_swi_errno(ts, open(s, open_modeflags[ARG(1)]));
|
||||
return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
|
||||
case SYS_CLOSE:
|
||||
return set_swi_errno(ts, close(ARG(0)));
|
||||
case SYS_WRITEC:
|
||||
|
||||
+34
-40
@@ -552,6 +552,7 @@ void cpu_loop (CPUSPARCState *env)
|
||||
env->pc = env->npc;
|
||||
env->npc = env->npc + 4;
|
||||
break;
|
||||
#ifndef TARGET_SPARC64
|
||||
case TT_WIN_OVF: /* window overflow */
|
||||
save_window(env);
|
||||
break;
|
||||
@@ -569,6 +570,9 @@ void cpu_loop (CPUSPARCState *env)
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
// XXX
|
||||
#endif
|
||||
case 0x100: // XXX, why do we get these?
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
@@ -696,33 +700,28 @@ void cpu_loop(CPUPPCState *env)
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
queue_signal(info.si_signo, &info);
|
||||
case EXCP_DSI:
|
||||
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
|
||||
fprintf(stderr, "Invalid data memory access: 0x%08x\n",
|
||||
env->spr[SPR_DAR]);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
|
||||
env->spr[DAR]);
|
||||
env->spr[SPR_DAR]);
|
||||
}
|
||||
switch (env->error_code & 0xF) {
|
||||
case EXCP_DSI_TRANSLATE:
|
||||
switch (env->error_code & 0xFF000000) {
|
||||
case 0x40000000:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
case EXCP_DSI_NOTSUP:
|
||||
case EXCP_DSI_EXTERNAL:
|
||||
case 0x04000000:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLADR;
|
||||
break;
|
||||
case EXCP_DSI_PROT:
|
||||
case 0x08000000:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
break;
|
||||
case EXCP_DSI_DABR:
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
break;
|
||||
default:
|
||||
/* Let's send a regular segfault... */
|
||||
fprintf(stderr, "Invalid segfault errno (%02x)\n",
|
||||
@@ -743,19 +742,14 @@ void cpu_loop(CPUPPCState *env)
|
||||
fprintf(stderr, "Invalid instruction fetch\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Invalid instruction fetch\n");
|
||||
switch (env->error_code) {
|
||||
case EXCP_ISI_TRANSLATE:
|
||||
switch (env->error_code & 0xFF000000) {
|
||||
case 0x40000000:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
case EXCP_ISI_GUARD:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLADR;
|
||||
break;
|
||||
case EXCP_ISI_NOEXEC:
|
||||
case EXCP_ISI_PROT:
|
||||
case 0x10000000:
|
||||
case 0x08000000:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
@@ -925,18 +919,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Decrementer exception\n");
|
||||
abort();
|
||||
case EXCP_RESA: /* Implementation specific */
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "RESA exception should never happen !\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "RESA exception should never happen !\n");
|
||||
abort();
|
||||
case EXCP_RESB: /* Implementation specific */
|
||||
/* Should not happen ! */
|
||||
fprintf(stderr, "RESB exception should never happen !\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "RESB exception should never happen !\n");
|
||||
abort();
|
||||
case EXCP_TRACE:
|
||||
/* Do nothing: we use this to trace execution */
|
||||
break;
|
||||
@@ -958,12 +940,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
case EXCP_BRANCH:
|
||||
/* We stopped because of a jump... */
|
||||
break;
|
||||
case EXCP_RFI:
|
||||
/* Should not occur: we always are in user mode */
|
||||
fprintf(stderr, "Return from interrupt ?\n");
|
||||
if (loglevel)
|
||||
fprintf(logfile, "Return from interrupt ?\n");
|
||||
abort();
|
||||
case EXCP_INTERRUPT:
|
||||
/* Don't know why this should ever happen... */
|
||||
break;
|
||||
@@ -997,7 +973,7 @@ void cpu_loop(CPUPPCState *env)
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
|
||||
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n"
|
||||
"usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
|
||||
"Linux CPU emulator (compiled for %s emulation)\n"
|
||||
"\n"
|
||||
@@ -1239,7 +1215,25 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
{
|
||||
ppc_def_t *def;
|
||||
int i;
|
||||
|
||||
/* Choose and initialise CPU */
|
||||
/* XXX: CPU model (or PVR) should be provided on command line */
|
||||
// ppc_find_by_name("750gx", &def);
|
||||
// ppc_find_by_name("750fx", &def);
|
||||
// ppc_find_by_name("750p", &def);
|
||||
ppc_find_by_name("750", &def);
|
||||
// ppc_find_by_name("G3", &def);
|
||||
// ppc_find_by_name("604r", &def);
|
||||
// ppc_find_by_name("604e", &def);
|
||||
// ppc_find_by_name("604", &def);
|
||||
if (def == NULL) {
|
||||
cpu_abort(cpu_single_env,
|
||||
"Unable to find PowerPC CPU definition\n");
|
||||
}
|
||||
cpu_ppc_register(cpu_single_env, def);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (i != 12 && i != 6 && i != 13)
|
||||
env->msr[i] = (regs->msr >> i) & 1;
|
||||
|
||||
+75
-9
@@ -547,7 +547,21 @@ static long do_setsockopt(int sockfd, int level, int optname,
|
||||
break;
|
||||
case SOL_IP:
|
||||
switch(optname) {
|
||||
case IP_TOS:
|
||||
case IP_TTL:
|
||||
case IP_HDRINCL:
|
||||
case IP_ROUTER_ALERT:
|
||||
case IP_RECVOPTS:
|
||||
case IP_RETOPTS:
|
||||
case IP_PKTINFO:
|
||||
case IP_MTU_DISCOVER:
|
||||
case IP_RECVERR:
|
||||
case IP_RECVTOS:
|
||||
#ifdef IP_FREEBIND
|
||||
case IP_FREEBIND:
|
||||
#endif
|
||||
case IP_MULTICAST_TTL:
|
||||
case IP_MULTICAST_LOOP:
|
||||
val = 0;
|
||||
if (optlen >= sizeof(uint32_t)) {
|
||||
if (get_user(val, (uint32_t *)optval))
|
||||
@@ -619,6 +633,45 @@ static long do_getsockopt(int sockfd, int level, int optname,
|
||||
/* These don't just return a single integer */
|
||||
goto unimplemented;
|
||||
default:
|
||||
goto int_case;
|
||||
}
|
||||
break;
|
||||
case SOL_TCP:
|
||||
/* TCP options all take an 'int' value. */
|
||||
int_case:
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
lv = sizeof(int);
|
||||
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
val = tswap32(val);
|
||||
if (len > lv)
|
||||
len = lv;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
return -EFAULT;
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case SOL_IP:
|
||||
switch(optname) {
|
||||
case IP_TOS:
|
||||
case IP_TTL:
|
||||
case IP_HDRINCL:
|
||||
case IP_ROUTER_ALERT:
|
||||
case IP_RECVOPTS:
|
||||
case IP_RETOPTS:
|
||||
case IP_PKTINFO:
|
||||
case IP_MTU_DISCOVER:
|
||||
case IP_RECVERR:
|
||||
case IP_RECVTOS:
|
||||
#ifdef IP_FREEBIND
|
||||
case IP_FREEBIND:
|
||||
#endif
|
||||
case IP_MULTICAST_TTL:
|
||||
case IP_MULTICAST_LOOP:
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (len < 0)
|
||||
@@ -627,14 +680,25 @@ static long do_getsockopt(int sockfd, int level, int optname,
|
||||
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
val = tswap32(val);
|
||||
if (len > lv)
|
||||
len = lv;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
return -EFAULT;
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
|
||||
unsigned char ucval = val;
|
||||
len = 1;
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval,&ucval,1))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
val = tswap32(val);
|
||||
if (len > sizeof(int))
|
||||
len = sizeof(int);
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto unimplemented;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -2756,11 +2820,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
#endif
|
||||
#ifdef TARGET_NR_truncate64
|
||||
case TARGET_NR_truncate64:
|
||||
goto unimplemented;
|
||||
ret = get_errno(truncate64((const char *)arg1, arg2));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_ftruncate64
|
||||
case TARGET_NR_ftruncate64:
|
||||
goto unimplemented;
|
||||
ret = get_errno(ftruncate64(arg1, arg2));
|
||||
break;
|
||||
#endif
|
||||
#ifdef TARGET_NR_stat64
|
||||
case TARGET_NR_stat64:
|
||||
|
||||
+3998
File diff suppressed because it is too large.
Load diff
@@ -222,7 +222,7 @@ static void do_info_registers(void)
|
||||
{
|
||||
#ifdef TARGET_I386
|
||||
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
|
||||
X86_DUMP_FPU | X86_DUMP_CCOP);
|
||||
X86_DUMP_FPU);
|
||||
#else
|
||||
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
|
||||
0);
|
||||
@@ -562,6 +562,22 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne
|
||||
term_printf("\n");
|
||||
}
|
||||
|
||||
static void do_sum(uint32_t start, uint32_t size)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint8_t buf[1];
|
||||
uint16_t sum;
|
||||
|
||||
sum = 0;
|
||||
for(addr = start; addr < (start + size); addr++) {
|
||||
cpu_physical_memory_rw(addr, buf, 1, 0);
|
||||
/* BSD sum algorithm ('sum' Unix command) */
|
||||
sum = (sum >> 1) | (sum << 15);
|
||||
sum += buf[0];
|
||||
}
|
||||
term_printf("%05d\n", sum);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int keycode;
|
||||
const char *name;
|
||||
@@ -751,6 +767,11 @@ static void do_system_reset(void)
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
|
||||
static void do_system_powerdown(void)
|
||||
{
|
||||
qemu_system_powerdown_request();
|
||||
}
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
|
||||
{
|
||||
@@ -864,6 +885,20 @@ static void mem_info(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void do_info_kqemu(void)
|
||||
{
|
||||
#ifdef USE_KQEMU
|
||||
int val;
|
||||
val = 0;
|
||||
if (cpu_single_env)
|
||||
val = cpu_single_env->kqemu_enabled;
|
||||
term_printf("kqemu is %s\n", val ? "enabled" : "disabled");
|
||||
#else
|
||||
term_printf("kqemu support is not compiled\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static term_cmd_t term_cmds[] = {
|
||||
{ "help|?", "s?", do_help,
|
||||
"[cmd]", "show the help" },
|
||||
@@ -906,6 +941,10 @@ static term_cmd_t term_cmds[] = {
|
||||
"keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
|
||||
{ "system_reset", "", do_system_reset,
|
||||
"", "reset the system" },
|
||||
{ "system_powerdown", "", do_system_powerdown,
|
||||
"", "send system power down event" },
|
||||
{ "sum", "ii", do_sum,
|
||||
"addr size", "compute the checksum of a memory region" },
|
||||
{ NULL, NULL, },
|
||||
};
|
||||
|
||||
@@ -934,6 +973,8 @@ static term_cmd_t info_cmds[] = {
|
||||
#endif
|
||||
{ "jit", "", do_info_jit,
|
||||
"", "show dynamic compiler info", },
|
||||
{ "kqemu", "", do_info_kqemu,
|
||||
"", "show kqemu information", },
|
||||
{ NULL, NULL, },
|
||||
};
|
||||
|
||||
|
||||
+5
-1
@@ -5,9 +5,13 @@
|
||||
project (http://www.nongnu.org/vgabios/).
|
||||
|
||||
- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
|
||||
available at http://site.voila.fr/jmayer/OpenHackWare/index.htm.
|
||||
available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
|
||||
|
||||
- Proll is a GPL'd boot PROM for Sparc JavaStations
|
||||
(http://people.redhat.com/zaitcev/linux/).
|
||||
Applying proll.patch allows circumventing some bugs and enables
|
||||
faster kernel load through a hack.
|
||||
|
||||
- video.x is a PowerMac NDRV compatible driver for a VGA frame
|
||||
buffer. It comes from the Mac-on-Linux project
|
||||
(http://www.maconlinux.org/).
|
||||
+1843
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
@@ -3067,11 +3067,12 @@ const struct powerpc_macro powerpc_macros[] = {
|
||||
const int powerpc_num_macros =
|
||||
sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
|
||||
|
||||
static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int dialect);
|
||||
static int
|
||||
print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
|
||||
int dialect);
|
||||
|
||||
/* Print a big endian PowerPC instruction. For convenience, also
|
||||
disassemble instructions supported by the Motorola PowerPC 601. */
|
||||
#include "cpu.h"
|
||||
|
||||
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
@@ -3083,14 +3084,19 @@ int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||
opc = bfd_getb32(buf);
|
||||
else
|
||||
opc = bfd_getl32(buf);
|
||||
return print_insn_powerpc (info->stream, opc, pc,
|
||||
PPC | B32 | M601);
|
||||
if (info->mach == bfd_mach_ppc64) {
|
||||
return print_insn_powerpc (info, opc, pc,
|
||||
PPC | B64);
|
||||
} else {
|
||||
return print_insn_powerpc (info, opc, pc,
|
||||
PPC | B32 | M601);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a PowerPC or POWER instruction. */
|
||||
|
||||
static int
|
||||
print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
|
||||
int dialect)
|
||||
{
|
||||
const struct powerpc_opcode *opcode;
|
||||
@@ -3136,9 +3142,9 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
continue;
|
||||
|
||||
/* The instruction is valid. */
|
||||
fprintf(out, "%s", opcode->name);
|
||||
(*info->fprintf_func)(info->stream, "%s", opcode->name);
|
||||
if (opcode->operands[0] != 0)
|
||||
fprintf(out, "\t");
|
||||
(*info->fprintf_func)(info->stream, "\t");
|
||||
|
||||
/* Now extract and print the operands. */
|
||||
need_comma = 0;
|
||||
@@ -3175,26 +3181,26 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
|
||||
if (need_comma)
|
||||
{
|
||||
fprintf(out, ",");
|
||||
(*info->fprintf_func)(info->stream, ",");
|
||||
need_comma = 0;
|
||||
}
|
||||
|
||||
/* Print the operand as directed by the flags. */
|
||||
if ((operand->flags & PPC_OPERAND_GPR) != 0)
|
||||
fprintf(out, "r%d", value);
|
||||
(*info->fprintf_func)(info->stream, "r%d", value);
|
||||
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
|
||||
fprintf(out, "f%d", value);
|
||||
(*info->fprintf_func)(info->stream, "f%d", value);
|
||||
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
|
||||
fprintf(out, "%08X", memaddr + value);
|
||||
(*info->fprintf_func)(info->stream, "%08X", memaddr + value);
|
||||
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
|
||||
fprintf(out, "%08X", value & 0xffffffff);
|
||||
(*info->fprintf_func)(info->stream, "%08X", value & 0xffffffff);
|
||||
else if ((operand->flags & PPC_OPERAND_CR) == 0
|
||||
|| (dialect & PPC_OPCODE_PPC) == 0)
|
||||
fprintf(out, "%d", value);
|
||||
(*info->fprintf_func)(info->stream, "%d", value);
|
||||
else
|
||||
{
|
||||
if (operand->bits == 3)
|
||||
fprintf(out, "cr%d", value);
|
||||
(*info->fprintf_func)(info->stream, "cr%d", value);
|
||||
else
|
||||
{
|
||||
static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
|
||||
@@ -3203,20 +3209,20 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
|
||||
cr = value >> 2;
|
||||
if (cr != 0)
|
||||
fprintf(out, "4*cr%d", cr);
|
||||
(*info->fprintf_func)(info->stream, "4*cr%d", cr);
|
||||
cc = value & 3;
|
||||
if (cc != 0)
|
||||
{
|
||||
if (cr != 0)
|
||||
fprintf(out, "+");
|
||||
fprintf(out, "%s", cbnames[cc]);
|
||||
(*info->fprintf_func)(info->stream, "+");
|
||||
(*info->fprintf_func)(info->stream, "%s", cbnames[cc]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (need_paren)
|
||||
{
|
||||
fprintf(out, ")");
|
||||
(*info->fprintf_func)(info->stream, ")");
|
||||
need_paren = 0;
|
||||
}
|
||||
|
||||
@@ -3224,7 +3230,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
need_comma = 1;
|
||||
else
|
||||
{
|
||||
fprintf(out, "(");
|
||||
(*info->fprintf_func)(info->stream, "(");
|
||||
need_paren = 1;
|
||||
}
|
||||
}
|
||||
@@ -3234,7 +3240,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
|
||||
}
|
||||
|
||||
/* We could not find a match. */
|
||||
fprintf(out, ".long 0x%x", insn);
|
||||
(*info->fprintf_func)(info->stream, ".long 0x%x", insn);
|
||||
|
||||
return 4;
|
||||
}
|
||||
@@ -53,6 +53,16 @@ SECTIONS
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.fini : { *(.fini) } =0x47ff041f
|
||||
. = ALIGN(32 / 8);
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
PROVIDE (__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE (__init_array_end = .);
|
||||
PROVIDE (__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE (__fini_array_end = .);
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
|
||||
+81
-26
@@ -22,7 +22,7 @@ QEMU has two operating modes:
|
||||
|
||||
@item
|
||||
Full system emulation. In this mode, QEMU emulates a full system (for
|
||||
example a PC), including a processor and various peripherials. It can
|
||||
example a PC), including a processor and various peripherals. It can
|
||||
be used to launch different Operating Systems without rebooting the
|
||||
PC or to debug system code.
|
||||
|
||||
@@ -39,13 +39,16 @@ performance.
|
||||
|
||||
For system emulation, the following hardware targets are supported:
|
||||
@itemize
|
||||
@item PC (x86 processor)
|
||||
@item PC (x86 or x86_64 processor)
|
||||
@item PREP (PowerPC processor)
|
||||
@item PowerMac (PowerPC processor, in progress)
|
||||
@item Sun4m (Sparc processor, in progress)
|
||||
@item G3 BW PowerMac (PowerPC processor)
|
||||
@item Mac99 PowerMac (PowerPC processor, in progress)
|
||||
@item Sun4m (32-bit Sparc processor)
|
||||
@item Sun4u (64-bit Sparc processor, in progress)
|
||||
@item Malta board (32-bit MIPS processor, in progress)
|
||||
@end itemize
|
||||
|
||||
For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported.
|
||||
For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
|
||||
|
||||
@chapter Installation
|
||||
|
||||
@@ -73,7 +76,7 @@ Download the experimental binary installer at
|
||||
@c man begin DESCRIPTION
|
||||
|
||||
The QEMU System emulator simulates the
|
||||
following PC peripherials:
|
||||
following PC peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@@ -192,6 +195,11 @@ Start in full screen.
|
||||
Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
|
||||
from a script.
|
||||
|
||||
@item -win2k-hack
|
||||
Use it when installing Windows 2000 to avoid a disk full bug. After
|
||||
Windows 2000 is installed, you no longer need this option (this option
|
||||
slows down the IDE transfers).
|
||||
|
||||
@end table
|
||||
|
||||
Network options:
|
||||
@@ -203,6 +211,10 @@ Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script
|
||||
is launched to configure the host network interface (usually tun0)
|
||||
corresponding to the virtual NE2000 card.
|
||||
|
||||
@item -nics n
|
||||
|
||||
Simulate @var{n} network cards (the default is 1).
|
||||
|
||||
@item -macaddr addr
|
||||
|
||||
Set the mac address of the first interface (the format is
|
||||
@@ -892,16 +904,13 @@ idle. You can install the utility from
|
||||
@url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this
|
||||
problem. Note that no such tool is needed for NT, 2000 or XP.
|
||||
|
||||
@subsubsection Windows 2000 disk full problems
|
||||
@subsubsection Windows 2000 disk full problem
|
||||
|
||||
Currently (release 0.6.0) QEMU has a bug which gives a @code{disk
|
||||
full} error during installation of some releases of Windows 2000. The
|
||||
workaround is to stop QEMU as soon as you notice that your disk image
|
||||
size is growing too fast (monitor it with @code{ls -ls}). Then
|
||||
relaunch QEMU to continue the installation. If you still experience
|
||||
the problem, relaunch QEMU again.
|
||||
|
||||
Future QEMU releases are likely to correct this bug.
|
||||
Windows 2000 has a bug which gives a disk full problem during its
|
||||
installation. When installing it, use the @option{-win2k-hack} QEMU
|
||||
option to enable a specific workaround. After Windows 2000 is
|
||||
installed, you no longer need this option (this option slows down the
|
||||
IDE transfers).
|
||||
|
||||
@subsubsection Windows XP security problems
|
||||
|
||||
@@ -930,7 +939,7 @@ problem.
|
||||
Use the executable @file{qemu-system-ppc} to simulate a complete PREP
|
||||
or PowerMac PowerPC system.
|
||||
|
||||
QEMU emulates the following PowerMac peripherials:
|
||||
QEMU emulates the following PowerMac peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@@ -947,7 +956,7 @@ Non Volatile RAM
|
||||
VIA-CUDA with ADB keyboard and mouse.
|
||||
@end itemize
|
||||
|
||||
QEMU emulates the following PREP peripherials:
|
||||
QEMU emulates the following PREP peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@@ -995,15 +1004,15 @@ Set the initial VGA graphic mode. The default is 800x600x15.
|
||||
More information is available at
|
||||
@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
|
||||
|
||||
@chapter Sparc System emulator invocation
|
||||
@chapter Sparc32 System emulator invocation
|
||||
|
||||
Use the executable @file{qemu-system-sparc} to simulate a JavaStation
|
||||
(sun4m architecture). The emulation is far from complete.
|
||||
(sun4m architecture). The emulation is somewhat complete.
|
||||
|
||||
QEMU emulates the following sun4m peripherials:
|
||||
QEMU emulates the following sun4m peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@item
|
||||
IOMMU
|
||||
@item
|
||||
TCX Frame buffer
|
||||
@@ -1012,14 +1021,60 @@ Lance (Am7990) Ethernet
|
||||
@item
|
||||
Non Volatile RAM M48T08
|
||||
@item
|
||||
Slave I/O: timers, interrupt controllers, Zilog serial ports
|
||||
Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard
|
||||
and power/reset logic
|
||||
@item
|
||||
ESP SCSI controller with hard disk and CD-ROM support
|
||||
@item
|
||||
Floppy drive
|
||||
@end itemize
|
||||
|
||||
QEMU uses the Proll, a PROM replacement available at
|
||||
@url{http://people.redhat.com/zaitcev/linux/}.
|
||||
The number of peripherals is fixed in the architecture.
|
||||
|
||||
A sample Linux kernel and ram disk image are available on the QEMU web
|
||||
site.
|
||||
QEMU uses the Proll, a PROM replacement available at
|
||||
@url{http://people.redhat.com/zaitcev/linux/}. The required
|
||||
QEMU-specific patches are included with the sources.
|
||||
|
||||
A sample Linux 2.6 series kernel and ram disk image are available on
|
||||
the QEMU web site. Please note that currently neither Linux 2.4
|
||||
series, NetBSD, nor OpenBSD kernels work.
|
||||
|
||||
@c man begin OPTIONS
|
||||
|
||||
The following options are specific to the Sparc emulation:
|
||||
|
||||
@table @option
|
||||
|
||||
@item -g WxH
|
||||
|
||||
Set the initial TCX graphic mode. The default is 1024x768.
|
||||
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
||||
@chapter Sparc64 System emulator invocation
|
||||
|
||||
Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
|
||||
The emulator is not usable for anything yet.
|
||||
|
||||
QEMU emulates the following sun4u peripherals:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
UltraSparc IIi APB PCI Bridge
|
||||
@item
|
||||
PCI VGA compatible card with VESA Bochs Extensions
|
||||
@item
|
||||
Non Volatile RAM M48T59
|
||||
@item
|
||||
PC-compatible serial ports
|
||||
@end itemize
|
||||
|
||||
@chapter MIPS System emulator invocation
|
||||
|
||||
Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
|
||||
The emulator begins to launch a Linux kernel.
|
||||
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
|
||||
+5
-4
@@ -127,7 +127,7 @@ static void format_print(void *opaque, const char *name)
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n"
|
||||
printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n"
|
||||
"usage: qemu-img command [command options]\n"
|
||||
"QEMU disk image utility\n"
|
||||
"\n"
|
||||
@@ -658,9 +658,10 @@ static int img_info(int argc, char **argv)
|
||||
get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
|
||||
allocated_size = get_allocated_file_size(filename);
|
||||
if (allocated_size < 0)
|
||||
error("Could not get file size '%s'", filename);
|
||||
get_human_readable_size(dsize_buf, sizeof(dsize_buf),
|
||||
allocated_size);
|
||||
sprintf(dsize_buf, "unavailable");
|
||||
else
|
||||
get_human_readable_size(dsize_buf, sizeof(dsize_buf),
|
||||
allocated_size);
|
||||
printf("image: %s\n"
|
||||
"file format: %s\n"
|
||||
"virtual size: %s (%lld bytes)\n"
|
||||
|
||||
+1
-2
@@ -44,8 +44,7 @@ User Mode Linux Copy On Write image format. Used to be the only growable
|
||||
image format in QEMU. It is supported only for compatibility with
|
||||
previous versions. It does not work on win32.
|
||||
@item vmdk
|
||||
VMware 3 and 4 compatible image format. Currently only supported as
|
||||
read-only.
|
||||
VMware 3 and 4 compatible image format.
|
||||
@item cloop
|
||||
Linux Compressed Loop image, useful only to reuse directly compressed
|
||||
CD-ROM images present for example in the Knoppix CD-ROMs.
|
||||
|
||||
+25
-3
@@ -22,7 +22,7 @@ QEMU has two operating modes:
|
||||
|
||||
@item
|
||||
Full system emulation. In this mode, QEMU emulates a full system
|
||||
(usually a PC), including a processor and various peripherials. It can
|
||||
(usually a PC), including a processor and various peripherals. It can
|
||||
be used to launch an different Operating System without rebooting the
|
||||
PC or to debug system code.
|
||||
|
||||
@@ -138,9 +138,31 @@ FPU and MMU.
|
||||
@itemize
|
||||
|
||||
@item Somewhat complete SPARC V8 emulation, including privileged
|
||||
instructions, FPU and MMU.
|
||||
instructions, FPU and MMU. SPARC V9 emulation includes most privileged
|
||||
instructions, FPU and I/D MMU, but misses VIS instructions.
|
||||
|
||||
@item Can run some SPARC Linux binaries.
|
||||
@item Can run some 32-bit SPARC Linux binaries.
|
||||
|
||||
@end itemize
|
||||
|
||||
Current QEMU limitations:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Tagged add/subtract instructions are not supported, but they are
|
||||
probably not used.
|
||||
|
||||
@item IPC syscalls are missing.
|
||||
|
||||
@item 128-bit floating point operations are not supported, though none of the
|
||||
real CPUs implement them either. FCMPE[SD] are not correctly
|
||||
implemented. Floating point exception support is untested.
|
||||
|
||||
@item Alignment is not enforced at all.
|
||||
|
||||
@item Atomic instructions are not correctly implemented.
|
||||
|
||||
@item Sparc64 emulators are not usable for anything yet.
|
||||
|
||||
@end itemize
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ static void sdl_resize(DisplayState *ds, int w, int h)
|
||||
// printf("resizing to %d %d\n", w, h);
|
||||
|
||||
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
|
||||
flags |= SDL_RESIZABLE;
|
||||
if (gui_fullscreen)
|
||||
flags |= SDL_FULLSCREEN;
|
||||
screen = SDL_SetVideoMode(w, h, 0, flags);
|
||||
|
||||
+1
-1
@@ -238,7 +238,7 @@ static void bootp_reply(struct bootp_t *bp)
|
||||
|
||||
void bootp_input(struct mbuf *m)
|
||||
{
|
||||
struct bootp_t *bp = (struct bootp_t *)m->m_data;
|
||||
struct bootp_t *bp = mtod(m, struct bootp_t *);
|
||||
|
||||
if (bp->bp_op == BOOTP_REQUEST) {
|
||||
bootp_reply(bp);
|
||||
|
||||
+3
-3
@@ -97,9 +97,9 @@ struct bootp_t {
|
||||
uint8_t bp_htype;
|
||||
uint8_t bp_hlen;
|
||||
uint8_t bp_hops;
|
||||
unsigned long bp_xid;
|
||||
unsigned short bp_secs;
|
||||
unsigned short unused;
|
||||
uint32_t bp_xid;
|
||||
uint16_t bp_secs;
|
||||
uint16_t unused;
|
||||
struct in_addr bp_ciaddr;
|
||||
struct in_addr bp_yiaddr;
|
||||
struct in_addr bp_siaddr;
|
||||
|
||||
+2
-2
@@ -83,8 +83,8 @@ struct icmp {
|
||||
struct ip idi_ip;
|
||||
/* options and then 64 bits of data */
|
||||
} id_ip;
|
||||
u_long id_mask;
|
||||
char id_data[1];
|
||||
uint32_t id_mask;
|
||||
char id_data[1];
|
||||
} icmp_dun;
|
||||
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||
|
||||
@@ -9,6 +9,10 @@ int inet_aton(const char *cp, struct in_addr *ia);
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void slirp_init(void);
|
||||
|
||||
void slirp_select_fill(int *pnfds,
|
||||
@@ -29,4 +33,8 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
|
||||
|
||||
extern const char *tftp_prefix;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -149,8 +149,7 @@
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* Define to sizeof(char *) */
|
||||
/* XXX: patch it */
|
||||
#define SIZEOF_CHAR_P 4
|
||||
#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8)
|
||||
|
||||
/* Define if you have random() */
|
||||
#undef HAVE_RANDOM
|
||||
|
||||
+12
-6
@@ -420,10 +420,16 @@ struct talk_request {
|
||||
#endif
|
||||
|
||||
struct cu_header {
|
||||
char dest[8];
|
||||
short family;
|
||||
u_short port;
|
||||
u_long addr;
|
||||
uint16_t d_family; // destination family
|
||||
uint16_t d_port; // destination port
|
||||
uint32_t d_addr; // destination address
|
||||
uint16_t s_family; // source family
|
||||
uint16_t s_port; // source port
|
||||
uint32_t so_addr; // source address
|
||||
uint32_t seqn; // sequence number
|
||||
uint16_t message; // message
|
||||
uint16_t data_type; // data type
|
||||
uint16_t pkt_len; // packet length
|
||||
} *cu_head;
|
||||
|
||||
switch(so->so_emu) {
|
||||
@@ -610,8 +616,8 @@ struct cu_header {
|
||||
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
|
||||
return;
|
||||
cu_head = mtod(m, struct cu_header *);
|
||||
cu_head->port = addr.sin_port;
|
||||
cu_head->addr = (u_long) our_addr.s_addr;
|
||||
cu_head->s_port = addr.sin_port;
|
||||
cu_head->so_addr = our_addr.s_addr;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -94,6 +94,7 @@ struct udpstat {
|
||||
|
||||
extern struct udpstat udpstat;
|
||||
extern struct socket udb;
|
||||
struct mbuf;
|
||||
|
||||
void udp_init _P((void));
|
||||
void udp_input _P((register struct mbuf *, int));
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#elif defined (TARGET_PPC)
|
||||
#define CPU_MEM_INDEX (msr_pr)
|
||||
#elif defined (TARGET_MIPS)
|
||||
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
|
||||
#elif defined (TARGET_SPARC)
|
||||
#define CPU_MEM_INDEX ((env->psrs) == 0)
|
||||
#endif
|
||||
@@ -66,6 +68,8 @@
|
||||
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
||||
#elif defined (TARGET_PPC)
|
||||
#define CPU_MEM_INDEX (msr_pr)
|
||||
#elif defined (TARGET_MIPS)
|
||||
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
|
||||
#elif defined (TARGET_SPARC)
|
||||
#define CPU_MEM_INDEX ((env->psrs) == 0)
|
||||
#endif
|
||||
|
||||
+10
-10
@@ -48,7 +48,7 @@
|
||||
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
|
||||
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
|
||||
target_ulong tlb_addr)
|
||||
{
|
||||
DATA_TYPE res;
|
||||
@@ -76,7 +76,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
DATA_TYPE res;
|
||||
int index;
|
||||
target_ulong tlb_addr;
|
||||
unsigned long physaddr;
|
||||
target_phys_addr_t physaddr;
|
||||
void *retaddr;
|
||||
|
||||
/* test if there is match for unaligned or IO access */
|
||||
@@ -99,7 +99,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* unaligned access in the same page */
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
@@ -117,7 +117,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
{
|
||||
DATA_TYPE res, res1, res2;
|
||||
int index, shift;
|
||||
unsigned long physaddr;
|
||||
target_phys_addr_t physaddr;
|
||||
target_ulong tlb_addr, addr1, addr2;
|
||||
|
||||
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
@@ -148,7 +148,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
res = (DATA_TYPE)res;
|
||||
} else {
|
||||
/* unaligned/aligned access in the same page */
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
|
||||
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
@@ -165,7 +165,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
int is_user,
|
||||
void *retaddr);
|
||||
|
||||
static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
|
||||
static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
|
||||
DATA_TYPE val,
|
||||
target_ulong tlb_addr,
|
||||
void *retaddr)
|
||||
@@ -192,7 +192,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
DATA_TYPE val,
|
||||
int is_user)
|
||||
{
|
||||
unsigned long physaddr;
|
||||
target_phys_addr_t physaddr;
|
||||
target_ulong tlb_addr;
|
||||
void *retaddr;
|
||||
int index;
|
||||
@@ -215,7 +215,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
is_user, retaddr);
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
@@ -231,7 +231,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
int is_user,
|
||||
void *retaddr)
|
||||
{
|
||||
unsigned long physaddr;
|
||||
target_phys_addr_t physaddr;
|
||||
target_ulong tlb_addr;
|
||||
int index, i;
|
||||
|
||||
@@ -259,7 +259,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
|
||||
}
|
||||
} else {
|
||||
/* aligned/unaligned access in the same page */
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
|
||||
glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
|
||||
}
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
|
||||
@@ -805,6 +805,23 @@ void OPPROTO op_subl_T0_T1_saturate(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_double_T1_saturate(void)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
val = T1;
|
||||
if (val >= 0x40000000) {
|
||||
T1 = 0x7fffffff;
|
||||
env->QF = 1;
|
||||
} else if (val <= (int32_t)0xc0000000) {
|
||||
T1 = 0x80000000;
|
||||
env->QF = 1;
|
||||
} else {
|
||||
T1 = val << 1;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* thumb shift by immediate */
|
||||
void OPPROTO op_shll_T0_im_thumb(void)
|
||||
{
|
||||
|
||||
+6
-11
@@ -1019,20 +1019,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||
case 0x5: /* saturating add/subtract */
|
||||
rd = (insn >> 12) & 0xf;
|
||||
rn = (insn >> 16) & 0xf;
|
||||
gen_movl_T0_reg(s, rn);
|
||||
if (op1 & 2) {
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (op1 & 1)
|
||||
gen_op_subl_T0_T1_saturate();
|
||||
else
|
||||
gen_op_addl_T0_T1_saturate();
|
||||
}
|
||||
gen_movl_T1_reg(s, rm);
|
||||
gen_movl_T0_reg(s, rm);
|
||||
gen_movl_T1_reg(s, rn);
|
||||
if (op1 & 2)
|
||||
gen_op_double_T1_saturate();
|
||||
if (op1 & 1)
|
||||
gen_op_subl_T0_T1_saturate();
|
||||
else
|
||||
gen_op_addl_T0_T1_saturate();
|
||||
gen_movl_reg_T0(s, rn);
|
||||
gen_movl_reg_T0(s, rd);
|
||||
break;
|
||||
case 0x8: /* signed multiply */
|
||||
case 0xa:
|
||||
@@ -2196,7 +2191,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
|
||||
int flags)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
union {
|
||||
uint32_t i;
|
||||
float s;
|
||||
} s0, s1;
|
||||
|
||||
@@ -214,6 +214,12 @@
|
||||
#define MSR_IA32_SYSENTER_ESP 0x175
|
||||
#define MSR_IA32_SYSENTER_EIP 0x176
|
||||
|
||||
#define MSR_MCG_CAP 0x179
|
||||
#define MSR_MCG_STATUS 0x17a
|
||||
#define MSR_MCG_CTL 0x17b
|
||||
|
||||
#define MSR_PAT 0x277
|
||||
|
||||
#define MSR_EFER 0xc0000080
|
||||
|
||||
#define MSR_EFER_SCE (1 << 0)
|
||||
@@ -246,6 +252,8 @@
|
||||
#define CPUID_PGE (1 << 13)
|
||||
#define CPUID_MCA (1 << 14)
|
||||
#define CPUID_CMOV (1 << 15)
|
||||
#define CPUID_PAT (1 << 16)
|
||||
#define CPUID_CLFLUSH (1 << 19)
|
||||
/* ... */
|
||||
#define CPUID_MMX (1 << 23)
|
||||
#define CPUID_FXSR (1 << 24)
|
||||
@@ -474,6 +482,8 @@ typedef struct CPUX86State {
|
||||
target_ulong kernelgsbase;
|
||||
#endif
|
||||
|
||||
uint64_t pat;
|
||||
|
||||
/* temporary data for USE_CODE_COPY mode */
|
||||
#ifdef USE_CODE_COPY
|
||||
uint32_t tmp0;
|
||||
|
||||
+4
-2
@@ -157,11 +157,11 @@ void helper_lldt_T0(void);
|
||||
void helper_ltr_T0(void);
|
||||
void helper_movl_crN_T0(int reg);
|
||||
void helper_movl_drN_T0(int reg);
|
||||
void helper_invlpg(unsigned int addr);
|
||||
void helper_invlpg(target_ulong addr);
|
||||
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
|
||||
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
|
||||
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
|
||||
int is_write, int is_user, int is_softmmu);
|
||||
void tlb_fill(target_ulong addr, int is_write, int is_user,
|
||||
@@ -190,6 +190,7 @@ void helper_idivq_EAX_T0(void);
|
||||
void helper_cmpxchg8b(void);
|
||||
void helper_cpuid(void);
|
||||
void helper_enter_level(int level, int data32);
|
||||
void helper_enter64_level(int level, int data64);
|
||||
void helper_sysenter(void);
|
||||
void helper_sysexit(void);
|
||||
void helper_syscall(int next_eip_addend);
|
||||
@@ -336,6 +337,7 @@ static inline void stfl(target_ulong ptr, float v)
|
||||
#define atan2 atan2l
|
||||
#define floor floorl
|
||||
#define ceil ceill
|
||||
#define ldexp ldexpl
|
||||
#else
|
||||
#define floatx_to_int32 float64_to_int32
|
||||
#define floatx_to_int64 float64_to_int64
|
||||
|
||||
+85
-19
@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index)
|
||||
#ifdef BUGGY_GCC_DIV64
|
||||
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
|
||||
call it from another function */
|
||||
uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den)
|
||||
uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
|
||||
{
|
||||
*q_ptr = num / den;
|
||||
return num % den;
|
||||
}
|
||||
|
||||
int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
|
||||
int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
|
||||
{
|
||||
*q_ptr = num / den;
|
||||
return num % den;
|
||||
@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
|
||||
|
||||
void helper_divl_EAX_T0(void)
|
||||
{
|
||||
unsigned int den, q, r;
|
||||
uint64_t num;
|
||||
unsigned int den, r;
|
||||
uint64_t num, q;
|
||||
|
||||
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
|
||||
den = T0;
|
||||
@@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
if (q > 0xffffffff)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
EAX = (uint32_t)q;
|
||||
EDX = (uint32_t)r;
|
||||
}
|
||||
|
||||
void helper_idivl_EAX_T0(void)
|
||||
{
|
||||
int den, q, r;
|
||||
int64_t num;
|
||||
int den, r;
|
||||
int64_t num, q;
|
||||
|
||||
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
|
||||
den = T0;
|
||||
@@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
|
||||
q = (num / den);
|
||||
r = (num % den);
|
||||
#endif
|
||||
if (q != (int32_t)q)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
EAX = (uint32_t)q;
|
||||
EDX = (uint32_t)r;
|
||||
}
|
||||
@@ -1334,6 +1338,20 @@ void helper_cpuid(void)
|
||||
ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
|
||||
EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
|
||||
break;
|
||||
case 0x80000005:
|
||||
/* cache info (L1 cache) */
|
||||
EAX = 0x01ff01ff;
|
||||
EBX = 0x01ff01ff;
|
||||
ECX = 0x40020140;
|
||||
EDX = 0x40020140;
|
||||
break;
|
||||
case 0x80000006:
|
||||
/* cache info (L2 cache) */
|
||||
EAX = 0;
|
||||
EBX = 0x42004200;
|
||||
ECX = 0x02008140;
|
||||
EDX = 0;
|
||||
break;
|
||||
case 0x80000008:
|
||||
/* virtual & phys address size in low 2 bytes. */
|
||||
EAX = 0x00003028;
|
||||
@@ -1383,6 +1401,37 @@ void helper_enter_level(int level, int data32)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void helper_enter64_level(int level, int data64)
|
||||
{
|
||||
target_ulong esp, ebp;
|
||||
ebp = EBP;
|
||||
esp = ESP;
|
||||
|
||||
if (data64) {
|
||||
/* 64 bit */
|
||||
esp -= 8;
|
||||
while (--level) {
|
||||
esp -= 8;
|
||||
ebp -= 8;
|
||||
stq(esp, ldq(ebp));
|
||||
}
|
||||
esp -= 8;
|
||||
stq(esp, T1);
|
||||
} else {
|
||||
/* 16 bit */
|
||||
esp -= 2;
|
||||
while (--level) {
|
||||
esp -= 2;
|
||||
ebp -= 2;
|
||||
stw(esp, lduw(ebp));
|
||||
}
|
||||
esp -= 2;
|
||||
stw(esp, T1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void helper_lldt_T0(void)
|
||||
{
|
||||
int selector;
|
||||
@@ -1963,6 +2012,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
|
||||
#endif
|
||||
sp_mask = get_sp_mask(env->segs[R_SS].flags);
|
||||
sp = ESP;
|
||||
/* XXX: ssp is zero in 64 bit ? */
|
||||
ssp = env->segs[R_SS].base;
|
||||
new_eflags = 0; /* avoid warning */
|
||||
#ifdef TARGET_X86_64
|
||||
@@ -2271,7 +2321,7 @@ void helper_movl_drN_T0(int reg)
|
||||
env->dr[reg] = T0;
|
||||
}
|
||||
|
||||
void helper_invlpg(unsigned int addr)
|
||||
void helper_invlpg(target_ulong addr)
|
||||
{
|
||||
cpu_x86_flush_tlb(env, addr);
|
||||
}
|
||||
@@ -2332,6 +2382,9 @@ void helper_wrmsr(void)
|
||||
case MSR_STAR:
|
||||
env->star = val;
|
||||
break;
|
||||
case MSR_PAT:
|
||||
env->pat = val;
|
||||
break;
|
||||
#ifdef TARGET_X86_64
|
||||
case MSR_LSTAR:
|
||||
env->lstar = val;
|
||||
@@ -2380,6 +2433,9 @@ void helper_rdmsr(void)
|
||||
case MSR_STAR:
|
||||
val = env->star;
|
||||
break;
|
||||
case MSR_PAT:
|
||||
val = env->pat;
|
||||
break;
|
||||
#ifdef TARGET_X86_64
|
||||
case MSR_LSTAR:
|
||||
val = env->lstar;
|
||||
@@ -2832,11 +2888,7 @@ void helper_frndint(void)
|
||||
|
||||
void helper_fscale(void)
|
||||
{
|
||||
CPU86_LDouble fpsrcop, fptemp;
|
||||
|
||||
fpsrcop = 2.0;
|
||||
fptemp = pow(fpsrcop,ST1);
|
||||
ST0 *= fptemp;
|
||||
ST0 = ldexp (ST0, (int)(ST1));
|
||||
}
|
||||
|
||||
void helper_fsin(void)
|
||||
@@ -3202,8 +3254,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: overflow support */
|
||||
static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
|
||||
/* return TRUE if overflow */
|
||||
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
|
||||
{
|
||||
uint64_t q, r, a1, a0;
|
||||
int i, qb;
|
||||
@@ -3216,6 +3268,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
|
||||
*plow = q;
|
||||
*phigh = r;
|
||||
} else {
|
||||
if (a1 >= b)
|
||||
return 1;
|
||||
/* XXX: use a better algorithm */
|
||||
for(i = 0; i < 64; i++) {
|
||||
a1 = (a1 << 1) | (a0 >> 63);
|
||||
@@ -3234,9 +3288,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
|
||||
*plow = a0;
|
||||
*phigh = a1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
|
||||
/* return TRUE if overflow */
|
||||
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
|
||||
{
|
||||
int sa, sb;
|
||||
sa = ((int64_t)*phigh < 0);
|
||||
@@ -3245,11 +3301,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
|
||||
sb = (b < 0);
|
||||
if (sb)
|
||||
b = -b;
|
||||
div64(plow, phigh, b);
|
||||
if (sa ^ sb)
|
||||
if (div64(plow, phigh, b) != 0)
|
||||
return 1;
|
||||
if (sa ^ sb) {
|
||||
if (*plow > (1ULL << 63))
|
||||
return 1;
|
||||
*plow = - *plow;
|
||||
} else {
|
||||
if (*plow >= (1ULL << 63))
|
||||
return 1;
|
||||
}
|
||||
if (sa)
|
||||
*phigh = - *phigh;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void helper_mulq_EAX_T0(void)
|
||||
@@ -3292,7 +3356,8 @@ void helper_divq_EAX_T0(void)
|
||||
}
|
||||
r0 = EAX;
|
||||
r1 = EDX;
|
||||
div64(&r0, &r1, T0);
|
||||
if (div64(&r0, &r1, T0))
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
EAX = r0;
|
||||
EDX = r1;
|
||||
}
|
||||
@@ -3305,7 +3370,8 @@ void helper_idivq_EAX_T0(void)
|
||||
}
|
||||
r0 = EAX;
|
||||
r1 = EDX;
|
||||
idiv64(&r0, &r1, T0);
|
||||
if (idiv64(&r0, &r1, T0))
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
EAX = r0;
|
||||
EDX = r1;
|
||||
}
|
||||
|
||||
+56
-13
@@ -106,7 +106,9 @@ CPUX86State *cpu_x86_init(void)
|
||||
env->cpuid_version = (family << 8) | (model << 4) | stepping;
|
||||
env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
|
||||
CPUID_TSC | CPUID_MSR | CPUID_MCE |
|
||||
CPUID_CX8 | CPUID_PGE | CPUID_CMOV);
|
||||
CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
|
||||
CPUID_PAT);
|
||||
env->pat = 0x0007040600070406ULL;
|
||||
env->cpuid_ext_features = 0;
|
||||
env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
|
||||
env->cpuid_xlevel = 0;
|
||||
@@ -128,6 +130,9 @@ CPUX86State *cpu_x86_init(void)
|
||||
env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
|
||||
env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
|
||||
env->cpuid_xlevel = 0x80000008;
|
||||
|
||||
/* these features are needed for Win64 and aren't fully implemented */
|
||||
env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
|
||||
#endif
|
||||
}
|
||||
cpu_single_env = env;
|
||||
@@ -250,7 +255,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
int flags)
|
||||
{
|
||||
int eflags, i;
|
||||
int eflags, i, nb;
|
||||
char cc_op_name[32];
|
||||
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
|
||||
|
||||
@@ -398,16 +403,54 @@ void cpu_dump_state(CPUState *env, FILE *f,
|
||||
}
|
||||
}
|
||||
if (flags & X86_DUMP_FPU) {
|
||||
cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
||||
(double)env->fpregs[0].d,
|
||||
(double)env->fpregs[1].d,
|
||||
(double)env->fpregs[2].d,
|
||||
(double)env->fpregs[3].d);
|
||||
cpu_fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
|
||||
(double)env->fpregs[4].d,
|
||||
(double)env->fpregs[5].d,
|
||||
(double)env->fpregs[7].d,
|
||||
(double)env->fpregs[8].d);
|
||||
int fptag;
|
||||
fptag = 0;
|
||||
for(i = 0; i < 8; i++) {
|
||||
fptag |= ((!env->fptags[i]) << i);
|
||||
}
|
||||
cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
|
||||
env->fpuc,
|
||||
(env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
|
||||
env->fpstt,
|
||||
fptag,
|
||||
env->mxcsr);
|
||||
for(i=0;i<8;i++) {
|
||||
#if defined(USE_X86LDOUBLE)
|
||||
union {
|
||||
long double d;
|
||||
struct {
|
||||
uint64_t lower;
|
||||
uint16_t upper;
|
||||
} l;
|
||||
} tmp;
|
||||
tmp.d = env->fpregs[i].d;
|
||||
cpu_fprintf(f, "FPR%d=%016llx %04x",
|
||||
i, tmp.l.lower, tmp.l.upper);
|
||||
#else
|
||||
cpu_fprintf(f, "FPR%d=%016llx",
|
||||
i, env->fpregs[i].mmx.q);
|
||||
#endif
|
||||
if ((i & 1) == 1)
|
||||
cpu_fprintf(f, "\n");
|
||||
else
|
||||
cpu_fprintf(f, " ");
|
||||
}
|
||||
if (env->hflags & HF_CS64_MASK)
|
||||
nb = 16;
|
||||
else
|
||||
nb = 8;
|
||||
for(i=0;i<nb;i++) {
|
||||
cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
|
||||
i,
|
||||
env->xmm_regs[i].XMM_L(3),
|
||||
env->xmm_regs[i].XMM_L(2),
|
||||
env->xmm_regs[i].XMM_L(1),
|
||||
env->xmm_regs[i].XMM_L(0));
|
||||
if ((i & 1) == 1)
|
||||
cpu_fprintf(f, "\n");
|
||||
else
|
||||
cpu_fprintf(f, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +551,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
|
||||
}
|
||||
|
||||
/* XXX: also flush 4MB pages */
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
|
||||
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
|
||||
{
|
||||
tlb_flush_page(env, addr);
|
||||
}
|
||||
|
||||
+28
-5
@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
|
||||
#endif
|
||||
|
||||
/* division, flags are undefined */
|
||||
/* XXX: add exceptions for overflow */
|
||||
|
||||
void OPPROTO op_divb_AL_T0(void)
|
||||
{
|
||||
@@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xff;
|
||||
q = (num / den);
|
||||
if (q > 0xff)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
q &= 0xff;
|
||||
r = (num % den) & 0xff;
|
||||
EAX = (EAX & ~0xffff) | (r << 8) | q;
|
||||
}
|
||||
@@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xff;
|
||||
q = (num / den);
|
||||
if (q != (int8_t)q)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
q &= 0xff;
|
||||
r = (num % den) & 0xff;
|
||||
EAX = (EAX & ~0xffff) | (r << 8) | q;
|
||||
}
|
||||
@@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xffff;
|
||||
q = (num / den);
|
||||
if (q > 0xffff)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
q &= 0xffff;
|
||||
r = (num % den) & 0xffff;
|
||||
EAX = (EAX & ~0xffff) | q;
|
||||
EDX = (EDX & ~0xffff) | r;
|
||||
@@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
q = (num / den) & 0xffff;
|
||||
q = (num / den);
|
||||
if (q != (int16_t)q)
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
q &= 0xffff;
|
||||
r = (num % den) & 0xffff;
|
||||
EAX = (EAX & ~0xffff) | q;
|
||||
EDX = (EDX & ~0xffff) | r;
|
||||
@@ -898,6 +909,11 @@ void op_addw_ESP_im(void)
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void op_subq_A0_2(void)
|
||||
{
|
||||
A0 -= 2;
|
||||
}
|
||||
|
||||
void op_subq_A0_8(void)
|
||||
{
|
||||
A0 -= 8;
|
||||
@@ -929,6 +945,13 @@ void OPPROTO op_enter_level(void)
|
||||
helper_enter_level(PARAM1, PARAM2);
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO op_enter64_level(void)
|
||||
{
|
||||
helper_enter64_level(PARAM1, PARAM2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_sysenter(void)
|
||||
{
|
||||
helper_sysenter();
|
||||
|
||||
+85
-33
@@ -1627,7 +1627,14 @@ static void gen_add_A0_ds_seg(DisasContext *s)
|
||||
override = R_DS;
|
||||
}
|
||||
if (must_add_seg) {
|
||||
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1948,10 +1955,14 @@ static void gen_push_T0(DisasContext *s)
|
||||
{
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
/* XXX: check 16 bit behaviour */
|
||||
gen_op_movq_A0_reg[R_ESP]();
|
||||
gen_op_subq_A0_8();
|
||||
gen_op_st_T0_A0[OT_QUAD + s->mem_index]();
|
||||
if (s->dflag) {
|
||||
gen_op_subq_A0_8();
|
||||
gen_op_st_T0_A0[OT_QUAD + s->mem_index]();
|
||||
} else {
|
||||
gen_op_subq_A0_2();
|
||||
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
|
||||
}
|
||||
gen_op_movq_ESP_A0();
|
||||
} else
|
||||
#endif
|
||||
@@ -1985,10 +1996,14 @@ static void gen_push_T1(DisasContext *s)
|
||||
{
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
/* XXX: check 16 bit behaviour */
|
||||
gen_op_movq_A0_reg[R_ESP]();
|
||||
gen_op_subq_A0_8();
|
||||
gen_op_st_T1_A0[OT_QUAD + s->mem_index]();
|
||||
if (s->dflag) {
|
||||
gen_op_subq_A0_8();
|
||||
gen_op_st_T1_A0[OT_QUAD + s->mem_index]();
|
||||
} else {
|
||||
gen_op_subq_A0_2();
|
||||
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
|
||||
}
|
||||
gen_op_movq_ESP_A0();
|
||||
} else
|
||||
#endif
|
||||
@@ -2020,9 +2035,8 @@ static void gen_pop_T0(DisasContext *s)
|
||||
{
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
/* XXX: check 16 bit behaviour */
|
||||
gen_op_movq_A0_reg[R_ESP]();
|
||||
gen_op_ld_T0_A0[OT_QUAD + s->mem_index]();
|
||||
gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index]();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -2041,7 +2055,7 @@ static void gen_pop_T0(DisasContext *s)
|
||||
static void gen_pop_update(DisasContext *s)
|
||||
{
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
if (CODE64(s) && s->dflag) {
|
||||
gen_stack_update(s, 8);
|
||||
} else
|
||||
#endif
|
||||
@@ -2105,26 +2119,48 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
|
||||
{
|
||||
int ot, opsize;
|
||||
|
||||
ot = s->dflag + OT_WORD;
|
||||
level &= 0x1f;
|
||||
opsize = 2 << s->dflag;
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
ot = s->dflag ? OT_QUAD : OT_WORD;
|
||||
opsize = 1 << ot;
|
||||
|
||||
gen_op_movl_A0_ESP();
|
||||
gen_op_addq_A0_im(-opsize);
|
||||
gen_op_movl_T1_A0();
|
||||
|
||||
gen_op_movl_A0_ESP();
|
||||
gen_op_addl_A0_im(-opsize);
|
||||
if (!s->ss32)
|
||||
gen_op_andl_A0_ffff();
|
||||
gen_op_movl_T1_A0();
|
||||
if (s->addseg)
|
||||
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
|
||||
/* push bp */
|
||||
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
||||
gen_op_st_T0_A0[ot + s->mem_index]();
|
||||
if (level) {
|
||||
gen_op_enter_level(level, s->dflag);
|
||||
/* push bp */
|
||||
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
||||
gen_op_st_T0_A0[ot + s->mem_index]();
|
||||
if (level) {
|
||||
gen_op_enter64_level(level, (ot == OT_QUAD));
|
||||
}
|
||||
gen_op_mov_reg_T1[ot][R_EBP]();
|
||||
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
|
||||
gen_op_mov_reg_T1[OT_QUAD][R_ESP]();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ot = s->dflag + OT_WORD;
|
||||
opsize = 2 << s->dflag;
|
||||
|
||||
gen_op_movl_A0_ESP();
|
||||
gen_op_addl_A0_im(-opsize);
|
||||
if (!s->ss32)
|
||||
gen_op_andl_A0_ffff();
|
||||
gen_op_movl_T1_A0();
|
||||
if (s->addseg)
|
||||
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
|
||||
/* push bp */
|
||||
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
||||
gen_op_st_T0_A0[ot + s->mem_index]();
|
||||
if (level) {
|
||||
gen_op_enter_level(level, s->dflag);
|
||||
}
|
||||
gen_op_mov_reg_T1[ot][R_EBP]();
|
||||
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
|
||||
gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
|
||||
}
|
||||
gen_op_mov_reg_T1[ot][R_EBP]();
|
||||
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
|
||||
gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
|
||||
}
|
||||
|
||||
static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
|
||||
@@ -2901,7 +2937,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
|
||||
if (mod != 3)
|
||||
goto illegal_op;
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
if (s->aflag == 2) {
|
||||
gen_op_movq_A0_reg[R_EDI]();
|
||||
} else
|
||||
#endif
|
||||
@@ -3697,7 +3733,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
break;
|
||||
case 0xc8: /* enter */
|
||||
{
|
||||
/* XXX: long mode support */
|
||||
int level;
|
||||
val = lduw_code(s->pc);
|
||||
s->pc += 2;
|
||||
@@ -3707,7 +3742,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
break;
|
||||
case 0xc9: /* leave */
|
||||
/* XXX: exception not precise (ESP is updated before potential exception) */
|
||||
/* XXX: may be invalid for 16 bit in long mode */
|
||||
if (CODE64(s)) {
|
||||
gen_op_mov_TN_reg[OT_QUAD][0][R_EBP]();
|
||||
gen_op_mov_reg_T0[OT_QUAD][R_ESP]();
|
||||
@@ -3926,7 +3960,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
else
|
||||
ot = dflag + OT_WORD;
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
if (s->aflag == 2) {
|
||||
offset_addr = ldq_code(s->pc);
|
||||
s->pc += 8;
|
||||
if (offset_addr == (int32_t)offset_addr)
|
||||
@@ -3955,7 +3989,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
break;
|
||||
case 0xd7: /* xlat */
|
||||
#ifdef TARGET_X86_64
|
||||
if (CODE64(s)) {
|
||||
if (s->aflag == 2) {
|
||||
gen_op_movq_A0_reg[R_EBX]();
|
||||
gen_op_addq_A0_AL();
|
||||
} else
|
||||
@@ -4779,6 +4813,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
val = ldsw_code(s->pc);
|
||||
s->pc += 2;
|
||||
gen_pop_T0(s);
|
||||
if (CODE64(s) && s->dflag)
|
||||
s->dflag = 2;
|
||||
gen_stack_update(s, val + (2 << s->dflag));
|
||||
if (s->dflag == 0)
|
||||
gen_op_andl_T0_ffff();
|
||||
@@ -5782,14 +5818,30 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
break;
|
||||
case 5: /* lfence */
|
||||
case 6: /* mfence */
|
||||
case 7: /* sfence */
|
||||
if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
|
||||
goto illegal_op;
|
||||
break;
|
||||
case 7: /* sfence / clflush */
|
||||
if ((modrm & 0xc7) == 0xc0) {
|
||||
/* sfence */
|
||||
if (!(s->cpuid_features & CPUID_SSE))
|
||||
goto illegal_op;
|
||||
} else {
|
||||
/* clflush */
|
||||
if (!(s->cpuid_features & CPUID_CLFLUSH))
|
||||
goto illegal_op;
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
case 0x10d: /* prefetch */
|
||||
modrm = ldub_code(s->pc++);
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
/* ignore for now */
|
||||
break;
|
||||
case 0x110 ... 0x117:
|
||||
case 0x128 ... 0x12f:
|
||||
case 0x150 ... 0x177:
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
#if !defined (__MIPS_CPU_H__)
|
||||
#define __MIPS_CPU_H__
|
||||
|
||||
#include "mips-defs.h"
|
||||
#include "cpu-defs.h"
|
||||
#include "config.h"
|
||||
#include "softfloat.h"
|
||||
|
||||
typedef union fpr_t fpr_t;
|
||||
union fpr_t {
|
||||
double d;
|
||||
float f;
|
||||
uint32_t u[2];
|
||||
};
|
||||
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
typedef struct tlb_t tlb_t;
|
||||
struct tlb_t {
|
||||
target_ulong VPN;
|
||||
target_ulong end;
|
||||
uint8_t ASID;
|
||||
uint8_t G;
|
||||
uint8_t C[2];
|
||||
uint8_t V[2];
|
||||
uint8_t D[2];
|
||||
target_ulong PFN[2];
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct CPUMIPSState CPUMIPSState;
|
||||
struct CPUMIPSState {
|
||||
/* General integer registers */
|
||||
target_ulong gpr[32];
|
||||
/* Special registers */
|
||||
target_ulong PC;
|
||||
uint32_t HI, LO;
|
||||
uint32_t DCR; /* ? */
|
||||
#if defined(MIPS_USES_FPU)
|
||||
/* Floating point registers */
|
||||
fpr_t fpr[16];
|
||||
/* Floating point special purpose registers */
|
||||
uint32_t fcr0;
|
||||
uint32_t fcr25;
|
||||
uint32_t fcr26;
|
||||
uint32_t fcr28;
|
||||
uint32_t fcsr;
|
||||
#endif
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
tlb_t tlb[16];
|
||||
#endif
|
||||
uint32_t CP0_index;
|
||||
uint32_t CP0_random;
|
||||
uint32_t CP0_EntryLo0;
|
||||
uint32_t CP0_EntryLo1;
|
||||
uint32_t CP0_Context;
|
||||
uint32_t CP0_PageMask;
|
||||
uint32_t CP0_Wired;
|
||||
uint32_t CP0_BadVAddr;
|
||||
uint32_t CP0_Count;
|
||||
uint32_t CP0_EntryHi;
|
||||
uint32_t CP0_Compare;
|
||||
uint32_t CP0_Status;
|
||||
#define CP0St_CU3 31
|
||||
#define CP0St_CU2 30
|
||||
#define CP0St_CU1 29
|
||||
#define CP0St_CU0 28
|
||||
#define CP0St_RP 27
|
||||
#define CP0St_RE 25
|
||||
#define CP0St_BEV 22
|
||||
#define CP0St_TS 21
|
||||
#define CP0St_SR 20
|
||||
#define CP0St_NMI 19
|
||||
#define CP0St_IM 8
|
||||
#define CP0St_UM 4
|
||||
#define CP0St_ERL 2
|
||||
#define CP0St_EXL 1
|
||||
#define CP0St_IE 0
|
||||
uint32_t CP0_Cause;
|
||||
#define CP0Ca_IV 23
|
||||
uint32_t CP0_EPC;
|
||||
uint32_t CP0_PRid;
|
||||
uint32_t CP0_Config0;
|
||||
#define CP0C0_M 31
|
||||
#define CP0C0_K23 28
|
||||
#define CP0C0_KU 25
|
||||
#define CP0C0_MDU 20
|
||||
#define CP0C0_MM 17
|
||||
#define CP0C0_BM 16
|
||||
#define CP0C0_BE 15
|
||||
#define CP0C0_AT 13
|
||||
#define CP0C0_AR 10
|
||||
#define CP0C0_MT 7
|
||||
#define CP0C0_K0 0
|
||||
uint32_t CP0_Config1;
|
||||
#define CP0C1_MMU 25
|
||||
#define CP0C1_IS 22
|
||||
#define CP0C1_IL 19
|
||||
#define CP0C1_IA 16
|
||||
#define CP0C1_DS 13
|
||||
#define CP0C1_DL 10
|
||||
#define CP0C1_DA 7
|
||||
#define CP0C1_PC 4
|
||||
#define CP0C1_WR 3
|
||||
#define CP0C1_CA 2
|
||||
#define CP0C1_EP 1
|
||||
#define CP0C1_FP 0
|
||||
uint32_t CP0_LLAddr;
|
||||
uint32_t CP0_WatchLo;
|
||||
uint32_t CP0_WatchHi;
|
||||
uint32_t CP0_Debug;
|
||||
#define CPDB_DBD 31
|
||||
#define CP0DB_DM 30
|
||||
#define CP0DB_LSNM 28
|
||||
#define CP0DB_Doze 27
|
||||
#define CP0DB_Halt 26
|
||||
#define CP0DB_CNT 25
|
||||
#define CP0DB_IBEP 24
|
||||
#define CP0DB_DBEP 21
|
||||
#define CP0DB_IEXI 20
|
||||
#define CP0DB_VER 15
|
||||
#define CP0DB_DEC 10
|
||||
#define CP0DB_SSt 8
|
||||
#define CP0DB_DINT 5
|
||||
#define CP0DB_DIB 4
|
||||
#define CP0DB_DDBS 3
|
||||
#define CP0DB_DDBL 2
|
||||
#define CP0DB_DBp 1
|
||||
#define CP0DB_DSS 0
|
||||
uint32_t CP0_DEPC;
|
||||
uint32_t CP0_TagLo;
|
||||
uint32_t CP0_DataLo;
|
||||
uint32_t CP0_ErrorEPC;
|
||||
uint32_t CP0_DESAVE;
|
||||
/* Qemu */
|
||||
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
|
||||
double ft0, ft1, ft2;
|
||||
#endif
|
||||
struct QEMUTimer *timer; /* Internal timer */
|
||||
int interrupt_request;
|
||||
jmp_buf jmp_env;
|
||||
int exception_index;
|
||||
int error_code;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
uint32_t hflags; /* CPU State */
|
||||
/* TMASK defines different execution modes */
|
||||
#define MIPS_HFLAGS_TMASK 0x00FF
|
||||
#define MIPS_HFLAG_MODE 0x001F /* execution modes */
|
||||
#define MIPS_HFLAG_UM 0x0001 /* user mode */
|
||||
#define MIPS_HFLAG_ERL 0x0002 /* Error mode */
|
||||
#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */
|
||||
#define MIPS_HFLAG_DM 0x0008 /* Debug mode */
|
||||
#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */
|
||||
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
|
||||
#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */
|
||||
/* Those flags keep the branch state if the translation is interrupted
|
||||
* between the branch instruction and the delay slot
|
||||
*/
|
||||
#define MIPS_HFLAG_BMASK 0x0F00
|
||||
#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */
|
||||
#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */
|
||||
#define MIPS_HFLAG_BL 0x0400 /* Likely branch */
|
||||
#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */
|
||||
target_ulong btarget; /* Jump / branch target */
|
||||
int bcond; /* Branch condition (if needed) */
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */
|
||||
/* soft mmu support */
|
||||
/* in order to avoid passing too many arguments to the memory
|
||||
write helpers, we store some rarely used information in the CPU
|
||||
context) */
|
||||
target_ulong mem_write_pc; /* host pc at which the memory was
|
||||
written */
|
||||
unsigned long mem_write_vaddr; /* target virtual addr at which the
|
||||
memory was written */
|
||||
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
|
||||
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
|
||||
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
|
||||
/* ice debug support */
|
||||
target_ulong breakpoints[MAX_BREAKPOINTS];
|
||||
int nb_breakpoints;
|
||||
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
|
||||
/* user data */
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
#include "cpu-all.h"
|
||||
|
||||
/* Memory access type :
|
||||
* may be needed for precise access rights control and precise exceptions.
|
||||
*/
|
||||
enum {
|
||||
/* 1 bit to define user level / supervisor access */
|
||||
ACCESS_USER = 0x00,
|
||||
ACCESS_SUPER = 0x01,
|
||||
/* 1 bit to indicate direction */
|
||||
ACCESS_STORE = 0x02,
|
||||
/* Type of instruction that generated the access */
|
||||
ACCESS_CODE = 0x10, /* Code fetch access */
|
||||
ACCESS_INT = 0x20, /* Integer load/store access */
|
||||
ACCESS_FLOAT = 0x30, /* floating point load/store access */
|
||||
};
|
||||
|
||||
/* Exceptions */
|
||||
enum {
|
||||
EXCP_NONE = -1,
|
||||
EXCP_RESET = 0,
|
||||
EXCP_SRESET,
|
||||
EXCP_DSS,
|
||||
EXCP_DINT,
|
||||
EXCP_NMI,
|
||||
EXCP_MCHECK,
|
||||
EXCP_EXT_INTERRUPT,
|
||||
EXCP_DFWATCH,
|
||||
EXCP_DIB, /* 8 */
|
||||
EXCP_IWATCH,
|
||||
EXCP_AdEL,
|
||||
EXCP_AdES,
|
||||
EXCP_TLBF,
|
||||
EXCP_IBE,
|
||||
EXCP_DBp,
|
||||
EXCP_SYSCALL,
|
||||
EXCP_BREAK,
|
||||
EXCP_CpU, /* 16 */
|
||||
EXCP_RI,
|
||||
EXCP_OVERFLOW,
|
||||
EXCP_TRAP,
|
||||
EXCP_DDBS,
|
||||
EXCP_DWATCH,
|
||||
EXCP_LAE, /* 22 */
|
||||
EXCP_SAE,
|
||||
EXCP_LTLBL,
|
||||
EXCP_TLBL,
|
||||
EXCP_TLBS,
|
||||
EXCP_DBE,
|
||||
EXCP_DDBL,
|
||||
EXCP_MTCP0 = 0x104, /* mtmsr instruction: */
|
||||
/* may change privilege level */
|
||||
EXCP_BRANCH = 0x108, /* branch instruction */
|
||||
EXCP_ERET = 0x10C, /* return from interrupt */
|
||||
EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
|
||||
EXCP_FLUSH = 0x109,
|
||||
};
|
||||
|
||||
int cpu_mips_exec(CPUMIPSState *s);
|
||||
CPUMIPSState *cpu_mips_init(void);
|
||||
uint32_t cpu_mips_get_clock (void);
|
||||
|
||||
#endif /* !defined (__MIPS_CPU_H__) */
|
||||
@@ -0,0 +1,166 @@
|
||||
#if !defined(__QEMU_MIPS_EXEC_H__)
|
||||
#define __QEMU_MIPS_EXEC_H__
|
||||
|
||||
#define DEBUG_OP
|
||||
|
||||
#include "mips-defs.h"
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
register struct CPUMIPSState *env asm(AREG0);
|
||||
|
||||
#if defined (USE_64BITS_REGS)
|
||||
typedef int64_t host_int_t;
|
||||
typedef uint64_t host_uint_t;
|
||||
#else
|
||||
typedef int32_t host_int_t;
|
||||
typedef uint32_t host_uint_t;
|
||||
#endif
|
||||
|
||||
register host_uint_t T0 asm(AREG1);
|
||||
register host_uint_t T1 asm(AREG2);
|
||||
register host_uint_t T2 asm(AREG3);
|
||||
|
||||
#if defined (USE_HOST_FLOAT_REGS)
|
||||
register double FT0 asm(FREG0);
|
||||
register double FT1 asm(FREG1);
|
||||
register double FT2 asm(FREG2);
|
||||
#else
|
||||
#define FT0 (env->ft0.d)
|
||||
#define FT1 (env->ft1.d)
|
||||
#define FT2 (env->ft2.d)
|
||||
#endif
|
||||
|
||||
#if defined (DEBUG_OP)
|
||||
#define RETURN() __asm__ __volatile__("nop");
|
||||
#else
|
||||
#define RETURN() __asm__ __volatile__("");
|
||||
#endif
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define ldul_user ldl_user
|
||||
#define ldul_kernel ldl_kernel
|
||||
|
||||
#define ACCESS_TYPE 0
|
||||
#define MEMSUFFIX _kernel
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define ACCESS_TYPE 1
|
||||
#define MEMSUFFIX _user
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
/* these access are slower, they must be as rare as possible */
|
||||
#define ACCESS_TYPE 2
|
||||
#define MEMSUFFIX _data
|
||||
#define DATA_SIZE 1
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 2
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 4
|
||||
#include "softmmu_header.h"
|
||||
|
||||
#define DATA_SIZE 8
|
||||
#include "softmmu_header.h"
|
||||
#undef ACCESS_TYPE
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define ldub(p) ldub_data(p)
|
||||
#define ldsb(p) ldsb_data(p)
|
||||
#define lduw(p) lduw_data(p)
|
||||
#define ldsw(p) ldsw_data(p)
|
||||
#define ldl(p) ldl_data(p)
|
||||
#define ldq(p) ldq_data(p)
|
||||
|
||||
#define stb(p, v) stb_data(p, v)
|
||||
#define stw(p, v) stw_data(p, v)
|
||||
#define stl(p, v) stl_data(p, v)
|
||||
#define stq(p, v) stq_data(p, v)
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
static inline void env_to_regs(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void regs_to_env(void)
|
||||
{
|
||||
}
|
||||
|
||||
#if (HOST_LONG_BITS == 32)
|
||||
void do_mult (void);
|
||||
void do_multu (void);
|
||||
void do_madd (void);
|
||||
void do_maddu (void);
|
||||
void do_msub (void);
|
||||
void do_msubu (void);
|
||||
#endif
|
||||
void do_mfc0(int reg, int sel);
|
||||
void do_mtc0(int reg, int sel);
|
||||
void do_tlbwi (void);
|
||||
void do_tlbwr (void);
|
||||
void do_tlbp (void);
|
||||
void do_tlbr (void);
|
||||
void do_lwl_raw (void);
|
||||
void do_lwr_raw (void);
|
||||
void do_swl_raw (void);
|
||||
void do_swr_raw (void);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void do_lwl_user (void);
|
||||
void do_lwl_kernel (void);
|
||||
void do_lwr_user (void);
|
||||
void do_lwr_kernel (void);
|
||||
void do_swl_user (void);
|
||||
void do_swl_kernel (void);
|
||||
void do_swr_user (void);
|
||||
void do_swr_kernel (void);
|
||||
#endif
|
||||
void do_pmon (int function);
|
||||
|
||||
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu);
|
||||
void do_interrupt (CPUState *env);
|
||||
|
||||
void cpu_loop_exit(void);
|
||||
void do_raise_exception_err (uint32_t exception, int error_code);
|
||||
void do_raise_exception (uint32_t exception);
|
||||
|
||||
void cpu_dump_state(CPUState *env, FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
int flags);
|
||||
void cpu_mips_irqctrl_init (void);
|
||||
uint32_t cpu_mips_get_random (CPUState *env);
|
||||
uint32_t cpu_mips_get_count (CPUState *env);
|
||||
void cpu_mips_store_count (CPUState *env, uint32_t value);
|
||||
void cpu_mips_store_compare (CPUState *env, uint32_t value);
|
||||
void cpu_mips_clock_init (CPUState *env);
|
||||
|
||||
#endif /* !defined(__QEMU_MIPS_EXEC_H__) */
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* MIPS emulation helpers for qemu.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
/* MIPS32 4K MMU emulation */
|
||||
#ifdef MIPS_USES_R4K_TLB
|
||||
static int map_address (CPUState *env, target_ulong *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type)
|
||||
{
|
||||
tlb_t *tlb;
|
||||
target_ulong tag;
|
||||
uint8_t ASID;
|
||||
int i, n;
|
||||
int ret;
|
||||
|
||||
ret = -2;
|
||||
tag = (address & 0xFFFFE000);
|
||||
ASID = env->CP0_EntryHi & 0x000000FF;
|
||||
for (i = 0; i < MIPS_TLB_NB; i++) {
|
||||
tlb = &env->tlb[i];
|
||||
/* Check ASID, virtual page number & size */
|
||||
if ((tlb->G == 1 || tlb->ASID == ASID) &&
|
||||
tlb->VPN == tag && address < tlb->end) {
|
||||
/* TLB match */
|
||||
n = (address >> 12) & 1;
|
||||
/* Check access rights */
|
||||
if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) {
|
||||
*physical = tlb->PFN[n] | (address & 0xFFF);
|
||||
*prot = PAGE_READ;
|
||||
if (tlb->D[n])
|
||||
*prot |= PAGE_WRITE;
|
||||
return 0;
|
||||
} else if (!(tlb->V[n] & 2)) {
|
||||
return -3;
|
||||
} else {
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type)
|
||||
{
|
||||
int user_mode;
|
||||
int ret;
|
||||
|
||||
/* User mode can only access useg */
|
||||
user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0;
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "user mode %d h %08x\n",
|
||||
user_mode, env->hflags);
|
||||
}
|
||||
#endif
|
||||
if (user_mode && address > 0x7FFFFFFFUL)
|
||||
return -1;
|
||||
ret = 0;
|
||||
if (address < 0x80000000UL) {
|
||||
if (!(env->hflags & MIPS_HFLAG_ERL)) {
|
||||
#ifdef MIPS_USES_R4K_TLB
|
||||
ret = map_address(env, physical, prot, address, rw, access_type);
|
||||
#else
|
||||
*physical = address + 0x40000000UL;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
#endif
|
||||
} else {
|
||||
*physical = address;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
}
|
||||
} else if (address < 0xA0000000UL) {
|
||||
/* kseg0 */
|
||||
/* XXX: check supervisor mode */
|
||||
*physical = address - 0x80000000UL;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
} else if (address < 0xC0000000UL) {
|
||||
/* kseg1 */
|
||||
/* XXX: check supervisor mode */
|
||||
*physical = address - 0xA0000000UL;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
} else if (address < 0xE0000000UL) {
|
||||
/* kseg2 */
|
||||
#ifdef MIPS_USES_R4K_TLB
|
||||
ret = map_address(env, physical, prot, address, rw, access_type);
|
||||
#else
|
||||
*physical = address;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
#endif
|
||||
} else {
|
||||
/* kseg3 */
|
||||
/* XXX: check supervisor mode */
|
||||
/* XXX: debug segment is not emulated */
|
||||
#ifdef MIPS_USES_R4K_TLB
|
||||
ret = map_address(env, physical, prot, address, rw, access_type);
|
||||
#else
|
||||
*physical = address;
|
||||
*prot = PAGE_READ | PAGE_WRITE;
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
|
||||
access_type, *physical, *prot, ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
#else
|
||||
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||
{
|
||||
target_ulong phys_addr;
|
||||
int prot;
|
||||
|
||||
if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
|
||||
return -1;
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
void cpu_mips_init_mmu (CPUState *env)
|
||||
{
|
||||
}
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int is_user, int is_softmmu)
|
||||
{
|
||||
target_ulong physical;
|
||||
int prot;
|
||||
int exception = 0, error_code = 0;
|
||||
int access_type;
|
||||
int ret = 0;
|
||||
|
||||
if (logfile) {
|
||||
cpu_dump_state(env, logfile, fprintf, 0);
|
||||
fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
|
||||
__func__, env->PC, address, rw, is_user, is_softmmu);
|
||||
}
|
||||
/* data access */
|
||||
/* XXX: put correct access by using cpu_restore_state()
|
||||
correctly */
|
||||
access_type = ACCESS_INT;
|
||||
if (env->user_mode_only) {
|
||||
/* user mode only emulation */
|
||||
ret = -2;
|
||||
goto do_fault;
|
||||
}
|
||||
ret = get_physical_address(env, &physical, &prot,
|
||||
address, rw, access_type);
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
|
||||
__func__, address, ret, physical, prot);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
|
||||
is_user, is_softmmu);
|
||||
} else if (ret < 0) {
|
||||
do_fault:
|
||||
switch (ret) {
|
||||
default:
|
||||
case -1:
|
||||
/* Reference to kernel address from user mode or supervisor mode */
|
||||
/* Reference to supervisor address from user mode */
|
||||
if (rw)
|
||||
exception = EXCP_AdES;
|
||||
else
|
||||
exception = EXCP_AdEL;
|
||||
break;
|
||||
case -2:
|
||||
/* No TLB match for a mapped address */
|
||||
if (rw)
|
||||
exception = EXCP_TLBS;
|
||||
else
|
||||
exception = EXCP_TLBL;
|
||||
error_code = 1;
|
||||
break;
|
||||
case -3:
|
||||
/* TLB match with no valid bit */
|
||||
if (rw)
|
||||
exception = EXCP_TLBS;
|
||||
else
|
||||
exception = EXCP_TLBL;
|
||||
error_code = 0;
|
||||
break;
|
||||
case -4:
|
||||
/* TLB match but 'D' bit is cleared */
|
||||
exception = EXCP_LTLBL;
|
||||
break;
|
||||
|
||||
}
|
||||
/* Raise exception */
|
||||
env->CP0_BadVAddr = address;
|
||||
env->CP0_Context = (env->CP0_Context & 0xff800000) |
|
||||
((address >> 8) & 0x007ffff0);
|
||||
env->CP0_EntryHi =
|
||||
(env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000);
|
||||
env->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void do_interrupt (CPUState *env)
|
||||
{
|
||||
target_ulong pc, offset;
|
||||
int cause = -1;
|
||||
|
||||
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
|
||||
fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
|
||||
__func__, env->PC, env->CP0_EPC, cause, env->exception_index);
|
||||
}
|
||||
if (env->exception_index == EXCP_EXT_INTERRUPT &&
|
||||
(env->hflags & MIPS_HFLAG_DM))
|
||||
env->exception_index = EXCP_DINT;
|
||||
offset = 0x180;
|
||||
switch (env->exception_index) {
|
||||
case EXCP_DSS:
|
||||
env->CP0_Debug |= 1 << CP0DB_DSS;
|
||||
/* Debug single step cannot be raised inside a delay slot and
|
||||
* resume will always occur on the next instruction
|
||||
* (but we assume the pc has always been updated during
|
||||
* code translation).
|
||||
*/
|
||||
env->CP0_DEPC = env->PC;
|
||||
goto enter_debug_mode;
|
||||
case EXCP_DINT:
|
||||
env->CP0_Debug |= 1 << CP0DB_DINT;
|
||||
goto set_DEPC;
|
||||
case EXCP_DIB:
|
||||
env->CP0_Debug |= 1 << CP0DB_DIB;
|
||||
goto set_DEPC;
|
||||
case EXCP_DBp:
|
||||
env->CP0_Debug |= 1 << CP0DB_DBp;
|
||||
goto set_DEPC;
|
||||
case EXCP_DDBS:
|
||||
env->CP0_Debug |= 1 << CP0DB_DDBS;
|
||||
goto set_DEPC;
|
||||
case EXCP_DDBL:
|
||||
env->CP0_Debug |= 1 << CP0DB_DDBL;
|
||||
goto set_DEPC;
|
||||
set_DEPC:
|
||||
if (env->hflags & MIPS_HFLAG_DS) {
|
||||
/* If the exception was raised from a delay slot,
|
||||
* come back to the jump
|
||||
*/
|
||||
env->CP0_DEPC = env->PC - 4;
|
||||
} else {
|
||||
env->CP0_DEPC = env->PC;
|
||||
}
|
||||
enter_debug_mode:
|
||||
env->hflags |= MIPS_HFLAG_DM;
|
||||
/* EJTAG probe trap enable is not implemented... */
|
||||
pc = 0xBFC00480;
|
||||
break;
|
||||
case EXCP_RESET:
|
||||
#ifdef MIPS_USES_R4K_TLB
|
||||
env->CP0_random = MIPS_TLB_NB - 1;
|
||||
#endif
|
||||
env->CP0_Wired = 0;
|
||||
env->CP0_Config0 = MIPS_CONFIG0;
|
||||
#if defined (MIPS_CONFIG1)
|
||||
env->CP0_Config1 = MIPS_CONFIG1;
|
||||
#endif
|
||||
#if defined (MIPS_CONFIG2)
|
||||
env->CP0_Config2 = MIPS_CONFIG2;
|
||||
#endif
|
||||
#if defined (MIPS_CONFIG3)
|
||||
env->CP0_Config3 = MIPS_CONFIG3;
|
||||
#endif
|
||||
env->CP0_WatchLo = 0;
|
||||
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
|
||||
goto set_error_EPC;
|
||||
case EXCP_SRESET:
|
||||
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
|
||||
(1 << CP0St_SR);
|
||||
env->CP0_WatchLo = 0;
|
||||
goto set_error_EPC;
|
||||
case EXCP_NMI:
|
||||
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
|
||||
(1 << CP0St_NMI);
|
||||
set_error_EPC:
|
||||
env->hflags = MIPS_HFLAG_ERL;
|
||||
if (env->hflags & MIPS_HFLAG_DS) {
|
||||
/* If the exception was raised from a delay slot,
|
||||
* come back to the jump
|
||||
*/
|
||||
env->CP0_ErrorEPC = env->PC - 4;
|
||||
} else {
|
||||
env->CP0_ErrorEPC = env->PC;
|
||||
}
|
||||
pc = 0xBFC00000;
|
||||
break;
|
||||
case EXCP_MCHECK:
|
||||
cause = 24;
|
||||
goto set_EPC;
|
||||
case EXCP_EXT_INTERRUPT:
|
||||
cause = 0;
|
||||
if (env->CP0_Cause & (1 << CP0Ca_IV))
|
||||
offset = 0x200;
|
||||
goto set_EPC;
|
||||
case EXCP_DWATCH:
|
||||
cause = 23;
|
||||
/* XXX: TODO: manage defered watch exceptions */
|
||||
goto set_EPC;
|
||||
case EXCP_AdEL:
|
||||
case EXCP_AdES:
|
||||
cause = 4;
|
||||
goto set_EPC;
|
||||
case EXCP_TLBL:
|
||||
case EXCP_TLBF:
|
||||
cause = 2;
|
||||
if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
|
||||
offset = 0x000;
|
||||
goto set_EPC;
|
||||
case EXCP_IBE:
|
||||
cause = 6;
|
||||
goto set_EPC;
|
||||
case EXCP_DBE:
|
||||
cause = 7;
|
||||
goto set_EPC;
|
||||
case EXCP_SYSCALL:
|
||||
cause = 8;
|
||||
goto set_EPC;
|
||||
case EXCP_BREAK:
|
||||
cause = 9;
|
||||
goto set_EPC;
|
||||
case EXCP_RI:
|
||||
cause = 10;
|
||||
goto set_EPC;
|
||||
case EXCP_CpU:
|
||||
cause = 11;
|
||||
/* XXX: fill in the faulty unit number */
|
||||
goto set_EPC;
|
||||
case EXCP_OVERFLOW:
|
||||
cause = 12;
|
||||
goto set_EPC;
|
||||
case EXCP_TRAP:
|
||||
cause = 13;
|
||||
goto set_EPC;
|
||||
case EXCP_LTLBL:
|
||||
cause = 1;
|
||||
goto set_EPC;
|
||||
case EXCP_TLBS:
|
||||
cause = 3;
|
||||
if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
|
||||
offset = 0x000;
|
||||
goto set_EPC;
|
||||
set_EPC:
|
||||
if (env->CP0_Status & (1 << CP0St_BEV)) {
|
||||
pc = 0xBFC00200;
|
||||
} else {
|
||||
pc = 0x80000000;
|
||||
}
|
||||
env->hflags |= MIPS_HFLAG_EXL;
|
||||
pc += offset;
|
||||
env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
|
||||
if (env->hflags & MIPS_HFLAG_DS) {
|
||||
/* If the exception was raised from a delay slot,
|
||||
* come back to the jump
|
||||
*/
|
||||
env->CP0_EPC = env->PC - 4;
|
||||
env->CP0_Cause |= 0x80000000;
|
||||
} else {
|
||||
env->CP0_EPC = env->PC;
|
||||
env->CP0_Cause &= ~0x80000000;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (logfile) {
|
||||
fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
|
||||
env->exception_index);
|
||||
}
|
||||
printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
|
||||
exit(1);
|
||||
}
|
||||
env->PC = pc;
|
||||
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
|
||||
fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
|
||||
" S %08x C %08x A %08x D %08x\n",
|
||||
__func__, env->PC, env->CP0_EPC, cause, env->exception_index,
|
||||
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
|
||||
env->CP0_DEPC);
|
||||
}
|
||||
env->exception_index = EXCP_NONE;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#if !defined (__QEMU_MIPS_DEFS_H__)
|
||||
#define __QEMU_MIPS_DEFS_H__
|
||||
|
||||
/* If we want to use 64 bits host regs... */
|
||||
//#define USE_64BITS_REGS
|
||||
/* If we want to use host float regs... */
|
||||
//#define USE_HOST_FLOAT_REGS
|
||||
|
||||
enum {
|
||||
MIPS_R4Kc = 0x00018000,
|
||||
MIPS_R4Kp = 0x00018300,
|
||||
};
|
||||
|
||||
/* Emulate MIPS R4Kc for now */
|
||||
#define MIPS_CPU MIPS_R4Kc
|
||||
|
||||
#if (MIPS_CPU == MIPS_R4Kc)
|
||||
/* 32 bits target */
|
||||
#define TARGET_LONG_BITS 32
|
||||
/* real pages are variable size... */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
|
||||
#define MIPS_USES_R4K_EXT
|
||||
/* Uses MIPS R4Kc TLB model */
|
||||
#define MIPS_USES_R4K_TLB
|
||||
#define MIPS_TLB_NB 16
|
||||
/* Have config1, runs in big-endian mode, uses TLB */
|
||||
#define MIPS_CONFIG0 \
|
||||
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \
|
||||
(1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0))
|
||||
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
|
||||
* 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
|
||||
* no performance counters, watch registers present, no code compression,
|
||||
* EJTAG present, no FPU
|
||||
*/
|
||||
#define MIPS_CONFIG1 \
|
||||
((15 << CP0C1_MMU) | \
|
||||
(0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
|
||||
(0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
|
||||
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
|
||||
(1 << CP0C1_EP) | (0 << CP0C1_FP))
|
||||
#elif defined (MIPS_CPU == MIPS_R4Kp)
|
||||
/* 32 bits target */
|
||||
#define TARGET_LONG_BITS 32
|
||||
/* real pages are variable size... */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
|
||||
#define MIPS_USES_R4K_EXT
|
||||
/* Uses MIPS R4Km FPM MMU model */
|
||||
#define MIPS_USES_R4K_FPM
|
||||
#else
|
||||
#error "MIPS CPU not defined"
|
||||
/* Remainder for other flags */
|
||||
//#define TARGET_MIPS64
|
||||
//define MIPS_USES_FPU
|
||||
#endif
|
||||
|
||||
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
|
||||
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
* MIPS emulation micro-operations for qemu.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "exec.h"
|
||||
|
||||
#ifndef CALL_FROM_TB0
|
||||
#define CALL_FROM_TB0(func) func();
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB1
|
||||
#define CALL_FROM_TB1(func, arg0) func(arg0);
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB1_CONST16
|
||||
#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB2
|
||||
#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB2_CONST16
|
||||
#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
|
||||
CALL_FROM_TB2(func, arg0, arg1);
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB3
|
||||
#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
|
||||
#endif
|
||||
#ifndef CALL_FROM_TB4
|
||||
#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
|
||||
func(arg0, arg1, arg2, arg3);
|
||||
#endif
|
||||
|
||||
#define REG 1
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 2
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 3
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 4
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 5
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 6
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 7
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 8
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 9
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 10
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 11
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 12
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 13
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 14
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 15
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 16
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 17
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 18
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 19
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 20
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 21
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 22
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 23
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 24
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 25
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 26
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 27
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 28
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 29
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 30
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
#define REG 31
|
||||
#include "op_template.c"
|
||||
#undef REG
|
||||
|
||||
#define TN T0
|
||||
#include "op_template.c"
|
||||
#undef TN
|
||||
#define TN T1
|
||||
#include "op_template.c"
|
||||
#undef TN
|
||||
#define TN T2
|
||||
#include "op_template.c"
|
||||
#undef TN
|
||||
|
||||
void op_dup_T0 (void)
|
||||
{
|
||||
T2 = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_load_HI (void)
|
||||
{
|
||||
T0 = env->HI;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_store_HI (void)
|
||||
{
|
||||
env->HI = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_load_LO (void)
|
||||
{
|
||||
T0 = env->LO;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_store_LO (void)
|
||||
{
|
||||
env->LO = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Load and store */
|
||||
#define MEMSUFFIX _raw
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#endif
|
||||
|
||||
/* Arithmetic */
|
||||
void op_add (void)
|
||||
{
|
||||
T0 += T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_addo (void)
|
||||
{
|
||||
target_ulong tmp;
|
||||
|
||||
tmp = T0;
|
||||
T0 += T1;
|
||||
if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
|
||||
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_sub (void)
|
||||
{
|
||||
T0 -= T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_subo (void)
|
||||
{
|
||||
target_ulong tmp;
|
||||
|
||||
tmp = T0;
|
||||
T0 = (int32_t)T0 - (int32_t)T1;
|
||||
if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
|
||||
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_mul (void)
|
||||
{
|
||||
T0 = (int32_t)T0 * (int32_t)T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_div (void)
|
||||
{
|
||||
if (T1 != 0) {
|
||||
env->LO = (int32_t)T0 / (int32_t)T1;
|
||||
env->HI = (int32_t)T0 % (int32_t)T1;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_divu (void)
|
||||
{
|
||||
if (T1 != 0) {
|
||||
env->LO = T0 / T1;
|
||||
env->HI = T0 % T1;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Logical */
|
||||
void op_and (void)
|
||||
{
|
||||
T0 &= T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_nor (void)
|
||||
{
|
||||
T0 = ~(T0 | T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_or (void)
|
||||
{
|
||||
T0 |= T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_xor (void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_sll (void)
|
||||
{
|
||||
T0 = T0 << T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_sra (void)
|
||||
{
|
||||
T0 = (int32_t)T0 >> T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_srl (void)
|
||||
{
|
||||
T0 = T0 >> T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_sllv (void)
|
||||
{
|
||||
T0 = T1 << (T0 & 0x1F);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_srav (void)
|
||||
{
|
||||
T0 = (int32_t)T1 >> (T0 & 0x1F);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_srlv (void)
|
||||
{
|
||||
T0 = T1 >> (T0 & 0x1F);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_clo (void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (T0 == (target_ulong)-1) {
|
||||
T0 = 32;
|
||||
} else {
|
||||
for (n = 0; n < 32; n++) {
|
||||
if (!(T0 & (1 << 31)))
|
||||
break;
|
||||
T0 = T0 << 1;
|
||||
}
|
||||
T0 = n;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_clz (void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (T0 == 0) {
|
||||
T0 = 32;
|
||||
} else {
|
||||
for (n = 0; n < 32; n++) {
|
||||
if (T0 & (1 << 31))
|
||||
break;
|
||||
T0 = T0 << 1;
|
||||
}
|
||||
T0 = n;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* 64 bits arithmetic */
|
||||
#if (HOST_LONG_BITS == 64)
|
||||
static inline uint64_t get_HILO (void)
|
||||
{
|
||||
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
|
||||
}
|
||||
|
||||
static inline void set_HILO (uint64_t HILO)
|
||||
{
|
||||
env->LO = HILO & 0xFFFFFFFF;
|
||||
env->HI = HILO >> 32;
|
||||
}
|
||||
|
||||
void op_mult (void)
|
||||
{
|
||||
set_HILO((int64_t)T0 * (int64_t)T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_multu (void)
|
||||
{
|
||||
set_HILO((uint64_t)T0 * (uint64_t)T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_madd (void)
|
||||
{
|
||||
int64_t tmp;
|
||||
|
||||
tmp = ((int64_t)T0 * (int64_t)T1);
|
||||
set_HILO((int64_t)get_HILO() + tmp);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_maddu (void)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = ((uint64_t)T0 * (uint64_t)T1);
|
||||
set_HILO(get_HILO() + tmp);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_msub (void)
|
||||
{
|
||||
int64_t tmp;
|
||||
|
||||
tmp = ((int64_t)T0 * (int64_t)T1);
|
||||
set_HILO((int64_t)get_HILO() - tmp);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_msubu (void)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = ((uint64_t)T0 * (uint64_t)T1);
|
||||
set_HILO(get_HILO() - tmp);
|
||||
RETURN();
|
||||
}
|
||||
#else
|
||||
void op_mult (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_mult);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_multu (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_multu);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_madd (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_madd);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_maddu (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_maddu);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_msub (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_msub);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_msubu (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_msubu);
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Conditional moves */
|
||||
void op_movn (void)
|
||||
{
|
||||
if (T1 != 0)
|
||||
env->gpr[PARAM1] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_movz (void)
|
||||
{
|
||||
if (T1 == 0)
|
||||
env->gpr[PARAM1] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Tests */
|
||||
#define OP_COND(name, cond) \
|
||||
void glue(op_, name) (void) \
|
||||
{ \
|
||||
if (cond) { \
|
||||
T0 = 1; \
|
||||
} else { \
|
||||
T0 = 0; \
|
||||
} \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
OP_COND(eq, T0 == T1);
|
||||
OP_COND(ne, T0 != T1);
|
||||
OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
|
||||
OP_COND(geu, T0 >= T1);
|
||||
OP_COND(lt, (int32_t)T0 < (int32_t)T1);
|
||||
OP_COND(ltu, T0 < T1);
|
||||
OP_COND(gez, (int32_t)T0 >= 0);
|
||||
OP_COND(gtz, (int32_t)T0 > 0);
|
||||
OP_COND(lez, (int32_t)T0 <= 0);
|
||||
OP_COND(ltz, (int32_t)T0 < 0);
|
||||
|
||||
/* Branchs */
|
||||
//#undef USE_DIRECT_JUMP
|
||||
#define EIP env->PC
|
||||
|
||||
/* Branch to register */
|
||||
void op_save_breg_target (void)
|
||||
{
|
||||
env->btarget = T2;
|
||||
}
|
||||
|
||||
void op_restore_breg_target (void)
|
||||
{
|
||||
T2 = env->btarget;
|
||||
}
|
||||
|
||||
void op_breg (void)
|
||||
{
|
||||
env->PC = T2;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Unconditional branch */
|
||||
void op_branch (void)
|
||||
{
|
||||
JUMP_TB(branch, PARAM1, 0, PARAM2);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_save_btarget (void)
|
||||
{
|
||||
env->btarget = PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Conditional branch */
|
||||
void op_set_bcond (void)
|
||||
{
|
||||
T2 = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_save_bcond (void)
|
||||
{
|
||||
env->bcond = T2;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_restore_bcond (void)
|
||||
{
|
||||
T2 = env->bcond;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_bcond (void)
|
||||
{
|
||||
if (T2) {
|
||||
JUMP_TB(bcond, PARAM1, 0, PARAM2);
|
||||
} else {
|
||||
JUMP_TB(bcond, PARAM1, 1, PARAM3);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Likely branch (used to skip the delay slot) */
|
||||
void op_blikely (void)
|
||||
{
|
||||
/* If the test is false, skip the delay slot */
|
||||
if (T2 == 0) {
|
||||
env->hflags = PARAM3;
|
||||
JUMP_TB(blikely, PARAM1, 1, PARAM2);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* CP0 functions */
|
||||
void op_mfc0 (void)
|
||||
{
|
||||
CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_mtc0 (void)
|
||||
{
|
||||
CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
void op_tlbwi (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_tlbwi);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_tlbwr (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_tlbwr);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_tlbp (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_tlbp);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_tlbr (void)
|
||||
{
|
||||
CALL_FROM_TB0(do_tlbr);
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Specials */
|
||||
void op_pmon (void)
|
||||
{
|
||||
CALL_FROM_TB1(do_pmon, PARAM1);
|
||||
}
|
||||
|
||||
void op_trap (void)
|
||||
{
|
||||
if (T0) {
|
||||
CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_set_lladdr (void)
|
||||
{
|
||||
env->CP0_LLAddr = T2;
|
||||
}
|
||||
|
||||
void debug_eret (void);
|
||||
void op_eret (void)
|
||||
{
|
||||
CALL_FROM_TB0(debug_eret);
|
||||
if (env->hflags & MIPS_HFLAG_ERL) {
|
||||
env->PC = env->CP0_ErrorEPC;
|
||||
env->hflags &= ~MIPS_HFLAG_ERL;
|
||||
} else {
|
||||
env->PC = env->CP0_EPC;
|
||||
env->hflags &= ~MIPS_HFLAG_EXL;
|
||||
}
|
||||
env->CP0_LLAddr = 1;
|
||||
}
|
||||
|
||||
void op_deret (void)
|
||||
{
|
||||
CALL_FROM_TB0(debug_eret);
|
||||
env->PC = env->CP0_DEPC;
|
||||
}
|
||||
|
||||
void op_save_state (void)
|
||||
{
|
||||
env->hflags = PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_save_pc (void)
|
||||
{
|
||||
env->PC = PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_raise_exception (void)
|
||||
{
|
||||
CALL_FROM_TB1(do_raise_exception, PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_raise_exception_err (void)
|
||||
{
|
||||
CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* MIPS emulation helpers for qemu.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "exec.h"
|
||||
|
||||
#define MIPS_DEBUG_DISAS
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exceptions processing helpers */
|
||||
void cpu_loop_exit(void)
|
||||
{
|
||||
longjmp(env->jmp_env, 1);
|
||||
}
|
||||
|
||||
void do_raise_exception_err (uint32_t exception, int error_code)
|
||||
{
|
||||
#if 1
|
||||
if (logfile && exception < 0x100)
|
||||
fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
|
||||
#endif
|
||||
env->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
T0 = 0;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void do_raise_exception (uint32_t exception)
|
||||
{
|
||||
do_raise_exception_err(exception, 0);
|
||||
}
|
||||
|
||||
#define MEMSUFFIX _raw
|
||||
#include "op_helper_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "op_helper_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "op_helper_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#endif
|
||||
|
||||
/* 64 bits arithmetic for 32 bits hosts */
|
||||
#if (HOST_LONG_BITS == 32)
|
||||
static inline uint64_t get_HILO (void)
|
||||
{
|
||||
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
|
||||
}
|
||||
|
||||
static inline void set_HILO (uint64_t HILO)
|
||||
{
|
||||
env->LO = HILO & 0xFFFFFFFF;
|
||||
env->HI = HILO >> 32;
|
||||
}
|
||||
|
||||
void do_mult (void)
|
||||
{
|
||||
set_HILO((int64_t)T0 * (int64_t)T1);
|
||||
}
|
||||
|
||||
void do_multu (void)
|
||||
{
|
||||
set_HILO((uint64_t)T0 * (uint64_t)T1);
|
||||
}
|
||||
|
||||
void do_madd (void)
|
||||
{
|
||||
int64_t tmp;
|
||||
|
||||
tmp = ((int64_t)T0 * (int64_t)T1);
|
||||
set_HILO((int64_t)get_HILO() + tmp);
|
||||
}
|
||||
|
||||
void do_maddu (void)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = ((uint64_t)T0 * (uint64_t)T1);
|
||||
set_HILO(get_HILO() + tmp);
|
||||
}
|
||||
|
||||
void do_msub (void)
|
||||
{
|
||||
int64_t tmp;
|
||||
|
||||
tmp = ((int64_t)T0 * (int64_t)T1);
|
||||
set_HILO((int64_t)get_HILO() - tmp);
|
||||
}
|
||||
|
||||
void do_msubu (void)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = ((uint64_t)T0 * (uint64_t)T1);
|
||||
set_HILO(get_HILO() - tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* CP0 helpers */
|
||||
void do_mfc0 (int reg, int sel)
|
||||
{
|
||||
const unsigned char *rn;
|
||||
|
||||
if (sel != 0 && reg != 16 && reg != 28) {
|
||||
rn = "invalid";
|
||||
goto print;
|
||||
}
|
||||
switch (reg) {
|
||||
case 0:
|
||||
T0 = env->CP0_index;
|
||||
rn = "Index";
|
||||
break;
|
||||
case 1:
|
||||
T0 = cpu_mips_get_random(env);
|
||||
rn = "Random";
|
||||
break;
|
||||
case 2:
|
||||
T0 = env->CP0_EntryLo0;
|
||||
rn = "EntryLo0";
|
||||
break;
|
||||
case 3:
|
||||
T0 = env->CP0_EntryLo1;
|
||||
rn = "EntryLo1";
|
||||
break;
|
||||
case 4:
|
||||
T0 = env->CP0_Context;
|
||||
rn = "Context";
|
||||
break;
|
||||
case 5:
|
||||
T0 = env->CP0_PageMask;
|
||||
rn = "PageMask";
|
||||
break;
|
||||
case 6:
|
||||
T0 = env->CP0_Wired;
|
||||
rn = "Wired";
|
||||
break;
|
||||
case 8:
|
||||
T0 = env->CP0_BadVAddr;
|
||||
rn = "BadVaddr";
|
||||
break;
|
||||
case 9:
|
||||
T0 = cpu_mips_get_count(env);
|
||||
rn = "Count";
|
||||
break;
|
||||
case 10:
|
||||
T0 = env->CP0_EntryHi;
|
||||
rn = "EntryHi";
|
||||
break;
|
||||
case 11:
|
||||
T0 = env->CP0_Compare;
|
||||
rn = "Compare";
|
||||
break;
|
||||
case 12:
|
||||
T0 = env->CP0_Status;
|
||||
if (env->hflags & MIPS_HFLAG_UM)
|
||||
T0 |= (1 << CP0St_UM);
|
||||
if (env->hflags & MIPS_HFLAG_ERL)
|
||||
T0 |= (1 << CP0St_ERL);
|
||||
if (env->hflags & MIPS_HFLAG_EXL)
|
||||
T0 |= (1 << CP0St_EXL);
|
||||
rn = "Status";
|
||||
break;
|
||||
case 13:
|
||||
T0 = env->CP0_Cause;
|
||||
rn = "Cause";
|
||||
break;
|
||||
case 14:
|
||||
T0 = env->CP0_EPC;
|
||||
rn = "EPC";
|
||||
break;
|
||||
case 15:
|
||||
T0 = env->CP0_PRid;
|
||||
rn = "PRid";
|
||||
break;
|
||||
case 16:
|
||||
switch (sel) {
|
||||
case 0:
|
||||
T0 = env->CP0_Config0;
|
||||
rn = "Config";
|
||||
break;
|
||||
case 1:
|
||||
T0 = env->CP0_Config1;
|
||||
rn = "Config1";
|
||||
break;
|
||||
default:
|
||||
rn = "Unknown config register";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
T0 = env->CP0_LLAddr >> 4;
|
||||
rn = "LLAddr";
|
||||
break;
|
||||
case 18:
|
||||
T0 = env->CP0_WatchLo;
|
||||
rn = "WatchLo";
|
||||
break;
|
||||
case 19:
|
||||
T0 = env->CP0_WatchHi;
|
||||
rn = "WatchHi";
|
||||
break;
|
||||
case 23:
|
||||
T0 = env->CP0_Debug;
|
||||
if (env->hflags & MIPS_HFLAG_DM)
|
||||
T0 |= 1 << CP0DB_DM;
|
||||
rn = "Debug";
|
||||
break;
|
||||
case 24:
|
||||
T0 = env->CP0_DEPC;
|
||||
rn = "DEPC";
|
||||
break;
|
||||
case 28:
|
||||
switch (sel) {
|
||||
case 0:
|
||||
T0 = env->CP0_TagLo;
|
||||
rn = "TagLo";
|
||||
break;
|
||||
case 1:
|
||||
T0 = env->CP0_DataLo;
|
||||
rn = "DataLo";
|
||||
break;
|
||||
default:
|
||||
rn = "unknown sel";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 30:
|
||||
T0 = env->CP0_ErrorEPC;
|
||||
rn = "ErrorEPC";
|
||||
break;
|
||||
case 31:
|
||||
T0 = env->CP0_DESAVE;
|
||||
rn = "DESAVE";
|
||||
break;
|
||||
default:
|
||||
rn = "unknown";
|
||||
break;
|
||||
}
|
||||
print:
|
||||
#if defined MIPS_DEBUG_DISAS
|
||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||
fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
|
||||
env->PC, rn, T0, reg, sel);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
void do_mtc0 (int reg, int sel)
|
||||
{
|
||||
const unsigned char *rn;
|
||||
uint32_t val, old, mask;
|
||||
|
||||
if (sel != 0 && reg != 16 && reg != 28) {
|
||||
val = -1;
|
||||
old = -1;
|
||||
rn = "invalid";
|
||||
goto print;
|
||||
}
|
||||
switch (reg) {
|
||||
case 0:
|
||||
val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
|
||||
old = env->CP0_index;
|
||||
env->CP0_index = val;
|
||||
rn = "Index";
|
||||
break;
|
||||
case 2:
|
||||
val = T0 & 0x03FFFFFFF;
|
||||
old = env->CP0_EntryLo0;
|
||||
env->CP0_EntryLo0 = val;
|
||||
rn = "EntryLo0";
|
||||
break;
|
||||
case 3:
|
||||
val = T0 & 0x03FFFFFFF;
|
||||
old = env->CP0_EntryLo1;
|
||||
env->CP0_EntryLo1 = val;
|
||||
rn = "EntryLo1";
|
||||
break;
|
||||
case 4:
|
||||
val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
|
||||
old = env->CP0_Context;
|
||||
env->CP0_Context = val;
|
||||
rn = "Context";
|
||||
break;
|
||||
case 5:
|
||||
val = T0 & 0x01FFE000;
|
||||
old = env->CP0_PageMask;
|
||||
env->CP0_PageMask = val;
|
||||
rn = "PageMask";
|
||||
break;
|
||||
case 6:
|
||||
val = T0 & 0x0000000F;
|
||||
old = env->CP0_Wired;
|
||||
env->CP0_Wired = val;
|
||||
rn = "Wired";
|
||||
break;
|
||||
case 9:
|
||||
val = T0;
|
||||
old = cpu_mips_get_count(env);
|
||||
cpu_mips_store_count(env, val);
|
||||
rn = "Count";
|
||||
break;
|
||||
case 10:
|
||||
val = T0 & 0xFFFFF0FF;
|
||||
old = env->CP0_EntryHi;
|
||||
env->CP0_EntryHi = val;
|
||||
rn = "EntryHi";
|
||||
break;
|
||||
case 11:
|
||||
val = T0;
|
||||
old = env->CP0_Compare;
|
||||
cpu_mips_store_compare(env, val);
|
||||
rn = "Compare";
|
||||
break;
|
||||
case 12:
|
||||
val = T0 & 0xFA78FF01;
|
||||
if (T0 & (1 << CP0St_UM))
|
||||
env->hflags |= MIPS_HFLAG_UM;
|
||||
else
|
||||
env->hflags &= ~MIPS_HFLAG_UM;
|
||||
if (T0 & (1 << CP0St_ERL))
|
||||
env->hflags |= MIPS_HFLAG_ERL;
|
||||
else
|
||||
env->hflags &= ~MIPS_HFLAG_ERL;
|
||||
if (T0 & (1 << CP0St_EXL))
|
||||
env->hflags |= MIPS_HFLAG_EXL;
|
||||
else
|
||||
env->hflags &= ~MIPS_HFLAG_EXL;
|
||||
old = env->CP0_Status;
|
||||
env->CP0_Status = val;
|
||||
/* If we unmasked an asserted IRQ, raise it */
|
||||
mask = 0x0000FF00;
|
||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||
fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
|
||||
old, val, env->CP0_Cause, old & mask, val & mask,
|
||||
env->CP0_Cause & mask);
|
||||
}
|
||||
#if 1
|
||||
if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
|
||||
!(env->hflags & MIPS_HFLAG_EXL) &&
|
||||
!(env->hflags & MIPS_HFLAG_ERL) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM) &&
|
||||
(env->CP0_Status & env->CP0_Cause & mask)) {
|
||||
if (logfile)
|
||||
fprintf(logfile, "Raise pending IRQs\n");
|
||||
env->interrupt_request |= CPU_INTERRUPT_HARD;
|
||||
do_raise_exception(EXCP_EXT_INTERRUPT);
|
||||
} else if (!(val & 0x00000001) && (old & 0x00000001)) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
}
|
||||
#endif
|
||||
rn = "Status";
|
||||
break;
|
||||
case 13:
|
||||
val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
|
||||
old = env->CP0_Cause;
|
||||
env->CP0_Cause = val;
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
/* Check if we ever asserted a software IRQ */
|
||||
for (i = 0; i < 2; i++) {
|
||||
mask = 0x100 << i;
|
||||
if ((val & mask) & !(old & mask))
|
||||
mips_set_irq(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rn = "Cause";
|
||||
break;
|
||||
case 14:
|
||||
val = T0;
|
||||
old = env->CP0_EPC;
|
||||
env->CP0_EPC = val;
|
||||
rn = "EPC";
|
||||
break;
|
||||
case 16:
|
||||
switch (sel) {
|
||||
case 0:
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
|
||||
#else
|
||||
val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
|
||||
#endif
|
||||
old = env->CP0_Config0;
|
||||
env->CP0_Config0 = val;
|
||||
rn = "Config0";
|
||||
break;
|
||||
default:
|
||||
val = -1;
|
||||
old = -1;
|
||||
rn = "bad config selector";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
val = T0;
|
||||
old = env->CP0_WatchLo;
|
||||
env->CP0_WatchLo = val;
|
||||
rn = "WatchLo";
|
||||
break;
|
||||
case 19:
|
||||
val = T0 & 0x40FF0FF8;
|
||||
old = env->CP0_WatchHi;
|
||||
env->CP0_WatchHi = val;
|
||||
rn = "WatchHi";
|
||||
break;
|
||||
case 23:
|
||||
val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
|
||||
if (T0 & (1 << CP0DB_DM))
|
||||
env->hflags |= MIPS_HFLAG_DM;
|
||||
else
|
||||
env->hflags &= ~MIPS_HFLAG_DM;
|
||||
old = env->CP0_Debug;
|
||||
env->CP0_Debug = val;
|
||||
rn = "Debug";
|
||||
break;
|
||||
case 24:
|
||||
val = T0;
|
||||
old = env->CP0_DEPC;
|
||||
env->CP0_DEPC = val;
|
||||
rn = "DEPC";
|
||||
break;
|
||||
case 28:
|
||||
switch (sel) {
|
||||
case 0:
|
||||
val = T0 & 0xFFFFFCF6;
|
||||
old = env->CP0_TagLo;
|
||||
env->CP0_TagLo = val;
|
||||
rn = "TagLo";
|
||||
break;
|
||||
default:
|
||||
val = -1;
|
||||
old = -1;
|
||||
rn = "invalid sel";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 30:
|
||||
val = T0;
|
||||
old = env->CP0_ErrorEPC;
|
||||
env->CP0_ErrorEPC = val;
|
||||
rn = "EPC";
|
||||
break;
|
||||
case 31:
|
||||
val = T0;
|
||||
old = env->CP0_DESAVE;
|
||||
env->CP0_DESAVE = val;
|
||||
rn = "DESAVE";
|
||||
break;
|
||||
default:
|
||||
val = -1;
|
||||
old = -1;
|
||||
rn = "unknown";
|
||||
break;
|
||||
}
|
||||
print:
|
||||
#if defined MIPS_DEBUG_DISAS
|
||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||
fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
|
||||
env->PC, rn, T0, val, reg, sel, old);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* TLB management */
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
static void invalidate_tb (int idx)
|
||||
{
|
||||
tlb_t *tlb;
|
||||
target_ulong addr, end;
|
||||
|
||||
tlb = &env->tlb[idx];
|
||||
if (tlb->V[0]) {
|
||||
addr = tlb->PFN[0];
|
||||
end = addr + (tlb->end - tlb->VPN);
|
||||
tb_invalidate_page_range(addr, end);
|
||||
}
|
||||
if (tlb->V[1]) {
|
||||
addr = tlb->PFN[1];
|
||||
end = addr + (tlb->end - tlb->VPN);
|
||||
tb_invalidate_page_range(addr, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_tb (int idx)
|
||||
{
|
||||
tlb_t *tlb;
|
||||
int size;
|
||||
|
||||
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
|
||||
tlb = &env->tlb[idx];
|
||||
tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
|
||||
tlb->ASID = env->CP0_EntryHi & 0x000000FF;
|
||||
size = env->CP0_PageMask >> 13;
|
||||
size = 4 * (size + 1);
|
||||
tlb->end = tlb->VPN + (1 << (8 + size));
|
||||
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
|
||||
tlb->V[0] = env->CP0_EntryLo0 & 2;
|
||||
tlb->D[0] = env->CP0_EntryLo0 & 4;
|
||||
tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
|
||||
tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
|
||||
tlb->V[1] = env->CP0_EntryLo1 & 2;
|
||||
tlb->D[1] = env->CP0_EntryLo1 & 4;
|
||||
tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
|
||||
tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
|
||||
}
|
||||
|
||||
void do_tlbwi (void)
|
||||
{
|
||||
/* Wildly undefined effects for CP0_index containing a too high value and
|
||||
MIPS_TLB_NB not being a power of two. But so does real silicon. */
|
||||
invalidate_tb(env->CP0_index & (MIPS_TLB_NB - 1));
|
||||
fill_tb(env->CP0_index & (MIPS_TLB_NB - 1));
|
||||
}
|
||||
|
||||
void do_tlbwr (void)
|
||||
{
|
||||
int r = cpu_mips_get_random(env);
|
||||
|
||||
invalidate_tb(r);
|
||||
fill_tb(r);
|
||||
}
|
||||
|
||||
void do_tlbp (void)
|
||||
{
|
||||
tlb_t *tlb;
|
||||
target_ulong tag;
|
||||
uint8_t ASID;
|
||||
int i;
|
||||
|
||||
tag = (env->CP0_EntryHi & 0xFFFFE000);
|
||||
ASID = env->CP0_EntryHi & 0x000000FF;
|
||||
for (i = 0; i < MIPS_TLB_NB; i++) {
|
||||
tlb = &env->tlb[i];
|
||||
/* Check ASID, virtual page number & size */
|
||||
if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
|
||||
/* TLB match */
|
||||
env->CP0_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == MIPS_TLB_NB) {
|
||||
env->CP0_index |= 0x80000000;
|
||||
}
|
||||
}
|
||||
|
||||
void do_tlbr (void)
|
||||
{
|
||||
tlb_t *tlb;
|
||||
int size;
|
||||
|
||||
tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
|
||||
env->CP0_EntryHi = tlb->VPN | tlb->ASID;
|
||||
size = (tlb->end - tlb->VPN) >> 12;
|
||||
env->CP0_PageMask = (size - 1) << 13;
|
||||
env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
|
||||
(tlb->PFN[0] >> 6);
|
||||
env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
|
||||
(tlb->PFN[1] >> 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
void op_dump_ldst (const unsigned char *func)
|
||||
{
|
||||
if (loglevel)
|
||||
fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
|
||||
}
|
||||
|
||||
void dump_sc (void)
|
||||
{
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
|
||||
T1, T0, env->CP0_LLAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void debug_eret (void)
|
||||
{
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
|
||||
env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
|
||||
env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void do_pmon (int function)
|
||||
{
|
||||
function /= 2;
|
||||
switch (function) {
|
||||
case 2: /* TODO: char inbyte(int waitflag); */
|
||||
if (env->gpr[4] == 0)
|
||||
env->gpr[2] = -1;
|
||||
/* Fall through */
|
||||
case 11: /* TODO: char inbyte (void); */
|
||||
env->gpr[2] = -1;
|
||||
break;
|
||||
case 3:
|
||||
case 12:
|
||||
printf("%c", env->gpr[4] & 0xFF);
|
||||
break;
|
||||
case 17:
|
||||
break;
|
||||
case 158:
|
||||
{
|
||||
unsigned char *fmt = (void *)env->gpr[4];
|
||||
printf("%s", fmt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
unsigned long pc;
|
||||
int ret;
|
||||
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (ret) {
|
||||
if (retaddr) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (unsigned long)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (tb) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
void glue(do_lwl, MEMSUFFIX) (void)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
target_ulong sav = T0;
|
||||
#endif
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
|
||||
/* XXX: this is valid only in big-endian mode
|
||||
* should be reverted for little-endian...
|
||||
*/
|
||||
switch (T0 & 3) {
|
||||
case 0:
|
||||
T0 = tmp;
|
||||
break;
|
||||
case 1:
|
||||
T0 = (tmp << 8) | (T1 & 0x000000FF);
|
||||
break;
|
||||
case 2:
|
||||
T0 = (tmp << 16) | (T1 & 0x0000FFFF);
|
||||
break;
|
||||
case 3:
|
||||
T0 = (tmp << 24) | (T1 & 0x00FFFFFF);
|
||||
break;
|
||||
}
|
||||
#if defined (DEBUG_OP)
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
|
||||
__func__, sav, tmp, T1, T0);
|
||||
}
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(do_lwr, MEMSUFFIX) (void)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
target_ulong sav = T0;
|
||||
#endif
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
|
||||
/* XXX: this is valid only in big-endian mode
|
||||
* should be reverted for little-endian...
|
||||
*/
|
||||
switch (T0 & 3) {
|
||||
case 0:
|
||||
T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
|
||||
break;
|
||||
case 1:
|
||||
T0 = (tmp >> 16) | (T1 & 0xFFFF0000);
|
||||
break;
|
||||
case 2:
|
||||
T0 = (tmp >> 8) | (T1 & 0xFF000000);
|
||||
break;
|
||||
case 3:
|
||||
T0 = tmp;
|
||||
break;
|
||||
}
|
||||
#if defined (DEBUG_OP)
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
|
||||
__func__, sav, tmp, T1, T0);
|
||||
}
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(do_swl, MEMSUFFIX) (void)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
target_ulong sav;
|
||||
#endif
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
|
||||
#if defined (DEBUG_OP)
|
||||
sav = tmp;
|
||||
#endif
|
||||
/* XXX: this is valid only in big-endian mode
|
||||
* should be reverted for little-endian...
|
||||
*/
|
||||
switch (T0 & 3) {
|
||||
case 0:
|
||||
tmp = T1;
|
||||
break;
|
||||
case 1:
|
||||
tmp = (tmp & 0xFF000000) | (T1 >> 8);
|
||||
break;
|
||||
case 2:
|
||||
tmp = (tmp & 0xFFFF0000) | (T1 >> 16);
|
||||
break;
|
||||
case 3:
|
||||
tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
|
||||
break;
|
||||
}
|
||||
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
|
||||
#if defined (DEBUG_OP)
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
|
||||
__func__, T0, sav, T1, tmp);
|
||||
}
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(do_swr, MEMSUFFIX) (void)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
target_ulong sav;
|
||||
#endif
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
|
||||
#if defined (DEBUG_OP)
|
||||
sav = tmp;
|
||||
#endif
|
||||
/* XXX: this is valid only in big-endian mode
|
||||
* should be reverted for little-endian...
|
||||
*/
|
||||
switch (T0 & 3) {
|
||||
case 0:
|
||||
tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
|
||||
break;
|
||||
case 1:
|
||||
tmp = (tmp & 0x0000FFFF) | (T1 << 16);
|
||||
break;
|
||||
case 2:
|
||||
tmp = (tmp & 0x000000FF) | (T1 << 8);
|
||||
break;
|
||||
case 3:
|
||||
tmp = T1;
|
||||
break;
|
||||
}
|
||||
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
|
||||
#if defined (DEBUG_OP)
|
||||
if (logfile) {
|
||||
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
|
||||
__func__, T0, sav, T1, tmp);
|
||||
}
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* MIPS emulation memory micro-operations for qemu.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Standard loads and stores */
|
||||
void glue(op_lb, MEMSUFFIX) (void)
|
||||
{
|
||||
T0 = glue(ldsb, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_lbu, MEMSUFFIX) (void)
|
||||
{
|
||||
T0 = glue(ldub, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_sb, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stb, MEMSUFFIX)(T0, T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_lh, MEMSUFFIX) (void)
|
||||
{
|
||||
T0 = glue(ldsw, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_lhu, MEMSUFFIX) (void)
|
||||
{
|
||||
T0 = glue(lduw, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_sh, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stw, MEMSUFFIX)(T0, T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_lw, MEMSUFFIX) (void)
|
||||
{
|
||||
T0 = glue(ldl, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_sw, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stl, MEMSUFFIX)(T0, T1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* "half" load and stores */
|
||||
void glue(op_lwl, MEMSUFFIX) (void)
|
||||
{
|
||||
CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_lwr, MEMSUFFIX) (void)
|
||||
{
|
||||
CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_swl, MEMSUFFIX) (void)
|
||||
{
|
||||
CALL_FROM_TB0(glue(do_swl, MEMSUFFIX));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_swr, MEMSUFFIX) (void)
|
||||
{
|
||||
CALL_FROM_TB0(glue(do_swr, MEMSUFFIX));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_ll, MEMSUFFIX) (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = glue(ldl, MEMSUFFIX)(T0);
|
||||
env->CP0_LLAddr = T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_sc, MEMSUFFIX) (void)
|
||||
{
|
||||
CALL_FROM_TB0(dump_sc);
|
||||
if (T0 == env->CP0_LLAddr) {
|
||||
glue(stl, MEMSUFFIX)(T0, T1);
|
||||
T0 = 1;
|
||||
} else {
|
||||
T0 = 0;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* MIPS emulation micro-operations templates for reg load & store for qemu.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#if defined(REG)
|
||||
void glue(op_load_gpr_T0_gpr, REG) (void)
|
||||
{
|
||||
T0 = env->gpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_store_T0_gpr_gpr, REG) (void)
|
||||
{
|
||||
env->gpr[REG] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_load_gpr_T1_gpr, REG) (void)
|
||||
{
|
||||
T1 = env->gpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_store_T1_gpr_gpr, REG) (void)
|
||||
{
|
||||
env->gpr[REG] = T1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue(op_load_gpr_T2_gpr, REG) (void)
|
||||
{
|
||||
T2 = env->gpr[REG];
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (TN)
|
||||
void glue(op_set_, TN) (void)
|
||||
{
|
||||
TN = PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void glue (op_reset_, TN) (void)
|
||||
{
|
||||
TN = 0;
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
+860
-260
File diff suppressed because it is too large.
Load diff
+6
-22
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PPC emulation definitions for qemu.
|
||||
* PowerPC emulation definitions for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
* Copyright (c) 2003-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,8 +20,12 @@
|
||||
#if !defined (__PPC_H__)
|
||||
#define __PPC_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dyngen-exec.h"
|
||||
|
||||
#define TARGET_LONG_BITS 32
|
||||
|
||||
register struct CPUPPCState *env asm(AREG0);
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
@@ -119,15 +123,6 @@ static inline uint32_t rotl (uint32_t i, int n)
|
||||
void do_raise_exception_err (uint32_t exception, int error_code);
|
||||
void do_raise_exception (uint32_t exception);
|
||||
|
||||
void do_load_cr (void);
|
||||
void do_store_cr (uint32_t mask);
|
||||
void do_load_xer (void);
|
||||
void do_store_xer (void);
|
||||
void do_load_msr (void);
|
||||
void do_store_msr (void);
|
||||
void do_load_fpscr (void);
|
||||
void do_store_fpscr (uint32_t mask);
|
||||
|
||||
void do_sraw(void);
|
||||
|
||||
void do_fctiw (void);
|
||||
@@ -143,20 +138,9 @@ void do_fcmpo (void);
|
||||
|
||||
void do_check_reservation (void);
|
||||
void do_icbi (void);
|
||||
void do_store_sr (uint32_t srnum);
|
||||
void do_store_ibat (int ul, int nr);
|
||||
void do_store_dbat (int ul, int nr);
|
||||
void do_tlbia (void);
|
||||
void do_tlbie (void);
|
||||
|
||||
void dump_state (void);
|
||||
void dump_rfi (void);
|
||||
void dump_store_sr (int srnum);
|
||||
void dump_store_ibat (int ul, int nr);
|
||||
void dump_store_dbat (int ul, int nr);
|
||||
void dump_store_tb (int ul);
|
||||
void dump_update_tb(uint32_t param);
|
||||
|
||||
static inline void env_to_regs(void)
|
||||
{
|
||||
}
|
||||
|
||||
+789
-258
File diff suppressed because it is too large.
Load diff
+108
-241
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PPC emulation micro-operations for qemu.
|
||||
* PowerPC emulation micro-operations for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
* Copyright (c) 2003-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -130,7 +130,7 @@
|
||||
#define REG 31
|
||||
#include "op_template.h"
|
||||
|
||||
/* PPC state maintenance operations */
|
||||
/* PowerPC state maintenance operations */
|
||||
/* set_Rc0 */
|
||||
PPC_OP(set_Rc0)
|
||||
{
|
||||
@@ -204,16 +204,6 @@ PPC_OP(update_nip)
|
||||
env->nip = PARAM(1);
|
||||
}
|
||||
|
||||
PPC_OP(debug)
|
||||
{
|
||||
env->nip = PARAM(1);
|
||||
#if defined (DEBUG_OP)
|
||||
dump_state();
|
||||
#endif
|
||||
do_raise_exception(EXCP_DEBUG);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Segment registers load and store with immediate index */
|
||||
PPC_OP(load_srin)
|
||||
{
|
||||
@@ -223,7 +213,7 @@ PPC_OP(load_srin)
|
||||
|
||||
PPC_OP(store_srin)
|
||||
{
|
||||
do_store_sr(T1 >> 28);
|
||||
do_store_sr(env, ((uint32_t)T1 >> 28), T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -235,7 +225,7 @@ PPC_OP(load_sdr1)
|
||||
|
||||
PPC_OP(store_sdr1)
|
||||
{
|
||||
regs->sdr1 = T0;
|
||||
do_store_sdr1(env, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -247,13 +237,13 @@ PPC_OP(exit_tb)
|
||||
/* Load/store special registers */
|
||||
PPC_OP(load_cr)
|
||||
{
|
||||
do_load_cr();
|
||||
T0 = do_load_cr(env);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(store_cr)
|
||||
{
|
||||
do_store_cr(PARAM(1));
|
||||
do_store_cr(env, T0, PARAM(1));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -279,25 +269,25 @@ PPC_OP(load_xer_bc)
|
||||
|
||||
PPC_OP(load_xer)
|
||||
{
|
||||
do_load_xer();
|
||||
T0 = do_load_xer(env);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(store_xer)
|
||||
{
|
||||
do_store_xer();
|
||||
do_store_xer(env, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(load_msr)
|
||||
{
|
||||
do_load_msr();
|
||||
T0 = do_load_msr(env);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(store_msr)
|
||||
{
|
||||
do_store_msr();
|
||||
do_store_msr(env, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -378,9 +368,20 @@ PPC_OP(load_ibat)
|
||||
T0 = regs->IBAT[PARAM(1)][PARAM(2)];
|
||||
}
|
||||
|
||||
PPC_OP(store_ibat)
|
||||
void op_store_ibatu (void)
|
||||
{
|
||||
do_store_ibat(PARAM(1), PARAM(2));
|
||||
do_store_ibatu(env, PARAM1, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_store_ibatl (void)
|
||||
{
|
||||
#if 1
|
||||
env->IBAT[1][PARAM1] = T0;
|
||||
#else
|
||||
do_store_ibatl(env, PARAM1, T0);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(load_dbat)
|
||||
@@ -388,21 +389,32 @@ PPC_OP(load_dbat)
|
||||
T0 = regs->DBAT[PARAM(1)][PARAM(2)];
|
||||
}
|
||||
|
||||
PPC_OP(store_dbat)
|
||||
void op_store_dbatu (void)
|
||||
{
|
||||
do_store_dbat(PARAM(1), PARAM(2));
|
||||
do_store_dbatu(env, PARAM1, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_store_dbatl (void)
|
||||
{
|
||||
#if 1
|
||||
env->DBAT[1][PARAM1] = T0;
|
||||
#else
|
||||
do_store_dbatl(env, PARAM1, T0);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* FPSCR */
|
||||
PPC_OP(load_fpscr)
|
||||
{
|
||||
do_load_fpscr();
|
||||
FT0 = do_load_fpscr(env);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(store_fpscr)
|
||||
{
|
||||
do_store_fpscr(PARAM(1));
|
||||
do_store_fpscr(env, FT0, PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -446,7 +458,7 @@ PPC_OP(b)
|
||||
|
||||
PPC_OP(b_T1)
|
||||
{
|
||||
regs->nip = T1;
|
||||
regs->nip = T1 & ~3;
|
||||
}
|
||||
|
||||
PPC_OP(btest)
|
||||
@@ -536,16 +548,10 @@ PPC_OP(add)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addo)
|
||||
void do_addo (void);
|
||||
void op_addo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -562,53 +568,24 @@ PPC_OP(addc)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addco)
|
||||
void do_addco (void);
|
||||
void op_addco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (T0 < T2) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addco();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* add extended */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(adde)
|
||||
void do_adde (void);
|
||||
void op_adde (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
RETURN();
|
||||
do_adde();
|
||||
}
|
||||
|
||||
void do_addeo (void);
|
||||
PPC_OP(addeo)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_addeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -642,18 +619,10 @@ PPC_OP(addme)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addmeo)
|
||||
void do_addmeo (void);
|
||||
void op_addmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca + (-1);
|
||||
if (T1 & (T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T1 != 0)
|
||||
xer_ca = 1;
|
||||
do_addmeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -670,26 +639,14 @@ PPC_OP(addze)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(addzeo)
|
||||
void do_addzeo (void);
|
||||
void op_addzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca;
|
||||
if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_addzeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* divide word */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(divw)
|
||||
{
|
||||
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
|
||||
@@ -700,16 +657,10 @@ PPC_OP(divw)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(divwo)
|
||||
void do_divwo (void);
|
||||
void op_divwo (void)
|
||||
{
|
||||
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = (-1) * (T0 >> 31);
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 = (Ts0 / Ts1);
|
||||
}
|
||||
do_divwo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -724,16 +675,10 @@ PPC_OP(divwu)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(divwuo)
|
||||
void do_divwuo (void);
|
||||
void op_divwuo (void)
|
||||
{
|
||||
if (T1 == 0) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = 0;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 /= T1;
|
||||
}
|
||||
do_divwuo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -765,17 +710,10 @@ PPC_OP(mullw)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(mullwo)
|
||||
void do_mullwo (void);
|
||||
void op_mullwo (void)
|
||||
{
|
||||
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
|
||||
|
||||
if ((int32_t)res != res) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
T0 = (int32_t)res;
|
||||
do_mullwo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -788,15 +726,10 @@ PPC_OP(neg)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(nego)
|
||||
void do_nego (void);
|
||||
void op_nego (void)
|
||||
{
|
||||
if (T0 == 0x80000000) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
T0 = -Ts0;
|
||||
}
|
||||
do_nego();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -807,16 +740,10 @@ PPC_OP(subf)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfo)
|
||||
void do_subfo (void);
|
||||
void op_subfo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_subfo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -832,52 +759,25 @@ PPC_OP(subfc)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfco)
|
||||
void do_subfco (void);
|
||||
void op_subfco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (T0 <= T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
do_subfco();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* substract from extended */
|
||||
/* candidate for helper (too long) */
|
||||
PPC_OP(subfe)
|
||||
void do_subfe (void);
|
||||
void op_subfe (void)
|
||||
{
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfe();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void do_subfeo (void);
|
||||
PPC_OP(subfeo)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -903,18 +803,10 @@ PPC_OP(subfme)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfmeo)
|
||||
void do_subfmeo (void);
|
||||
void op_subfmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca - 1;
|
||||
if (~T1 & (~T1 ^ T0) & (1 << 31)) {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T1 != -1)
|
||||
xer_ca = 1;
|
||||
do_subfmeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -931,21 +823,10 @@ PPC_OP(subfze)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(subfzeo)
|
||||
void do_subfzeo (void);
|
||||
void op_subfzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca;
|
||||
if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
} else {
|
||||
xer_ov = 0;
|
||||
}
|
||||
if (T0 < ~T1) {
|
||||
xer_ca = 1;
|
||||
} else {
|
||||
xer_ca = 0;
|
||||
}
|
||||
do_subfzeo();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -1162,7 +1043,7 @@ PPC_OP(slw)
|
||||
}
|
||||
|
||||
/* shift right algebraic word */
|
||||
PPC_OP(sraw)
|
||||
void op_sraw (void)
|
||||
{
|
||||
do_sraw();
|
||||
RETURN();
|
||||
@@ -1215,10 +1096,9 @@ PPC_OP(fmul)
|
||||
}
|
||||
|
||||
/* fdiv - fdiv. */
|
||||
void do_fdiv (void);
|
||||
PPC_OP(fdiv)
|
||||
{
|
||||
do_fdiv();
|
||||
FT0 = float64_div(FT0, FT1, &env->fp_status);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -1319,25 +1199,24 @@ PPC_OP(fcmpo)
|
||||
|
||||
/*** Floating-point move ***/
|
||||
/* fabs */
|
||||
void do_fabs (void);
|
||||
PPC_OP(fabs)
|
||||
{
|
||||
do_fabs();
|
||||
FT0 = float64_abs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fnabs */
|
||||
void do_fnabs (void);
|
||||
PPC_OP(fnabs)
|
||||
{
|
||||
do_fnabs();
|
||||
FT0 = float64_abs(FT0);
|
||||
FT0 = float64_chs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fneg */
|
||||
PPC_OP(fneg)
|
||||
{
|
||||
FT0 = -FT0;
|
||||
FT0 = float64_chs(FT0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -1355,48 +1234,30 @@ PPC_OP(fneg)
|
||||
/* Special op to check and maybe clear reservation */
|
||||
PPC_OP(check_reservation)
|
||||
{
|
||||
do_check_reservation();
|
||||
if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
|
||||
env->reserve = -1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Return from interrupt */
|
||||
PPC_OP(rfi)
|
||||
void do_rfi (void);
|
||||
void op_rfi (void)
|
||||
{
|
||||
regs->nip = regs->spr[SRR0] & ~0x00000003;
|
||||
#if 1 // TRY
|
||||
T0 = regs->spr[SRR1] & ~0xFFF00000;
|
||||
#else
|
||||
T0 = regs->spr[SRR1] & ~0xFFFF0000;
|
||||
#endif
|
||||
do_store_msr();
|
||||
#if defined (DEBUG_OP)
|
||||
dump_rfi();
|
||||
#endif
|
||||
// do_tlbia();
|
||||
do_raise_exception(EXCP_RFI);
|
||||
do_rfi();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Trap word */
|
||||
PPC_OP(tw)
|
||||
void do_tw (uint32_t cmp, int flags);
|
||||
void op_tw (void)
|
||||
{
|
||||
if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) ||
|
||||
(Ts0 > Ts1 && (PARAM(1) & 0x08)) ||
|
||||
(Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
|
||||
(T0 < T1 && (PARAM(1) & 0x02)) ||
|
||||
(T0 > T1 && (PARAM(1) & 0x01)))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
do_tw(T1, PARAM(1));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
PPC_OP(twi)
|
||||
void op_twi (void)
|
||||
{
|
||||
if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) ||
|
||||
(Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) ||
|
||||
(Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
|
||||
(T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
|
||||
(T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
do_tw(PARAM(1), PARAM(2));
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@@ -1420,3 +1281,9 @@ PPC_OP(tlbie)
|
||||
do_tlbie();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void op_store_pir (void)
|
||||
{
|
||||
env->spr[SPR_PIR] = T0 & 0x0000000FUL;
|
||||
RETURN();
|
||||
}
|
||||
+348
-328
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PPC emulation helpers for qemu.
|
||||
* PowerPC emulation helpers for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
* Copyright (c) 2003-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -29,6 +29,14 @@
|
||||
#include "op_helper_mem.h"
|
||||
#endif
|
||||
|
||||
//#define DEBUG_OP
|
||||
//#define DEBUG_EXCEPTIONS
|
||||
//#define FLUSH_ALL_TLBS
|
||||
|
||||
#define Ts0 (long)((target_long)T0)
|
||||
#define Ts1 (long)((target_long)T1)
|
||||
#define Ts2 (long)((target_long)T2)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exceptions processing helpers */
|
||||
void cpu_loop_exit(void)
|
||||
@@ -42,12 +50,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
|
||||
printf("Raise exception %3x code : %d\n", exception, error_code);
|
||||
#endif
|
||||
switch (exception) {
|
||||
case EXCP_EXTERNAL:
|
||||
case EXCP_DECR:
|
||||
printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n");
|
||||
if (msr_ee == 0)
|
||||
return;
|
||||
break;
|
||||
case EXCP_PROGRAM:
|
||||
if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
|
||||
return;
|
||||
@@ -66,90 +68,229 @@ void do_raise_exception (uint32_t exception)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers for "fat" micro operations */
|
||||
/* Special registers load and store */
|
||||
void do_load_cr (void)
|
||||
/* Fixed point operations helpers */
|
||||
void do_addo (void)
|
||||
{
|
||||
T0 = (env->crf[0] << 28) |
|
||||
(env->crf[1] << 24) |
|
||||
(env->crf[2] << 20) |
|
||||
(env->crf[3] << 16) |
|
||||
(env->crf[4] << 12) |
|
||||
(env->crf[5] << 8) |
|
||||
(env->crf[6] << 4) |
|
||||
(env->crf[7] << 0);
|
||||
}
|
||||
|
||||
void do_store_cr (uint32_t mask)
|
||||
{
|
||||
int i, sh;
|
||||
|
||||
for (i = 0, sh = 7; i < 8; i++, sh --) {
|
||||
if (mask & (1 << sh))
|
||||
env->crf[i] = (T0 >> (sh * 4)) & 0xF;
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_load_xer (void)
|
||||
void do_addco (void)
|
||||
{
|
||||
T0 = (xer_so << XER_SO) |
|
||||
(xer_ov << XER_OV) |
|
||||
(xer_ca << XER_CA) |
|
||||
(xer_bc << XER_BC);
|
||||
}
|
||||
|
||||
void do_store_xer (void)
|
||||
{
|
||||
xer_so = (T0 >> XER_SO) & 0x01;
|
||||
xer_ov = (T0 >> XER_OV) & 0x01;
|
||||
xer_ca = (T0 >> XER_CA) & 0x01;
|
||||
xer_bc = (T0 >> XER_BC) & 0x1f;
|
||||
}
|
||||
|
||||
void do_load_msr (void)
|
||||
{
|
||||
T0 = (msr_pow << MSR_POW) |
|
||||
(msr_ile << MSR_ILE) |
|
||||
(msr_ee << MSR_EE) |
|
||||
(msr_pr << MSR_PR) |
|
||||
(msr_fp << MSR_FP) |
|
||||
(msr_me << MSR_ME) |
|
||||
(msr_fe0 << MSR_FE0) |
|
||||
(msr_se << MSR_SE) |
|
||||
(msr_be << MSR_BE) |
|
||||
(msr_fe1 << MSR_FE1) |
|
||||
(msr_ip << MSR_IP) |
|
||||
(msr_ir << MSR_IR) |
|
||||
(msr_dr << MSR_DR) |
|
||||
(msr_ri << MSR_RI) |
|
||||
(msr_le << MSR_LE);
|
||||
}
|
||||
|
||||
void do_store_msr (void)
|
||||
{
|
||||
#if 1 // TRY
|
||||
if (((T0 >> MSR_IR) & 0x01) != msr_ir ||
|
||||
((T0 >> MSR_DR) & 0x01) != msr_dr ||
|
||||
((T0 >> MSR_PR) & 0x01) != msr_pr)
|
||||
{
|
||||
do_tlbia();
|
||||
T2 = T0;
|
||||
T0 += T1;
|
||||
if (likely(T0 >= T2)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_adde (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_addeo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 += T1 + xer_ca;
|
||||
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_addmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca + (-1);
|
||||
if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T1 != 0))
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
void do_addzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 += xer_ca;
|
||||
if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T0 >= T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_divwo (void)
|
||||
{
|
||||
if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
|
||||
xer_ov = 0;
|
||||
T0 = (Ts0 / Ts1);
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = (-1) * ((uint32_t)T0 >> 31);
|
||||
}
|
||||
}
|
||||
|
||||
void do_divwuo (void)
|
||||
{
|
||||
if (likely((uint32_t)T1 != 0)) {
|
||||
xer_ov = 0;
|
||||
T0 = (uint32_t)T0 / (uint32_t)T1;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
T0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void do_mullwo (void)
|
||||
{
|
||||
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
|
||||
|
||||
if (likely((int32_t)res == res)) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
T0 = (int32_t)res;
|
||||
}
|
||||
|
||||
void do_nego (void)
|
||||
{
|
||||
if (likely(T0 != INT32_MIN)) {
|
||||
xer_ov = 0;
|
||||
T0 = -Ts0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void do_subfco (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 - T0;
|
||||
if (likely(T0 > T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfe (void)
|
||||
{
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfeo (void)
|
||||
{
|
||||
T2 = T0;
|
||||
T0 = T1 + ~T0 + xer_ca;
|
||||
if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void do_subfmeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca - 1;
|
||||
if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_so = 1;
|
||||
xer_ov = 1;
|
||||
}
|
||||
if (likely(T1 != -1))
|
||||
xer_ca = 1;
|
||||
}
|
||||
|
||||
void do_subfzeo (void)
|
||||
{
|
||||
T1 = T0;
|
||||
T0 = ~T0 + xer_ca;
|
||||
if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
|
||||
xer_ov = 0;
|
||||
} else {
|
||||
xer_ov = 1;
|
||||
xer_so = 1;
|
||||
}
|
||||
if (likely(T0 >= ~T1)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
}
|
||||
#endif
|
||||
msr_pow = (T0 >> MSR_POW) & 0x03;
|
||||
msr_ile = (T0 >> MSR_ILE) & 0x01;
|
||||
msr_ee = (T0 >> MSR_EE) & 0x01;
|
||||
msr_pr = (T0 >> MSR_PR) & 0x01;
|
||||
msr_fp = (T0 >> MSR_FP) & 0x01;
|
||||
msr_me = (T0 >> MSR_ME) & 0x01;
|
||||
msr_fe0 = (T0 >> MSR_FE0) & 0x01;
|
||||
msr_se = (T0 >> MSR_SE) & 0x01;
|
||||
msr_be = (T0 >> MSR_BE) & 0x01;
|
||||
msr_fe1 = (T0 >> MSR_FE1) & 0x01;
|
||||
msr_ip = (T0 >> MSR_IP) & 0x01;
|
||||
msr_ir = (T0 >> MSR_IR) & 0x01;
|
||||
msr_dr = (T0 >> MSR_DR) & 0x01;
|
||||
msr_ri = (T0 >> MSR_RI) & 0x01;
|
||||
msr_le = (T0 >> MSR_LE) & 0x01;
|
||||
}
|
||||
|
||||
/* shift right arithmetic helper */
|
||||
@@ -157,95 +298,31 @@ void do_sraw (void)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (likely(!(T1 & 0x20UL))) {
|
||||
if (likely(T1 != 0)) {
|
||||
ret = (int32_t)T0 >> (T1 & 0x1fUL);
|
||||
if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
|
||||
xer_ca = 0;
|
||||
if (T1 & 0x20) {
|
||||
ret = (-1) * (T0 >> 31);
|
||||
if (ret < 0 && (T0 & ~0x80000000) != 0)
|
||||
} else {
|
||||
xer_ca = 1;
|
||||
#if 1 // TRY
|
||||
} else if (T1 == 0) {
|
||||
}
|
||||
} else {
|
||||
ret = T0;
|
||||
#endif
|
||||
xer_ca = 0;
|
||||
}
|
||||
} else {
|
||||
ret = (-1) * ((uint32_t)T0 >> 31);
|
||||
if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
|
||||
xer_ca = 0;
|
||||
} else {
|
||||
ret = (int32_t)T0 >> (T1 & 0x1f);
|
||||
if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0)
|
||||
xer_ca = 1;
|
||||
}
|
||||
}
|
||||
T0 = ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Floating point operations helpers */
|
||||
void do_load_fpscr (void)
|
||||
{
|
||||
/* The 32 MSB of the target fpr are undefined.
|
||||
* They'll be zero...
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define WORD0 0
|
||||
#define WORD1 1
|
||||
#else
|
||||
#define WORD0 1
|
||||
#define WORD1 0
|
||||
#endif
|
||||
u.s.u[WORD0] = 0;
|
||||
u.s.u[WORD1] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
|
||||
FT0 = u.d;
|
||||
}
|
||||
|
||||
void do_store_fpscr (uint32_t mask)
|
||||
{
|
||||
/*
|
||||
* We use only the 32 LSB of the incoming fpr
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i, rnd_type;
|
||||
|
||||
u.d = FT0;
|
||||
if (mask & 0x80)
|
||||
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
|
||||
for (i = 1; i < 7; i++) {
|
||||
if (mask & (1 << (7 - i)))
|
||||
env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
|
||||
}
|
||||
/* TODO: update FEX & VX */
|
||||
/* Set rounding mode */
|
||||
switch (env->fpscr[0] & 0x3) {
|
||||
case 0:
|
||||
/* Best approximation (round to nearest) */
|
||||
rnd_type = float_round_nearest_even;
|
||||
break;
|
||||
case 1:
|
||||
/* Smaller magnitude (round toward zero) */
|
||||
rnd_type = float_round_to_zero;
|
||||
break;
|
||||
case 2:
|
||||
/* Round toward +infinite */
|
||||
rnd_type = float_round_up;
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
/* Round toward -infinite */
|
||||
rnd_type = float_round_down;
|
||||
break;
|
||||
}
|
||||
set_float_rounding_mode(rnd_type, &env->fp_status);
|
||||
}
|
||||
|
||||
void do_fctiw (void)
|
||||
{
|
||||
union {
|
||||
@@ -254,7 +331,7 @@ void do_fctiw (void)
|
||||
} p;
|
||||
|
||||
/* XXX: higher bits are not supposed to be significant.
|
||||
* to make tests easier, return the same as a real PPC 750 (aka G3)
|
||||
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
|
||||
*/
|
||||
p.i = float64_to_int32(FT0, &env->fp_status);
|
||||
p.i |= 0xFFF80000ULL << 32;
|
||||
@@ -269,7 +346,7 @@ void do_fctiwz (void)
|
||||
} p;
|
||||
|
||||
/* XXX: higher bits are not supposed to be significant.
|
||||
* to make tests easier, return the same as a real PPC 750 (aka G3)
|
||||
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
|
||||
*/
|
||||
p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
|
||||
p.i |= 0xFFF80000ULL << 32;
|
||||
@@ -278,29 +355,23 @@ void do_fctiwz (void)
|
||||
|
||||
void do_fnmadd (void)
|
||||
{
|
||||
FT0 = (FT0 * FT1) + FT2;
|
||||
if (!isnan(FT0))
|
||||
FT0 = -FT0;
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
FT0 = float64_add(FT0, FT2, &env->fp_status);
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
|
||||
void do_fnmsub (void)
|
||||
{
|
||||
FT0 = (FT0 * FT1) - FT2;
|
||||
if (!isnan(FT0))
|
||||
FT0 = -FT0;
|
||||
}
|
||||
|
||||
void do_fdiv (void)
|
||||
{
|
||||
if (FT0 == -0.0 && FT1 == -0.0)
|
||||
FT0 = 0.0 / 0.0;
|
||||
else
|
||||
FT0 /= FT1;
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
FT0 = float64_sub(FT0, FT2, &env->fp_status);
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
|
||||
void do_fsqrt (void)
|
||||
{
|
||||
FT0 = sqrt(FT0);
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
}
|
||||
|
||||
void do_fres (void)
|
||||
@@ -310,7 +381,7 @@ void do_fres (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (isnormal(FT0)) {
|
||||
if (likely(isnormal(FT0))) {
|
||||
FT0 = (float)(1.0 / FT0);
|
||||
} else {
|
||||
p.d = FT0;
|
||||
@@ -336,8 +407,9 @@ void do_frsqrte (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (isnormal(FT0) && FT0 > 0.0) {
|
||||
FT0 = (float)(1.0 / sqrt(FT0));
|
||||
if (likely(isnormal(FT0) && FT0 > 0.0)) {
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
FT0 = float32_div(1.0, FT0, &env->fp_status);
|
||||
} else {
|
||||
p.d = FT0;
|
||||
if (p.i == 0x8000000000000000ULL) {
|
||||
@@ -366,16 +438,18 @@ void do_fsel (void)
|
||||
|
||||
void do_fcmpu (void)
|
||||
{
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = 0x01;
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x04UL;
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
env->fpscr[6] |= 0x1;
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = 0x08;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = 0x04;
|
||||
} else {
|
||||
T0 = 0x02;
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
}
|
||||
@@ -383,8 +457,16 @@ void do_fcmpu (void)
|
||||
void do_fcmpo (void)
|
||||
{
|
||||
env->fpscr[4] &= ~0x1;
|
||||
if (isnan(FT0) || isnan(FT1)) {
|
||||
T0 = 0x01;
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x04UL;
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
/* I don't know how to test "quiet" nan... */
|
||||
if (0 /* || ! quiet_nan(...) */) {
|
||||
@@ -394,56 +476,51 @@ void do_fcmpo (void)
|
||||
} else {
|
||||
env->fpscr[4] |= 0x8;
|
||||
}
|
||||
} else if (FT0 < FT1) {
|
||||
T0 = 0x08;
|
||||
} else if (FT0 > FT1) {
|
||||
T0 = 0x04;
|
||||
} else {
|
||||
T0 = 0x02;
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
}
|
||||
|
||||
void do_fabs (void)
|
||||
void do_rfi (void)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
p.d = FT0;
|
||||
p.i &= ~0x8000000000000000ULL;
|
||||
FT0 = p.d;
|
||||
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
|
||||
T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
|
||||
do_store_msr(env, T0);
|
||||
#if defined (DEBUG_OP)
|
||||
dump_rfi();
|
||||
#endif
|
||||
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
}
|
||||
|
||||
void do_fnabs (void)
|
||||
void do_tw (uint32_t cmp, int flags)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
p.d = FT0;
|
||||
p.i |= 0x8000000000000000ULL;
|
||||
FT0 = p.d;
|
||||
if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
|
||||
(Ts0 > (int32_t)cmp && (flags & 0x08)) ||
|
||||
(Ts0 == (int32_t)cmp && (flags & 0x04)) ||
|
||||
(T0 < cmp && (flags & 0x02)) ||
|
||||
(T0 > cmp && (flags & 0x01)))))
|
||||
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
|
||||
}
|
||||
|
||||
/* Instruction cache invalidation helper */
|
||||
#define ICACHE_LINE_SIZE 32
|
||||
|
||||
void do_check_reservation (void)
|
||||
{
|
||||
if ((env->reserve & ~0x03) == T0)
|
||||
env->reserve = -1;
|
||||
}
|
||||
|
||||
void do_icbi (void)
|
||||
{
|
||||
/* Invalidate one cache line */
|
||||
uint32_t tmp;
|
||||
/* Invalidate one cache line :
|
||||
* PowerPC specification says this is to be treated like a load
|
||||
* (not a fetch) by the MMU. To be sure it will be so,
|
||||
* do the load "by hand".
|
||||
*/
|
||||
#if defined(TARGET_PPC64)
|
||||
if (!msr_sf)
|
||||
T0 &= 0xFFFFFFFFULL;
|
||||
#endif
|
||||
tmp = ldl_kernel(T0);
|
||||
T0 &= ~(ICACHE_LINE_SIZE - 1);
|
||||
tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MMU related helpers */
|
||||
/* TLB invalidation helpers */
|
||||
void do_tlbia (void)
|
||||
{
|
||||
@@ -452,119 +529,62 @@ void do_tlbia (void)
|
||||
|
||||
void do_tlbie (void)
|
||||
{
|
||||
#if !defined(FLUSH_ALL_TLBS)
|
||||
tlb_flush_page(env, T0);
|
||||
}
|
||||
|
||||
void do_store_sr (uint32_t srnum)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
dump_store_sr(srnum);
|
||||
#endif
|
||||
#if 0 // TRY
|
||||
{
|
||||
uint32_t base, page;
|
||||
|
||||
base = srnum << 28;
|
||||
for (page = base; page != base + 0x100000000; page += 0x1000)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
#else
|
||||
tlb_flush(env, 1);
|
||||
do_tlbia();
|
||||
#endif
|
||||
env->sr[srnum] = T0;
|
||||
}
|
||||
|
||||
/* For BATs, we may not invalidate any TLBs if the change is only on
|
||||
* protection bits for user mode.
|
||||
*/
|
||||
void do_store_ibat (int ul, int nr)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
dump_store_ibat(ul, nr);
|
||||
#endif
|
||||
#if 0 // TRY
|
||||
{
|
||||
uint32_t base, length, page;
|
||||
|
||||
base = env->IBAT[0][nr];
|
||||
length = (((base >> 2) & 0x000007FF) + 1) << 17;
|
||||
base &= 0xFFFC0000;
|
||||
for (page = base; page != base + length; page += 0x1000)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
#else
|
||||
tlb_flush(env, 1);
|
||||
#endif
|
||||
env->IBAT[ul][nr] = T0;
|
||||
}
|
||||
|
||||
void do_store_dbat (int ul, int nr)
|
||||
{
|
||||
#if defined (DEBUG_OP)
|
||||
dump_store_dbat(ul, nr);
|
||||
#endif
|
||||
#if 0 // TRY
|
||||
{
|
||||
uint32_t base, length, page;
|
||||
base = env->DBAT[0][nr];
|
||||
length = (((base >> 2) & 0x000007FF) + 1) << 17;
|
||||
base &= 0xFFFC0000;
|
||||
for (page = base; page != base + length; page += 0x1000)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
#else
|
||||
tlb_flush(env, 1);
|
||||
#endif
|
||||
env->DBAT[ul][nr] = T0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Special helpers for debug */
|
||||
void dump_state (void)
|
||||
{
|
||||
// cpu_dump_state(env, stdout, fprintf, 0);
|
||||
}
|
||||
/* Softmmu support */
|
||||
#if !defined (CONFIG_USER_ONLY)
|
||||
|
||||
void dump_rfi (void)
|
||||
{
|
||||
#if 0
|
||||
printf("Return from interrupt => 0x%08x\n", env->nip);
|
||||
// cpu_dump_state(env, stdout, fprintf, 0);
|
||||
#endif
|
||||
}
|
||||
#define MMUSUFFIX _mmu
|
||||
#define GETPC() (__builtin_return_address(0))
|
||||
|
||||
void dump_store_sr (int srnum)
|
||||
{
|
||||
#if 0
|
||||
printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0);
|
||||
#endif
|
||||
}
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
static void _dump_store_bat (char ID, int ul, int nr)
|
||||
{
|
||||
printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n",
|
||||
ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip);
|
||||
}
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
void dump_store_ibat (int ul, int nr)
|
||||
{
|
||||
_dump_store_bat('I', ul, nr);
|
||||
}
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
void dump_store_dbat (int ul, int nr)
|
||||
{
|
||||
_dump_store_bat('D', ul, nr);
|
||||
}
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
|
||||
void dump_store_tb (int ul)
|
||||
/* try to fill the TLB and return an exception if error. If retaddr is
|
||||
NULL, it means that the function was called in C code (i.e. not
|
||||
from generated code or from helper.c) */
|
||||
/* XXX: fix it to restore all registers */
|
||||
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
|
||||
{
|
||||
printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0);
|
||||
}
|
||||
TranslationBlock *tb;
|
||||
CPUState *saved_env;
|
||||
target_phys_addr_t pc;
|
||||
int ret;
|
||||
|
||||
void dump_update_tb(uint32_t param)
|
||||
{
|
||||
#if 0
|
||||
printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0);
|
||||
#endif
|
||||
/* XXX: hack to restore env in all cases, even if not called from
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
||||
if (!likely(ret == 0)) {
|
||||
if (likely(retaddr)) {
|
||||
/* now we have a real cpu fault */
|
||||
pc = (target_phys_addr_t)retaddr;
|
||||
tb = tb_find_pc(pc);
|
||||
if (likely(tb)) {
|
||||
/* the PC is inside the translated code. It means that we have
|
||||
a virtual CPU fault */
|
||||
cpu_restore_state(tb, env, pc, NULL);
|
||||
}
|
||||
}
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
}
|
||||
env = saved_env;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
@@ -3,10 +3,12 @@ void glue(do_lsw, MEMSUFFIX) (int dst)
|
||||
uint32_t tmp;
|
||||
int sh;
|
||||
|
||||
#if 0
|
||||
if (loglevel > 0) {
|
||||
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
|
||||
__func__, T0, T1, dst);
|
||||
}
|
||||
#endif
|
||||
for (; T1 > 3; T1 -= 4, T0 += 4) {
|
||||
ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
|
||||
if (dst == 32)
|
||||
@@ -25,10 +27,12 @@ void glue(do_stsw, MEMSUFFIX) (int src)
|
||||
{
|
||||
int sh;
|
||||
|
||||
#if 0
|
||||
if (loglevel > 0) {
|
||||
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
|
||||
__func__, T0, T1, src);
|
||||
}
|
||||
#endif
|
||||
for (; T1 > 3; T1 -= 4, T0 += 4) {
|
||||
glue(stl, MEMSUFFIX)(T0, ugpr(src++));
|
||||
if (src == 32)
|
||||
@@ -45,10 +49,12 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
|
||||
uint32_t tmp;
|
||||
int sh;
|
||||
|
||||
#if 0
|
||||
if (loglevel > 0) {
|
||||
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
|
||||
__func__, T0, T1, dst);
|
||||
}
|
||||
#endif
|
||||
for (; T1 > 3; T1 -= 4, T0 += 4) {
|
||||
tmp = glue(ldl, MEMSUFFIX)(T0);
|
||||
ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
|
||||
@@ -70,10 +76,12 @@ void glue(do_stsw_le, MEMSUFFIX) (int src)
|
||||
uint32_t tmp;
|
||||
int sh;
|
||||
|
||||
#if 0
|
||||
if (loglevel > 0) {
|
||||
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
|
||||
__func__, T0, T1, src);
|
||||
}
|
||||
#endif
|
||||
for (; T1 > 3; T1 -= 4, T0 += 4) {
|
||||
tmp = ((ugpr(src++) & 0xFF000000) >> 24);
|
||||
tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* PPC emulation micro-operations for qemu.
|
||||
* PowerPC emulation micro-operations for qemu.
|
||||
*
|
||||
* Copyright (c) 2003 Jocelyn Mayer
|
||||
* Copyright (c) 2003-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -175,7 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void)
|
||||
|
||||
void OPPROTO glue(op_store_sr, REG)(void)
|
||||
{
|
||||
do_store_sr(REG);
|
||||
do_store_sr(env, REG, T0);
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
+147
-888
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+99
-10
@@ -6,12 +6,13 @@
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_FPREGS 32
|
||||
#define TARGET_FPREG_T float
|
||||
#define TARGET_PAGE_BITS 12 /* 4k */
|
||||
#else
|
||||
#define TARGET_LONG_BITS 64
|
||||
#define TARGET_FPREGS 64
|
||||
#define TARGET_FPREG_T double
|
||||
#define TARGET_PAGE_BITS 12 /* XXX */
|
||||
#endif
|
||||
#define TARGET_FPREG_T float
|
||||
|
||||
#include "cpu-defs.h"
|
||||
|
||||
@@ -22,6 +23,7 @@
|
||||
/*#define EXCP_INTERRUPT 0x100*/
|
||||
|
||||
/* trap definitions */
|
||||
#ifndef TARGET_SPARC64
|
||||
#define TT_TFAULT 0x01
|
||||
#define TT_ILL_INSN 0x02
|
||||
#define TT_PRIV_INSN 0x03
|
||||
@@ -33,6 +35,25 @@
|
||||
#define TT_EXTINT 0x10
|
||||
#define TT_DIV_ZERO 0x2a
|
||||
#define TT_TRAP 0x80
|
||||
#else
|
||||
#define TT_TFAULT 0x08
|
||||
#define TT_TMISS 0x09
|
||||
#define TT_ILL_INSN 0x10
|
||||
#define TT_PRIV_INSN 0x11
|
||||
#define TT_NFPU_INSN 0x20
|
||||
#define TT_FP_EXCP 0x21
|
||||
#define TT_CLRWIN 0x24
|
||||
#define TT_DIV_ZERO 0x28
|
||||
#define TT_DFAULT 0x30
|
||||
#define TT_DMISS 0x31
|
||||
#define TT_DPROT 0x32
|
||||
#define TT_PRIV_ACT 0x37
|
||||
#define TT_EXTINT 0x40
|
||||
#define TT_SPILL 0x80
|
||||
#define TT_FILL 0xc0
|
||||
#define TT_WOTHER 0x10
|
||||
#define TT_TRAP 0x100
|
||||
#endif
|
||||
|
||||
#define PSR_NEG (1<<23)
|
||||
#define PSR_ZERO (1<<22)
|
||||
@@ -49,6 +70,17 @@
|
||||
/* Trap base register */
|
||||
#define TBR_BASE_MASK 0xfffff000
|
||||
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define PS_IG (1<<11)
|
||||
#define PS_MG (1<<10)
|
||||
#define PS_RED (1<<5)
|
||||
#define PS_PEF (1<<4)
|
||||
#define PS_AM (1<<3)
|
||||
#define PS_PRIV (1<<2)
|
||||
#define PS_IE (1<<1)
|
||||
#define PS_AG (1<<0)
|
||||
#endif
|
||||
|
||||
/* Fcc */
|
||||
#define FSR_RD1 (1<<31)
|
||||
#define FSR_RD0 (1<<30)
|
||||
@@ -119,15 +151,15 @@ typedef struct CPUSPARCState {
|
||||
target_ulong npc; /* next program counter */
|
||||
target_ulong y; /* multiply/divide register */
|
||||
uint32_t psr; /* processor state register */
|
||||
uint32_t fsr; /* FPU state register */
|
||||
target_ulong fsr; /* FPU state register */
|
||||
uint32_t cwp; /* index of current register window (extracted
|
||||
from PSR) */
|
||||
uint32_t wim; /* window invalid mask */
|
||||
uint32_t tbr; /* trap base register */
|
||||
target_ulong tbr; /* trap base register */
|
||||
int psrs; /* supervisor mode (extracted from PSR) */
|
||||
int psrps; /* previous supervisor mode */
|
||||
int psret; /* enable traps */
|
||||
int psrpil; /* interrupt level */
|
||||
uint32_t psrpil; /* interrupt level */
|
||||
int psref; /* enable fpu */
|
||||
jmp_buf jmp_env;
|
||||
int user_mode_only;
|
||||
@@ -144,19 +176,51 @@ typedef struct CPUSPARCState {
|
||||
context) */
|
||||
unsigned long mem_write_pc; /* host pc at which the memory was
|
||||
written */
|
||||
unsigned long mem_write_vaddr; /* target virtual addr at which the
|
||||
target_ulong mem_write_vaddr; /* target virtual addr at which the
|
||||
memory was written */
|
||||
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
|
||||
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
|
||||
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
|
||||
/* MMU regs */
|
||||
#if defined(TARGET_SPARC64)
|
||||
uint64_t lsu;
|
||||
#define DMMU_E 0x8
|
||||
#define IMMU_E 0x4
|
||||
uint64_t immuregs[16];
|
||||
uint64_t dmmuregs[16];
|
||||
uint64_t itlb_tag[64];
|
||||
uint64_t itlb_tte[64];
|
||||
uint64_t dtlb_tag[64];
|
||||
uint64_t dtlb_tte[64];
|
||||
#else
|
||||
uint32_t mmuregs[16];
|
||||
#endif
|
||||
/* temporary float registers */
|
||||
float ft0, ft1, ft2;
|
||||
double dt0, dt1, dt2;
|
||||
float ft0, ft1;
|
||||
double dt0, dt1;
|
||||
float_status fp_status;
|
||||
#if defined(TARGET_SPARC64)
|
||||
target_ulong t0, t1, t2;
|
||||
#define MAXTL 4
|
||||
uint64_t t0, t1, t2;
|
||||
uint64_t tpc[MAXTL];
|
||||
uint64_t tnpc[MAXTL];
|
||||
uint64_t tstate[MAXTL];
|
||||
uint32_t tt[MAXTL];
|
||||
uint32_t xcc; /* Extended integer condition codes */
|
||||
uint32_t asi;
|
||||
uint32_t pstate;
|
||||
uint32_t tl;
|
||||
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
|
||||
uint64_t agregs[8]; /* alternate general registers */
|
||||
uint64_t bgregs[8]; /* backup for normal global registers */
|
||||
uint64_t igregs[8]; /* interrupt general registers */
|
||||
uint64_t mgregs[8]; /* mmu general registers */
|
||||
uint64_t version;
|
||||
uint64_t fprs;
|
||||
uint64_t tick_cmpr, stick_cmpr;
|
||||
#endif
|
||||
#if !defined(TARGET_SPARC64) && !defined(reg_T2)
|
||||
target_ulong t2;
|
||||
#endif
|
||||
|
||||
/* ice debug support */
|
||||
@@ -165,6 +229,24 @@ typedef struct CPUSPARCState {
|
||||
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
|
||||
|
||||
} CPUSPARCState;
|
||||
#if defined(TARGET_SPARC64)
|
||||
#define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
|
||||
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
|
||||
env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \
|
||||
} while (0)
|
||||
#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL)
|
||||
#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \
|
||||
env->fsr = _tmp & 0x3fcfc1c3ffULL; \
|
||||
} while (0)
|
||||
// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II)
|
||||
#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \
|
||||
(0 << 24) | (MAXTL << 8) | (NWINDOWS - 1))
|
||||
#else
|
||||
#define GET_FSR32(env) (env->fsr)
|
||||
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
|
||||
env->fsr = _tmp & 0xcfc1ffff; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
CPUSPARCState *cpu_sparc_init(void);
|
||||
int cpu_sparc_exec(CPUSPARCState *s);
|
||||
@@ -194,10 +276,17 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
|
||||
cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC))
|
||||
#define PUT_CCR(env, val) do { int _tmp = val; \
|
||||
env->xcc = _tmp >> 4; \
|
||||
env->psr = (_tmp & 0xf) << 20; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
struct siginfo;
|
||||
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
||||
|
||||
#define TARGET_PAGE_BITS 12 /* 4k */
|
||||
#include "cpu-all.h"
|
||||
|
||||
#endif
|
||||
+36
-5
@@ -1,23 +1,41 @@
|
||||
#ifndef EXEC_SPARC_H
|
||||
#define EXEC_SPARC_H 1
|
||||
#include "dyngen-exec.h"
|
||||
#include "config.h"
|
||||
|
||||
register struct CPUSPARCState *env asm(AREG0);
|
||||
#ifdef TARGET_SPARC64
|
||||
#define T0 (env->t0)
|
||||
#define T1 (env->t1)
|
||||
#define T2 (env->t2)
|
||||
#define REGWPTR env->regwptr
|
||||
#else
|
||||
register uint32_t T0 asm(AREG1);
|
||||
register uint32_t T1 asm(AREG2);
|
||||
register uint32_t T2 asm(AREG3);
|
||||
|
||||
#undef REG_REGWPTR // Broken
|
||||
#ifdef REG_REGWPTR
|
||||
register uint32_t *REGWPTR asm(AREG3);
|
||||
#define reg_REGWPTR
|
||||
|
||||
#ifdef AREG4
|
||||
register uint32_t T2 asm(AREG4);
|
||||
#define reg_T2
|
||||
#else
|
||||
#define T2 (env->t2)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define REGWPTR env->regwptr
|
||||
register uint32_t T2 asm(AREG3);
|
||||
#define reg_T2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FT0 (env->ft0)
|
||||
#define FT1 (env->ft1)
|
||||
#define FT2 (env->ft2)
|
||||
#define DT0 (env->dt0)
|
||||
#define DT1 (env->dt1)
|
||||
#define DT2 (env->dt2)
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
@@ -38,14 +56,27 @@ void do_fsqrts(void);
|
||||
void do_fsqrtd(void);
|
||||
void do_fcmps(void);
|
||||
void do_fcmpd(void);
|
||||
#ifdef TARGET_SPARC64
|
||||
void do_fabsd(void);
|
||||
void do_fcmps_fcc1(void);
|
||||
void do_fcmpd_fcc1(void);
|
||||
void do_fcmps_fcc2(void);
|
||||
void do_fcmpd_fcc2(void);
|
||||
void do_fcmps_fcc3(void);
|
||||
void do_fcmpd_fcc3(void);
|
||||
void do_popc();
|
||||
void do_wrpstate();
|
||||
void do_done();
|
||||
void do_retry();
|
||||
#endif
|
||||
void do_ldd_kernel(target_ulong addr);
|
||||
void do_ldd_user(target_ulong addr);
|
||||
void do_ldd_raw(target_ulong addr);
|
||||
void do_interrupt(int intno);
|
||||
void raise_exception(int tt);
|
||||
void memcpy32(target_ulong *dst, const target_ulong *src);
|
||||
target_ulong mmu_probe(target_ulong address, int mmulev);
|
||||
void dump_mmu(void);
|
||||
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
|
||||
void dump_mmu(CPUState *env);
|
||||
void helper_debug();
|
||||
void do_wrpsr();
|
||||
void do_rdpsr();
|
||||
|
||||
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user