From: yajin Date: Wed, 14 Jan 2009 22:56:30 +0000 (+0800) Subject: merage qemu master X-Git-Url: https://repo.or.cz/w/qemu/qemu-JZ.git/commitdiff_plain/ee4babaa782631ed963118c77d2c0c7051e6e71c merage qemu master --- diff --git a/Makefile b/Makefile index 871970aa7c..8cbdcda136 100644 --- a/Makefile +++ b/Makefile @@ -221,8 +221,9 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr ifdef INSTALL_BLOBS BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -video.x openbios-sparc32 openbios-sparc64 pxe-ne2k_pci.bin \ -pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin bamboo.dtb +video.x openbios-sparc32 openbios-sparc64 openbios-ppc \ +pxe-ne2k_pci.bin pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin \ +bamboo.dtb else BLOBS= endif @@ -354,6 +355,7 @@ tarbin: $(datadir)/video.x \ $(datadir)/openbios-sparc32 \ $(datadir)/openbios-sparc64 \ + $(datadir)/openbios-ppc \ $(datadir)/pxe-ne2k_pci.bin \ $(datadir)/pxe-rtl8139.bin \ $(datadir)/pxe-pcnet.bin \ diff --git a/Makefile.target b/Makefile.target index 5db1302203..1718d86c6f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -593,10 +593,7 @@ ifdef CONFIG_OSS LIBS += $(CONFIG_OSS_LIB) endif -SOUND_HW = sb16.o es1370.o -ifdef CONFIG_AC97 -SOUND_HW += ac97.o -endif +SOUND_HW = sb16.o es1370.o ac97.o ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o adlib.o fmopl.o: CFLAGS := ${CFLAGS} -DBUILD_Y8950=0 @@ -649,7 +646,7 @@ OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o OBJS+= prep_pci.o ppc_prep.o # Mac shared devices -OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o +OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o escc.o # OldWorld PowerMac OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o # NewWorld PowerMac @@ -666,7 +663,7 @@ OBJS+= kvm_ppc.o endif endif ifeq ($(TARGET_BASE_ARCH), mips) -OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o mips_pavo.o +OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o mips_pavo.o nand_bpage.o OBJS+= mips_jz.o mips_jz_clk.o OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o OBJS+= g364fb.o jazz_led.o @@ -697,7 +694,7 @@ OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o OBJS+= cirrus_vga.o parallel.o ptimer.o else OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o -OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o sparc32_dma.o +OBJS+= slavio_timer.o escc.o slavio_misc.o fdc.o sparc32_dma.o OBJS+= cs4231.o ptimer.o eccmemctl.o sbi.o sun4c_intctl.o endif endif diff --git a/block-qcow.c b/block-qcow.c index 1fecf3078b..91c53b1b8e 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -339,28 +339,33 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, return -1; } else { cluster_offset = bdrv_getlength(s->hd); - /* round to cluster size */ - cluster_offset = (cluster_offset + s->cluster_size - 1) & - ~(s->cluster_size - 1); - bdrv_truncate(s->hd, cluster_offset + s->cluster_size); - /* if encrypted, we must initialize the cluster - content which won't be written */ - if (s->crypt_method && - (n_end - n_start) < s->cluster_sectors) { - uint64_t start_sect; - start_sect = (offset & ~(s->cluster_size - 1)) >> 9; - memset(s->cluster_data + 512, 0x00, 512); - for(i = 0; i < s->cluster_sectors; i++) { - if (i < n_start || i >= n_end) { - encrypt_sectors(s, start_sect + i, - s->cluster_data, - s->cluster_data + 512, 1, 1, - &s->aes_encrypt_key); - if (bdrv_pwrite(s->hd, cluster_offset + i * 512, - s->cluster_data, 512) != 512) - return -1; + if (allocate == 1) { + /* round to cluster size */ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + bdrv_truncate(s->hd, cluster_offset + s->cluster_size); + /* if encrypted, we must initialize the cluster + content which won't be written */ + if (s->crypt_method && + (n_end - n_start) < s->cluster_sectors) { + uint64_t start_sect; + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; + memset(s->cluster_data + 512, 0x00, 512); + for(i = 0; i < s->cluster_sectors; i++) { + if (i < n_start || i >= n_end) { + encrypt_sectors(s, start_sect + i, + s->cluster_data, + s->cluster_data + 512, 1, 1, + &s->aes_encrypt_key); + if (bdrv_pwrite(s->hd, cluster_offset + i * 512, + s->cluster_data, 512) != 512) + return -1; + } } } + } else if (allocate == 2) { + cluster_offset |= QCOW_OFLAG_COMPRESSED | + (uint64_t)compressed_size << (63 - s->cluster_bits); } } /* update L2 table */ diff --git a/block-qcow2.c b/block-qcow2.c index 707109e449..9aa7261e3f 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -2024,6 +2024,7 @@ static int qcow_snapshot_create(BlockDriverState *bs, if (!snapshots1) goto fail; memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); + qemu_free(s->snapshots); s->snapshots = snapshots1; s->snapshots[s->nb_snapshots++] = *sn; diff --git a/cache-utils.c b/cache-utils.c index 7c98144ae5..7df1fcf51c 100644 --- a/cache-utils.c +++ b/cache-utils.c @@ -1,6 +1,6 @@ #include "cache-utils.h" -#ifdef __powerpc__ +#if defined HOST_PPC || defined HOST_PPC64 struct qemu_cache_conf qemu_cache_conf = { .dcache_bsize = 16, .icache_bsize = 16 @@ -68,4 +68,4 @@ void qemu_cache_utils_init(char **envp) } #endif -#endif /* __powerpc__ */ +#endif /* HOST_PPC || HOST_PPC64 */ diff --git a/cache-utils.h b/cache-utils.h index 0598b96eba..8847dbbf7b 100644 --- a/cache-utils.h +++ b/cache-utils.h @@ -1,7 +1,9 @@ #ifndef QEMU_CACHE_UTILS_H #define QEMU_CACHE_UTILS_H -#ifdef __powerpc__ +#include "config-host.h" + +#if defined HOST_PPC || defined HOST_PPC64 struct qemu_cache_conf { unsigned long dcache_bsize; unsigned long icache_bsize; diff --git a/configure b/configure index 0d18534e68..a8ea55a6e4 100755 --- a/configure +++ b/configure @@ -27,7 +27,8 @@ static="no" cross_prefix="" cc="gcc" audio_drv_list="" -audio_card_list="" +audio_card_list="ac97 es1370 sb16" +audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus" host_cc="gcc" ar="ar" make="make" @@ -519,8 +520,8 @@ echo " --disable-sdl disable SDL" echo " --enable-cocoa enable COCOA (Mac OS X only)" echo " --audio-drv-list=LIST set audio drivers list:" echo " Available drivers: $audio_possible_drivers" -echo " --audio-card-list=LIST set list of additional emulated audio cards" -echo " Available cards: ac97 adlib cs4231a gus" +echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_list]" +echo " Available cards: $audio_possible_cards" echo " --enable-mixemu enable mixer emulation" echo " --disable-brlapi disable BrlAPI" echo " --disable-vnc-tls disable TLS encryption for VNC server" @@ -963,6 +964,12 @@ int main(void) { return 0; } EOF if test "$kerneldir" != "" ; then kvm_cflags=-I"$kerneldir"/include + if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) \ + -a -d "$kerneldir/arch/x86/include" ; then + kvm_cflags="$kvm_cflags -I$kerneldir/arch/x86/include" + elif test -d "$kerneldir/arch/$cpu/include" ; then + kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include" + fi else kvm_cflags="" fi diff --git a/cpu-exec.c b/cpu-exec.c index f574877e6f..e179786232 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -424,6 +424,16 @@ int cpu_exec(CPUState *env1) next_tb = 0; } #elif defined(TARGET_MIPS) +if (interrupt_request & CPU_INTERRUPT_HARD) +{ +if (env->CP0_Cause&0x400) +{ + printf("HARD INT \n"); + printf("env->CP0_Status %x env->CP0_Cause %x CP0Ca_IP_mask %x \n",env->CP0_Status,env->CP0_Cause,CP0Ca_IP_mask); + printf("CP0St_IE %x CP0St_EXL %x CP0St_ERL %x \n",CP0St_IE,CP0St_EXL,CP0St_ERL); + printf("env->hflags %x MIPS_HFLAG_DM %x \n",env->hflags ,MIPS_HFLAG_DM); +} +} if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && (env->CP0_Status & (1 << CP0St_IE)) && diff --git a/exec.c b/exec.c index e633b74dc0..a19c06c9cf 100644 --- a/exec.c +++ b/exec.c @@ -2379,6 +2379,8 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif +//printf("Unassigned mem readb " TARGET_FMT_plx " pc %x \n", addr,cpu_single_env->active_tc.PC); +//exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 0, 0, 0, 1); #endif @@ -2390,6 +2392,8 @@ static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr) #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif +//printf("Unassigned mem readw " TARGET_FMT_plx " pc %x \n", addr,cpu_single_env->active_tc.PC); +//exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 0, 0, 0, 2); #endif @@ -2401,6 +2405,8 @@ static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr) #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif +//printf("Unassigned mem readl " TARGET_FMT_plx " pc %x \n", addr,cpu_single_env->active_tc.PC); +//exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 0, 0, 0, 4); #endif @@ -2412,6 +2418,8 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); #endif +//printf("Unassigned mem writeb " TARGET_FMT_plx " = 0x%x PC %x \n", addr, val,cpu_single_env->active_tc.PC); +//if (addr!=0x20 )exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 1, 0, 0, 1); #endif @@ -2422,6 +2430,8 @@ static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); #endif +//printf("Unassigned mem writew " TARGET_FMT_plx " = 0x%x PC %x \n", addr, val,cpu_single_env->active_tc.PC); +//exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 1, 0, 0, 2); #endif @@ -2432,6 +2442,8 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); #endif +//printf("Unassigned mem writel " TARGET_FMT_plx " = 0x%x PC %x \n", addr, val,cpu_single_env->active_tc.PC); +//exit(-1); #if defined(TARGET_SPARC) do_unassigned_access(addr, 1, 0, 0, 4); #endif diff --git a/gdbstub.c b/gdbstub.c index b8198ee29f..a3ff07aed9 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -694,7 +694,7 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) #define NUM_CORE_REGS 86 #else -#define NUM_CORE_REGS 73 +#define NUM_CORE_REGS 72 #endif #ifdef TARGET_ABI32 @@ -728,7 +728,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) case 69: GET_REGA(env->npc); case 70: GET_REGA(env->fsr); case 71: GET_REGA(0); /* csr */ - case 72: GET_REGA(0); + default: GET_REGA(0); } #else if (n < 64) { diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index 70d4af6b2a..151f3c2ab5 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -998,12 +998,12 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, uint64_t physical, page_size, end; int prot, zbits, ret; - if (env->user_mode_only) { +#if defined(CONFIG_USER_ONLY) ret = 2; - } else { +#else ret = virtual_to_physical(env, &physical, &zbits, &prot, address, mmu_idx, rw); - } +#endif switch (ret) { case 0: /* No fault */ diff --git a/hw/apb_pci.c b/hw/apb_pci.c index d847888549..f222f3c0eb 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -22,12 +22,23 @@ * THE SOFTWARE. */ -/* XXX This file and most of its contests are somewhat misnamed. The +/* XXX This file and most of its contents are somewhat misnamed. The Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is the secondary PCI bridge. */ #include "hw.h" #include "pci.h" + +/* debug APB */ +//#define DEBUG_APB + +#ifdef DEBUG_APB +#define APB_DPRINTF(fmt, args...) \ +do { printf("APB: " fmt , ##args); } while (0) +#else +#define APB_DPRINTF(fmt, args...) +#endif + typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" @@ -37,13 +48,13 @@ static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { APBState *s = opaque; - int i; - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } - s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + APB_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr, + val); + s->config_reg = val; } static uint32_t pci_apb_config_readl (void *opaque, @@ -51,10 +62,13 @@ static uint32_t pci_apb_config_readl (void *opaque, { APBState *s = opaque; uint32_t val; - int devfn; - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); + val = s->config_reg; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + APB_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr, + val); return val; } @@ -209,12 +223,11 @@ static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level) PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, - qemu_irq *pic) + qemu_irq *pic, PCIBus **bus2, PCIBus **bus3) { APBState *s; PCIDevice *d; int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - PCIBus *secondary; s = qemu_mallocz(sizeof(APBState)); /* Ultrasparc PBM main bus */ @@ -255,9 +268,9 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, d->config[0x0E] = 0x00; // header_type /* APB secondary busses */ - secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 1"); - pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 2"); - return secondary; + *bus2 = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, + "Advanced PCI Bus secondary bridge 1"); + *bus3 = pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, + "Advanced PCI Bus secondary bridge 2"); + return s->bus; } diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index f7bdd1465b..066b96944c 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -303,12 +303,10 @@ void axisdev88_init (ram_addr_t ram_size, int vga_ram_size, } /* Add the two ethernet blocks. */ - nd_table[0].model = nd_table[0].model ? nd_table[0].model : "fseth"; - eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000); - if (nb_nics > 1) { - nd_table[1].model = nd_table[1].model ? nd_table[1].model : "fseth"; - eth[1] = etraxfs_eth_init(&nd_table[1], env, pic->irq + 26, 0x30036000); - } + eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000, 1); + if (nb_nics > 1) + eth[1] = etraxfs_eth_init(&nd_table[1], env, + pic->irq + 26, 0x30036000, 2); /* The DMA Connector block is missing, hardwire things for now. */ etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); diff --git a/hw/e1000.c b/hw/e1000.c index 09cb96a0a6..ccf9bc0e74 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -570,6 +570,21 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) return 0; } +static void +e1000_set_link_status(VLANClientState *vc) +{ + E1000State *s = vc->opaque; + uint32_t old_status = s->mac_reg[STATUS]; + + if (vc->link_down) + s->mac_reg[STATUS] &= ~E1000_STATUS_LU; + else + s->mac_reg[STATUS] |= E1000_STATUS_LU; + + if (s->mac_reg[STATUS] != old_status) + set_ics(s, 0, E1000_ICR_LSC); +} + static int e1000_can_receive(void *opaque) { @@ -1073,6 +1088,7 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, e1000_receive, e1000_can_receive, d); + d->vc->link_status_changed = e1000_set_link_status; qemu_format_nic_info_str(d->vc, d->nd->macaddr); diff --git a/hw/slavio_serial.c b/hw/escc.c similarity index 85% rename from hw/slavio_serial.c rename to hw/escc.c index 1028ed944c..372ad5acf4 100644 --- a/hw/slavio_serial.c +++ b/hw/escc.c @@ -1,5 +1,5 @@ /* - * QEMU Sparc SLAVIO serial port emulation + * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation * * Copyright (c) 2003-2005 Fabrice Bellard * @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "sun4m.h" +#include "escc.h" #include "qemu-char.h" #include "console.h" @@ -36,7 +36,7 @@ //#define DEBUG_MOUSE /* - * This is the serial port, mouse and keyboard part of chip STP2001 + * On Sparc32 this is the serial port, mouse and keyboard 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 * @@ -44,6 +44,14 @@ * mouse and keyboard ports don't implement all functions and they are * only asynchronous. There is no DMA. * + * Z85C30 is also used on PowerMacs. There are some small differences + * between Sparc version (sunzilog) and PowerMac (pmac): + * Offset between control and data registers + * There is some kind of lockup bug, but we can ignore it + * CTS is inverted + * DMA on pmac using DBDMA chip + * pmac can do IRDA and faster rates, sunzilog can only do 38400 + * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz */ /* @@ -102,13 +110,14 @@ typedef struct ChannelState { CharDriverState *chr; int e0_mode, led_mode, caps_lock_mode, num_lock_mode; int disabled; + int clock; } ChannelState; struct SerialState { struct ChannelState chn[2]; + int it_shift; }; -#define SERIAL_SIZE 8 #define SERIAL_CTRL 0 #define SERIAL_DATA 1 @@ -257,7 +266,7 @@ static uint32_t get_queue(void *opaque) return val; } -static int slavio_serial_update_irq_chn(ChannelState *s) +static int escc_update_irq_chn(ChannelState *s) { if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) || // tx ints enabled, pending @@ -271,23 +280,23 @@ static int slavio_serial_update_irq_chn(ChannelState *s) return 0; } -static void slavio_serial_update_irq(ChannelState *s) +static void escc_update_irq(ChannelState *s) { int irq; - irq = slavio_serial_update_irq_chn(s); - irq |= slavio_serial_update_irq_chn(s->otherchn); + irq = escc_update_irq_chn(s); + irq |= escc_update_irq_chn(s->otherchn); SER_DPRINTF("IRQ = %d\n", irq); qemu_set_irq(s->irq, irq); } -static void slavio_serial_reset_chn(ChannelState *s) +static void escc_reset_chn(ChannelState *s) { int i; s->reg = 0; - for (i = 0; i < SERIAL_SIZE; i++) { + for (i = 0; i < SERIAL_REGS; i++) { s->rregs[i] = 0; s->wregs[i] = 0; } @@ -311,11 +320,11 @@ static void slavio_serial_reset_chn(ChannelState *s) clear_queue(s); } -static void slavio_serial_reset(void *opaque) +static void escc_reset(void *opaque) { SerialState *s = opaque; - slavio_serial_reset_chn(&s->chn[0]); - slavio_serial_reset_chn(&s->chn[1]); + escc_reset_chn(&s->chn[0]); + escc_reset_chn(&s->chn[1]); } static inline void set_rxint(ChannelState *s) @@ -339,7 +348,7 @@ static inline void set_rxint(ChannelState *s) s->rregs[R_INTR] |= INTR_RXINTA; else s->otherchn->rregs[R_INTR] |= INTR_RXINTB; - slavio_serial_update_irq(s); + escc_update_irq(s); } static inline void set_txint(ChannelState *s) @@ -360,7 +369,7 @@ static inline void set_txint(ChannelState *s) s->rregs[R_INTR] |= INTR_TXINTA; else s->otherchn->rregs[R_INTR] |= INTR_TXINTB; - slavio_serial_update_irq(s); + escc_update_irq(s); } static inline void clr_rxint(ChannelState *s) @@ -382,7 +391,7 @@ static inline void clr_rxint(ChannelState *s) } if (s->txint) set_txint(s); - slavio_serial_update_irq(s); + escc_update_irq(s); } static inline void clr_txint(ChannelState *s) @@ -404,10 +413,10 @@ static inline void clr_txint(ChannelState *s) } if (s->rxint) set_rxint(s); - slavio_serial_update_irq(s); + escc_update_irq(s); } -static void slavio_serial_update_parameters(ChannelState *s) +static void escc_update_parameters(ChannelState *s) { int speed, parity, data_bits, stop_bits; QEMUSerialSetParams ssp; @@ -442,7 +451,7 @@ static void slavio_serial_update_parameters(ChannelState *s) data_bits = 8; break; } - speed = 2457600 / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2); + speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2); switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) { case TXCTRL1_CLK1X: break; @@ -466,8 +475,7 @@ static void slavio_serial_update_parameters(ChannelState *s) qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); } -static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) +static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { SerialState *serial = opaque; ChannelState *s; @@ -475,8 +483,8 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, int newreg, channel; val &= 0xff; - saddr = (addr & 3) >> 1; - channel = addr >> 2; + saddr = (addr >> serial->it_shift) & 1; + channel = (addr >> (serial->it_shift + 1)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -513,13 +521,13 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, case W_TXCTRL1: case W_TXCTRL2: s->wregs[s->reg] = val; - slavio_serial_update_parameters(s); + escc_update_parameters(s); break; case W_BRGLO: case W_BRGHI: s->wregs[s->reg] = val; s->rregs[s->reg] = val; - slavio_serial_update_parameters(s); + escc_update_parameters(s); break; case W_MINTR: switch (val & MINTR_RST_MASK) { @@ -527,13 +535,13 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, default: break; case MINTR_RST_B: - slavio_serial_reset_chn(&serial->chn[0]); + escc_reset_chn(&serial->chn[0]); return; case MINTR_RST_A: - slavio_serial_reset_chn(&serial->chn[1]); + escc_reset_chn(&serial->chn[1]); return; case MINTR_RST_ALL: - slavio_serial_reset(serial); + escc_reset(serial); return; } break; @@ -564,7 +572,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, } } -static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) +static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr) { SerialState *serial = opaque; ChannelState *s; @@ -572,8 +580,8 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret; int channel; - saddr = (addr & 3) >> 1; - channel = addr >> 2; + saddr = (addr >> serial->it_shift) & 1; + channel = (addr >> (serial->it_shift + 1)) & 1; s = &serial->chn[channel]; switch (saddr) { case SERIAL_CTRL: @@ -624,7 +632,7 @@ static void serial_receive_byte(ChannelState *s, int ch) static void serial_receive_break(ChannelState *s) { s->rregs[R_STATUS] |= STATUS_BRK; - slavio_serial_update_irq(s); + escc_update_irq(s); } static void serial_receive1(void *opaque, const uint8_t *buf, int size) @@ -640,19 +648,19 @@ static void serial_event(void *opaque, int event) serial_receive_break(s); } -static CPUReadMemoryFunc *slavio_serial_mem_read[3] = { - slavio_serial_mem_readb, +static CPUReadMemoryFunc *escc_mem_read[3] = { + escc_mem_readb, NULL, NULL, }; -static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { - slavio_serial_mem_writeb, +static CPUWriteMemoryFunc *escc_mem_write[3] = { + escc_mem_writeb, NULL, NULL, }; -static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) +static void escc_save_chn(QEMUFile *f, ChannelState *s) { uint32_t tmp = 0; @@ -668,15 +676,15 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) qemu_put_buffer(f, s->rregs, SERIAL_REGS); } -static void slavio_serial_save(QEMUFile *f, void *opaque) +static void escc_save(QEMUFile *f, void *opaque) { SerialState *s = opaque; - slavio_serial_save_chn(f, &s->chn[0]); - slavio_serial_save_chn(f, &s->chn[1]); + escc_save_chn(f, &s->chn[0]); + escc_save_chn(f, &s->chn[1]); } -static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) +static int escc_load_chn(QEMUFile *f, ChannelState *s, int version_id) { uint32_t tmp; @@ -698,43 +706,49 @@ static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) return 0; } -static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) +static int escc_load(QEMUFile *f, void *opaque, int version_id) { SerialState *s = opaque; int ret; - ret = slavio_serial_load_chn(f, &s->chn[0], version_id); + ret = escc_load_chn(f, &s->chn[0], version_id); if (ret != 0) return ret; - ret = slavio_serial_load_chn(f, &s->chn[1], version_id); + ret = escc_load_chn(f, &s->chn[1], version_id); return ret; } -SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, - CharDriverState *chr1, CharDriverState *chr2) +int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB, + CharDriverState *chrA, CharDriverState *chrB, + int clock, int it_shift) { - int slavio_serial_io_memory, i; + int escc_io_memory, i; SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) - return NULL; + return 0; - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, - slavio_serial_mem_write, - s); - cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); + escc_io_memory = cpu_register_io_memory(0, escc_mem_read, + escc_mem_write, + s); + if (base) + cpu_register_physical_memory(base, ESCC_SIZE << it_shift, + escc_io_memory); - s->chn[0].chr = chr1; - s->chn[1].chr = chr2; + s->it_shift = it_shift; + s->chn[0].chr = chrB; + s->chn[1].chr = chrA; s->chn[0].disabled = 0; s->chn[1].disabled = 0; + s->chn[0].irq = irqB; + s->chn[1].irq = irqA; for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].type = ser; + s->chn[i].clock = clock / 2; if (s->chn[i].chr) { qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); @@ -742,11 +756,13 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; - register_savevm("slavio_serial", base, 2, slavio_serial_save, - slavio_serial_load, s); - qemu_register_reset(slavio_serial_reset, s); - slavio_serial_reset(s); - return s; + if (base) + register_savevm("escc", base, 2, escc_save, escc_load, s); + else + register_savevm("escc", -1, 2, escc_save, escc_load, s); + qemu_register_reset(escc_reset, s); + escc_reset(s); + return escc_io_memory; } static const uint8_t keycodes[128] = { @@ -887,7 +903,7 @@ static void sunmouse_event(void *opaque, } void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, - int disabled) + int disabled, int clock, int it_shift) { int slavio_serial_io_memory, i; SerialState *s; @@ -895,10 +911,13 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, s = qemu_mallocz(sizeof(SerialState)); if (!s) return; + + s->it_shift = it_shift; for (i = 0; i < 2; i++) { s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].chr = NULL; + s->chn[i].clock = clock / 2; } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; @@ -907,16 +926,16 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, s->chn[0].disabled = disabled; s->chn[1].disabled = disabled; - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, - slavio_serial_mem_write, + slavio_serial_io_memory = cpu_register_io_memory(0, escc_mem_read, + escc_mem_write, s); - cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); + cpu_register_physical_memory(base, ESCC_SIZE << it_shift, + slavio_serial_io_memory); qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse"); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); - register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, - slavio_serial_load, s); - qemu_register_reset(slavio_serial_reset, s); - slavio_serial_reset(s); + register_savevm("slavio_serial_mouse", base, 2, escc_save, escc_load, s); + qemu_register_reset(escc_reset, s); + escc_reset(s); } diff --git a/hw/escc.h b/hw/escc.h new file mode 100644 index 0000000000..015b9d0089 --- /dev/null +++ b/hw/escc.h @@ -0,0 +1,8 @@ +/* escc.c */ +#define ESCC_SIZE 4 +int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB, + CharDriverState *chrA, CharDriverState *chrB, + int clock, int it_shift); + +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, + int disabled, int clock, int it_shift); diff --git a/hw/etraxfs.c b/hw/etraxfs.c index 01b5a6e6fe..e409a94e25 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -94,12 +94,10 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, } /* Add the two ethernet blocks. */ - nd_table[0].model = nd_table[0].model ? nd_table[0].model : "fseth"; - eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000); - if (nb_nics > 1) { - nd_table[1].model = nd_table[1].model ? nd_table[1].model : "fseth"; - eth[1] = etraxfs_eth_init(&nd_table[1], env, pic->irq + 26, 0x30036000); - } + eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000, 1); + if (nb_nics > 1) + eth[1] = etraxfs_eth_init(&nd_table[1], env, + pic->irq + 26, 0x30036000, 2); /* The DMA Connector block is missing, hardwire things for now. */ etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); diff --git a/hw/etraxfs.h b/hw/etraxfs.h index 0c9fdbb608..17dca29a44 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -37,6 +37,6 @@ struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi, target_phys_addr_t base); void *etraxfs_eth_init(NICInfo *nd, CPUState *env, - qemu_irq *irq, target_phys_addr_t base); + qemu_irq *irq, target_phys_addr_t base, int phyaddr); void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, target_phys_addr_t base); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 239e0d872c..cce89178a5 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -45,6 +45,8 @@ struct qemu_phy { uint32_t regs[32]; + int link; + unsigned int (*read)(struct qemu_phy *phy, unsigned int req); void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); @@ -59,13 +61,15 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) switch (regnum) { case 1: + if (!phy->link) + break; /* MR1. */ /* Speeds and modes. */ r |= (1 << 13) | (1 << 14); r |= (1 << 11) | (1 << 12); r |= (1 << 5); /* Autoneg complete. */ r |= (1 << 3); /* Autoneg able. */ - r |= (1 << 2); /* Link. */ + r |= (1 << 2); /* link. */ break; case 5: /* Link partner ability. @@ -83,6 +87,9 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) int duplex = 0; int speed_100 = 0; + if (!phy->link) + break; + /* Are we advertising 100 half or 100 duplex ? */ speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); @@ -125,6 +132,7 @@ tdk_init(struct qemu_phy *phy) phy->regs[3] = 0xe400; /* Autonegotiation advertisement reg. */ phy->regs[4] = 0x01E1; + phy->link = 1; phy->read = tdk_read; phy->write = tdk_write; @@ -530,6 +538,13 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len) return len; } +static void eth_set_link(VLANClientState *vc) +{ + struct fs_eth *eth = vc->opaque; + D(printf("%s %d\n", __func__, vc->link_down)); + eth->phy.link = !vc->link_down; +} + static CPUReadMemoryFunc *eth_read[] = { NULL, NULL, ð_readl, @@ -541,11 +556,13 @@ static CPUWriteMemoryFunc *eth_write[] = { }; void *etraxfs_eth_init(NICInfo *nd, CPUState *env, - qemu_irq *irq, target_phys_addr_t base) + qemu_irq *irq, target_phys_addr_t base, int phyaddr) { struct etraxfs_dma_client *dma = NULL; struct fs_eth *eth = NULL; + qemu_check_nic_model(nd, "fseth"); + dma = qemu_mallocz(sizeof *dma * 2); if (!dma) return NULL; @@ -565,7 +582,7 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, eth->dma_in = dma + 1; /* Connect the phy. */ - eth->phyaddr = 1; + eth->phyaddr = phyaddr & 0x1f; tdk_init(ð->phy); mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); @@ -574,6 +591,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, eth_receive, eth_can_receive, eth); + eth->vc->opaque = eth; + eth->vc->link_status_changed = eth_set_link; return dma; err: diff --git a/hw/flash.h b/hw/flash.h index faba93d7e1..70e3b9ec3f 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -26,6 +26,18 @@ void nand_getpins(struct nand_flash_s *s, int *rb); void nand_setio(struct nand_flash_s *s, uint8_t value); uint8_t nand_getio(struct nand_flash_s *s); +/* nand_bpage.c */ +struct nand_bflash_s; +struct nand_bflash_s *nandb_init(int manf_id, int chip_id); +void nandb_write_data16(struct nand_bflash_s *s, uint16_t value); +uint16_t nandb_read_data16(struct nand_bflash_s *s); +void nandb_write_data8(struct nand_bflash_s *s, uint8_t value); +uint8_t nandb_read_data8(struct nand_bflash_s *s); +void nandb_write_address(struct nand_bflash_s *s, uint16_t value); +void nandb_write_command(struct nand_bflash_s *s, uint16_t value); + + + #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_SAMSUNG 0xec #define NAND_MFR_FUJITSU 0x04 diff --git a/hw/ide.c b/hw/ide.c index 915390ae0a..7dd41f7aae 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -955,7 +955,7 @@ static void ide_read_dma_cb(void *opaque, int ret) s->io_buffer_index = 0; s->io_buffer_size = n * 512; #ifdef DEBUG_AIO - printf("aio_read: sector_num=%lld n=%d\n", sector_num, n); + printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n); #endif bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, ide_read_dma_cb, bm); @@ -1067,7 +1067,7 @@ static void ide_write_dma_cb(void *opaque, int ret) if (dma_buf_rw(bm, 0) == 0) goto eot; #ifdef DEBUG_AIO - printf("aio_write: sector_num=%lld n=%d\n", sector_num, n); + printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n); #endif bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_write_dma_cb, bm); @@ -2467,7 +2467,8 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0xff; break; case 1: - if (!ide_if[0].bs && !ide_if[1].bs) + if ((!ide_if[0].bs && !ide_if[1].bs) || + (s != ide_if && !s->bs)) ret = 0; else if (!hob) ret = s->error; @@ -3185,9 +3186,10 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x51] = 0x04; // enable IDE0 if (secondary_ide_enabled) { /* XXX: if not enabled, really disable the seconday IDE controller */ - pci_conf[0x51] = 0x80; /* enable IDE1 */ + pci_conf[0x51] |= 0x08; /* enable IDE1 */ } pci_register_io_region((PCIDevice *)d, 0, 0x8, diff --git a/hw/integratorcp.c b/hw/integratorcp.c index a2d3d4306c..fdbfe202fd 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -497,18 +497,8 @@ static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size, exit(1); } pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: smc91c111\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } + if (nd_table[0].vlan) + smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); pl110_init(ds, 0xc0000000, pic[22], 0); integrator_binfo.ram_size = ram_size; diff --git a/hw/macio.c b/hw/macio.c index 7f0d9f7910..2a98dfb318 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -25,6 +25,7 @@ #include "hw.h" #include "ppc_mac.h" #include "pci.h" +#include "escc.h" typedef struct macio_state_t macio_state_t; struct macio_state_t { @@ -32,6 +33,7 @@ struct macio_state_t { int pic_mem_index; int dbdma_mem_index; int cuda_mem_index; + int escc_mem_index; void *nvram; int nb_ide; int ide_mem_index[4]; @@ -59,6 +61,10 @@ static void macio_map (PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0x08000, 0x1000, macio_state->dbdma_mem_index); } + if (macio_state->escc_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE << 4, + macio_state->escc_mem_index); + } if (macio_state->cuda_mem_index >= 0) { cpu_register_physical_memory(addr + 0x16000, 0x2000, macio_state->cuda_mem_index); @@ -75,7 +81,7 @@ static void macio_map (PCIDevice *pci_dev, int region_num, void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, int dbdma_mem_index, int cuda_mem_index, void *nvram, - int nb_ide, int *ide_mem_index) + int nb_ide, int *ide_mem_index, int escc_mem_index) { PCIDevice *d; macio_state_t *macio_state; @@ -89,6 +95,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, macio_state->pic_mem_index = pic_mem_index; macio_state->dbdma_mem_index = dbdma_mem_index; macio_state->cuda_mem_index = cuda_mem_index; + macio_state->escc_mem_index = escc_mem_index; macio_state->nvram = nvram; if (nb_ide > 4) nb_ide = 4; diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 71ba3fb0a2..f06c25a54c 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -241,18 +241,8 @@ static void mcf5208evb_init(ram_addr_t ram_size, int vga_ram_size, fprintf(stderr, "Too many NICs\n"); exit(1); } - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "mcf_fec") == 0) { - mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: mcf_fec\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } + if (nd_table[0].vlan) + mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36); /* 0xfc000000 SCM. */ /* 0xfc004000 XBS. */ diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 49ae69bd5e..413c5694db 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -446,6 +446,8 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) mcf_fec_state *s; int iomemtype; + qemu_check_nic_model(nd, "mcf_fec"); + s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); s->irq = irq; iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, diff --git a/hw/mips_int.c b/hw/mips_int.c index ad48b4f706..f7e4c62050 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -6,12 +6,23 @@ IRQ may change */ void cpu_mips_update_irq(CPUState *env) { +// if (interrupt_request & CPU_INTERRUPT_HARD) +//{ +//if (env->CP0_Cause&0x400) +//{ +// printf("cpu_mips_update_irq \n"); +// printf("env->CP0_Status %x env->CP0_Cause %x CP0Ca_IP_mask %x \n",env->CP0_Status,env->CP0_Cause,CP0Ca_IP_mask); +// printf("CP0St_IE %x CP0St_EXL %x CP0St_ERL %x \n",CP0St_IE,CP0St_EXL,CP0St_ERL); +// printf("env->hflags %x MIPS_HFLAG_DM %x \n",env->hflags ,MIPS_HFLAG_DM); +//} +//} if ((env->CP0_Status & (1 << CP0St_IE)) && !(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && !(env->interrupt_request & CPU_INTERRUPT_HARD)) { + printf("cpu_mips_update_irq \n"); cpu_interrupt(env, CPU_INTERRUPT_HARD); } } else @@ -26,9 +37,15 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) return; if (level) { - env->CP0_Cause |= 1 << (irq + CP0Ca_IP); + env->CP0_Cause |= 1 << (irq + CP0Ca_IP); + if (env->CP0_Status & 0x1) + { + printf("irq %d env->CP0_Cause %x \n",irq,env->CP0_Cause); + printf("status %x\n",env->CP0_Status); + } } else { env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); + //printf("clear irq %d env->CP0_Cause %x \n",irq,env->CP0_Cause); } cpu_mips_update_irq(env); } diff --git a/hw/mips_jz.c b/hw/mips_jz.c index 07c8c4c4e0..28f4e13cf6 100755 --- a/hw/mips_jz.c +++ b/hw/mips_jz.c @@ -1,7 +1,7 @@ /* * QEMU JZ Soc emulation * - * Copyright (c) 2008 yajin (yajin@vm-kernel.org) + * Copyright (c) 2009 yajin (yajin@vm-kernel.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,23 +31,33 @@ #include "hw.h" #include "mips.h" -#include "mips_jz.h" #include "sysemu.h" #include "qemu-timer.h" #include "qemu-char.h" #include "flash.h" #include "soc_dma.h" #include "audio/audio.h" +#include "pc.h" +#include "osdep.h" +#include "mips_jz.h" +#include "console.h" -#define DEBUG_CPM (1<<0x1) +#define DEBUG /*global debug on/off */ -#define DEBUG_FLAG (DEBUG_CPM) +#define DEBUG_CPM (1<<0x0) +#define DEBUG_EMC (1<<0x1) +#define DEBUG_GPIO (1<<0x2) +#define DEBUG_RTC (1<<0x3) +#define DEBUG_TCU (1<<0x4) +#define DEBUG_LCDC (1<<0x5) +#define DEBUG_DMA (1<<0x6) +#define DEBUG_FLAG 0//DEBUG_TCU// (DEBUG_CPM|DEBUG_EMC|DEBUG_GPIO \ + // | DEBUG_RTC | DEBUG_TCU | DEBUG_LCDC | DEBUG_DMA) #ifdef DEBUG - FILE *fp; -static void debug_init() +static void debug_init(void) { fp = fopen("jz4740.txt", "w+"); if (fp == NULL) @@ -79,7 +89,7 @@ static void debug_out(uint32_t flag, const char *format, ...) } #endif -static uint32_t jz4740_badwidth_read8(void *opaque, target_phys_addr_t addr) +uint32_t jz4740_badwidth_read8(void *opaque, target_phys_addr_t addr) { uint8_t ret; @@ -88,8 +98,8 @@ static uint32_t jz4740_badwidth_read8(void *opaque, target_phys_addr_t addr) return ret; } -static void jz4740_badwidth_write8(void *opaque, target_phys_addr_t addr, - uint32_t value) +void jz4740_badwidth_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) { uint8_t val8 = value; @@ -97,7 +107,7 @@ static void jz4740_badwidth_write8(void *opaque, target_phys_addr_t addr, cpu_physical_memory_write(addr, (void *) &val8, 1); } -static uint32_t jz4740_badwidth_read16(void *opaque, target_phys_addr_t addr) +uint32_t jz4740_badwidth_read16(void *opaque, target_phys_addr_t addr) { uint16_t ret; JZ4740_16B_REG(addr); @@ -105,8 +115,8 @@ static uint32_t jz4740_badwidth_read16(void *opaque, target_phys_addr_t addr) return ret; } -static void jz4740_badwidth_write16(void *opaque, target_phys_addr_t addr, - uint32_t value) +void jz4740_badwidth_write16(void *opaque, target_phys_addr_t addr, + uint32_t value) { uint16_t val16 = value; @@ -114,7 +124,7 @@ static void jz4740_badwidth_write16(void *opaque, target_phys_addr_t addr, cpu_physical_memory_write(addr, (void *) &val16, 2); } -static uint32_t jz4740_badwidth_read32(void *opaque, target_phys_addr_t addr) +uint32_t jz4740_badwidth_read32(void *opaque, target_phys_addr_t addr) { uint32_t ret; @@ -123,8 +133,8 @@ static uint32_t jz4740_badwidth_read32(void *opaque, target_phys_addr_t addr) return ret; } -static void jz4740_badwidth_write32(void *opaque, target_phys_addr_t addr, - uint32_t value) +void jz4740_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) { JZ4740_32B_REG(addr); cpu_physical_memory_write(addr, (void *) &value, 4); @@ -145,13 +155,17 @@ struct jz4740_cpm_s uint32_t uhccdr; uint32_t uhctst; uint32_t ssicdr; + + uint32_t lcr; + uint32_t clkgr; + uint32_t scr; }; static void jz4740_dump_clocks(jz_clk parent) { jz_clk i = parent; - debug_out(DEBUG_CPM, "clock %x rate 0x%x \n", i->name, i->rate); + debug_out(DEBUG_CPM, "clock %s rate %d \n", i->name, i->rate); for (i = i->child1; i; i = i->sibling) jz4740_dump_clocks(i); } @@ -160,7 +174,9 @@ static inline void jz4740_cpccr_update(struct jz4740_cpm_s *s, uint32_t new_value) { uint32_t ldiv, mdiv, pdiv, hdiv, cdiv, udiv; - uint32_t div_table[10] = { 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 }; + uint32_t div_table[10] = { + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 + }; if (unlikely(new_value == s->cpccr)) return; @@ -212,7 +228,9 @@ static inline void jz4740_cppcr_update(struct jz4740_cpm_s *s, uint32_t new_value) { uint32_t pllm, plln, pllod, pllbp, pllen; - uint32_t pll0[4] = { 1, 2, 2, 4 }; + uint32_t pll0[4] = { + 1, 2, 2, 4 + }; pllen = new_value & CPM_CPPCR_PLLEN; @@ -302,13 +320,21 @@ static void jz4740_cpm_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct jz4740_cpm_s *s = (struct jz4740_cpm_s *) opaque; - int offset = addr - s->base; - switch (offset) + switch (addr) { case 0x0: jz4740_cpccr_update(s, value); break; + case 0x4: + s->lcr = value & 0xff; + break; + case 0x20: + s->clkgr = value & 0xffff; + break; + case 0x24: + s->scr = value & 0xffff; + break; case 0x10: jz4740_cppcr_update(s, value); break; @@ -332,8 +358,8 @@ static void jz4740_cpm_write(void *opaque, target_phys_addr_t addr, break; default: cpu_abort(s->soc->env, - "jz4740_cpm_write undefined addr " JZ_FMT_plx " value %x \n", - addr, value); + "jz4740_cpm_write undefined addr " JZ_FMT_plx + " value %x \n", addr, value); } } @@ -342,12 +368,17 @@ static void jz4740_cpm_write(void *opaque, target_phys_addr_t addr, static uint32_t jz474_cpm_read(void *opaque, target_phys_addr_t addr) { struct jz4740_cpm_s *s = (struct jz4740_cpm_s *) opaque; - int offset = addr - s->base; - switch (offset) + switch (addr) { case 0x0: return s->cpccr; + case 0x4: + return s->lcr; + case 0x20: + return s->clkgr; + case 0x24: + return s->scr; case 0x10: return s->cppcr; case 0x60: @@ -372,15 +403,11 @@ static uint32_t jz474_cpm_read(void *opaque, target_phys_addr_t addr) static CPUReadMemoryFunc *jz4740_cpm_readfn[] = { - jz4740_badwidth_read32, - jz4740_badwidth_read32, - jz474_cpm_read, + jz4740_badwidth_read32, jz4740_badwidth_read32, jz474_cpm_read, }; static CPUWriteMemoryFunc *jz4740_cpm_writefn[] = { - jz4740_badwidth_write32, - jz4740_badwidth_write32, - jz4740_cpm_write, + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_cpm_write, }; static void jz4740_cpm_reset(struct jz4740_cpm_s *s) @@ -393,6 +420,10 @@ static void jz4740_cpm_reset(struct jz4740_cpm_s *s) s->uhccdr = 0x00000004; s->uhctst = 0x0; s->ssicdr = 0x00000004; + + s->lcr = 0xf8; + s->clkgr = 0x0; + s->scr = 0x1500; } static struct jz4740_cpm_s *jz4740_cpm_init(struct jz_state_s *soc) @@ -431,8 +462,8 @@ struct jz4740_intc_s static uint32_t jz4740_intc_read(void *opaque, target_phys_addr_t addr) { struct jz4740_intc_s *s = (struct jz4740_intc_s *) opaque; - int offset = addr - s->base; - switch (offset) + + switch (addr) { case 0x8: case 0xc: @@ -456,12 +487,10 @@ static void jz4740_intc_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct jz4740_intc_s *s = (struct jz4740_intc_s *) opaque; - int offset = addr - s->base; - switch (offset) + switch (addr) { case 0x0: - case 0x10: JZ4740_RO_REG(addr); break; case 0x4: @@ -473,6 +502,9 @@ static void jz4740_intc_write(void *opaque, target_phys_addr_t addr, case 0xc: s->icmr &= ~value; break; + case 0x10: + s->icpr = value; + break; default: cpu_abort(s->soc->env, "jz4740_intc_write undefined addr " JZ_FMT_plx @@ -482,15 +514,11 @@ static void jz4740_intc_write(void *opaque, target_phys_addr_t addr, static CPUReadMemoryFunc *jz4740_intc_readfn[] = { - jz4740_badwidth_read32, - jz4740_badwidth_read32, - jz4740_intc_read, + jz4740_badwidth_read32, jz4740_badwidth_read32, jz4740_intc_read, }; static CPUWriteMemoryFunc *jz4740_intc_writefn[] = { - jz4740_badwidth_write32, - jz4740_badwidth_write32, - jz4740_intc_write, + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_intc_write, }; static void jz4740_intc_reset(struct jz4740_intc_s *s) @@ -505,14 +533,19 @@ static void jz4740_set_irq(void *opaque, int irq, int level) struct jz4740_intc_s *s = (struct jz4740_intc_s *) opaque; uint32_t irq_mask = 1 << irq; - s->icsr |= irq_mask; - s->icpr |= irq_mask; - s->icpr &= ~s->icmr; - - if (((~s->icmr) & irq_mask) && (level)) - qemu_set_irq(s->parent_irq, 1); + s->icpr &= ~irq_mask; + if (level) + { + s->icsr |= irq_mask; + //printf("s->icmr %x \n",s->icmr); + if (!(s->icmr & irq_mask)) + { + s->icpr |= irq_mask; + qemu_set_irq(s->parent_irq, 1); + } + } else - qemu_set_irq(s->parent_irq, 0); + qemu_set_irq(s->parent_irq, 0); } static qemu_irq *jz4740_intc_init(struct jz_state_s *soc, qemu_irq parent_irq) @@ -538,6 +571,7 @@ struct jz4740_emc_s target_phys_addr_t base; struct jz_state_s *soc; + uint32_t bcr; uint32_t smcr1; /*0x13010014 */ uint32_t smcr2; /*0x13010018 */ uint32_t smcr3; /*0x1301001c */ @@ -606,29 +640,29 @@ static void jz4740_emc_reset(struct jz4740_emc_s *s) static uint32_t jz4740_emc_read8(void *opaque, target_phys_addr_t addr) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + + switch (addr) { case 0x108: case 0x109: case 0x10a: case 0x10b: - return (s->nfpar0 >> ((offset - 0x108) * 8)) & 0xff; + return (s->nfpar0 >> ((addr - 0x108) * 8)) & 0xff; case 0x10c: case 0x10d: case 0x10e: case 0x10f: - return (s->nfpar1 >> ((offset - 0x10c) * 8)) & 0xff; + return (s->nfpar1 >> ((addr - 0x10c) * 8)) & 0xff; case 0x110: case 0x111: case 0x112: case 0x113: - return (s->nfpar2 >> ((offset - 0x110) * 8)) & 0xff; + return (s->nfpar2 >> ((addr - 0x110) * 8)) & 0xff; case 0xa000: case 0xa001: case 0xa002: case 0xa003: - return (s->sdmr >> ((offset - 0xa000) * 8)) & 0xff; + return (s->sdmr >> ((addr - 0xa000) * 8)) & 0xff; default: cpu_abort(s->soc->env, "jz4740_emc_read8 undefined addr " JZ_FMT_plx " \n", addr); @@ -641,30 +675,30 @@ static uint32_t jz4740_emc_read8(void *opaque, target_phys_addr_t addr) static uint32_t jz4740_emc_read16(void *opaque, target_phys_addr_t addr) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + + switch (addr) { case 0x108: case 0x10a: - return (s->nfpar0 >> ((offset - 0x108) * 8)) & 0xffff; + return (s->nfpar0 >> ((addr - 0x108) * 8)) & 0xffff; case 0x10c: case 0x10e: - return (s->nfpar1 >> ((offset - 0x10c) * 8)) & 0xffff; + return (s->nfpar1 >> ((addr - 0x10c) * 8)) & 0xffff; case 0x110: case 0x112: - return (s->nfpar2 >> ((offset - 0x110) * 8)) & 0xffff; + return (s->nfpar2 >> ((addr - 0x110) * 8)) & 0xffff; case 0x11c: case 0x11e: - return (s->nferr0 >> ((offset - 0x11c) * 8)) & 0xffff; + return (s->nferr0 >> ((addr - 0x11c) * 8)) & 0xffff; case 0x120: case 0x122: - return (s->nferr1 >> ((offset - 0x120) * 8)) & 0xffff; + return (s->nferr1 >> ((addr - 0x120) * 8)) & 0xffff; case 0x124: case 0x126: - return (s->nferr2 >> ((offset - 0x124) * 8)) & 0xffff; + return (s->nferr2 >> ((addr - 0x124) * 8)) & 0xffff; case 0x128: case 0x12a: - return (s->nferr3 >> ((offset - 0x128) * 8)) & 0xffff; + return (s->nferr3 >> ((addr - 0x128) * 8)) & 0xffff; default: cpu_abort(s->soc->env, "jz4740_emc_read16 undefined addr " JZ_FMT_plx " \n", addr); @@ -675,9 +709,11 @@ static uint32_t jz4740_emc_read16(void *opaque, target_phys_addr_t addr) static uint32_t jz4740_emc_read32(void *opaque, target_phys_addr_t addr) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + + switch (addr) { + case 0x0: + return s->bcr; case 0x14: return s->smcr1; case 0x18: @@ -733,33 +769,30 @@ static void jz4740_emc_write8(void *opaque, target_phys_addr_t addr, uint32_t value) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + debug_out(DEBUG_EMC, "jz4740_emc_write8 addr %x value %x\n", addr, value); + + switch (addr) { case 0x108: case 0x109: case 0x10a: case 0x10b: - s->nfpar0 |= (value & 0xff) << ((offset - 0x108) * 8); + s->nfpar0 |= (value & 0xff) << ((addr - 0x108) * 8); break; case 0x10c: case 0x10d: case 0x10e: case 0x10f: - s->nfpar1 |= (value & 0xff) << ((offset - 0x10c) * 8); + s->nfpar1 |= (value & 0xff) << ((addr - 0x10c) * 8); break; case 0x110: case 0x111: case 0x112: case 0x113: - s->nfpar2 |= (value & 0xff) << ((offset - 0x110) * 8); + s->nfpar2 |= (value & 0xff) << ((addr - 0x110) * 8); break; - case 0xa000: - case 0xa001: - case 0xa002: - case 0xa003: - s->sdmr |= (value & 0xff) << ((offset - 0x110) * 8); + case 0xa000 ... 0xa3ff: break; default: cpu_abort(s->soc->env, @@ -771,32 +804,32 @@ static void jz4740_emc_write16(void *opaque, target_phys_addr_t addr, uint32_t value) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + debug_out(DEBUG_EMC, "jz4740_emc_write16 addr %x value %x\n", addr, value); + switch (addr) { case 0x108: case 0x10a: - s->nfpar0 |= (value & 0xffff) << ((offset - 0x108) * 8); + s->nfpar0 |= (value & 0xffff) << ((addr - 0x108) * 8); break; case 0x10c: case 0x10e: - s->nfpar1 |= (value & 0xffff) << ((offset - 0x10c) * 8); + s->nfpar1 |= (value & 0xffff) << ((addr - 0x10c) * 8); break; case 0x110: case 0x112: - s->nfpar2 |= (value & 0xffff) << ((offset - 0x110) * 8); + s->nfpar2 |= (value & 0xffff) << ((addr - 0x110) * 8); break; case 0x84: case 0x86: - s->rtcsr |= (value & 0xffff) << ((offset - 0x84) * 8); + s->rtcsr |= (value & 0xffff) << ((addr - 0x84) * 8); break; case 0x88: case 0x8a: - s->rtcnt |= (value & 0xffff) << ((offset - 0x88) * 8); + s->rtcnt |= (value & 0xffff) << ((addr - 0x88) * 8); break; case 0x8c: - s->rtcor |= (value & 0xffff) << ((offset - 0x8c) * 8); + s->rtcor |= (value & 0xffff) << ((addr - 0x8c) * 8); break; default: cpu_abort(s->soc->env, @@ -814,9 +847,9 @@ static void jz4740_emc_write32(void *opaque, target_phys_addr_t addr, uint32_t value) { struct jz4740_emc_s *s = (struct jz4740_emc_s *) opaque; - int offset = addr - s->base; - switch (offset) + debug_out(DEBUG_EMC, "jz4740_emc_write32 addr %x value %x\n", addr, value); + switch (addr) { case 0x104: case 0x11c: @@ -825,6 +858,9 @@ static void jz4740_emc_write32(void *opaque, target_phys_addr_t addr, case 0x128: JZ4740_RO_REG(addr); break; + case 0x0: + s->bcr = value; + break; case 0x14: s->smcr1 = value & 0xfff77cf; break; @@ -927,19 +963,16 @@ static void jz4740_emc_write32(void *opaque, target_phys_addr_t addr, } static CPUReadMemoryFunc *jz4740_emc_readfn[] = { - jz4740_emc_read8, - jz4740_emc_read16, - jz4740_emc_read32, + jz4740_emc_read8, jz4740_emc_read16, jz4740_emc_read32, }; static CPUWriteMemoryFunc *jz4740_emc_writefn[] = { - jz4740_emc_write8, - jz4740_emc_write16, - jz4740_emc_write32, + jz4740_emc_write8, jz4740_emc_write16, jz4740_emc_write32, }; -static struct jz4740_emc_s *jz4740_emc_init(struct jz_state_s *soc, qemu_irq irq) +static struct jz4740_emc_s *jz4740_emc_init(struct jz_state_s *soc, + qemu_irq irq) { int iomemtype; struct jz4740_emc_s *s = (struct jz4740_emc_s *) qemu_mallocz(sizeof(*s)); @@ -956,6 +989,1639 @@ static struct jz4740_emc_s *jz4740_emc_init(struct jz_state_s *soc, qemu_irq irq } +struct jz4740_gpio_s +{ + qemu_irq irq; + target_phys_addr_t base; + struct jz_state_s *soc; + + uint32_t papin[4]; + uint32_t padat[4]; + uint32_t paim[4]; + uint32_t pape[4]; + uint32_t pafun[4]; + uint32_t pasel[4]; + uint32_t padir[4]; + uint32_t patrg[4]; + uint32_t paflg[4]; +}; + +static void jz4740_gpio_reset(struct jz4740_gpio_s *s) +{ + memset(s->papin, 0x0, sizeof(s->papin)); + memset(s->padat, 0x0, sizeof(s->padat)); + memset(s->paim, 0xffffffff, sizeof(s->paim)); + memset(s->pape, 0x0, sizeof(s->pape)); + memset(s->pafun, 0x0, sizeof(s->pafun)); + memset(s->pasel, 0x0, sizeof(s->pasel)); + memset(s->padir, 0x0, sizeof(s->padir)); + memset(s->patrg, 0x0, sizeof(s->patrg)); + memset(s->paflg, 0x0, sizeof(s->paflg)); +} + +static uint32_t jz4740_gpio_read(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_gpio_s *s = (struct jz4740_gpio_s *) opaque; + uint32_t group; + debug_out(DEBUG_GPIO, "jz4740_gpio_read addr %x\n", addr); + + switch (addr) + { + case 0x14: + case 0x114: + case 0x214: + case 0x314: + case 0x18: + case 0x118: + case 0x218: + case 0x318: + case 0x24: + case 0x124: + case 0x224: + case 0x324: + case 0x28: + case 0x128: + case 0x228: + case 0x328: + case 0x34: + case 0x134: + case 0x234: + case 0x334: + case 0x38: + case 0x138: + case 0x238: + case 0x338: + case 0x44: + case 0x144: + case 0x244: + case 0x344: + case 0x48: + case 0x148: + case 0x248: + case 0x348: + case 0x54: + case 0x154: + case 0x254: + case 0x354: + case 0x58: + case 0x158: + case 0x258: + case 0x358: + case 0x64: + case 0x164: + case 0x264: + case 0x364: + case 0x68: + case 0x168: + case 0x268: + case 0x368: + case 0x74: + case 0x174: + case 0x274: + case 0x374: + case 0x78: + case 0x178: + case 0x278: + case 0x378: + case 0x84: + case 0x184: + case 0x284: + case 0x384: + JZ4740_WO_REG(addr); + break; + + case 0x0: + case 0x100: + case 0x200: + case 0x300: + group = (addr - 0x0) / 0x100; + if (addr == 0x200) + { + /*GPIO(C) PIN 30 -> NAND FLASH R/B. */ + /*FOR NAND FLASH.PIN 30 ----|_____|------ */ + s->papin[2] &= 0x40000000; + if (s->papin[2]) + s->papin[2] &= ~0x40000000; + else + s->papin[2] |= 0x40000000; + } + return s->papin[group]; + case 0x10: + case 0x110: + case 0x210: + case 0x310: + group = (addr - 0x10) / 0x100; + return s->padat[group]; + case 0x20: + case 0x120: + case 0x220: + case 0x320: + group = (addr - 0x20) / 0x100; + return s->paim[group]; + case 0x30: + case 0x130: + case 0x230: + case 0x330: + group = (addr - 0x30) / 0x100; + return s->pape[group]; + case 0x40: + case 0x140: + case 0x240: + case 0x340: + group = (addr - 0x40) / 0x100; + return s->pafun[group]; + case 0x50: + case 0x150: + case 0x250: + case 0x350: + group = (addr - 0x50) / 0x100; + return s->pasel[group]; + case 0x60: + case 0x160: + case 0x260: + case 0x360: + group = (addr - 0x60) / 0x100; + return s->padir[group]; + case 0x70: + case 0x170: + case 0x270: + case 0x370: + group = (addr - 0x70) / 0x100; + return s->patrg[group]; + case 0x80: + case 0x180: + case 0x280: + case 0x380: + group = (addr - 0x80) / 0x100; + return s->paflg[group]; + default: + cpu_abort(s->soc->env, + "jz4740_gpio_read undefined addr " JZ_FMT_plx " \n", addr); + } + return (0); +} + +static void jz4740_gpio_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_gpio_s *s = (struct jz4740_gpio_s *) opaque; + uint32_t group; + + debug_out(DEBUG_GPIO, "jz4740_gpio_write addr %x value %x\n", addr, value); + + switch (addr) + { + case 0x0: + case 0x100: + case 0x200: + case 0x300: + case 0x10: + case 0x110: + case 0x210: + case 0x310: + case 0x20: + case 0x120: + case 0x220: + case 0x320: + case 0x30: + case 0x130: + case 0x230: + case 0x330: + case 0x40: + case 0x140: + case 0x240: + case 0x340: + case 0x50: + case 0x150: + case 0x250: + case 0x350: + case 0x60: + case 0x160: + case 0x260: + case 0x360: + case 0x70: + case 0x170: + case 0x270: + case 0x370: + case 0x80: + case 0x180: + case 0x280: + case 0x380: + JZ4740_RO_REG(addr); + break; + case 0x14: + case 0x114: + case 0x214: + case 0x314: + group = (addr - 0x14) / 0x100; + s->padat[group] = value; + break; + case 0x18: + case 0x118: + case 0x218: + case 0x318: + group = (addr - 0x18) / 0x100; + s->padat[group] &= ~value; + break; + case 0x24: + case 0x124: + case 0x224: + case 0x324: + group = (addr - 0x24) / 0x100; + s->paim[group] = value; + break; + case 0x28: + case 0x128: + case 0x228: + case 0x328: + group = (addr - 0x28) / 0x100; + s->paim[group] &= ~value; + break; + case 0x34: + case 0x134: + case 0x234: + case 0x334: + group = (addr - 0x34) / 0x100; + s->pape[group] = value; + break; + case 0x38: + case 0x138: + case 0x238: + case 0x338: + group = (addr - 0x38) / 0x100; + s->pape[group] &= ~value; + break; + case 0x44: + case 0x144: + case 0x244: + case 0x344: + group = (addr - 0x44) / 0x100; + s->pafun[group] = value; + break; + case 0x48: + case 0x148: + case 0x248: + case 0x348: + group = (addr - 0x48) / 0x100; + s->pafun[group] &= ~value; + break; + case 0x54: + case 0x154: + case 0x254: + case 0x354: + group = (addr - 0x54) / 0x100; + s->pasel[group] = value; + break; + case 0x58: + case 0x158: + case 0x258: + case 0x358: + group = (addr - 0x58) / 0x100; + s->pasel[group] &= ~value; + break; + case 0x64: + case 0x164: + case 0x264: + case 0x364: + group = (addr - 0x64) / 0x100; + s->padir[group] = value; + break; + case 0x68: + case 0x168: + case 0x268: + case 0x368: + group = (addr - 0x68) / 0x100; + s->padir[group] &= ~value; + break; + case 0x74: + case 0x174: + case 0x274: + case 0x374: + group = (addr - 0x74) / 0x100; + s->patrg[group] = value; + break; + case 0x78: + case 0x178: + case 0x278: + case 0x378: + group = (addr - 0x78) / 0x100; + s->patrg[group] &= ~value; + break; + case 0x84: + case 0x184: + case 0x284: + case 0x384: + group = (addr - 0x74) / 0x100; + s->paflg[group] &= ~value; + break; + default: + cpu_abort(s->soc->env, + "jz4740_gpio_write undefined addr " JZ_FMT_plx + " value %x \n", addr, value); + + } + + +} + + +static CPUReadMemoryFunc *jz4740_gpio_readfn[] = { + jz4740_badwidth_read32, jz4740_badwidth_read32, jz4740_gpio_read, +}; + +static CPUWriteMemoryFunc *jz4740_gpio_writefn[] = { + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_gpio_write, +}; + +static struct jz4740_gpio_s *jz4740_gpio_init(struct jz_state_s *soc, + qemu_irq irq) +{ + int iomemtype; + struct jz4740_gpio_s *s = (struct jz4740_gpio_s *) qemu_mallocz(sizeof(*s)); + s->base = JZ4740_PHYS_BASE(JZ4740_GPIO_BASE); + s->soc = soc; + s->irq = irq; + + jz4740_gpio_reset(s); + + iomemtype = + cpu_register_io_memory(0, jz4740_gpio_readfn, jz4740_gpio_writefn, s); + cpu_register_physical_memory(s->base, 0x00010000, iomemtype); + return s; + +} + +struct jz4740_rtc_s +{ + qemu_irq irq; + target_phys_addr_t base; + struct jz_state_s *soc; + + QEMUTimer *hz_tm; + //struct tm tm; + //int sec_offset; + int64_t next; + + uint32_t rtccr; + uint32_t rtcsr; + uint32_t rtcsar; + uint32_t rtcgr; + + uint32_t hcr; + uint32_t hwfcr; + uint32_t hrcr; + uint32_t hwcr; + uint32_t hwrsr; + uint32_t hspr; + +}; + + +static void jz4740_rtc_update_interrupt(struct jz4740_rtc_s *s) +{ + if (((s->rtcsr & 0x40) && (s->rtcsr & 0x20)) + || ((s->rtcsr & 0x10) && (s->rtcsr & 0x8))) + qemu_set_irq(s->irq, 1); + else + qemu_set_irq(s->irq, 0); +} + +static inline void jz4740_rtc_start(struct jz4740_rtc_s *s) +{ + s->next = +qemu_get_clock(rt_clock); + qemu_mod_timer(s->hz_tm, s->next); +} + +static inline void jz4740_rtc_stop(struct jz4740_rtc_s *s) +{ + qemu_del_timer(s->hz_tm); + s->next = -qemu_get_clock(rt_clock); + if (s->next < 1) + s->next = 1; +} + +static void jz4740_rtc_hz(void *opaque) +{ + struct jz4740_rtc_s *s = (struct jz4740_rtc_s *) opaque; + + s->next += 1000; + qemu_mod_timer(s->hz_tm, s->next); + if (s->rtccr & 0x1) + { + s->rtcsr++; + s->rtccr |= 0x40; + if (s->rtcsr & 0x4) + { + if (s->rtcsr == s->rtcsar) + s->rtccr |= 0x10; + } + jz4740_rtc_update_interrupt(s); + } +} + +static void jz4740_rtc_reset(struct jz4740_rtc_s *s) +{ + s->rtccr = 0x81; + + s->next = 1000; + + /*Maybe rtcsr need to be saved to file */ + s->rtcsr = 0; + //s->sec_offset = 0; + //qemu_get_timedate(&s->tm, s->sec_offset); + jz4740_rtc_start(s); + +} + +static uint32_t jz4740_rtc_read(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_rtc_s *s = (struct jz4740_rtc_s *) opaque; + + debug_out(DEBUG_RTC, "jz4740_rtc_read addr %x\n", addr); + switch (addr) + { + case 0x0: + return s->rtccr | 0x80; + case 0x4: + return s->rtcsr; + case 0x8: + return s->rtcsar; + case 0xc: + return s->rtcgr; + case 0x20: + return s->hcr; + case 0x24: + return s->hwfcr; + case 0x28: + return s->hrcr; + case 0x2c: + return s->hwcr; + case 0x30: + return s->hwrsr; + case 0x34: + return s->hspr; + default: + cpu_abort(s->soc->env, + "jz4740_rtc_read undefined addr " JZ_FMT_plx "\n", addr); + } + + return (0); +} + +static void jz4740_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_rtc_s *s = (struct jz4740_rtc_s *) opaque; + + debug_out(DEBUG_RTC, "jz4740_rtc_write addr %x value %x\n", addr, value); + + switch (addr) + { + case 0x0: + s->rtccr = value & 0x2d; + if (!value & 0x40) + s->rtccr &= ~0x40; + if (!value & 0x10) + s->rtccr &= ~0x10; + if (s->rtccr & 0x1) + { + jz4740_rtc_start(s); + jz4740_rtc_update_interrupt(s); + } + break; + case 0x4: + s->rtcsr = value; + //s->sec_offset = qemu_timedate_diff(&s->tm); + break; + case 0x8: + s->rtcsar = value; + break; + case 0xc: + s->rtcgr = value & 0x13ffffff; + break; + case 0x20: + s->hcr = value & 0x1; + break; + case 0x24: + s->hwfcr = value & 0xffe0; + break; + case 0x28: + s->hrcr = value & 0xfe0; + break; + case 0x2c: + s->hwcr = value & 0x1; + break; + case 0x30: + s->hwrsr = value & 0x33; + break; + case 0x34: + s->hspr = value; + break; + default: + cpu_abort(s->soc->env, + "jz4740_rtc_write undefined addr " JZ_FMT_plx + " value %x \n", addr, value); + } + +} + +static CPUReadMemoryFunc *jz4740_rtc_readfn[] = { + jz4740_badwidth_read32, jz4740_badwidth_read32, jz4740_rtc_read, +}; + +static CPUWriteMemoryFunc *jz4740_rtc_writefn[] = { + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_rtc_write, +}; + +static struct jz4740_rtc_s *jz4740_rtc_init(struct jz_state_s *soc, + qemu_irq irq) +{ + int iomemtype; + struct jz4740_rtc_s *s = (struct jz4740_rtc_s *) qemu_mallocz(sizeof(*s)); + s->base = JZ4740_PHYS_BASE(JZ4740_RTC_BASE); + s->soc = soc; + s->irq = irq; + + s->hz_tm = qemu_new_timer(rt_clock, jz4740_rtc_hz, s); + + jz4740_rtc_reset(s); + + iomemtype = + cpu_register_io_memory(0, jz4740_rtc_readfn, jz4740_rtc_writefn, s); + cpu_register_physical_memory(s->base, 0x00001000, iomemtype); + return s; +} + +struct jz4740_tcu_s +{ + qemu_irq tcu_irq0; + qemu_irq tcu_irq1; + qemu_irq tcu_irq2; + + target_phys_addr_t base; + struct jz_state_s *soc; + + + QEMUTimer *half_timer[8]; + QEMUTimer *full_timer[8]; + int64_t time[8]; + + uint32_t tsr; + uint32_t ter; + uint32_t tfr; + uint32_t tmr; + + uint32_t tdfr[8]; + uint32_t tdhr[8]; + uint32_t tcnt[8]; + uint32_t tcsr[8]; + + uint32_t prescale[8]; + uint32_t freq[8]; +}; + +static void jz4740_tcu_update_interrupt(struct jz4740_tcu_s *s) +{ + //printf("s->tfr %x s->tmr %x \n",s->tfr,s->tmr); + if (((s->tfr & 0x1) & (~(s->tmr & 0x1))) + || ((s->tfr & 0x10000) & (~(s->tmr & 0x10000)))) + { + qemu_set_irq(s->tcu_irq0, 1); + } + // else + // qemu_set_irq(s->tcu_irq0, 0); +#if 0 + if (((s->tfr & 0x2) & (~(s->tmr & 0x2))) + || ((s->tfr & 0x20000) & (~(s->tmr & 0x20000)))) + { + qemu_set_irq(s->tcu_irq1, 1); + } + else + qemu_set_irq(s->tcu_irq1, 0); + + if (((s->tfr & 0xfc) & (~(s->tmr & 0xfc))) + || ((s->tfr & 0xfc0000) & (~(s->tmr & 0xfc0000)))) + { + qemu_set_irq(s->tcu_irq2, 1); + } + else + qemu_set_irq(s->tcu_irq2, 0); + #endif +} + +#undef TCU_INDEX +#define TCU_INDEX 0 +#include "mips_jz_glue.h" +#define TCU_INDEX 1 +#include "mips_jz_glue.h" +#define TCU_INDEX 2 +#include "mips_jz_glue.h" +#define TCU_INDEX 3 +#include "mips_jz_glue.h" +#define TCU_INDEX 4 +#include "mips_jz_glue.h" +#define TCU_INDEX 5 +#include "mips_jz_glue.h" +#define TCU_INDEX 6 +#include "mips_jz_glue.h" +#define TCU_INDEX 7 +#include "mips_jz_glue.h" +#undef TCU_INDEX + +#define jz4740_tcu_start(s) do { \ + jz4740_tcu_start_half0(s); \ + jz4740_tcu_start_full0(s); \ + jz4740_tcu_start_half1(s); \ + jz4740_tcu_start_full1(s); \ + jz4740_tcu_start_half2(s); \ + jz4740_tcu_start_full2(s); \ + jz4740_tcu_start_half3(s); \ + jz4740_tcu_start_full3(s); \ + jz4740_tcu_start_half4(s); \ + jz4740_tcu_start_full4(s); \ + jz4740_tcu_start_half5(s); \ + jz4740_tcu_start_full5(s); \ + jz4740_tcu_start_half6(s); \ + jz4740_tcu_start_full6(s); \ + jz4740_tcu_start_half7(s); \ + jz4740_tcu_start_full7(s); \ +}while (0) + +static void jz4740_tcu_if_reset(struct jz4740_tcu_s *s) +{ + int i; + + s->tsr = 0x0; + s->ter = 0x0; + s->tfr = 0x0; + s->tmr = 0x0; + for (i = 0; i < 8; i++) + { + s->tdfr[i] = 0xffff; + s->tdhr[i] = 0x8000; + s->tcnt[i] = 0x0; + s->tcsr[i] = 0x0; + s->half_timer[i] = NULL; + s->full_timer[i] = NULL; + } +} + +static void jz4740_tcu_if_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_if_write8 addr %x value %x\n", addr, + value); + + switch (addr) + { + case 0x14: + s->ter |= (value & 0xff); + jz4740_tcu_start(s); + break; + case 0x18: + s->ter &= ~(value & 0xff); + jz4740_tcu_start(s); + break; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_if_write8 undefined addr " JZ_FMT_plx + " value %x \n", addr, value); + } + +} + +static void jz4740_tcu_if_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_if_write32 addr %x value %x\n", addr, + value); + + fprintf(fp, "jz4740_tcu_if_write32 addr %x value %x\n", addr, + value); + switch (addr) + { + case 0x2c: + s->tsr |= (value & 0x100ff); + jz4740_tcu_start(s); + break; + case 0x3c: + s->tsr &= ~(value & 0x100ff); + jz4740_tcu_start(s); + break; + case 0x24: + s->tfr |= (value & 0xff00ff); + break; + case 0x28: + s->tfr &= ~(value & 0xff00ff); + break; + case 0x34: + s->tmr |= (value & 0xff00ff); + jz4740_tcu_update_interrupt(s); + break; + case 0x38: + s->tmr &= ~(value & 0xff00ff); + jz4740_tcu_update_interrupt(s); + break; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_if_write32 undefined addr " JZ_FMT_plx + " value %x \n", addr, value); + + } +} + +static uint32_t jz4740_tcu_if_read8(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_if_read8 addr %x\n", addr); + + switch (addr) + { + case 0x10: + return s->ter; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_if_read8 undefined addr " JZ_FMT_plx "\n", addr); + } + return (0); +} + +static uint32_t jz4740_tcu_if_read32(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_if_read32 addr %x\n", addr); + + switch (addr) + { + case 0x1c: + return s->tsr; + case 0x20: + return s->tfr; + case 0x30: + return s->tmr; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_if_read32 undefined addr " JZ_FMT_plx "\n", addr); + + } + return (0); + +} + +static CPUReadMemoryFunc *jz4740_tcu_if_readfn[] = { + jz4740_tcu_if_read8, jz4740_badwidth_read32, jz4740_tcu_if_read32, +}; + +static CPUWriteMemoryFunc *jz4740_tcu_if_writefn[] = { + jz4740_tcu_if_write8, jz4740_badwidth_write32, jz4740_tcu_if_write32, +}; + +static struct jz4740_tcu_s *jz4740_tcu_if_init(struct jz_state_s *soc, + qemu_irq tcu_irq0, + qemu_irq tcu_irq1, + qemu_irq tcu_irq2) +{ + int iomemtype; + //int i; + + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) qemu_mallocz(sizeof(*s)); + s->base = JZ4740_PHYS_BASE(JZ4740_TCU_BASE); + s->soc = soc; + s->tcu_irq0 = tcu_irq0; + s->tcu_irq1 = tcu_irq1; + s->tcu_irq2 = tcu_irq2; + + jz4740_tcu_if_reset(s); + + iomemtype = + cpu_register_io_memory(0, jz4740_tcu_if_readfn, jz4740_tcu_if_writefn, + s); + cpu_register_physical_memory(s->base, 0x00000040, iomemtype); + return s; + +} + +static void jz4740_tcu_init(struct jz_state_s *soc, + struct jz4740_tcu_s *s, int timer_index) +{ + switch (timer_index) + { + case 0x0: + jz4740_tcu_init0(soc, s); + break; + case 0x1: + jz4740_tcu_init1(soc, s); + break; + case 0x2: + jz4740_tcu_init2(soc, s); + break; + case 0x3: + jz4740_tcu_init3(soc, s); + break; + case 0x4: + jz4740_tcu_init4(soc, s); + break; + case 0x5: + jz4740_tcu_init5(soc, s); + break; + case 0x6: + jz4740_tcu_init6(soc, s); + break; + case 0x7: + jz4740_tcu_init7(soc, s); + break; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_init undefined timer %x \n", timer_index); + } +} + +typedef void (*jz4740_lcd_fn_t) (uint8_t * d, const uint8_t * s, int width, + const uint16_t * pal); +struct jz_fb_descriptor +{ + uint32_t fdadr; /* Frame descriptor address register */ + uint32_t fsadr; /* Frame source address register */ + uint32_t fidr; /* Frame ID register */ + uint32_t ldcmd; /* Command register */ +}; + +struct jz4740_lcdc_s +{ + qemu_irq irq; + + target_phys_addr_t base; + struct jz_state_s *soc; + + DisplayState *state; + QEMUConsole *console; + jz4740_lcd_fn_t *line_fn_tab; + jz4740_lcd_fn_t line_fn; + + + uint32_t lcdcfg; + uint32_t lcdvsync; + uint32_t lcdhsync; + uint32_t lcdvat; + uint32_t lcddah; + uint32_t lcddav; + uint32_t lcdps; + uint32_t lcdcls; + uint32_t lcdspl; + uint32_t lcdrev; + uint32_t lcdctrl; + uint32_t lcdstate; + uint32_t lcdiid; + uint32_t lcdda0; + uint32_t lcdsa0; + uint32_t lcdfid0; + uint32_t lcdcmd0; + uint32_t lcdda1; + uint32_t lcdsa1; + uint32_t lcdfid1; + uint32_t lcdcmd1; + + uint32_t ena; + uint32_t dis; + uint32_t width; + uint32_t height; + uint32_t bpp; /*bit per second */ + uint16_t palette[256]; + uint32_t invalidate; + +}; + +/*bit per pixel*/ +static const int jz4740_lcd_bpp[0x6] = { + 1, 2, 4, 8, 16, 32 /*4740 uses 32 bit for 24bpp */ +}; + +static void jz4740_lcdc_reset(struct jz4740_lcdc_s *s) +{ + +} + +static uint32_t jz4740_lcdc_read(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_lcdc_s *s = (struct jz4740_lcdc_s *) opaque; + + debug_out(DEBUG_LCDC, "jz4740_lcdc_read addr %x \n", addr); + switch (addr) + { + case 0x0: + return s->lcdcfg; + case 0x4: + return s->lcdvsync; + case 0x8: + return s->lcdhsync; + case 0xc: + return s->lcdvat; + case 0x10: + return s->lcddah; + case 0x14: + return s->lcddav; + case 0x18: + return s->lcdps; + case 0x1c: + return s->lcdcls; + case 0x20: + return s->lcdspl; + case 0x24: + return s->lcdrev; + case 0x30: + return s->lcdctrl; + case 0x34: + return s->lcdstate; + case 0x38: + return s->lcdiid; + case 0x40: + return s->lcdda0; + case 0x44: + return s->lcdsa0; + case 0x48: + return s->lcdfid0; + case 0x4c: + return s->lcdcmd0; + case 0x50: + return s->lcdda1; + case 0x54: + return s->lcdsa1; + case 0x58: + return s->lcdfid1; + case 0x5c: + return s->lcdcmd1; + default: + cpu_abort(s->soc->env, + "jz4740_lcdc_read undefined addr " JZ_FMT_plx " \n", addr); + + } + +} + +static void jz4740_lcdc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_lcdc_s *s = (struct jz4740_lcdc_s *) opaque; + + debug_out(DEBUG_LCDC, "jz4740_lcdc_write addr %x value %x\n", addr, value); + + switch (addr) + { + case 0x44: + case 0x48: + case 0x4c: + JZ4740_RO_REG(addr); + break; + case 0x0: + s->lcdcfg = value & 0x80ffffbf; + break; + case 0x4: + s->lcdvsync = value & 0x7ff07ff; + break; + case 0x8: + s->lcdhsync = value & 0x7ff07ff; + break; + case 0xc: + s->lcdvat = value & 0x7ff07ff; + break; + case 0x10: + s->lcddah = value & 0x7ff07ff; + s->width = (value & 0x7ff) - ((value >> 16) & 0x7ff); + break; + case 0x14: + s->height = (value & 0x7ff) - ((value >> 16) & 0x7ff); + s->lcddav = value & 0x7ff07ff; + break; + case 0x18: + s->lcdps = value & 0x7ff07ff; + break; + case 0x1c: + s->lcdcls = value & 0x7ff07ff; + break; + case 0x20: + s->lcdspl = value & 0x7ff07ff; + break; + case 0x24: + s->lcdrev = value & 0x7ff0000; + break; + case 0x30: + s->lcdctrl = value & 0x3fff3fff; + s->ena = (value & 0x8) >> 3; + s->dis = (value & 0x10) >> 4; + s->bpp = jz4740_lcd_bpp[value & 0x7]; + if ((s->bpp == 1)) + { + fprintf(stderr, "bpp =1 is not supported\n"); + exit(-1); + } + s->line_fn = s->line_fn_tab[value & 0x7]; + break; + case 0x34: + s->lcdstate = value & 0xbf; + break; + case 0x38: + s->lcdiid = value; + break; + case 0x40: + s->lcdda0 = value; + break; + case 0x50: + s->lcdda1 = value; + break; + default: + cpu_abort(s->soc->env, + "jz4740_lcdc_write undefined addr " JZ_FMT_plx " value %x \n", + addr, value); + } + +} + +static CPUReadMemoryFunc *jz4740_lcdc_readfn[] = { + jz4740_badwidth_read32, jz4740_badwidth_read32, jz4740_lcdc_read, +}; + +static CPUWriteMemoryFunc *jz4740_lcdc_writefn[] = { + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_lcdc_write, +}; + +#include "pixel_ops.h" +#define JZ4740_LCD_PANEL +#define DEPTH 8 +#include "mips_jz_glue.h" +#define DEPTH 15 +#include "mips_jz_glue.h" +#define DEPTH 16 +#include "mips_jz_glue.h" +#define DEPTH 24 +#include "mips_jz_glue.h" +#define DEPTH 32 +#include "mips_jz_glue.h" +#undef JZ4740_LCD_PANEL + +static void *jz4740_lcd_get_buffer(struct jz4740_lcdc_s *s, + target_phys_addr_t addr) +{ + uint32_t pd; + + pd = cpu_get_physical_page_desc(addr); + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + /* TODO */ + cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n", + __FUNCTION__); + else + return phys_ram_base + + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); +} + +static void jz4740_lcd_update_display(void *opaque) +{ + struct jz4740_lcdc_s *s = (struct jz4740_lcdc_s *) opaque; + + uint8_t *src, *dest; + struct jz_fb_descriptor *fb_des; + + int step, linesize; + int y; + + + if (!s->ena) + return; + if (s->dis) + return; + + if (!s->lcdda0) + return; + + fb_des = (struct jz_fb_descriptor *) jz4740_lcd_get_buffer(s, s->lcdda0); + s->lcdda0 = fb_des->fdadr; + s->lcdsa0 = fb_des->fsadr; + s->lcdfid0 = fb_des->fidr; + s->lcdcmd0 = fb_des->ldcmd; + + src = (uint8_t *) jz4740_lcd_get_buffer(s, fb_des->fsadr); + if (s->lcdcmd0 & (0x1 << 28)) + { + /*palette */ + memcpy(s->palette, src, sizeof(s->palette)); + return; + } + + /*frame buffer */ + + if (s->width != ds_get_width(s->state) || + s->height != ds_get_height(s->state)) + { + qemu_console_resize(s->console, s->width, s->height); + s->invalidate = 1; + } + + step = (s->width * s->bpp) >> 3; + dest = ds_get_data(s->state); + linesize = ds_get_linesize(s->state); + + //printf("s->width %d s->height %d s->bpp %d linesize %d \n",s->width,s->height ,s->bpp,linesize); + + for (y = 0; y < s->height; y++) + { + s->line_fn(dest, src, s->width, s->palette); + //memcpy(dest,src,step); + src += step; + dest += linesize; + } + + + dpy_update(s->state, 0, 0, s->width, s->height); + s->lcdstate |= 0x20; + if ((s->lcdcmd0 & 0x40000000) && (!(s->lcdctrl & 0x2000))) + qemu_set_irq(s->irq, 1); +} + +static inline void jz4740_lcd_invalidate_display(void *opaque) +{ + struct jz4740_lcdc_s *s = (struct jz4740_lcdc_s *) opaque; + s->invalidate = 1; +} + +static struct jz4740_lcdc_s *jz4740_lcdc_init(struct jz_state_s *soc, + qemu_irq irq, DisplayState * ds) +{ + int iomemtype; + + struct jz4740_lcdc_s *s = (struct jz4740_lcdc_s *) qemu_mallocz(sizeof(*s)); + s->base = JZ4740_PHYS_BASE(JZ4740_LCD_BASE); + s->soc = soc; + s->irq = irq; + s->state = ds; + + + jz4740_lcdc_reset(s); + + iomemtype = + cpu_register_io_memory(0, jz4740_lcdc_readfn, jz4740_lcdc_writefn, s); + cpu_register_physical_memory(s->base, 0x10000, iomemtype); + + s->console = graphic_console_init(s->state, jz4740_lcd_update_display, + jz4740_lcd_invalidate_display, + NULL, NULL, s); + switch (ds_get_bits_per_pixel(s->state)) + { + case 0x0: + s->line_fn_tab = qemu_mallocz(sizeof(jz4740_lcd_fn_t) * 6); + break; + case 8: + s->line_fn_tab = jz4740_lcd_draw_fn_8; + break; + case 15: + s->line_fn_tab = jz4740_lcd_draw_fn_15; + break; + case 16: + s->line_fn_tab = jz4740_lcd_draw_fn_16; + break; + case 24: + s->line_fn_tab = jz4740_lcd_draw_fn_24; + break; + case 32: + s->line_fn_tab = jz4740_lcd_draw_fn_32; + break; + default: + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); + exit(1); + } + + return s; + +} + +#define JZ4740_DMA_NUM 6 +struct jz4740_dma_s +{ + qemu_irq irq; + + target_phys_addr_t base; + struct jz_state_s *soc; + + uint32_t dmac; + uint32_t dirqp; + uint32_t ddr; + uint32_t ddrs; + + uint32_t dsa[JZ4740_DMA_NUM]; + uint32_t dta[JZ4740_DMA_NUM]; + uint32_t dtc[JZ4740_DMA_NUM]; + uint32_t drs[JZ4740_DMA_NUM]; + uint32_t dcs[JZ4740_DMA_NUM]; + uint32_t dcm[JZ4740_DMA_NUM]; + uint32_t dda[JZ4740_DMA_NUM]; + +}; + +struct jz4740_desc_s +{ + uint32_t dcmd; /* DCMD value for the current transfer */ + uint32_t dsadr; /* DSAR value for the current transfer */ + uint32_t dtadr; /* DTAR value for the current transfer */ + uint32_t ddadr; /* Points to the next descriptor + transfer count */ +}; + +static inline void jz4740_dma_transfer(struct jz4740_dma_s *s, + target_phys_addr_t src, + target_phys_addr_t dest, uint32_t len) +{ + uint32_t pd_src, pd_dest; + uint8_t *sr, *de; + + pd_src = cpu_get_physical_page_desc(src); + if ((pd_src & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + /* TODO */ + cpu_abort(cpu_single_env, "%s: DMA source address %x outside RAM!\n", + __FUNCTION__, src); + else + sr = phys_ram_base + + (pd_src & TARGET_PAGE_MASK) + (src & ~TARGET_PAGE_MASK); + + pd_dest = cpu_get_physical_page_desc(dest); + if ((pd_dest & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + /* TODO */ + cpu_abort(cpu_single_env, + "%s: DMA destination address %x outside RAM!\n", + __FUNCTION__, dest); + else + de = phys_ram_base + + (pd_dest & TARGET_PAGE_MASK) + (dest & ~TARGET_PAGE_MASK); + + memcpy(de, sr, len); +} + +static inline uint32_t jz4740_dma_unit_size(struct jz4740_dma_s *s, + uint32_t cmd) +{ + switch ((cmd & 0x700) >> 8) + { + case 0x0: + return 4; + case 0x1: + return 1; + case 0x2: + return 2; + case 0x3: + return 16; + case 0x4: + return 32; + } + return (0); +} + + +/*No-descriptor transfer*/ +static inline void jz4740_dma_ndrun(struct jz4740_dma_s *s, int channel) +{ + uint32_t len; + + len = jz4740_dma_unit_size(s, s->dcs[channel]) * s->dtc[channel]; + + jz4740_dma_transfer(s, s->dsa[channel], s->dta[channel], len); + + /*finish dma transfer */ + s->dtc[channel] = 0; + /*set DIR QP */ + s->dirqp |= 1 << channel; + + /*some cleanup work */ + /*clean AR TT GLOBAL AR */ + s->dcs[channel] &= 0xffffffe7; + s->dmac &= 0xfffffffb; + + if (s->dcm[channel] & 0x2) + qemu_set_irq(s->irq, 1); +} + + /*descriptor transfer */ +static inline void jz4740_dma_drun(struct jz4740_dma_s *s, int channel) +{ + struct jz4740_desc_s *desc; + target_phys_addr_t desc_phy; + uint32_t pd; + + desc_phy = s->dda[channel]; + if (desc_phy & 0xf) + cpu_abort(s->soc->env, + "jz4740_dma_drun descriptor address " JZ_FMT_plx + " must be 4 bytes aligned \n", desc_phy); + + pd = cpu_get_physical_page_desc(desc_phy); + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + cpu_abort(cpu_single_env, + "%s: DMA descriptor address " JZ_FMT_plx " outside RAM!\n", + __FUNCTION__, desc_phy); + else + desc = (struct jz4740_desc_s *) (phys_ram_base + + (pd & TARGET_PAGE_MASK) + + (desc_phy & ~TARGET_PAGE_MASK)); + + if (!desc) + cpu_abort(cpu_single_env, + "%s: DMA descriptor " JZ_FMT_plx " is NULL!\n", __FUNCTION__, + (uint32_t) desc); + + while (1) + { + if ((desc->dcmd & 0x8) && (!(desc->dcmd & 0x10))) + { + /*Stop DMA and set DCSN.INV=1 */ + s->dcs[channel] |= 1 << 6; + return; + } + jz4740_dma_transfer(s, desc->dtadr, desc->dsadr, + (desc->ddadr & 0xffffff) * + jz4740_dma_unit_size(s, desc->dcmd)); + + if ((desc->dcmd) & (1 << 3)) + /*clear v */ + desc->dcmd &= ~(1 << 4); + if (desc->dcmd & 0x1) + /*set DCSN.CT=1 */ + s->dcs[channel] |= 0x2; + else + /*set DCSN.TT=1 */ + s->dcs[channel] |= 0x8; + + if (desc->dcmd & 0x2) + qemu_set_irq(s->irq, 1); + + if ((desc->dcmd) & 0x1) + { + /*fetch next descriptor */ + desc_phy = s->dda[channel] & 0xfffff000; + desc_phy += (desc->dtadr & 0xff000000) >> 24; + pd = cpu_get_physical_page_desc(desc_phy); + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + cpu_abort(cpu_single_env, + "%s: DMA descriptor address %x outside RAM!\n", + __FUNCTION__, desc_phy); + else + desc = (struct jz4740_desc_s *) (phys_ram_base + + (pd & TARGET_PAGE_MASK) + + + (desc_phy & + ~TARGET_PAGE_MASK)); + if (!desc) + cpu_abort(cpu_single_env, + "%s: DMA descriptor %x is NULL!\n", + __FUNCTION__, (uint32_t) desc); + } + else + break; + } +} + +static void jz4740_dma_en_channel(struct jz4740_dma_s *s, int channel) +{ + if (s->dmac & 0x1) + { + if (s->dcs[channel] & (1 << 31)) + { + /*NON DESCRIPTOR */ + jz4740_dma_ndrun(s, channel); + } + } +} + +static inline void jz4740_dma_en_global(struct jz4740_dma_s *s) +{ + int channel; + for (channel = 0; channel < JZ4740_DMA_NUM; channel++) + { + jz4740_dma_en_channel(s, channel); + } +} + +static inline void jz4740_dma_en_dbn(struct jz4740_dma_s *s, int channel) +{ + if ((s->dmac & 0x1) && (s->dcs[channel] & (1 << 31))) + { + jz4740_dma_drun(s, channel); + } +} + +static void jz4740_dma_reset(struct jz4740_dma_s *s) +{ + +} + +static uint32_t jz4740_dma_read(void *opaque, target_phys_addr_t addr) +{ + struct jz4740_dma_s *s = (struct jz4740_dma_s *) opaque; + int channel; + + debug_out(DEBUG_DMA, "jz4740_dma_read addr %x \n", addr); + switch (addr) + { + case 0x300: + return s->dmac; + case 0x304: + return s->dirqp; + case 0x308: + return s->ddr; + case 0x0: + case 0x20: + case 0x40: + case 0x60: + case 0x80: + case 0xa0: + channel = (addr - 0x0) / 0x20; + return s->dsa[channel]; + case 0x4: + case 0x24: + case 0x44: + case 0x64: + case 0x84: + case 0xa4: + channel = (addr - 0x4) / 0x20; + return s->dta[channel]; + case 0x8: + case 0x28: + case 0x48: + case 0x68: + case 0x88: + case 0xa8: + channel = (addr - 0x8) / 0x20; + return s->dtc[channel]; + case 0xc: + case 0x2c: + case 0x4c: + case 0x6c: + case 0x8c: + case 0xac: + channel = (addr - 0xc) / 0x20; + return s->drs[channel]; + case 0x10: + case 0x30: + case 0x50: + case 0x70: + case 0x90: + case 0xb0: + channel = (addr - 0x10) / 0x20; + return s->dcs[channel]; + case 0x14: + case 0x34: + case 0x54: + case 0x74: + case 0x94: + case 0xb4: + channel = (addr - 0x14) / 0x20; + return s->dcm[channel]; + case 0x18: + case 0x38: + case 0x58: + case 0x78: + case 0x98: + case 0xb8: + channel = (addr - 0x18) / 0x20; + return s->dda[channel]; + default: + cpu_abort(s->soc->env, + "jz4740_dma_read undefined addr " JZ_FMT_plx " \n", addr); + } + return (0); +} + +static void jz4740_dma_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_dma_s *s = (struct jz4740_dma_s *) opaque; + int channel; + + debug_out(DEBUG_DMA, "jz4740_dma_write addr %x value %x \n", addr, value); + switch (addr) + { + case 0x304: + JZ4740_RO_REG(addr); + break; + case 0x300: + s->dmac = value & 0x30d; + if (s->dmac & 0x1) + jz4740_dma_en_global(s); + break; + case 0x308: + case 0x30c: + s->ddr = value & 0xff; + for (channel = 0; channel < JZ4740_DMA_NUM; channel++) + { + if (s->ddr & (1 << channel)) + { + jz4740_dma_en_dbn(s, channel); + break; + } + } + break; + case 0x0: + case 0x20: + case 0x40: + case 0x60: + case 0x80: + case 0xa0: + channel = (addr - 0x0) / 0x20; + s->dsa[channel] = value; + break; + case 0x4: + case 0x24: + case 0x44: + case 0x64: + case 0x84: + case 0xa4: + channel = (addr - 0x4) / 0x20; + s->dta[channel] = value; + break; + case 0x8: + case 0x28: + case 0x48: + case 0x68: + case 0x88: + case 0xa8: + channel = (addr - 0x8) / 0x20; + s->dtc[channel] = value; + break; + case 0xc: + case 0x2c: + case 0x4c: + case 0x6c: + case 0x8c: + case 0xac: + channel = (addr - 0xc) / 0x20; + s->drs[channel] = value & 0x10; + if (s->drs[channel] != 0x8) + { + fprintf(stderr, "Only auto request is supproted \n"); + } + break; + case 0x10: + case 0x30: + case 0x50: + case 0x70: + case 0x90: + case 0xb0: + channel = (addr - 0x10) / 0x20; + s->dcs[channel] = value & 0x80ff005f; + if (s->dcs[channel] & 0x1) + jz4740_dma_en_channel(s, channel); + break; + case 0x14: + case 0x34: + case 0x54: + case 0x74: + case 0x94: + case 0xb4: + channel = (addr - 0x14) / 0x20; + s->dcm[channel] = value & 0xcff79f; + break; + case 0x18: + case 0x38: + case 0x58: + case 0x78: + case 0x98: + case 0xb8: + channel = (addr - 0x18) / 0x20; + s->dda[channel] = 0xfffffff0; + break; + default: + cpu_abort(s->soc->env, + "jz4740_dma_read undefined addr " JZ_FMT_plx " \n", addr); + } + +} + +static CPUReadMemoryFunc *jz4740_dma_readfn[] = { + jz4740_badwidth_read32, jz4740_badwidth_read32, jz4740_dma_read, +}; + +static CPUWriteMemoryFunc *jz4740_dma_writefn[] = { + jz4740_badwidth_write32, jz4740_badwidth_write32, jz4740_dma_write, +}; + + +static struct jz4740_dma_s *jz4740_dma_init(struct jz_state_s *soc, + qemu_irq irq) +{ + int iomemtype; + struct jz4740_dma_s *s = (struct jz4740_dma_s *) qemu_mallocz(sizeof(*s)); + s->base = JZ4740_PHYS_BASE(JZ4740_DMAC_BASE); + s->soc = soc; + s->irq = irq; + + jz4740_dma_reset(s); + + iomemtype = + cpu_register_io_memory(0, jz4740_dma_readfn, jz4740_dma_writefn, s); + cpu_register_physical_memory(s->base, 0x00010000, iomemtype); + return s; + +} static void jz4740_cpu_reset(void *opaque) { @@ -963,7 +2629,7 @@ static void jz4740_cpu_reset(void *opaque) } struct jz_state_s *jz4740_init(unsigned long sdram_size, - uint32_t osc_extal_freq) + uint32_t osc_extal_freq, DisplayState * ds) { struct jz_state_s *s = (struct jz_state_s *) qemu_mallocz(sizeof(struct jz_state_s)); @@ -990,10 +2656,9 @@ struct jz_state_s *jz4740_init(unsigned long sdram_size, /*map sram to 0x80000000 and sdram to 0x80004000 */ sram_base = qemu_ram_alloc(s->sram_size); - cpu_register_physical_memory(JZ4740_SRAM_BASE, s->sram_size, - (sram_base | IO_MEM_RAM)); + cpu_register_physical_memory(0x0, s->sram_size, (sram_base | IO_MEM_RAM)); sdram_base = qemu_ram_alloc(s->sdram_size); - cpu_register_physical_memory(JZ4740_SDRAM_BASE, s->sdram_size, + cpu_register_physical_memory(JZ4740_SRAM_SIZE, s->sdram_size, (sdram_base | IO_MEM_RAM)); /* Init internal devices */ @@ -1006,7 +2671,16 @@ struct jz_state_s *jz4740_init(unsigned long sdram_size, intc = jz4740_intc_init(s, s->env->irq[2]); s->cpm = jz4740_cpm_init(s); - s->emc = jz4740_emc_init(s,intc[2]); + s->emc = jz4740_emc_init(s, intc[2]); + s->gpio = jz4740_gpio_init(s, intc[25]); + s->rtc = jz4740_rtc_init(s, intc[15]); + s->tcu = jz4740_tcu_if_init(s, intc[23], intc[22], intc[21]); + jz4740_tcu_init(s, s->tcu, 0); + s->lcdc = jz4740_lcdc_init(s, intc[30], ds); + s->dma = jz4740_dma_init(s, intc[20]); + + if (serial_hds[0]) + serial_mm_init(0x10030000, 2, intc[9], 57600, serial_hds[0], 1); return s; } diff --git a/hw/mips_jz.h b/hw/mips_jz.h index 4f0275e17d..f28bfc3a30 100755 --- a/hw/mips_jz.h +++ b/hw/mips_jz.h @@ -102,14 +102,17 @@ -#if TARGET_PHYS_ADDR_BITS == 32 -#define JZ_FMT_plx "%#08x" -#elif TARGET_PHYS_ADDR_BITS == 64 -#define JZ_FMT_plx "%#08" PRIx64 -#else -#error TARGET_PHYS_ADDR_BITS undefined -#endif - +#define JZ_FMT_plx "%#16x" + +uint32_t jz4740_badwidth_read8(void *opaque, target_phys_addr_t addr); +uint32_t jz4740_badwidth_read16(void *opaque, target_phys_addr_t addr); +uint32_t jz4740_badwidth_read32(void *opaque, target_phys_addr_t addr); +void jz4740_badwidth_write8(void *opaque, target_phys_addr_t addr, + uint32_t value); +void jz4740_badwidth_write16(void *opaque, target_phys_addr_t addr, + uint32_t value); +void jz4740_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value); #define IO_ACCESS_VERBOSE 1 @@ -159,7 +162,7 @@ struct clk { unsigned long rate; /* Current rate (if .running) */ unsigned int divisor; /* Rate relative to input (if .enabled) */ unsigned int multiplier; /* Rate relative to input (if .enabled) */ - int usecount; + //int usecount; }; typedef struct clk *jz_clk; void jz_clk_init(struct jz_state_s *mpu,uint32_t osc_extal_freq); @@ -174,7 +177,7 @@ void jz_clk_reparent(jz_clk clk, jz_clk parent); /*mips_jz.c*/ struct jz_state_s *jz4740_init(unsigned long sdram_size, - uint32_t osc_extal_freq); + uint32_t osc_extal_freq,DisplayState * ds); enum jz_cpu_model { jz4740, @@ -195,7 +198,11 @@ struct jz_state_s { struct jz4740_cpm_s *cpm; struct jz4740_emc_s *emc; - + struct jz4740_gpio_s *gpio; + struct jz4740_rtc_s *rtc; + struct jz4740_tcu_s *tcu; + struct jz4740_lcdc_s *lcdc; + struct jz4740_dma_s *dma; }; diff --git a/hw/mips_jz_clk.c b/hw/mips_jz_clk.c index c5ac296a24..60e85e290d 100755 --- a/hw/mips_jz_clk.c +++ b/hw/mips_jz_clk.c @@ -1,7 +1,7 @@ /* * JZ Soc clocks. * - * Copyright (C) 2006-2008 yajin + * Copyright (C) 2009 yajin * * * This program is free software; you can redistribute it and/or @@ -33,7 +33,7 @@ static struct clk osc_extal = { - .name = "osc_extal_12M", + .name = "osc_extal", .rate = 12000000, .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740, }; @@ -151,18 +151,6 @@ struct clk *jz_findclk(struct jz_state_s *cpu, const char *name) cpu_abort(cpu->env, "%s: %s not found\n", __FUNCTION__, name); } -void jz_clk_get(struct clk *clk) -{ - clk->usecount++; -} - -void jz_clk_put(struct clk *clk) -{ - if (!(clk->usecount--)) - cpu_abort(cpu_single_env, "%s: %s is not in use\n", - __FUNCTION__, clk->name); -} - static void jz_clk_update(struct clk *clk) { int parent, running; @@ -175,7 +163,7 @@ static void jz_clk_update(struct clk *clk) parent = 1; running = parent && (clk->enabled || - ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); + ((clk->flags & ALWAYS_ENABLED))); if (clk->running != running) { clk->running = running; @@ -244,14 +232,6 @@ void jz_clk_onoff(struct clk *clk, int on) jz_clk_update(clk); } -void jz_clk_canidle(struct clk *clk, int can) -{ - if (can) - jz_clk_put(clk); - else - jz_clk_get(clk); -} - void jz_clk_setrate(struct clk *clk, int divide, int multiply) { clk->divisor = divide; diff --git a/hw/mips_jz_glue.h b/hw/mips_jz_glue.h index 0aebbc3b56..9e41c4e645 100755 --- a/hw/mips_jz_glue.h +++ b/hw/mips_jz_glue.h @@ -1,486 +1,486 @@ -/* - * QEMU JZ Soc emulation glue code - * - * Copyright (c) 2009 yajin (yajin@vm-kernel.org) - * - * 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. - */ - - - -#ifdef TCU_INDEX -static inline void glue(jz4740_tcu_time_sync, - TCU_INDEX) (struct jz4740_tcu_s * s) -{ - int64_t distance; - int64_t temp; - - if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) - && (s->freq[TCU_INDEX] != 0)) - { - //debug_out(DEBUG_TCU, "jz4740_tcu_time_sync%x \n", TCU_INDEX); - /*first enable timer */ - if (s->time[TCU_INDEX] == 0) - { - s->time[TCU_INDEX] = qemu_get_clock(vm_clock); - s->tcnt[TCU_INDEX] = 0; - return; - } - distance = qemu_get_clock(vm_clock) - s->time[TCU_INDEX]; - //debug_out(DEBUG_TCU, - // "s->freq[TCU_INDEX] %d s->prescale[TCU_INDEX] %d \n", - // s->freq[TCU_INDEX], s->prescale[TCU_INDEX]); - // debug_out(DEBUG_TCU, "distance %lld s->time[TCU_INDEX] %lld \n", - // distance, s->time[TCU_INDEX]); - //temp = muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec); - temp = muldiv64(distance, 46875, ticks_per_sec); - if (temp != 0) - { - /*distance is too short */ - s->tcnt[TCU_INDEX] += temp; - s->time[TCU_INDEX] = qemu_get_clock(vm_clock); - } - else - { - /*distance is too short. - * Do not sync timer this timer. - */ - } - - //printf("%lld distance %lld \n",muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec),distance); - - if (s->tcnt[TCU_INDEX] >= 0x10000) - s->tcnt[TCU_INDEX] = 0x0; - - - } -} - -static inline void glue(jz4740_tcu_start_half, - TCU_INDEX) (struct jz4740_tcu_s * s) -{ - int64_t next = qemu_get_clock(vm_clock); - int64_t count; - - /*The timer has not beed initialized */ - if (!s->half_timer[TCU_INDEX]) - return; - - if ((!(s->tsr & (1 << (TCU_INDEX+16)))) && (s->ter & (1 << (TCU_INDEX+16))) - && (s->freq[TCU_INDEX] != 0)) - { - glue(jz4740_tcu_time_sync, TCU_INDEX) (s); - /*calculate next fire time */ - count = - (s->tdhr[TCU_INDEX] - s->tcnt[TCU_INDEX]) * s->prescale[TCU_INDEX]; - next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); - qemu_mod_timer(s->half_timer[TCU_INDEX], next); - - } - else - qemu_del_timer(s->half_timer[TCU_INDEX]); - -} - -static inline void glue(jz4740_tcu_start_full, - TCU_INDEX) (struct jz4740_tcu_s * s) -{ - int64_t next = qemu_get_clock(vm_clock); - int64_t count; - - /*The timer has not beed initialized */ - if (!s->full_timer[TCU_INDEX]) - return; - - debug_out(DEBUG_TCU, "s->tsr %d s->ter %d s->freq[TCU_INDEX] %d \n", - s->tsr , s->ter ,s->freq[TCU_INDEX]); -printf("s->tsr %d s->ter %d s->freq[TCU_INDEX] %d \n", - s->tsr , s->ter ,s->freq[TCU_INDEX]); - if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) - && (s->freq[TCU_INDEX] != 0)) - { - glue(jz4740_tcu_time_sync, TCU_INDEX) (s); - printf("tdfr %x \n",s->tdfr[TCU_INDEX] ); - /*calculate next fire time */ - count = - (s->tdfr[TCU_INDEX] - s->tcnt[TCU_INDEX]) * s->prescale[TCU_INDEX]; - printf("tdfr11 %x count %lld\n",s->tdfr[TCU_INDEX],count ); - next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); - qemu_mod_timer(s->full_timer[TCU_INDEX], next); - debug_out(DEBUG_TCU, "s->tdfr[TCU_INDEX] %d s->tcnt[TCU_INDEX] %d next %lld \n", - s->tdfr[TCU_INDEX] , s->tcnt[TCU_INDEX] ,next); - printf("s->tdfr[TCU_INDEX]22 %x s->tcnt[TCU_INDEX] %x next %lld \n", - s->tdfr[TCU_INDEX] , s->tcnt[TCU_INDEX] ,next); - - } - else - qemu_del_timer(s->full_timer[TCU_INDEX]); -} - - -/* - * TCNT will reset to 0 if it reach to TDFR. - * So for the half compare, the next fire count is (TDFR-TDHR) + TDHR - * - */ -static void glue(jz4740_tcu_half_cb, TCU_INDEX) (void *opaque) -{ - struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; - int64_t next = qemu_get_clock(vm_clock); - int64_t count; - - if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) - && (s->freq[TCU_INDEX] != 0)) - { - count = s->tdfr[TCU_INDEX] * s->prescale[TCU_INDEX]; - next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); - qemu_mod_timer(s->half_timer[TCU_INDEX], next); - s->tfr |= 1 << (16 + TCU_INDEX); - jz4740_tcu_update_interrupt(s); - s->tcnt[TCU_INDEX] = s->tdhr[TCU_INDEX]; - s->time[TCU_INDEX] = qemu_get_clock(vm_clock); - } - else - qemu_del_timer(s->half_timer[TCU_INDEX]); -} - - -static void glue(jz4740_tcu_full_cb, TCU_INDEX) (void *opaque) -{ - struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; - int64_t next = qemu_get_clock(vm_clock); - int64_t count; - - if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) - && (s->freq[TCU_INDEX] != 0)) - { - //printf("s->tdfr[TCU_INDEX] %x s->prescale[TCU_INDEX] %x \n",s->tdfr[TCU_INDEX] ,s->prescale[TCU_INDEX] ); - count = s->tdfr[TCU_INDEX] * s->prescale[TCU_INDEX]; - next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); - //printf("count %lld next %lld \n",count,next); - qemu_mod_timer(s->full_timer[TCU_INDEX], next); - s->tfr |= 1 << TCU_INDEX; - jz4740_tcu_update_interrupt(s); - s->tcnt[TCU_INDEX] = 0; - s->time[TCU_INDEX] = qemu_get_clock(vm_clock); - } - else - qemu_del_timer(s->full_timer[TCU_INDEX]); -} - -static uint32_t glue(jz4740_tcu_read, TCU_INDEX) (void *opaque, - target_phys_addr_t addr) -{ - struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; - - debug_out(DEBUG_TCU, "jz4740_tcu_read%x addr %x\n", TCU_INDEX, addr); - addr -= 0x40 + TCU_INDEX * 0x10; - - switch (addr) - { - case 0x0: - return s->tdfr[TCU_INDEX]; - case 0x4: - return s->tdhr[TCU_INDEX]; - case 0x8: - glue(jz4740_tcu_time_sync, TCU_INDEX) (s); - //debug_out(DEBUG_TCU, "s->tcnt %x\n", s->tcnt[TCU_INDEX]); - //printf("s->tcnt %x\n", s->tcnt[TCU_INDEX]); - return s->tcnt[TCU_INDEX]; - case 0xc: - return s->tcsr[TCU_INDEX]; - default: - cpu_abort(s->soc->env, - "jz4740_tcu_read undefined addr %x timer %x \n", addr, - TCU_INDEX); - } - return (0); -} - -static void glue(jz4740_tcu_write, TCU_INDEX) (void *opaque, - target_phys_addr_t addr, - uint32_t value) -{ - struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; - - debug_out(DEBUG_TCU, "jz4740_tcu_write%x addr %x value %x \n", TCU_INDEX, - addr, value); -printf( "jz4740_tcu_write%x addr %x value %x \n", TCU_INDEX, - addr, value); - addr -= 0x40 + TCU_INDEX * 0x10; - - switch (addr) - { - case 0x0: - /*TDFR*/ - - s->tdfr[TCU_INDEX] = value & 0xffff; - printf("s->tdfr[TCU_INDEX] %x \n",s->tdfr[TCU_INDEX] ); - glue(jz4740_tcu_start_full, TCU_INDEX) (s); - break; - case 0x4: - /*TDHR*/ s->tdhr[TCU_INDEX] = value & 0xffff; - glue(jz4740_tcu_start_half, TCU_INDEX) (s); - break; - case 0x8: - /*TCNT*/ s->tcnt[TCU_INDEX] = value & 0xffff; - s->time[TCU_INDEX] = qemu_get_clock(vm_clock); - glue(jz4740_tcu_start_half, TCU_INDEX) (s); - glue(jz4740_tcu_start_full, TCU_INDEX) (s); - break; - case 0xc: - s->tcsr[TCU_INDEX] = value & 0x3bf; - switch (value & 0x7) - { - case 0x1: - s->freq[TCU_INDEX] = jz_clk_getrate(jz_findclk(s->soc, "pclk")); - break; - case 0x2: - s->freq[TCU_INDEX] = jz_clk_getrate(jz_findclk(s->soc, "osc_32K")); - break; - case 0x4: - s->freq[TCU_INDEX] = - jz_clk_getrate(jz_findclk(s->soc, "osc_extal")); - break; - default: - s->freq[TCU_INDEX] = 0x0; - break; - } - s->prescale[TCU_INDEX] = 1 << (((value & 0x38) >> 3) * 2); - printf("s->prescale[TCU_INDEX] %x\n",s->prescale[TCU_INDEX] ); - glue(jz4740_tcu_start_half, TCU_INDEX) (s); - glue(jz4740_tcu_start_full, TCU_INDEX) (s); - break; - default: - cpu_abort(s->soc->env, - "jz4740_tcu_write undefined addr %x timer %x \n", addr, - TCU_INDEX); - - } -} - - -static CPUReadMemoryFunc *glue(jz4740_tcu_readfn, TCU_INDEX)[] = -{ -jz4740_badwidth_read16, - glue(jz4740_tcu_read, TCU_INDEX), jz4740_badwidth_read16,}; - -static CPUWriteMemoryFunc *glue(jz4740_tcu_writefn, TCU_INDEX)[] = -{ -jz4740_badwidth_write16, - glue(jz4740_tcu_write, TCU_INDEX), jz4740_badwidth_write16,}; - -static void glue(jz4740_tcu_init, TCU_INDEX) (struct jz_state_s * soc, - struct jz4740_tcu_s * s) -{ - int iomemtype; - - s->half_timer[TCU_INDEX] = - qemu_new_timer(vm_clock, glue(jz4740_tcu_half_cb, TCU_INDEX), s); - s->full_timer[TCU_INDEX] = - qemu_new_timer(vm_clock, glue(jz4740_tcu_full_cb, TCU_INDEX), s); - - iomemtype = - cpu_register_io_memory(0, glue(jz4740_tcu_readfn, TCU_INDEX), - glue(jz4740_tcu_writefn, TCU_INDEX), s); - cpu_register_physical_memory(s->base + 0x00000040 + TCU_INDEX * 0x10, - 0x00000010, iomemtype); -} - -#undef TCU_INDEX -#endif - - - -#ifdef JZ4740_LCD_PANEL - -#if DEPTH == 8 -# define BPP 1 -# define PIXEL_TYPE uint8_t -#elif DEPTH == 15 || DEPTH == 16 -# define BPP 2 -# define PIXEL_TYPE uint16_t -#elif DEPTH == 24 -# define BPP 3 -# define PIXEL_TYPE uint32_t -#elif DEPTH == 32 -# define BPP 4 -# define PIXEL_TYPE uint32_t -#else -# error unsupport depth -#endif - -/* - * 2-bit colour - */ -static void glue(draw_line2_, DEPTH) (uint8_t * d, const uint8_t * s, int width, - const uint16_t * pal) -{ - uint8_t v, r, g, b; - - do - { - v = ldub_raw((void *) s); - r = (pal[v & 3] >> 4) & 0xf0; - g = pal[v & 3] & 0xf0; - b = (pal[v & 3] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - v >>= 2; - r = (pal[v & 3] >> 4) & 0xf0; - g = pal[v & 3] & 0xf0; - b = (pal[v & 3] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - v >>= 2; - r = (pal[v & 3] >> 4) & 0xf0; - g = pal[v & 3] & 0xf0; - b = (pal[v & 3] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - v >>= 2; - r = (pal[v & 3] >> 4) & 0xf0; - g = pal[v & 3] & 0xf0; - b = (pal[v & 3] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - s++; - width -= 4; - } - while (width > 0); -} - -/* - * 4-bit colour - */ -static void glue(draw_line4_, DEPTH) (uint8_t * d, const uint8_t * s, int width, - const uint16_t * pal) -{ - uint8_t v, r, g, b; - - do - { - v = ldub_raw((void *) s); - r = (pal[v & 0xf] >> 4) & 0xf0; - g = pal[v & 0xf] & 0xf0; - b = (pal[v & 0xf] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - v >>= 4; - r = (pal[v & 0xf] >> 4) & 0xf0; - g = pal[v & 0xf] & 0xf0; - b = (pal[v & 0xf] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - d += BPP; - s++; - width -= 2; - } - while (width > 0); -} - -/* - * 8-bit colour - */ -static void glue(draw_line8_, DEPTH) (uint8_t * d, const uint8_t * s, int width, - const uint16_t * pal) -{ - uint8_t v, r, g, b; - - do - { - v = ldub_raw((void *) s); - r = (pal[v] >> 4) & 0xf0; - g = pal[v] & 0xf0; - b = (pal[v] << 4) & 0xf0; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - s++; - d += BPP; - } - while (--width != 0); -} - - -/* - * 16-bit colour - */ -static void glue(draw_line16_, DEPTH) (uint8_t * d, const uint8_t * s, - int width, const uint16_t * pal) -{ -#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 2); -#else - uint16_t v; - uint8_t r, g, b; - - do - { - v = lduw_raw((void *) s); - r = (v >> 8) & 0xf8; - g = (v >> 3) & 0xfc; - b = (v << 3) & 0xf8; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - s += 2; - d += BPP; - } - while (--width != 0); -#endif -} - -/* - * 24-bit colour. JZ4740 uses 4 bytes to store 18/24 bit color. - */ -static void glue(draw_line24_, DEPTH) (uint8_t * d, const uint8_t * s, - int width, const uint16_t * pal) -{ -#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 4); -#else - uint32_t v; - uint8_t r, g, b; - - do - { - v = ldl_raw((void *) s); - r = (v >> 16) & 0xff; - g = (v >> 8) & 0xff; - b = (v >> 0) & 0xff; - ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); - s += 3; - d += BPP; - } - while (--width != 0); -#endif -} - -static jz4740_lcd_fn_t glue(jz4740_lcd_draw_fn_, DEPTH)[6] = -{ - NULL, /*0x0 *//*1 bit per pixel */ - (jz4740_lcd_fn_t) glue(draw_line2_, DEPTH), /*0x1 *//*2 bit per pixel */ - (jz4740_lcd_fn_t) glue(draw_line4_, DEPTH), /*0x2 *//*4 bit per pixel */ - (jz4740_lcd_fn_t) glue(draw_line8_, DEPTH), /*0x3 *//*8 bit per pixel */ - (jz4740_lcd_fn_t) glue(draw_line16_, DEPTH), /*0x4 *//*15/16 bit per pixel */ - (jz4740_lcd_fn_t) glue(draw_line24_, DEPTH), /*0x5 *//*18/24 bit per pixel */ -}; - - -#undef DEPTH -#undef BPP -#undef PIXEL_TYPE - -#endif +/* + * QEMU JZ Soc emulation glue code + * + * Copyright (c) 2009 yajin (yajin@vm-kernel.org) + * + * 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. + */ + + + +#ifdef TCU_INDEX +static inline void glue(jz4740_tcu_time_sync, + TCU_INDEX) (struct jz4740_tcu_s * s) +{ + int64_t distance; + int64_t temp; + + if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) + && (s->freq[TCU_INDEX] != 0)) + { + //debug_out(DEBUG_TCU, "jz4740_tcu_time_sync%x \n", TCU_INDEX); + /*first enable timer */ + if (s->time[TCU_INDEX] == 0) + { + s->time[TCU_INDEX] = qemu_get_clock(vm_clock); + s->tcnt[TCU_INDEX] = 0; + return; + } + distance = qemu_get_clock(vm_clock) - s->time[TCU_INDEX]; + //debug_out(DEBUG_TCU, + // "s->freq[TCU_INDEX] %d s->prescale[TCU_INDEX] %d \n", + // s->freq[TCU_INDEX], s->prescale[TCU_INDEX]); + // debug_out(DEBUG_TCU, "distance %lld s->time[TCU_INDEX] %lld \n", + // distance, s->time[TCU_INDEX]); + //temp = muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec); + temp = muldiv64(distance, 46875, ticks_per_sec); + if (temp != 0) + { + /*distance is too short */ + s->tcnt[TCU_INDEX] += temp; + s->time[TCU_INDEX] = qemu_get_clock(vm_clock); + } + else + { + /*distance is too short. + * Do not sync timer this timer. + */ + } + + //printf("%lld distance %lld \n",muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec),distance); + + if (s->tcnt[TCU_INDEX] >= 0x10000) + s->tcnt[TCU_INDEX] = 0x0; + + + } +} + +static inline void glue(jz4740_tcu_start_half, + TCU_INDEX) (struct jz4740_tcu_s * s) +{ + int64_t next = qemu_get_clock(vm_clock); + int64_t count; + + /*The timer has not beed initialized */ + if (!s->half_timer[TCU_INDEX]) + return; + + if ((!(s->tsr & (1 << (TCU_INDEX+16)))) && (s->ter & (1 << (TCU_INDEX+16))) + && (s->freq[TCU_INDEX] != 0)) + { + glue(jz4740_tcu_time_sync, TCU_INDEX) (s); + /*calculate next fire time */ + count = + (s->tdhr[TCU_INDEX] - s->tcnt[TCU_INDEX]) * s->prescale[TCU_INDEX]; + next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); + qemu_mod_timer(s->half_timer[TCU_INDEX], next); + + } + else + qemu_del_timer(s->half_timer[TCU_INDEX]); + +} + +static inline void glue(jz4740_tcu_start_full, + TCU_INDEX) (struct jz4740_tcu_s * s) +{ + int64_t next = qemu_get_clock(vm_clock); + int64_t count; + + /*The timer has not beed initialized */ + if (!s->full_timer[TCU_INDEX]) + return; + + debug_out(DEBUG_TCU, "s->tsr %d s->ter %d s->freq[TCU_INDEX] %d \n", + s->tsr , s->ter ,s->freq[TCU_INDEX]); +printf("s->tsr %d s->ter %d s->freq[TCU_INDEX] %d \n", + s->tsr , s->ter ,s->freq[TCU_INDEX]); + if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) + && (s->freq[TCU_INDEX] != 0)) + { + glue(jz4740_tcu_time_sync, TCU_INDEX) (s); + printf("tdfr %x \n",s->tdfr[TCU_INDEX] ); + /*calculate next fire time */ + count = + (s->tdfr[TCU_INDEX] - s->tcnt[TCU_INDEX]) * s->prescale[TCU_INDEX]; + printf("tdfr11 %x count %lld\n",s->tdfr[TCU_INDEX],count ); + next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); + qemu_mod_timer(s->full_timer[TCU_INDEX], next); + debug_out(DEBUG_TCU, "s->tdfr[TCU_INDEX] %d s->tcnt[TCU_INDEX] %d next %lld \n", + s->tdfr[TCU_INDEX] , s->tcnt[TCU_INDEX] ,next); + printf("s->tdfr[TCU_INDEX]22 %x s->tcnt[TCU_INDEX] %x next %lld \n", + s->tdfr[TCU_INDEX] , s->tcnt[TCU_INDEX] ,next); + + } + else + qemu_del_timer(s->full_timer[TCU_INDEX]); +} + + +/* + * TCNT will reset to 0 if it reach to TDFR. + * So for the half compare, the next fire count is (TDFR-TDHR) + TDHR + * + */ +static void glue(jz4740_tcu_half_cb, TCU_INDEX) (void *opaque) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + int64_t next = qemu_get_clock(vm_clock); + int64_t count; + + if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) + && (s->freq[TCU_INDEX] != 0)) + { + count = s->tdfr[TCU_INDEX] * s->prescale[TCU_INDEX]; + next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); + qemu_mod_timer(s->half_timer[TCU_INDEX], next); + s->tfr |= 1 << (16 + TCU_INDEX); + jz4740_tcu_update_interrupt(s); + s->tcnt[TCU_INDEX] = s->tdhr[TCU_INDEX]; + s->time[TCU_INDEX] = qemu_get_clock(vm_clock); + } + else + qemu_del_timer(s->half_timer[TCU_INDEX]); +} + + +static void glue(jz4740_tcu_full_cb, TCU_INDEX) (void *opaque) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + int64_t next = qemu_get_clock(vm_clock); + int64_t count; + + if ((!(s->tsr & (1 << TCU_INDEX))) && (s->ter & (1 << TCU_INDEX)) + && (s->freq[TCU_INDEX] != 0)) + { + //printf("s->tdfr[TCU_INDEX] %x s->prescale[TCU_INDEX] %x \n",s->tdfr[TCU_INDEX] ,s->prescale[TCU_INDEX] ); + count = s->tdfr[TCU_INDEX] * s->prescale[TCU_INDEX]; + next += muldiv64(count, ticks_per_sec, s->freq[TCU_INDEX]); + //printf("count %lld next %lld \n",count,next); + qemu_mod_timer(s->full_timer[TCU_INDEX], next); + s->tfr |= 1 << TCU_INDEX; + jz4740_tcu_update_interrupt(s); + s->tcnt[TCU_INDEX] = 0; + s->time[TCU_INDEX] = qemu_get_clock(vm_clock); + } + else + qemu_del_timer(s->full_timer[TCU_INDEX]); +} + +static uint32_t glue(jz4740_tcu_read, TCU_INDEX) (void *opaque, + target_phys_addr_t addr) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_read%x addr %x\n", TCU_INDEX, addr); + addr -= 0x40 + TCU_INDEX * 0x10; + + switch (addr) + { + case 0x0: + return s->tdfr[TCU_INDEX]; + case 0x4: + return s->tdhr[TCU_INDEX]; + case 0x8: + glue(jz4740_tcu_time_sync, TCU_INDEX) (s); + //debug_out(DEBUG_TCU, "s->tcnt %x\n", s->tcnt[TCU_INDEX]); + //printf("s->tcnt %x\n", s->tcnt[TCU_INDEX]); + return s->tcnt[TCU_INDEX]; + case 0xc: + return s->tcsr[TCU_INDEX]; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_read undefined addr %x timer %x \n", addr, + TCU_INDEX); + } + return (0); +} + +static void glue(jz4740_tcu_write, TCU_INDEX) (void *opaque, + target_phys_addr_t addr, + uint32_t value) +{ + struct jz4740_tcu_s *s = (struct jz4740_tcu_s *) opaque; + + debug_out(DEBUG_TCU, "jz4740_tcu_write%x addr %x value %x \n", TCU_INDEX, + addr, value); +printf( "jz4740_tcu_write%x addr %x value %x \n", TCU_INDEX, + addr, value); + addr -= 0x40 + TCU_INDEX * 0x10; + + switch (addr) + { + case 0x0: + /*TDFR*/ + + s->tdfr[TCU_INDEX] = value & 0xffff; + printf("s->tdfr[TCU_INDEX] %x \n",s->tdfr[TCU_INDEX] ); + glue(jz4740_tcu_start_full, TCU_INDEX) (s); + break; + case 0x4: + /*TDHR*/ s->tdhr[TCU_INDEX] = value & 0xffff; + glue(jz4740_tcu_start_half, TCU_INDEX) (s); + break; + case 0x8: + /*TCNT*/ s->tcnt[TCU_INDEX] = value & 0xffff; + s->time[TCU_INDEX] = qemu_get_clock(vm_clock); + glue(jz4740_tcu_start_half, TCU_INDEX) (s); + glue(jz4740_tcu_start_full, TCU_INDEX) (s); + break; + case 0xc: + s->tcsr[TCU_INDEX] = value & 0x3bf; + switch (value & 0x7) + { + case 0x1: + s->freq[TCU_INDEX] = jz_clk_getrate(jz_findclk(s->soc, "pclk")); + break; + case 0x2: + s->freq[TCU_INDEX] = jz_clk_getrate(jz_findclk(s->soc, "osc_32K")); + break; + case 0x4: + s->freq[TCU_INDEX] = + jz_clk_getrate(jz_findclk(s->soc, "osc_extal")); + break; + default: + s->freq[TCU_INDEX] = 0x0; + break; + } + s->prescale[TCU_INDEX] = 1 << (((value & 0x38) >> 3) * 2); + printf("s->prescale[TCU_INDEX] %x\n",s->prescale[TCU_INDEX] ); + glue(jz4740_tcu_start_half, TCU_INDEX) (s); + glue(jz4740_tcu_start_full, TCU_INDEX) (s); + break; + default: + cpu_abort(s->soc->env, + "jz4740_tcu_write undefined addr %x timer %x \n", addr, + TCU_INDEX); + + } +} + + +static CPUReadMemoryFunc *glue(jz4740_tcu_readfn, TCU_INDEX)[] = +{ +jz4740_badwidth_read16, + glue(jz4740_tcu_read, TCU_INDEX), jz4740_badwidth_read16,}; + +static CPUWriteMemoryFunc *glue(jz4740_tcu_writefn, TCU_INDEX)[] = +{ +jz4740_badwidth_write16, + glue(jz4740_tcu_write, TCU_INDEX), jz4740_badwidth_write16,}; + +static void glue(jz4740_tcu_init, TCU_INDEX) (struct jz_state_s * soc, + struct jz4740_tcu_s * s) +{ + int iomemtype; + + s->half_timer[TCU_INDEX] = + qemu_new_timer(vm_clock, glue(jz4740_tcu_half_cb, TCU_INDEX), s); + s->full_timer[TCU_INDEX] = + qemu_new_timer(vm_clock, glue(jz4740_tcu_full_cb, TCU_INDEX), s); + + iomemtype = + cpu_register_io_memory(0, glue(jz4740_tcu_readfn, TCU_INDEX), + glue(jz4740_tcu_writefn, TCU_INDEX), s); + cpu_register_physical_memory(s->base + 0x00000040 + TCU_INDEX * 0x10, + 0x00000010, iomemtype); +} + +#undef TCU_INDEX +#endif + + + +#ifdef JZ4740_LCD_PANEL + +#if DEPTH == 8 +# define BPP 1 +# define PIXEL_TYPE uint8_t +#elif DEPTH == 15 || DEPTH == 16 +# define BPP 2 +# define PIXEL_TYPE uint16_t +#elif DEPTH == 24 +# define BPP 3 +# define PIXEL_TYPE uint32_t +#elif DEPTH == 32 +# define BPP 4 +# define PIXEL_TYPE uint32_t +#else +# error unsupport depth +#endif + +/* + * 2-bit colour + */ +static void glue(draw_line2_, DEPTH) (uint8_t * d, const uint8_t * s, int width, + const uint16_t * pal) +{ + uint8_t v, r, g, b; + + do + { + v = ldub_raw((void *) s); + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + s++; + width -= 4; + } + while (width > 0); +} + +/* + * 4-bit colour + */ +static void glue(draw_line4_, DEPTH) (uint8_t * d, const uint8_t * s, int width, + const uint16_t * pal) +{ + uint8_t v, r, g, b; + + do + { + v = ldub_raw((void *) s); + r = (pal[v & 0xf] >> 4) & 0xf0; + g = pal[v & 0xf] & 0xf0; + b = (pal[v & 0xf] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + v >>= 4; + r = (pal[v & 0xf] >> 4) & 0xf0; + g = pal[v & 0xf] & 0xf0; + b = (pal[v & 0xf] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + d += BPP; + s++; + width -= 2; + } + while (width > 0); +} + +/* + * 8-bit colour + */ +static void glue(draw_line8_, DEPTH) (uint8_t * d, const uint8_t * s, int width, + const uint16_t * pal) +{ + uint8_t v, r, g, b; + + do + { + v = ldub_raw((void *) s); + r = (pal[v] >> 4) & 0xf0; + g = pal[v] & 0xf0; + b = (pal[v] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + s++; + d += BPP; + } + while (--width != 0); +} + + +/* + * 16-bit colour + */ +static void glue(draw_line16_, DEPTH) (uint8_t * d, const uint8_t * s, + int width, const uint16_t * pal) +{ +#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + uint16_t v; + uint8_t r, g, b; + + do + { + v = lduw_raw((void *) s); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + s += 2; + d += BPP; + } + while (--width != 0); +#endif +} + +/* + * 24-bit colour. JZ4740 uses 4 bytes to store 18/24 bit color. + */ +static void glue(draw_line24_, DEPTH) (uint8_t * d, const uint8_t * s, + int width, const uint16_t * pal) +{ +#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + memcpy(d, s, width * 4); +#else + uint32_t v; + uint8_t r, g, b; + + do + { + v = ldl_raw((void *) s); + r = (v >> 16) & 0xff; + g = (v >> 8) & 0xff; + b = (v >> 0) & 0xff; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH) (r, g, b); + s += 3; + d += BPP; + } + while (--width != 0); +#endif +} + +static jz4740_lcd_fn_t glue(jz4740_lcd_draw_fn_, DEPTH)[6] = +{ + NULL, /*0x0 *//*1 bit per pixel */ + (jz4740_lcd_fn_t) glue(draw_line2_, DEPTH), /*0x1 *//*2 bit per pixel */ + (jz4740_lcd_fn_t) glue(draw_line4_, DEPTH), /*0x2 *//*4 bit per pixel */ + (jz4740_lcd_fn_t) glue(draw_line8_, DEPTH), /*0x3 *//*8 bit per pixel */ + (jz4740_lcd_fn_t) glue(draw_line16_, DEPTH), /*0x4 *//*15/16 bit per pixel */ + (jz4740_lcd_fn_t) glue(draw_line24_, DEPTH), /*0x5 *//*18/24 bit per pixel */ +}; + + +#undef DEPTH +#undef BPP +#undef PIXEL_TYPE + +#endif diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 972c71c9d8..3ca036bba0 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -487,19 +487,16 @@ static void audio_init (PCIBus *pci_bus) static void network_init (PCIBus *pci_bus) { int i; - NICInfo *nd; for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (!nd->model) { - nd->model = "pcnet"; - } - if (i == 0 && strcmp(nd->model, "pcnet") == 0) { + NICInfo *nd = &nd_table[i]; + int devfn = -1; + + if (i == 0 && (!nd->model || strcmp(nd->model, "pcnet") == 0)) /* The malta board has a PCNet card using PCI SLOT 11 */ - pci_nic_init(pci_bus, nd, 88); - } else { - pci_nic_init(pci_bus, nd, -1); - } + devfn = 88; + + pci_nic_init(pci_bus, nd, devfn, "pcnet"); } } diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index dc62f696a0..83f1a63e5c 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -175,19 +175,9 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size, if (serial_hds[0]) serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "mipsnet") == 0) { - /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ - mipsnet_init(0x4200, env->irq[2], &nd_table[0]); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: mipsnet\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } + if (nd_table[0].vlan) + /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ + mipsnet_init(0x4200, env->irq[2], &nd_table[0]); } QEMUMachine mips_mipssim_machine = { diff --git a/hw/mips_pavo.c b/hw/mips_pavo.c index d9252441c1..f98e7e90a2 100755 --- a/hw/mips_pavo.c +++ b/hw/mips_pavo.c @@ -55,8 +55,141 @@ struct mips_pavo_s { struct jz_state_s *soc; + + struct nand_bflash_s *nand; }; +static uint32_t pavo_nand_read8(void *opaque, target_phys_addr_t addr) +{ + struct mips_pavo_s *s = (struct mips_pavo_s *) opaque; + + switch (addr) + { + case 0x8000: /*NAND_COMMAND*/ + case 0x10000: /*NAND_ADDRESS*/ + jz4740_badwidth_read8(s,addr); + break; + case 0x0: /*NAND_DATA*/ + return nandb_read_data8(s->nand); + break; + default: + jz4740_badwidth_read8(s,addr); + break; + } + return 0; +} + +static void pavo_nand_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct mips_pavo_s *s = (struct mips_pavo_s *) opaque; + + //printf("write addr %x value %x \n",addr,value); + + switch (addr) + { + case 0x8000: /*NAND_COMMAND*/ + nandb_write_command(s->nand,value); + break; + case 0x10000: /*NAND_ADDRESS*/ + nandb_write_address(s->nand,value); + break; + case 0x0: /*NAND_DATA*/ + nandb_write_data8(s->nand,value); + break; + default: + jz4740_badwidth_write8(s,addr,value); + break; + } +} + + +CPUReadMemoryFunc *pavo_nand_readfn[] = { + pavo_nand_read8, + jz4740_badwidth_read16, + jz4740_badwidth_read32, +}; +CPUWriteMemoryFunc *pavo_nand_writefn[] = { + pavo_nand_write8, + jz4740_badwidth_write16, + jz4740_badwidth_write32, +}; + +static void pavo_nand_setup(struct mips_pavo_s *s) +{ + int iomemtype; + + /*K9K8G08U0*/ + s->nand = nandb_init(NAND_MFR_SAMSUNG,0xd3); + + iomemtype = cpu_register_io_memory(0, pavo_nand_readfn, + pavo_nand_writefn, s); + cpu_register_physical_memory(0x18000000, 0x20000, iomemtype); +} + +static int pavo_nand_read_page(struct mips_pavo_s *s,uint8_t *buf, uint16_t page_addr) +{ + uint8_t *p; + int i; + + p=(uint8_t *)buf; + + /*send command 0x0*/ + pavo_nand_write8(s,0x00008000,0); + /*send page address */ + pavo_nand_write8(s,0x00010000,page_addr&0xff); + pavo_nand_write8(s,0x00010000,(page_addr>>8)&0x7); + pavo_nand_write8(s,0x00010000,(page_addr>>11)&0xff); + pavo_nand_write8(s,0x00010000,(page_addr>>19)&0xff); + pavo_nand_write8(s,0x00010000,(page_addr>>27)&0xff); + /*send command 0x30*/ + pavo_nand_write8(s,0x00008000,0x30); + + for (i=0;i<0x800;i++) + { + *p++ = pavo_nand_read8(s,0x00000000); + } + return 1; +} + +/*read the u-boot from NAND Flash into internal RAM*/ +static int pavo_boot_from_nand(struct mips_pavo_s *s) +{ + uint32_t len; + uint8_t nand_page[0x800],*load_dest; + uint32_t nand_pages,i; + + //int fd; + + + len = 0x2000; /*8K*/ + + /*put the first page into internal ram*/ + load_dest = phys_ram_base; + + nand_pages = len/0x800; + //fd = open("u-boot.bin", O_RDWR | O_CREAT); + for (i=0;isoc->env->active_tc.PC = 0x80000004; + + //close(fd); + return 0; + +} + + + static int pavo_rom_emu(struct mips_pavo_s *s) +{ + if (pavo_boot_from_nand(s)<0) + return (-1); + return (0); +} static void mips_pavo_init(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState * ds, @@ -68,11 +201,17 @@ static void mips_pavo_init(ram_addr_t ram_size, int vga_ram_size, if (ram_size < PAVO_RAM_SIZE + JZ4740_SRAM_SIZE) { - fprintf(stderr, "This architecture uses %i bytes of memory\n", + fprintf(stderr, "This architecture uses %d bytes of memory\n", PAVO_RAM_SIZE + JZ4740_SRAM_SIZE); exit(1); } - s->soc = jz4740_init(PAVO_RAM_SIZE, PAVO_OSC_EXTAL); + s->soc = jz4740_init(PAVO_RAM_SIZE, PAVO_OSC_EXTAL,ds); + pavo_nand_setup(s); + if (pavo_rom_emu(s)<0) + { + fprintf(stderr,"boot from nand failed \n"); + exit(-1); + } } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 6551b02e0b..c12ab54b09 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -247,18 +247,8 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size, isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "ne2k_isa") == 0) { - isa_ne2000_init(0x300, i8259[9], &nd_table[0]); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } + if (nd_table[0].vlan) + isa_ne2000_init(0x300, i8259[9], &nd_table[0]); if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { fprintf(stderr, "qemu: too many IDE bus\n"); diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 13217b2da0..67b873511c 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -7,10 +7,15 @@ /* XXX: do not use a global */ uint32_t cpu_mips_get_random (CPUState *env) { - static uint32_t seed = 0; + static uint32_t lfsr = 1; + static uint32_t prev_idx = 0; uint32_t idx; - seed = seed * 314159 + 1; - idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; + /* Don't return same value twice, so get another value */ + do { + lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); + idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; + } while (idx == prev_idx); + prev_idx = idx; return idx; } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 0eb4c1ed1a..04ce322870 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -236,6 +236,8 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) { MIPSnetState *s; + qemu_check_nic_model(nd, "mipsnet"); + s = qemu_mallocz(sizeof(MIPSnetState)); if (!s) return; diff --git a/hw/musicpal.c b/hw/musicpal.c index 1c932ec3f7..f64bb1c89f 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -714,6 +714,8 @@ static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) mv88w8618_eth_state *s; int iomemtype; + qemu_check_nic_model(nd, "mv88w8618"); + s = qemu_mallocz(sizeof(mv88w8618_eth_state)); if (!s) return; diff --git a/hw/ne2000.c b/hw/ne2000.c index 200db90b9e..a85730f8c7 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -722,6 +722,8 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) { NE2000State *s; + qemu_check_nic_model(nd, "ne2k_isa"); + s = qemu_mallocz(sizeof(NE2000State)); if (!s) return; diff --git a/hw/pc.c b/hw/pc.c index 64c08a4342..6a1c8ec242 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -764,7 +764,6 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, PCIBus *pci_bus; int piix3_devfn = -1; CPUState *env; - NICInfo *nd; qemu_irq *cpu_irq; qemu_irq *i8259; int index; @@ -1000,27 +999,12 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, } for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (!nd->model) { - if (pci_enabled) { - nd->model = "ne2k_pci"; - } else { - nd->model = "ne2k_isa"; - } - } - if (strcmp(nd->model, "ne2k_isa") == 0) { + NICInfo *nd = &nd_table[i]; + + if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) pc_init_ne2k_isa(nd, i8259); - } else if (pci_enabled) { - if (strcmp(nd->model, "?") == 0) - fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); - pci_nic_init(pci_bus, nd, -1); - } else if (strcmp(nd->model, "?") == 0) { - fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); - exit(1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); - exit(1); - } + else + pci_nic_init(pci_bus, nd, -1, "ne2k_pci"); } if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { diff --git a/hw/pci.c b/hw/pci.c index 8252d21b95..bba50d0e17 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -652,33 +652,43 @@ void pci_info(void) pci_for_each_device(0, pci_info_device); } +static const char * const pci_nic_models[] = { + "ne2k_pci", + "i82551", + "i82557b", + "i82559er", + "rtl8139", + "e1000", + "pcnet", + "virtio", + NULL +}; + +typedef void (*PCINICInitFn)(PCIBus *, NICInfo *, int); + +static PCINICInitFn pci_nic_init_fns[] = { + pci_ne2000_init, + pci_i82551_init, + pci_i82557b_init, + pci_i82559er_init, + pci_rtl8139_init, + pci_e1000_init, + pci_pcnet_init, + virtio_net_init, + NULL +}; + /* Initialize a PCI NIC. */ -void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, + const char *default_model) { - if (strcmp(nd->model, "ne2k_pci") == 0) { - pci_ne2000_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82551") == 0) { - pci_i82551_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82557b") == 0) { - pci_i82557b_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82559er") == 0) { - pci_i82559er_init(bus, nd, devfn); - } else if (strcmp(nd->model, "rtl8139") == 0) { - pci_rtl8139_init(bus, nd, devfn); - } else if (strcmp(nd->model, "e1000") == 0) { - pci_e1000_init(bus, nd, devfn); - } else if (strcmp(nd->model, "pcnet") == 0) { - pci_pcnet_init(bus, nd, devfn); - } else if (strcmp(nd->model, "virtio") == 0) { - virtio_net_init(bus, nd, devfn); - } else if (strcmp(nd->model, "?") == 0) { - fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er" - " ne2k_pci pcnet rtl8139 e1000 virtio\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); - exit (1); - } + int i; + + qemu_check_nic_model_list(nd, pci_nic_models, default_model); + + for (i = 0; pci_nic_models[i]; i++) + if (strcmp(nd->model, pci_nic_models[i]) == 0) + pci_nic_init_fns[i](bus, nd, devfn); } typedef struct { diff --git a/hw/pci.h b/hw/pci.h index 3b1caf5ca8..76f4474a5c 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -118,7 +118,8 @@ typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, qemu_irq *pic, int devfn_min, int nirq); -void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, + const char *default_model); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); uint32_t pci_data_read(void *opaque, uint32_t addr, int len); int pci_bus_num(PCIBus *s); @@ -168,8 +169,9 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); PCIBus *pci_prep_init(qemu_irq *pic); /* apb_pci.c */ -PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, - qemu_irq *pic); +PCIBus *pci_apb_init(target_phys_addr_t special_base, + target_phys_addr_t mem_base, + qemu_irq *pic, PCIBus **bus2, PCIBus **bus3); /* sh_pci.c */ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, diff --git a/hw/pci_host.h b/hw/pci_host.h index e2e428a271..c4f42a40e1 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -25,6 +25,16 @@ /* Worker routines for a PCI host controller that uses an {address,data} register pair to access PCI configuration space. */ +/* debug PCI */ +//#define DEBUG_PCI + +#ifdef DEBUG_PCI +#define PCI_DPRINTF(fmt, args...) \ +do { printf("pci_host_data: " fmt , ##args); } while (0) +#else +#define PCI_DPRINTF(fmt, args...) +#endif + typedef struct { uint32_t config_reg; PCIBus *bus; @@ -33,6 +43,9 @@ typedef struct { static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val) { PCIHostState *s = opaque; + + PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); if (s->config_reg & (1u << 31)) pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); } @@ -43,6 +56,8 @@ static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val) #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif + PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); if (s->config_reg & (1u << 31)) pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); } @@ -53,6 +68,8 @@ static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val) #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif + PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); if (s->config_reg & (1u << 31)) pci_data_write(s->bus, s->config_reg, val, 4); } @@ -60,9 +77,14 @@ static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val) static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr) { PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) return 0xff; - return pci_data_read(s->bus, s->config_reg | (addr & 3), 1); + val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1); + PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); + return val; } static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr) @@ -72,6 +94,8 @@ static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr) if (!(s->config_reg & (1 << 31))) return 0xffff; val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); + PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif @@ -85,6 +109,8 @@ static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr) if (!(s->config_reg & (1 << 31))) return 0xffffffff; val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); + PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", + (target_phys_addr_t)addr, val); #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif diff --git a/hw/pcnet.c b/hw/pcnet.c index 102166ed22..61989685bb 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2087,6 +2087,8 @@ void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, PCNetState *d; int lance_io_memory; + qemu_check_nic_model(nd, "lance"); + d = qemu_mallocz(sizeof(PCNetState)); if (!d) return; diff --git a/hw/ppc.h b/hw/ppc.h index 297f55060f..75eb11a328 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -33,3 +33,11 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); void ppc40x_irq_init (CPUState *env); void ppc6xx_irq_init (CPUState *env); void ppc970_irq_init (CPUState *env); + +/* PPC machines for OpenBIOS */ +enum { + ARCH_PREP = 0, + ARCH_MAC99, + ARCH_HEATHROW, +}; + diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index a6fc75823c..bc8a47b468 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -90,7 +90,6 @@ static void bamboo_init(ram_addr_t ram_size, int vga_ram_size, const char *cpu_model) { unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; - NICInfo *nd; PCIBus *pcibus; CPUState *env; uint64_t elf_entry; @@ -118,13 +117,9 @@ static void bamboo_init(ram_addr_t ram_size, int vga_ram_size, /* Register network interfaces. */ for (i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (!nd->model) { - /* There are no PCI NICs on the Bamboo board, but there are - * PCI slots, so we can pick model whatever we want. */ - nd->model = "e1000"; - } - pci_nic_init(pcibus, nd, -1); + /* There are no PCI NICs on the Bamboo board, but there are + * PCI slots, so we can pick whatever default model we want. */ + pci_nic_init(pcibus, &nd_table[i], -1, "e1000"); } } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 5bdb80536b..e6fbfcfd30 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -31,6 +31,7 @@ #include "net.h" #include "sysemu.h" #include "boards.h" +#include "escc.h" #define MAX_IDE_BUS 2 @@ -80,7 +81,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size, m48t59_t *m48t59; int vga_bios_size, bios_size; qemu_irq *dummy_irq; - int pic_mem_index, dbdma_mem_index, cuda_mem_index; + int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index; int ide_mem_index[2]; int ppc_boot_device; int index; @@ -262,13 +263,12 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size, /* XXX: suppress that */ dummy_irq = i8259_init(NULL); - /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]); - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); - } + escc_mem_index = escc_init(0x80013000, dummy_irq[4], dummy_irq[5], + serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); + + for(i = 0; i < nb_nics; i++) + pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); @@ -295,7 +295,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size, dbdma_init(&dbdma_mem_index); macio_init(pci_bus, 0x0022, 0, pic_mem_index, dbdma_mem_index, - cuda_mem_index, NULL, 2, ide_mem_index); + cuda_mem_index, NULL, 2, ide_mem_index, escc_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index c833d1758f..cc70fb7dc7 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -31,12 +31,14 @@ #define BIOS_FILENAME "ppc_rom.bin" #define VGABIOS_FILENAME "video.x" #define NVRAM_SIZE 0x2000 -#define PROM_FILENAME "openbios-ppc32" +#define PROM_FILENAME "openbios-ppc" #define PROM_ADDR 0xfff00000 #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 +#define ESCC_CLOCK 3686400 + /* DBDMA */ void dbdma_init (int *dbdma_mem_index); @@ -46,7 +48,7 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq); /* MacIO */ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, int dbdma_mem_index, int cuda_mem_index, void *nvram, - int nb_ide, int *ide_mem_index); + int nb_ide, int *ide_mem_index, int escc_mem_index); /* NewWorld PowerMac IDE */ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 1d5e9d67f1..3eb1061526 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -33,17 +33,12 @@ #include "pci.h" #include "boards.h" #include "fw_cfg.h" +#include "escc.h" #define MAX_IDE_BUS 2 #define VGA_BIOS_SIZE 65536 #define CFG_ADDR 0xf0000510 -enum { - ARCH_PREP = 0, - ARCH_MAC99, - ARCH_HEATHROW, -}; - /* temporary frame buffer OSI calls for the video.x driver. The right solution is to modify the driver to use VGA PCI I/Os */ /* XXX: to be removed. This is no way related to emulation */ @@ -132,7 +127,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, int vga_bios_size, bios_size; qemu_irq *dummy_irq; int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; - int ide_mem_index[2]; + int escc_mem_index, ide_mem_index[2]; int ppc_boot_device; BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; int index; @@ -149,8 +144,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + /* Set time-base frequency to 16.6 Mhz */ + cpu_ppc_tb_init(env, 16600000UL); env->osi_call = vga_osi_call; qemu_register_reset(&cpu_ppc_reset, env); envs[i] = env; @@ -160,10 +155,17 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, * the boot vector is at 0xFFF00100, then we need a 1MB BIOS. * But the NVRAM is located at 0xFFF04000... */ - cpu_abort(env, "G3BW Mac hardware can not handle 1 MB BIOS\n"); + cpu_abort(env, "G3 Beige Mac hardware can not handle 1 MB BIOS\n"); } /* allocate RAM */ + if (ram_size > (2047 << 20)) { + fprintf(stderr, + "qemu: Too much memory for this machine: %d MB, maximum 2047 MB\n", + ((unsigned int)ram_size / (1 << 20))); + exit(1); + } + ram_offset = qemu_ram_alloc(ram_size); cpu_register_physical_memory(0, ram_size, ram_offset); @@ -260,7 +262,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, #endif } if (ppc_boot_device == '\0') { - fprintf(stderr, "No valid boot device for Mac99 machine\n"); + fprintf(stderr, "No valid boot device for G3 Beige machine\n"); exit(1); } } @@ -302,14 +304,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, /* XXX: suppress that */ dummy_irq = i8259_init(NULL); - /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], 115200, serial_hds[0]); + escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], + serial_hds[1], ESCC_CLOCK, 4); - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); - } + for(i = 0; i < nb_nics; i++) + pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); /* First IDE channel is a CMD646 on the PCI bus */ @@ -356,7 +355,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, dbdma_init(&dbdma_mem_index); macio_init(pci_bus, 0x0010, 1, pic_mem_index, dbdma_mem_index, - cuda_mem_index, nvr, 2, ide_mem_index); + cuda_mem_index, nvr, 2, ide_mem_index, escc_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 571c48e138..6c0d8fe7cf 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -671,11 +671,13 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size, if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { - if (nd_table[i].model == NULL - || strcmp(nd_table[i].model, "ne2k_isa") == 0) { + if (nd_table[i].model == NULL) { + nd_table[i].model = "ne2k_isa"; + } + if (strcmp(nd_table[i].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); } else { - pci_nic_init(pci_bus, &nd_table[i], -1); + pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); } } diff --git a/hw/r2d.c b/hw/r2d.c index 5d5eb1e498..88853e7102 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -230,9 +230,9 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size, drives_table[drive_get_index(IF_IDE, 0, 0)].bdrv, NULL); /* NIC: rtl8139 on-board, and 2 slots. */ - pci_rtl8139_init(pci, &nd_table[0], 2 << 3); + pci_nic_init(pci, &nd_table[0], 2 << 3, "rtl8139"); for (i = 1; i < nb_nics; i++) - pci_nic_init(pci, &nd_table[i], -1); + pci_nic_init(pci, &nd_table[i], -1, "ne2k_pci"); /* Todo: register on board registers */ { diff --git a/hw/realview.c b/hw/realview.c index a9d20edc52..e285338009 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -121,12 +121,12 @@ static void realview_init(ram_addr_t ram_size, int vga_ram_size, } for(n = 0; n < nb_nics; n++) { nd = &nd_table[n]; - if (!nd->model) - nd->model = done_smc ? "rtl8139" : "smc91c111"; - if (strcmp(nd->model, "smc91c111") == 0) { + + if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) { smc91c111_init(nd, 0x4e000000, pic[28]); + done_smc = 1; } else { - pci_nic_init(pci_bus, nd, -1); + pci_nic_init(pci_bus, nd, -1, "rtl8139"); } } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 8be63c5050..70cb080d26 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -472,6 +472,8 @@ typedef struct RTL8139State { uint32_t currTxDesc; /* C+ mode */ + uint32_t cplus_enabled; + uint32_t currCPlusRxDesc; uint32_t currCPlusTxDesc; @@ -1232,6 +1234,8 @@ static void rtl8139_reset(RTL8139State *s) s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; s->CpCmd = 0x0; /* reset C+ mode */ + s->cplus_enabled = 0; + // s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation // s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex @@ -1420,6 +1424,8 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); + s->cplus_enabled = 1; + /* mask unwriteable bits */ val = SET_MASKED(val, 0xff84, s->CpCmd); @@ -2367,7 +2373,7 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 /* handle C+ transmit mode register configuration */ - if (rtl8139_cp_transmitter_enabled(s)) + if (s->cplus_enabled) { DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); @@ -3190,6 +3196,8 @@ static void rtl8139_save(QEMUFile* f,void* opaque) qemu_put_be64(f, s->TCTR_base); RTL8139TallyCounters_save(f, &s->tally_counters); + + qemu_put_be32s(f, &s->cplus_enabled); } static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) @@ -3199,7 +3207,7 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) int ret; /* just 2 versions for now */ - if (version_id > 3) + if (version_id > 4) return -EINVAL; if (version_id >= 3) { @@ -3299,6 +3307,12 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) RTL8139TallyCounters_clear(&s->tally_counters); } + if (version_id >= 4) { + qemu_get_be32s(f, &s->cplus_enabled); + } else { + s->cplus_enabled = s->CpCmd != 0; + } + return 0; } @@ -3447,7 +3461,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - register_savevm("rtl8139", -1, 3, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139", -1, 4, rtl8139_save, rtl8139_load, s); #ifdef RTL8139_ONBOARD_TIMER s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 27a3158f97..f5b29a7049 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -695,6 +695,8 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) smc91c111_state *s; int iomemtype; + qemu_check_nic_model(nd, "smc91c111"); + s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); iomemtype = cpu_register_io_memory(0, smc91c111_readfn, smc91c111_writefn, s); diff --git a/hw/stellaris.c b/hw/stellaris.c index 703ef7e42c..7069518bd7 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1361,10 +1361,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, pl022_init(0x40008000, pic[7], NULL, NULL); } } - if (board->dc4 & (1 << 28)) { - /* FIXME: Obey network model. */ + if (board->dc4 & (1 << 28)) stellaris_enet_init(&nd_table[0], 0x40048000, pic[42]); - } if (board->peripherals & BP_GAMEPAD) { qemu_irq gpad_irq[5]; static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index a5cd16389e..88c56204e3 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -389,6 +389,8 @@ void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) stellaris_enet_state *s; int iomemtype; + qemu_check_nic_model(nd, "stellaris"); + s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn, stellaris_enet_writefn, s); diff --git a/hw/sun4m.c b/hw/sun4m.c index e6a538a9f3..d3c1e199ad 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -35,6 +35,7 @@ #include "pc.h" #include "isa.h" #include "fw_cfg.h" +#include "escc.h" //#define DEBUG_IRQ @@ -88,6 +89,8 @@ #define MAX_CPUS 16 #define MAX_PILS 16 +#define ESCC_CLOCK 4915200 + struct sun4m_hwdef { target_phys_addr_t iommu_base, slavio_base; target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; @@ -533,16 +536,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: lance\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); @@ -551,11 +545,11 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, slavio_cpu_irq, smp_cpus); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], - nographic); + nographic, ESCC_CLOCK, 1); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], - serial_hds[1], serial_hds[0]); + escc_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], slavio_irq[hwdef->ser_irq], + serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1); slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->apc_base, @@ -1325,16 +1319,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: lance\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); nvram = m48t59_init(sbi_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); @@ -1343,11 +1328,11 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, sbi_cpu_irq, smp_cpus); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, sbi_irq[hwdef->ms_kb_irq], - nographic); + nographic, ESCC_CLOCK, 1); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(hwdef->serial_base, sbi_irq[hwdef->ser_irq], - serial_hds[1], serial_hds[0]); + escc_init(hwdef->serial_base, sbi_irq[hwdef->ser_irq], sbi_irq[hwdef->ser_irq], + serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); if (drive_get_max_bus(IF_SCSI) > 0) { fprintf(stderr, "qemu: too many SCSI bus\n"); @@ -1540,26 +1525,18 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, tcx_init(ds, hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: lance\n"); - exit (1); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 2); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], - nographic); + nographic, ESCC_CLOCK, 1); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], - serial_hds[1], serial_hds[0]); + escc_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], + slavio_irq[hwdef->ser_irq], serial_hds[0], serial_hds[1], + ESCC_CLOCK, 1); slavio_misc = slavio_misc_init(0, 0, hwdef->aux1_base, 0, slavio_irq[hwdef->me_irq], NULL, &fdc_tc); diff --git a/hw/sun4m.h b/hw/sun4m.h index f6d822ee39..c9601ed32b 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -48,12 +48,6 @@ void sun4c_irq_info(void *opaque); void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, qemu_irq *cpu_irqs, unsigned int num_cpus); -/* slavio_serial.c */ -SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, - CharDriverState *chr1, CharDriverState *chr2); -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, - int disabled); - /* slavio_misc.c */ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, target_phys_addr_t aux1_base, diff --git a/hw/sun4u.c b/hw/sun4u.c index b3ecc1e347..91e7538da1 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -344,6 +344,48 @@ static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; static fdctrl_t *floppy_controller; +static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + DPRINTF("Mapping region %d registers at %08x\n", region_num, addr); + switch (region_num) { + case 0: + isa_mmio_init(addr, 0x1000000); + break; + case 1: + isa_mmio_init(addr, 0x800000); + break; + } +} + +/* EBUS (Eight bit bus) bridge */ +static void +pci_ebus_init(PCIBus *bus, int devfn) +{ + PCIDevice *s; + + s = pci_register_device(bus, "EBUS", sizeof(*s), devfn, NULL, NULL); + s->config[0x00] = 0x8e; // vendor_id : Sun + s->config[0x01] = 0x10; + s->config[0x02] = 0x00; // device_id + s->config[0x03] = 0x10; + s->config[0x04] = 0x06; // command = bus master, pci mem + s->config[0x05] = 0x00; + s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + s->config[0x07] = 0x03; // status = medium devsel + s->config[0x08] = 0x01; // revision + s->config[0x09] = 0x00; // programming i/f + s->config[0x0A] = 0x80; // class_sub = misc bridge + s->config[0x0B] = 0x06; // class_base = PCI_bridge + s->config[0x0D] = 0x0a; // latency_timer + s->config[0x0E] = 0x00; // header_type + + pci_register_io_region(s, 0, 0x1000000, PCI_ADDRESS_SPACE_MEM, + ebus_mmio_mapfunc); + pci_register_io_region(s, 1, 0x800000, PCI_ADDRESS_SPACE_MEM, + ebus_mmio_mapfunc); +} + static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, const char *boot_devices, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, @@ -357,7 +399,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, unsigned int i; ram_addr_t ram_offset, prom_offset, vga_ram_offset; long initrd_size, kernel_size; - PCIBus *pci_bus; + PCIBus *pci_bus, *pci_bus2, *pci_bus3; QEMUBH *bh; qemu_irq *irq; int drive_index; @@ -462,11 +504,16 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, } } } - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL, &pci_bus2, + &pci_bus3); isa_mem_base = VGA_BASE; vga_ram_offset = qemu_ram_alloc(vga_ram_size); - pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + vga_ram_offset, - vga_ram_offset, vga_ram_size); + pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_offset, + vga_ram_offset, vga_ram_size, + 0, 0); + + // XXX Should be pci_bus3 + pci_ebus_init(pci_bus, -1); i = 0; if (hwdef->console_serial_base) { @@ -488,11 +535,8 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size, } } - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); - } + for(i = 0; i < nb_nics; i++) + pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index e5d02f2bb9..267aa42d6a 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -194,12 +194,12 @@ static void versatile_init(ram_addr_t ram_size, int vga_ram_size, so many of the qemu PCI devices are not useable. */ for(n = 0; n < nb_nics; n++) { nd = &nd_table[n]; - if (!nd->model) - nd->model = done_smc ? "rtl8139" : "smc91c111"; - if (strcmp(nd->model, "smc91c111") == 0) { + + if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) { smc91c111_init(nd, 0x10010000, sic[25]); + done_smc = 1; } else { - pci_nic_init(pci_bus, nd, -1); + pci_nic_init(pci_bus, nd, -1, "rtl8139"); } } if (usb_enabled) { diff --git a/hw/virtio-net.c b/hw/virtio-net.c index de1f7ceca3..54c0030eb3 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -20,6 +20,7 @@ typedef struct VirtIONet { VirtIODevice vdev; uint8_t mac[6]; + uint16_t status; VirtQueue *rx_vq; VirtQueue *tx_vq; VLANClientState *vc; @@ -42,13 +43,28 @@ static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config) VirtIONet *n = to_virtio_net(vdev); struct virtio_net_config netcfg; + netcfg.status = n->status; memcpy(netcfg.mac, n->mac, 6); memcpy(config, &netcfg, sizeof(netcfg)); } +static void virtio_net_set_link_status(VLANClientState *vc) +{ + VirtIONet *n = vc->opaque; + uint16_t old_status = n->status; + + if (vc->link_down) + n->status &= ~VIRTIO_NET_S_LINK_UP; + else + n->status |= VIRTIO_NET_S_LINK_UP; + + if (n->status != old_status) + virtio_notify_config(&n->vdev); +} + static uint32_t virtio_net_get_features(VirtIODevice *vdev) { - uint32_t features = (1 << VIRTIO_NET_F_MAC); + uint32_t features = (1 << VIRTIO_NET_F_MAC) | (1 << VIRTIO_NET_F_STATUS); return features; } @@ -299,7 +315,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) return 0; } -PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) +void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) { VirtIONet *n; static int virtio_net_id; @@ -307,9 +323,10 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000, 0, VIRTIO_ID_NET, 0x02, 0x00, 0x00, - 6, sizeof(VirtIONet)); + sizeof(struct virtio_net_config), + sizeof(VirtIONet)); if (!n) - return NULL; + return; n->vdev.get_config = virtio_net_update_config; n->vdev.get_features = virtio_net_get_features; @@ -317,8 +334,10 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); memcpy(n->mac, nd->macaddr, 6); + n->status = VIRTIO_NET_S_LINK_UP; n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, virtio_net_receive, virtio_net_can_receive, n); + n->vc->link_status_changed = virtio_net_set_link_status; qemu_format_nic_info_str(n->vc, n->mac); @@ -328,6 +347,4 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) register_savevm("virtio-net", virtio_net_id++, 2, virtio_net_save, virtio_net_load, n); - - return (PCIDevice *)n; } diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 0d9f71ba1a..148ec47126 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -37,16 +37,21 @@ #define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */ #define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ #define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ +#define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */ + +#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define TX_TIMER_INTERVAL 150000 /* 150 us */ /* Maximum packet size we can receive from tap device: header + 64k */ #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10)) -/* The config defining mac address (6 bytes) */ struct virtio_net_config { + /* The config defining mac address (6 bytes) */ uint8_t mac[6]; + /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ + uint16_t status; } __attribute__((packed)); /* This is the first element of the scatter-gather list. If you don't @@ -75,6 +80,6 @@ struct virtio_net_hdr_mrg_rxbuf uint16_t num_buffers; /* Number of merged rx buffers */ }; -PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn); +void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn); #endif diff --git a/monitor.c b/monitor.c index 745c3350b2..7ff98909b5 100644 --- a/monitor.c +++ b/monitor.c @@ -1516,6 +1516,7 @@ static const term_cmd_t term_cmds[] = { "value", "set maximum speed (in bytes) for migrations" }, { "balloon", "i", do_balloon, "target", "request VM to change it's memory allocation (in MB)" }, + { "set_link", "ss", do_set_link, "name [up|down]" }, { NULL, NULL, }, }; diff --git a/net.c b/net.c index 15f915396d..86ee7d540d 100644 --- a/net.c +++ b/net.c @@ -299,7 +299,8 @@ static int parse_unix_path(struct sockaddr_un *uaddr, const char *str) void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]) { snprintf(vc->info_str, sizeof(vc->info_str), - "macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + vc->model, macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); } @@ -386,12 +387,15 @@ void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) VLANState *vlan = vc1->vlan; VLANClientState *vc; + if (vc1->link_down) + return; + #ifdef DEBUG_NET printf("vlan %d send:\n", vlan->id); hex_dump(stdout, buf, size); #endif for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1) { + if (vc != vc1 && !vc->link_down) { vc->fd_read(vc->opaque, buf, size); } } @@ -446,6 +450,8 @@ ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, /* slirp network adapter */ static int slirp_inited; +static int slirp_restrict; +static char *slirp_ip; static VLANClientState *slirp_vc; int slirp_can_output(void) @@ -482,7 +488,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) { if (!slirp_inited) { slirp_inited = 1; - slirp_init(); + slirp_init(slirp_restrict, slirp_ip); } slirp_vc = qemu_new_vlan_client(vlan, model, name, slirp_receive, NULL, NULL); @@ -500,7 +506,7 @@ void net_slirp_redir(const char *redir_str) if (!slirp_inited) { slirp_inited = 1; - slirp_init(); + slirp_init(slirp_restrict, slirp_ip); } p = redir_str; @@ -586,7 +592,7 @@ void net_slirp_smb(const char *exported_dir) if (!slirp_inited) { slirp_inited = 1; - slirp_init(); + slirp_init(slirp_restrict, slirp_ip); } /* XXX: better tmp dir construction */ @@ -646,6 +652,7 @@ typedef struct TAPState { VLANClientState *vc; int fd; char down_script[1024]; + char down_script_arg[128]; } TAPState; #ifdef HAVE_IOVEC @@ -972,8 +979,10 @@ static int net_tap_init(VLANState *vlan, const char *model, snprintf(s->vc->info_str, sizeof(s->vc->info_str), "ifname=%s,script=%s,downscript=%s", ifname, setup_script, down_script); - if (down_script && strcmp(down_script, "no")) + if (down_script && strcmp(down_script, "no")) { snprintf(s->down_script, sizeof(s->down_script), "%s", down_script); + snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname); + } return 0; } @@ -1491,6 +1500,40 @@ VLANState *qemu_find_vlan(int id) return vlan; } +void qemu_check_nic_model(NICInfo *nd, const char *model) +{ + const char *models[2]; + + models[0] = model; + models[1] = NULL; + + qemu_check_nic_model_list(nd, models, model); +} + +void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, + const char *default_model) +{ + int i, exit_status = 0; + + if (!nd->model) + nd->model = strdup(default_model); + + if (strcmp(nd->model, "?") != 0) { + for (i = 0 ; models[i]; i++) + if (strcmp(nd->model, models[i]) == 0) + return; + + fprintf(stderr, "qemu: Unsupported NIC model: %s\n", nd->model); + exit_status = 1; + } + + fprintf(stderr, "qemu: Supported NIC models: "); + for (i = 0 ; models[i]; i++) + fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n'); + + exit(exit_status); +} + int net_client_init(const char *device, const char *p) { char buf[1024]; @@ -1553,6 +1596,12 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "hostname", p)) { pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); } + if (get_param_value(buf, sizeof(buf), "restrict", p)) { + slirp_restrict = (buf[0] == 'y') ? 1 : 0; + } + if (get_param_value(buf, sizeof(buf), "ip", p)) { + slirp_ip = strdup(buf); + } vlan->nb_host_devs++; ret = net_slirp_init(vlan, device, name); } else @@ -1683,6 +1732,36 @@ void do_info_network(void) } } +int do_set_link(const char *name, const char *up_or_down) +{ + VLANState *vlan; + VLANClientState *vc = NULL; + + for (vlan = first_vlan; vlan != NULL; vlan = vlan->next) + for (vc = vlan->first_client; vc != NULL; vc = vc->next) + if (strcmp(vc->name, name) == 0) + goto done; +done: + + if (!vc) { + term_printf("could not find network device '%s'", name); + return 0; + } + + if (strcmp(up_or_down, "up") == 0) + vc->link_down = 0; + else if (strcmp(up_or_down, "down") == 0) + vc->link_down = 1; + else + term_printf("invalid link status '%s'; only 'up' or 'down' valid\n", + up_or_down); + + if (vc->link_status_changed) + vc->link_status_changed(vc); + + return 1; +} + void net_cleanup(void) { VLANState *vlan; @@ -1694,13 +1773,10 @@ void net_cleanup(void) for(vc = vlan->first_client; vc != NULL; vc = vc->next) { if (vc->fd_read == tap_receive) { - char ifname[64]; TAPState *s = vc->opaque; - if (strcmp(vc->model, "tap") == 0 && - sscanf(vc->info_str, "ifname=%63s ", ifname) == 1 && - s->down_script[0]) - launch_script(s->down_script, ifname, s->fd); + if (s->down_script[0]) + launch_script(s->down_script, s->down_script_arg, s->fd); } #if defined(CONFIG_VDE) if (vc->fd_read == vde_from_qemu) { diff --git a/net.h b/net.h index b89d1650a0..291807a65c 100644 --- a/net.h +++ b/net.h @@ -9,12 +9,16 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); typedef struct VLANClientState VLANClientState; +typedef void (LinkStatusChanged)(VLANClientState *); + struct VLANClientState { IOReadHandler *fd_read; IOReadvHandler *fd_readv; /* Packets may still be sent if this returns zero. It's used to rate-limit the slirp code. */ IOCanRWHandler *fd_can_read; + LinkStatusChanged *link_status_changed; + int link_down; void *opaque; struct VLANClientState *next; struct VLANState *vlan; @@ -43,9 +47,13 @@ ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]); +void qemu_check_nic_model(NICInfo *nd, const char *model); +void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, + const char *default_model); void qemu_handler_true(void *opaque); void do_info_network(void); +int do_set_link(const char *name, const char *up_or_down); /* NIC info */ diff --git a/pc-bios/README b/pc-bios/README index 665bd7d592..8313638f7d 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -41,7 +41,8 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 and Sparc64 images are built from SVN revision 237. + The included Sparc32 and Sparc64 images are built from SVN revision 395. + The included PowerPC image is built from SVN revision 406. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/bios-pq/0002_e820-high-mem.patch b/pc-bios/bios-pq/0002_e820-high-mem.patch deleted file mode 100644 index 2886e85669..0000000000 --- a/pc-bios/bios-pq/0002_e820-high-mem.patch +++ /dev/null @@ -1,129 +0,0 @@ -From: Izik Eidus - -add support to memory above the pci hole - -the new memory region is mapped after address 0x100000000, -the bios take the size of the memory after the 0x100000000 from -three new cmos bytes. - -diff --git a/bios/rombios.c b/bios/rombios.c -index 1be0816..b70f249 100644 ---- a/bios/rombios.c -+++ b/bios/rombios.c -@@ -4442,22 +4442,25 @@ BX_DEBUG_INT15("case default:\n"); - #endif // BX_USE_PS2_MOUSE - - --void set_e820_range(ES, DI, start, end, type) -+void set_e820_range(ES, DI, start, end, extra_start, extra_end, type) - Bit16u ES; - Bit16u DI; - Bit32u start; - Bit32u end; -+ Bit8u extra_start; -+ Bit8u extra_end; - Bit16u type; - { - write_word(ES, DI, start); - write_word(ES, DI+2, start >> 16); -- write_word(ES, DI+4, 0x00); -+ write_word(ES, DI+4, extra_start); - write_word(ES, DI+6, 0x00); - - end -= start; -+ extra_end -= extra_start; - write_word(ES, DI+8, end); - write_word(ES, DI+10, end >> 16); -- write_word(ES, DI+12, 0x0000); -+ write_word(ES, DI+12, extra_end); - write_word(ES, DI+14, 0x0000); - - write_word(ES, DI+16, type); -@@ -4470,7 +4473,9 @@ int15_function32(regs, ES, DS, FLAGS) - Bit16u ES, DS, FLAGS; - { - Bit32u extended_memory_size=0; // 64bits long -+ Bit32u extra_lowbits_memory_size=0; - Bit16u CX,DX; -+ Bit8u extra_highbits_memory_size=0; - - BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax); - -@@ -4544,11 +4549,18 @@ ASM_END - extended_memory_size += (1L * 1024 * 1024); - } - -+ extra_lowbits_memory_size = inb_cmos(0x5c); -+ extra_lowbits_memory_size <<= 8; -+ extra_lowbits_memory_size |= inb_cmos(0x5b); -+ extra_lowbits_memory_size *= 64; -+ extra_lowbits_memory_size *= 1024; -+ extra_highbits_memory_size = inb_cmos(0x5d); -+ - switch(regs.u.r16.bx) - { - case 0: - set_e820_range(ES, regs.u.r16.di, -- 0x0000000L, 0x0009f000L, 1); -+ 0x0000000L, 0x0009f000L, 0, 0, 1); - regs.u.r32.ebx = 1; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4557,7 +4569,7 @@ ASM_END - break; - case 1: - set_e820_range(ES, regs.u.r16.di, -- 0x0009f000L, 0x000a0000L, 2); -+ 0x0009f000L, 0x000a0000L, 0, 0, 2); - regs.u.r32.ebx = 2; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4566,7 +4578,7 @@ ASM_END - break; - case 2: - set_e820_range(ES, regs.u.r16.di, -- 0x000e8000L, 0x00100000L, 2); -+ 0x000e8000L, 0x00100000L, 0, 0, 2); - regs.u.r32.ebx = 3; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4577,7 +4589,7 @@ ASM_END - #if BX_ROMBIOS32 - set_e820_range(ES, regs.u.r16.di, - 0x00100000L, -- extended_memory_size - ACPI_DATA_SIZE, 1); -+ extended_memory_size - ACPI_DATA_SIZE ,0, 0, 1); - regs.u.r32.ebx = 4; - #else - set_e820_range(ES, regs.u.r16.di, -@@ -4593,7 +4605,7 @@ ASM_END - case 4: - set_e820_range(ES, regs.u.r16.di, - extended_memory_size - ACPI_DATA_SIZE, -- extended_memory_size, 3); // ACPI RAM -+ extended_memory_size ,0, 0, 3); // ACPI RAM - regs.u.r32.ebx = 5; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4603,7 +4615,20 @@ ASM_END - case 5: - /* 256KB BIOS area at the end of 4 GB */ - set_e820_range(ES, regs.u.r16.di, -- 0xfffc0000L, 0x00000000L, 2); -+ 0xfffc0000L, 0x00000000L ,0, 0, 2); -+ if (extra_highbits_memory_size || extra_lowbits_memory_size) -+ regs.u.r32.ebx = 6; -+ else -+ regs.u.r32.ebx = 0; -+ regs.u.r32.eax = 0x534D4150; -+ regs.u.r32.ecx = 0x14; -+ CLEAR_CF(); -+ return; -+ case 6: -+ /* Maping of memory above 4 GB */ -+ set_e820_range(ES, regs.u.r16.di, 0x00000000L, -+ extra_lowbits_memory_size, 1, extra_highbits_memory_size -+ + 1, 1); - regs.u.r32.ebx = 0; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; diff --git a/pc-bios/bios-pq/0003_smp-startup-poll.patch b/pc-bios/bios-pq/0003_smp-startup-poll.patch deleted file mode 100644 index cd1a3ff034..0000000000 --- a/pc-bios/bios-pq/0003_smp-startup-poll.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Avi Kivity - -instead of timing out, wait until all cpus are up - -diff --git a/bios/rombios32.c b/bios/rombios32.c -index ef98a41..05ba40d 100644 ---- a/bios/rombios32.c -+++ b/bios/rombios32.c -@@ -512,7 +512,12 @@ void smp_probe(void) - sipi_vector = AP_BOOT_ADDR >> 12; - writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector); - -+#ifndef BX_QEMU - delay_ms(10); -+#else -+ while (cmos_readb(0x5f) + 1 != readw(&smp_cpus)) -+ ; -+#endif - } - BX_INFO("Found %d cpu(s)\n", readw(&smp_cpus)); - } diff --git a/pc-bios/bios-pq/0005_hpet.patch b/pc-bios/bios-pq/0005_hpet.patch deleted file mode 100644 index 9347cb501e..0000000000 --- a/pc-bios/bios-pq/0005_hpet.patch +++ /dev/null @@ -1,190 +0,0 @@ -BOCHS BIOS changes to support HPET in QEMU. - -Signed-off-by Beth Kon - -Index: bochs-2.3.7/bios/acpi-dsdt.dsl -=================================================================== ---- bochs-2.3.7.orig/bios/acpi-dsdt.dsl 2008-10-15 12:39:14.000000000 -0500 -+++ bochs-2.3.7/bios/acpi-dsdt.dsl 2008-10-28 07:58:40.000000000 -0500 -@@ -159,6 +159,26 @@ - Return (MEMP) - } - } -+#ifdef BX_QEMU -+ Device(HPET) { -+ Name(_HID, EISAID("PNP0103")) -+ Name(_UID, 0) -+ Method (_STA, 0, NotSerialized) { -+ Return(0x0F) -+ } -+ Name(_CRS, ResourceTemplate() { -+ DWordMemory( -+ ResourceConsumer, PosDecode, MinFixed, MaxFixed, -+ NonCacheable, ReadWrite, -+ 0x00000000, -+ 0xFED00000, -+ 0xFED003FF, -+ 0x00000000, -+ 0x00000400 /* 1K memory: FED00000 - FED003FF */ -+ ) -+ }) -+ } -+#endif - } - - Scope(\_SB.PCI0) { -Index: bochs-2.3.7/bios/rombios32.c -=================================================================== ---- bochs-2.3.7.orig/bios/rombios32.c 2008-10-15 12:39:36.000000000 -0500 -+++ bochs-2.3.7/bios/rombios32.c 2008-11-12 14:41:41.000000000 -0600 -@@ -1087,7 +1087,11 @@ - struct rsdt_descriptor_rev1 - { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ -+#ifdef BX_QEMU -+ uint32_t table_offset_entry [4]; /* Array of pointers to other */ -+#else - uint32_t table_offset_entry [3]; /* Array of pointers to other */ -+#endif - /* ACPI tables */ - }; - -@@ -1227,6 +1231,32 @@ - #endif - }; - -+#ifdef BX_QEMU -+/* -+ * * ACPI 2.0 Generic Address Space definition. -+ * */ -+struct acpi_20_generic_address { -+ uint8_t address_space_id; -+ uint8_t register_bit_width; -+ uint8_t register_bit_offset; -+ uint8_t reserved; -+ uint64_t address; -+}; -+ -+/* -+ * * HPET Description Table -+ * */ -+struct acpi_20_hpet { -+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ -+ uint32_t timer_block_id; -+ struct acpi_20_generic_address addr; -+ uint8_t hpet_number; -+ uint16_t min_tick; -+ uint8_t page_protect; -+}; -+#define ACPI_HPET_ADDRESS 0xFED00000UL -+#endif -+ - struct madt_io_apic - { - APIC_HEADER_DEF -@@ -1237,6 +1267,17 @@ - * lines start */ - }; - -+#ifdef BX_QEMU -+struct madt_int_override -+{ -+ APIC_HEADER_DEF -+ uint8_t bus; /* Identifies ISA Bus */ -+ uint8_t source; /* Bus-relative interrupt source */ -+ uint32_t gsi; /* GSI that source will signal */ -+ uint16_t flags; /* MPS INTI flags */ -+}; -+#endif -+ - #include "acpi-dsdt.hex" - - static inline uint16_t cpu_to_le16(uint16_t x) -@@ -1342,6 +1383,10 @@ - struct facs_descriptor_rev1 *facs; - struct multiple_apic_table *madt; - uint8_t *dsdt, *ssdt; -+#ifdef BX_QEMU -+ struct acpi_20_hpet *hpet; -+ uint32_t hpet_addr; -+#endif - uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr; - uint32_t acpi_tables_size, madt_addr, madt_size; - int i; -@@ -1384,10 +1429,21 @@ - madt_addr = addr; - madt_size = sizeof(*madt) + - sizeof(struct madt_processor_apic) * smp_cpus + -+#ifdef BX_QEMU -+ sizeof(struct madt_io_apic) + sizeof(struct madt_int_override); -+#else - sizeof(struct madt_io_apic); -+#endif - madt = (void *)(addr); - addr += madt_size; - -+#ifdef BX_QEMU -+ addr = (addr + 7) & ~7; -+ hpet_addr = addr; -+ hpet = (void *)(addr); -+ addr += sizeof(*hpet); -+#endif -+ - acpi_tables_size = addr - base_addr; - - BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n", -@@ -1410,6 +1466,9 @@ - rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); - rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); - rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr); -+#ifdef BX_QEMU -+ rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr); -+#endif - acpi_build_table_header((struct acpi_table_header *)rsdt, - "RSDT", sizeof(*rsdt), 1); - -@@ -1448,6 +1507,9 @@ - { - struct madt_processor_apic *apic; - struct madt_io_apic *io_apic; -+#ifdef BX_QEMU -+ struct madt_int_override *int_override; -+#endif - - memset(madt, 0, madt_size); - madt->local_apic_address = cpu_to_le32(0xfee00000); -@@ -1467,10 +1529,34 @@ - io_apic->io_apic_id = smp_cpus; - io_apic->address = cpu_to_le32(0xfec00000); - io_apic->interrupt = cpu_to_le32(0); -+#ifdef BX_QEMU -+ io_apic++; -+ -+ int_override = (void *)io_apic; -+ int_override->type = APIC_XRUPT_OVERRIDE; -+ int_override->length = sizeof(*int_override); -+ int_override->bus = cpu_to_le32(0); -+ int_override->source = cpu_to_le32(0); -+ int_override->gsi = cpu_to_le32(2); -+ int_override->flags = cpu_to_le32(0); -+#endif - - acpi_build_table_header((struct acpi_table_header *)madt, - "APIC", madt_size, 1); - } -+ -+#ifdef BX_QEMU -+ /* HPET */ -+ memset(hpet, 0, sizeof(*hpet)); -+ /* Note timer_block_id value must be kept in sync with value advertised by -+ * emulated hpet -+ */ -+ hpet->timer_block_id = cpu_to_le32(0x8086a201); -+ hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS); -+ acpi_build_table_header((struct acpi_table_header *)hpet, -+ "HPET", sizeof(*hpet), 1); -+#endif -+ - } - - /* SMBIOS entry point -- must be written to a 16-bit aligned address diff --git a/pc-bios/bios-pq/HEAD b/pc-bios/bios-pq/HEAD index 928a2334bb..1f604ae821 100644 --- a/pc-bios/bios-pq/HEAD +++ b/pc-bios/bios-pq/HEAD @@ -1 +1 @@ -370a7e0d8419bc05192d766c11b7221e5ffc0f75 +7342176bb0fa9d6cc63b37f6ac239e3f70b74219 diff --git a/pc-bios/bios-pq/series b/pc-bios/bios-pq/series index 0e7558c47b..556c0e48dc 100644 --- a/pc-bios/bios-pq/series +++ b/pc-bios/bios-pq/series @@ -1,4 +1 @@ 0001_bx-qemu.patch -0002_e820-high-mem.patch -0003_smp-startup-poll.patch -0005_hpet.patch diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 5120192ded..ac444c1492 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc new file mode 100644 index 0000000000..53cf42ba08 Binary files /dev/null and b/pc-bios/openbios-ppc differ diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 dissimilarity index 71% index 7c5d0127b4..8f4170b551 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 99e0d790e8..e00c5ddbb0 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 92ec234575..c919e3b22d 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -81,21 +81,16 @@ static void *aio_thread(void *unused) if (len == -1 && errno == EINTR) continue; else if (len == -1) { - pthread_mutex_lock(&lock); - aiocb->ret = -errno; - pthread_mutex_unlock(&lock); + offset = -errno; break; } else if (len == 0) break; offset += len; - - pthread_mutex_lock(&lock); - aiocb->ret = offset; - pthread_mutex_unlock(&lock); } pthread_mutex_lock(&lock); + aiocb->ret = offset; idle_threads++; pthread_mutex_unlock(&lock); diff --git a/qemu-doc.texi b/qemu-doc.texi index aea4210a7f..5a12dc9e5e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -72,7 +72,7 @@ For system emulation, the following hardware targets are supported: @item PC (x86 or x86_64 processor) @item ISA PC (old style PC without PCI bus) @item PREP (PowerPC processor) -@item G3 BW PowerMac (PowerPC processor) +@item G3 Beige PowerMac (PowerPC processor) @item Mac99 PowerMac (PowerPC processor, in progress) @item Sun4m/Sun4c/Sun4d (32-bit Sparc processor) @item Sun4u/Sun4v (64-bit Sparc processor, in progress) @@ -184,8 +184,8 @@ PCI UHCI USB controller and a virtual USB hub. SMP is supported with up to 255 CPUs. -Note that adlib, ac97, gus and cs4231a are only available when QEMU -was configured with --audio-card-list option containing the name(s) of +Note that adlib, gus and cs4231a are only available when QEMU was +configured with --audio-card-list option containing the name(s) of required card(s). QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL diff --git a/qemu-nbd.c b/qemu-nbd.c index ed64b6b2da..59bd2f14f3 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -190,7 +190,7 @@ int main(int argc, char **argv) char *device = NULL; char *socket = NULL; char sockpath[128]; - const char *sopt = "hVbo:p:rsnP:c:dvk:e:t"; + const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t"; struct option lopt[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, diff --git a/slirp/bootp.c b/slirp/bootp.c index 750fae3d05..bf704abf52 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -219,16 +219,18 @@ static void bootp_reply(struct bootp_t *bp) *q++ = 0xff; *q++ = 0x00; - *q++ = RFC1533_GATEWAY; - *q++ = 4; - memcpy(q, &saddr.sin_addr, 4); - q += 4; - - *q++ = RFC1533_DNS; - *q++ = 4; - dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); - memcpy(q, &dns_addr, 4); - q += 4; + if (!slirp_restrict) { + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); + memcpy(q, &dns_addr, 4); + q += 4; + } *q++ = RFC2132_LEASE_TIME; *q++ = 4; diff --git a/slirp/ip.h b/slirp/ip.h index a8cdb0d3fb..3079f90f9b 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -183,35 +183,31 @@ struct ip_timestamp { #define IP_MSS 576 /* default maximum segment size */ -#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ -#include -#else #if SIZEOF_CHAR_P == 4 -typedef caddr_t caddr32_t; -#else -typedef u_int32_t caddr32_t; -#endif -#endif - -#if SIZEOF_CHAR_P == 4 -typedef struct ipq *ipqp_32; -typedef struct ipasfrag *ipasfragp_32; +struct mbuf_ptr { + struct mbuf *mptr; + uint32_t dummy; +}; #else -typedef caddr32_t ipqp_32; -typedef caddr32_t ipasfragp_32; +struct mbuf_ptr { + struct mbuf *mptr; +}; #endif +struct qlink { + void *next, *prev; +}; /* * Overlay for ip header used by other protocols (tcp, udp). */ struct ipovly { - caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ + struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ u_int8_t ih_x1; /* (unused) */ u_int8_t ih_pr; /* protocol */ u_int16_t ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ -}; +} __attribute__((packed)); /* * Ip reassembly queue structure. Each fragment @@ -221,44 +217,30 @@ struct ipovly { * size 28 bytes */ struct ipq { - ipqp_32 next,prev; /* to other reass headers */ + struct qlink frag_link; /* to ip headers of fragments */ + struct qlink ip_link; /* to other reass headers */ u_int8_t ipq_ttl; /* time for reass q to live */ u_int8_t ipq_p; /* protocol of this fragment */ u_int16_t ipq_id; /* sequence id for reassembly */ - ipasfragp_32 ipq_next,ipq_prev; - /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; }; /* * Ip header, when holding a fragment. * - * Note: ipf_next must be at same offset as ipq_next above + * Note: ipf_link must be at same offset as frag_link above */ struct ipasfrag { -#ifdef WORDS_BIGENDIAN - u_int ip_v:4, - ip_hl:4; -#else - u_int ip_hl:4, - ip_v:4; -#endif - /* BUG : u_int changed to u_int8_t. - * sizeof(u_int)==4 on linux 2.0 - */ - u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit - * to avoid destroying tos (PPPDTRuu); - * copied from (ip_off&IP_MF) */ - u_int16_t ip_len; - u_int16_t ip_id; - u_int16_t ip_off; - u_int8_t ip_ttl; - u_int8_t ip_p; - u_int16_t ip_sum; - ipasfragp_32 ipf_next; /* next fragment */ - ipasfragp_32 ipf_prev; /* previous fragment */ + struct qlink ipf_link; + struct ip ipf_ip; }; +#define ipf_off ipf_ip.ip_off +#define ipf_tos ipf_ip.ip_tos +#define ipf_len ipf_ip.ip_len +#define ipf_next ipf_link.next +#define ipf_prev ipf_link.prev + /* * Structure stored in mbuf in inpcb.ip_options * and passed to ip_output when ip options are in use. diff --git a/slirp/ip_input.c b/slirp/ip_input.c index b04684027d..116ee4565f 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -43,6 +43,7 @@ */ #include +#include #include "ip_icmp.h" #ifdef LOG_ENABLED @@ -51,7 +52,7 @@ struct ipstat ipstat; struct ipq ipq; -static struct ip *ip_reass(register struct ipasfrag *ip, +static struct ip *ip_reass(register struct ip *ip, register struct ipq *fp); static void ip_freef(struct ipq *fp); static void ip_enq(register struct ipasfrag *p, @@ -65,7 +66,7 @@ static void ip_deq(register struct ipasfrag *p); void ip_init() { - ipq.next = ipq.prev = (ipqp_32)&ipq; + ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link; ip_id = tt.tv_sec & 0xffff; udp_init(); tcp_init(); @@ -136,6 +137,27 @@ ip_input(m) STAT(ipstat.ips_tooshort++); goto bad; } + + if (slirp_restrict) { + if (memcmp(&ip->ip_dst.s_addr, &special_addr, 3)) { + if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP) + goto bad; + } else { + int host = ntohl(ip->ip_dst.s_addr) & 0xff; + struct ex_list *ex_ptr; + + if (host == 0xff) + goto bad; + + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_addr == host) + break; + + if (!ex_ptr) + goto bad; + } + } + /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); @@ -167,18 +189,20 @@ ip_input(m) */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; + struct qlink *l; /* * Look for queue of fragments * of this datagram. */ - for (fp = (struct ipq *) ipq.next; fp != &ipq; - fp = (struct ipq *) fp->next) - if (ip->ip_id == fp->ipq_id && - ip->ip_src.s_addr == fp->ipq_src.s_addr && - ip->ip_dst.s_addr == fp->ipq_dst.s_addr && - ip->ip_p == fp->ipq_p) + for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) { + fp = container_of(l, struct ipq, ip_link); + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) goto found; - fp = 0; + } + fp = NULL; found: /* @@ -188,9 +212,9 @@ ip_input(m) */ ip->ip_len -= hlen; if (ip->ip_off & IP_MF) - ((struct ipasfrag *)ip)->ipf_mff |= 1; + ip->ip_tos |= 1; else - ((struct ipasfrag *)ip)->ipf_mff &= ~1; + ip->ip_tos &= ~1; ip->ip_off <<= 3; @@ -199,9 +223,9 @@ ip_input(m) * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ - if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + if (ip->ip_tos & 1 || ip->ip_off) { STAT(ipstat.ips_fragments++); - ip = ip_reass((struct ipasfrag *)ip, fp); + ip = ip_reass(ip, fp); if (ip == 0) return; STAT(ipstat.ips_reassembled++); @@ -237,6 +261,8 @@ bad: return; } +#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink))) +#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink))) /* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for @@ -244,7 +270,7 @@ bad: * is given as fp; otherwise have to make a chain. */ static struct ip * -ip_reass(register struct ipasfrag *ip, register struct ipq *fp) +ip_reass(register struct ip *ip, register struct ipq *fp) { register struct mbuf *m = dtom(ip); register struct ipasfrag *q; @@ -271,13 +297,13 @@ ip_reass(register struct ipasfrag *ip, register struct ipq *fp) struct mbuf *t; if ((t = m_get()) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); - insque_32(fp, &ipq); + insque(&fp->ip_link, &ipq.ip_link); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; - fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; - fp->ipq_src = ((struct ip *)ip)->ip_src; - fp->ipq_dst = ((struct ip *)ip)->ip_dst; + fp->frag_link.next = fp->frag_link.prev = &fp->frag_link; + fp->ipq_src = ip->ip_src; + fp->ipq_dst = ip->ip_dst; q = (struct ipasfrag *)fp; goto insert; } @@ -285,9 +311,9 @@ ip_reass(register struct ipasfrag *ip, register struct ipq *fp) /* * Find a segment which begins after this one does. */ - for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; - q = (struct ipasfrag *)q->ipf_next) - if (q->ip_off > ip->ip_off) + for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; + q = q->ipf_next) + if (q->ipf_off > ip->ip_off) break; /* @@ -295,9 +321,9 @@ ip_reass(register struct ipasfrag *ip, register struct ipq *fp) * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ - if (q->ipf_prev != (ipasfragp_32)fp) { - i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + - ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; + if (q->ipf_prev != &fp->frag_link) { + struct ipasfrag *pq = q->ipf_prev; + i = pq->ipf_off + pq->ipf_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; @@ -311,17 +337,18 @@ ip_reass(register struct ipasfrag *ip, register struct ipq *fp) * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { - i = (ip->ip_off + ip->ip_len) - q->ip_off; - if (i < q->ip_len) { - q->ip_len -= i; - q->ip_off += i; + while (q != (struct ipasfrag*)&fp->frag_link && + ip->ip_off + ip->ip_len > q->ipf_off) { + i = (ip->ip_off + ip->ip_len) - q->ipf_off; + if (i < q->ipf_len) { + q->ipf_len -= i; + q->ipf_off += i; m_adj(dtom(q), i); break; } - q = (struct ipasfrag *) q->ipf_next; - m_freem(dtom((struct ipasfrag *) q->ipf_prev)); - ip_deq((struct ipasfrag *) q->ipf_prev); + q = q->ipf_next; + m_freem(dtom(q->ipf_prev)); + ip_deq(q->ipf_prev); } insert: @@ -329,27 +356,26 @@ insert: * Stick new segment in its place; * check for complete reassembly. */ - ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + ip_enq(iptofrag(ip), q->ipf_prev); next = 0; - for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; - q = (struct ipasfrag *) q->ipf_next) { - if (q->ip_off != next) + for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; + q = q->ipf_next) { + if (q->ipf_off != next) return (0); - next += q->ip_len; + next += q->ipf_len; } - if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) + if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1) return (0); /* * Reassembly is complete; concatenate fragments. */ - q = (struct ipasfrag *) fp->ipq_next; + q = fp->frag_link.next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; - while (q != (struct ipasfrag *)fp) { - struct mbuf *t; - t = dtom(q); + while (q != (struct ipasfrag*)&fp->frag_link) { + struct mbuf *t = dtom(q); q = (struct ipasfrag *) q->ipf_next; m_cat(m, t); } @@ -360,7 +386,7 @@ insert: * dequeue and discard fragment reassembly header. * Make header visible. */ - ip = (struct ipasfrag *) fp->ipq_next; + q = fp->frag_link.next; /* * If the fragments concatenated to an mbuf that's @@ -372,23 +398,23 @@ insert: if (m->m_flags & M_EXT) { int delta; delta = (char *)ip - m->m_dat; - ip = (struct ipasfrag *)(m->m_ext + delta); + q = (struct ipasfrag *)(m->m_ext + delta); } /* DEBUG_ARG("ip = %lx", (long)ip); * ip=(struct ipasfrag *)m->m_data; */ + ip = fragtoip(q); ip->ip_len = next; - ip->ipf_mff &= ~1; - ((struct ip *)ip)->ip_src = fp->ipq_src; - ((struct ip *)ip)->ip_dst = fp->ipq_dst; - remque_32(fp); + ip->ip_tos &= ~1; + ip->ip_src = fp->ipq_src; + ip->ip_dst = fp->ipq_dst; + remque(&fp->ip_link); (void) m_free(dtom(fp)); - m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); - return ((struct ip *)ip); + return ip; dropfrag: STAT(ipstat.ips_fragdropped++); @@ -405,13 +431,12 @@ ip_freef(struct ipq *fp) { register struct ipasfrag *q, *p; - for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; - q = p) { - p = (struct ipasfrag *) q->ipf_next; + for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) { + p = q->ipf_next; ip_deq(q); m_freem(dtom(q)); } - remque_32(fp); + remque(&fp->ip_link); (void) m_free(dtom(fp)); } @@ -424,10 +449,10 @@ ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev) { DEBUG_CALL("ip_enq"); DEBUG_ARG("prev = %lx", (long)prev); - p->ipf_prev = (ipasfragp_32) prev; + p->ipf_prev = prev; p->ipf_next = prev->ipf_next; - ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; - prev->ipf_next = (ipasfragp_32) p; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p; + prev->ipf_next = p; } /* @@ -448,20 +473,21 @@ ip_deq(register struct ipasfrag *p) void ip_slowtimo() { - register struct ipq *fp; + struct qlink *l; DEBUG_CALL("ip_slowtimo"); - fp = (struct ipq *) ipq.next; - if (fp == 0) + l = ipq.ip_link.next; + + if (l == 0) return; - while (fp != &ipq) { - --fp->ipq_ttl; - fp = (struct ipq *) fp->next; - if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + while (l != &ipq.ip_link) { + struct ipq *fp = container_of(l, struct ipq, ip_link); + l = l->next; + if (--fp->ipq_ttl == 0) { STAT(ipstat.ips_fragtimeout++); - ip_freef((struct ipq *) fp->prev); + ip_freef(fp); } } } diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 7e4cfa98a2..6c5db54c95 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -5,7 +5,7 @@ extern "C" { #endif -void slirp_init(void); +void slirp_init(int restrict, char *special_ip); void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); @@ -20,13 +20,16 @@ void slirp_output(const uint8_t *pkt, int pkt_len); int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port); -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; extern char slirp_hostname[33]; void slirp_stats(void); +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, + int size); +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port); #ifdef __cplusplus } diff --git a/slirp/main.h b/slirp/main.h index c01addac4b..ed51385599 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -44,6 +44,8 @@ extern int towrite_max; extern int ppp_exit; extern int tcp_keepintvl; extern uint8_t client_ethaddr[6]; +extern const char *slirp_special_ip; +extern int slirp_restrict; #define PROTO_SLIP 0x1 #ifdef USE_PPP @@ -51,3 +53,4 @@ extern uint8_t client_ethaddr[6]; #endif void if_encap(const uint8_t *ip_data, int ip_data_len); +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags); diff --git a/slirp/misc.c b/slirp/misc.c index 9ff3176397..f558b3c0f7 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -83,39 +83,6 @@ getouraddr() our_addr.s_addr = loopback_addr.s_addr; } -#if SIZEOF_CHAR_P == 8 - -struct quehead_32 { - u_int32_t qh_link; - u_int32_t qh_rlink; -}; - -inline void -insque_32(a, b) - void *a; - void *b; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - register struct quehead_32 *head = (struct quehead_32 *) b; - element->qh_link = head->qh_link; - head->qh_link = (u_int32_t)element; - element->qh_rlink = (u_int32_t)head; - ((struct quehead_32 *)(element->qh_link))->qh_rlink - = (u_int32_t)element; -} - -inline void -remque_32(a) - void *a; -{ - register struct quehead_32 *element = (struct quehead_32 *) a; - ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; - ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -#endif /* SIZEOF_CHAR_P == 8 */ - struct quehead { struct quehead *qh_link; struct quehead *qh_rlink; @@ -169,7 +136,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port) (*ex_ptr)->ex_fport = port; (*ex_ptr)->ex_addr = addr; (*ex_ptr)->ex_pty = do_pty; - (*ex_ptr)->ex_exec = strdup(exec); + (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec); (*ex_ptr)->ex_next = tmp_ptr; return 0; } diff --git a/slirp/sbuf.c b/slirp/sbuf.c index b0e0838405..2e6e2b2140 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -108,7 +108,7 @@ sbappend(so, m) * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) - ret = send(so->s, m->m_data, m->m_len, 0); + ret = slirp_send(so, m->m_data, m->m_len, 0); if (ret <= 0) { /* diff --git a/slirp/slirp.c b/slirp/slirp.c index 17b40e249a..0394496ab3 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu-common.h" +#include "qemu-char.h" #include "slirp.h" +#include "hw/hw.h" /* host address */ struct in_addr our_addr; @@ -45,6 +48,8 @@ static struct in_addr client_ipaddr; static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 }; +const char *slirp_special_ip = CTL_SPECIAL; +int slirp_restrict; int do_slowtimo; int link_up; struct timeval tt; @@ -163,7 +168,10 @@ static void slirp_cleanup(void) } #endif -void slirp_init(void) +static void slirp_state_save(QEMUFile *f, void *opaque); +static int slirp_state_load(QEMUFile *f, void *opaque, int version_id); + +void slirp_init(int restrict, char *special_ip) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); @@ -176,6 +184,7 @@ void slirp_init(void) #endif link_up = 1; + slirp_restrict = restrict; if_init(); ip_init(); @@ -191,9 +200,13 @@ void slirp_init(void) fprintf (stderr, "Warning: No DNS servers found\n"); } - inet_aton(CTL_SPECIAL, &special_addr); + if (special_ip) + slirp_special_ip = special_ip; + + inet_aton(slirp_special_ip, &special_addr); alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); getouraddr(); + register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL); } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) @@ -249,7 +262,7 @@ void slirp_select_fill(int *pnfds, * in the fragment queue, or there are TCP connections active */ do_slowtimo = ((tcb.so_next != &tcb) || - ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + (&ipq.ip_link != ipq.ip_link.next)); for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; @@ -736,9 +749,291 @@ int slirp_redir(int is_udp, int host_port, return 0; } -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, int guest_port) { return add_exec(&exec_list, do_pty, (char *)args, addr_low_byte, htons(guest_port)); } + +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) +{ + if (so->s == -1 && so->extra) { + qemu_chr_write(so->extra, buf, len); + return len; + } + + return send(so->s, buf, len, flags); +} + +static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port) +{ + struct socket *so; + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == + special_addr.s_addr + && (ntohl(so->so_faddr.s_addr) & 0xff) == + addr_low_byte + && htons(so->so_fport) == guest_port) + return so; + } + + return NULL; +} + +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port) +{ + struct iovec iov[2]; + struct socket *so; + + if (!link_up) + return 0; + + so = slirp_find_ctl_socket(addr_low_byte, guest_port); + + if (!so || so->so_state & SS_NOFDREF) + return 0; + + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) + return 0; + + return sopreprbuf(so, iov, NULL); +} + +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, + int size) +{ + int ret; + struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port); + + if (!so) + return; + + ret = soreadbuf(so, (const char *)buf, size); + + if (ret > 0) + tcp_output(sototcpcb(so)); +} + +static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp) +{ + int i; + + qemu_put_sbe16(f, tp->t_state); + for (i = 0; i < TCPT_NTIMERS; i++) + qemu_put_sbe16(f, tp->t_timer[i]); + qemu_put_sbe16(f, tp->t_rxtshift); + qemu_put_sbe16(f, tp->t_rxtcur); + qemu_put_sbe16(f, tp->t_dupacks); + qemu_put_be16(f, tp->t_maxseg); + qemu_put_sbyte(f, tp->t_force); + qemu_put_be16(f, tp->t_flags); + qemu_put_be32(f, tp->snd_una); + qemu_put_be32(f, tp->snd_nxt); + qemu_put_be32(f, tp->snd_up); + qemu_put_be32(f, tp->snd_wl1); + qemu_put_be32(f, tp->snd_wl2); + qemu_put_be32(f, tp->iss); + qemu_put_be32(f, tp->snd_wnd); + qemu_put_be32(f, tp->rcv_wnd); + qemu_put_be32(f, tp->rcv_nxt); + qemu_put_be32(f, tp->rcv_up); + qemu_put_be32(f, tp->irs); + qemu_put_be32(f, tp->rcv_adv); + qemu_put_be32(f, tp->snd_max); + qemu_put_be32(f, tp->snd_cwnd); + qemu_put_be32(f, tp->snd_ssthresh); + qemu_put_sbe16(f, tp->t_idle); + qemu_put_sbe16(f, tp->t_rtt); + qemu_put_be32(f, tp->t_rtseq); + qemu_put_sbe16(f, tp->t_srtt); + qemu_put_sbe16(f, tp->t_rttvar); + qemu_put_be16(f, tp->t_rttmin); + qemu_put_be32(f, tp->max_sndwnd); + qemu_put_byte(f, tp->t_oobflags); + qemu_put_byte(f, tp->t_iobc); + qemu_put_sbe16(f, tp->t_softerror); + qemu_put_byte(f, tp->snd_scale); + qemu_put_byte(f, tp->rcv_scale); + qemu_put_byte(f, tp->request_r_scale); + qemu_put_byte(f, tp->requested_s_scale); + qemu_put_be32(f, tp->ts_recent); + qemu_put_be32(f, tp->ts_recent_age); + qemu_put_be32(f, tp->last_ack_sent); +} + +static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) +{ + uint32_t off; + + qemu_put_be32(f, sbuf->sb_cc); + qemu_put_be32(f, sbuf->sb_datalen); + off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data); + qemu_put_sbe32(f, off); + off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data); + qemu_put_sbe32(f, off); + qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); +} + +static void slirp_socket_save(QEMUFile *f, struct socket *so) +{ + qemu_put_be32(f, so->so_urgc); + qemu_put_be32(f, so->so_faddr.s_addr); + qemu_put_be32(f, so->so_laddr.s_addr); + qemu_put_be16(f, so->so_fport); + qemu_put_be16(f, so->so_lport); + qemu_put_byte(f, so->so_iptos); + qemu_put_byte(f, so->so_emu); + qemu_put_byte(f, so->so_type); + qemu_put_be32(f, so->so_state); + slirp_sbuf_save(f, &so->so_rcv); + slirp_sbuf_save(f, &so->so_snd); + slirp_tcp_save(f, so->so_tcpcb); +} + +static void slirp_state_save(QEMUFile *f, void *opaque) +{ + struct ex_list *ex_ptr; + + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_pty == 3) { + struct socket *so; + so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport)); + if (!so) + continue; + + qemu_put_byte(f, 42); + slirp_socket_save(f, so); + } + qemu_put_byte(f, 0); +} + +static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp) +{ + int i; + + tp->t_state = qemu_get_sbe16(f); + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = qemu_get_sbe16(f); + tp->t_rxtshift = qemu_get_sbe16(f); + tp->t_rxtcur = qemu_get_sbe16(f); + tp->t_dupacks = qemu_get_sbe16(f); + tp->t_maxseg = qemu_get_be16(f); + tp->t_force = qemu_get_sbyte(f); + tp->t_flags = qemu_get_be16(f); + tp->snd_una = qemu_get_be32(f); + tp->snd_nxt = qemu_get_be32(f); + tp->snd_up = qemu_get_be32(f); + tp->snd_wl1 = qemu_get_be32(f); + tp->snd_wl2 = qemu_get_be32(f); + tp->iss = qemu_get_be32(f); + tp->snd_wnd = qemu_get_be32(f); + tp->rcv_wnd = qemu_get_be32(f); + tp->rcv_nxt = qemu_get_be32(f); + tp->rcv_up = qemu_get_be32(f); + tp->irs = qemu_get_be32(f); + tp->rcv_adv = qemu_get_be32(f); + tp->snd_max = qemu_get_be32(f); + tp->snd_cwnd = qemu_get_be32(f); + tp->snd_ssthresh = qemu_get_be32(f); + tp->t_idle = qemu_get_sbe16(f); + tp->t_rtt = qemu_get_sbe16(f); + tp->t_rtseq = qemu_get_be32(f); + tp->t_srtt = qemu_get_sbe16(f); + tp->t_rttvar = qemu_get_sbe16(f); + tp->t_rttmin = qemu_get_be16(f); + tp->max_sndwnd = qemu_get_be32(f); + tp->t_oobflags = qemu_get_byte(f); + tp->t_iobc = qemu_get_byte(f); + tp->t_softerror = qemu_get_sbe16(f); + tp->snd_scale = qemu_get_byte(f); + tp->rcv_scale = qemu_get_byte(f); + tp->request_r_scale = qemu_get_byte(f); + tp->requested_s_scale = qemu_get_byte(f); + tp->ts_recent = qemu_get_be32(f); + tp->ts_recent_age = qemu_get_be32(f); + tp->last_ack_sent = qemu_get_be32(f); + tcp_template(tp); +} + +static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf) +{ + uint32_t off, sb_cc, sb_datalen; + + sb_cc = qemu_get_be32(f); + sb_datalen = qemu_get_be32(f); + + sbreserve(sbuf, sb_datalen); + + if (sbuf->sb_datalen != sb_datalen) + return -ENOMEM; + + sbuf->sb_cc = sb_cc; + + off = qemu_get_sbe32(f); + sbuf->sb_wptr = sbuf->sb_data + off; + off = qemu_get_sbe32(f); + sbuf->sb_rptr = sbuf->sb_data + off; + qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); + + return 0; +} + +static int slirp_socket_load(QEMUFile *f, struct socket *so) +{ + if (tcp_attach(so) < 0) + return -ENOMEM; + + so->so_urgc = qemu_get_be32(f); + so->so_faddr.s_addr = qemu_get_be32(f); + so->so_laddr.s_addr = qemu_get_be32(f); + so->so_fport = qemu_get_be16(f); + so->so_lport = qemu_get_be16(f); + so->so_iptos = qemu_get_byte(f); + so->so_emu = qemu_get_byte(f); + so->so_type = qemu_get_byte(f); + so->so_state = qemu_get_be32(f); + if (slirp_sbuf_load(f, &so->so_rcv) < 0) + return -ENOMEM; + if (slirp_sbuf_load(f, &so->so_snd) < 0) + return -ENOMEM; + slirp_tcp_load(f, so->so_tcpcb); + + return 0; +} + +static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) +{ + struct ex_list *ex_ptr; + int r; + + while ((r = qemu_get_byte(f))) { + int ret; + struct socket *so = socreate(); + + if (!so) + return -ENOMEM; + + ret = slirp_socket_load(f, so); + + if (ret < 0) + return ret; + + if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr) + return -EINVAL; + + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_pty == 3 && + (ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr && + so->so_fport == ex_ptr->ex_fport) + break; + + if (!ex_ptr) + return -EINVAL; + + so->extra = (void *)ex_ptr->ex_exec; + } + + return 0; +} diff --git a/slirp/slirp.h b/slirp/slirp.h index 3002e0bb04..d57fb12363 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -266,14 +266,6 @@ void if_start _P((struct ttys *)); void lprint _P((const char *, ...)); -#if SIZEOF_CHAR_P == 4 -# define insque_32 insque -# define remque_32 remque -#else - void insque_32 _P((void *, void *)); - void remque_32 _P((void *)); -#endif - #ifndef _WIN32 #include #endif diff --git a/slirp/socket.c b/slirp/socket.c index 00694e2c71..9def541dae 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -5,13 +5,13 @@ * terms and conditions of the copyright. */ +#include "qemu-common.h" #define WANT_SYS_IOCTL_H #include #include "ip_icmp.h" #ifdef __sun__ #include #endif -#include "qemu-common.h" static void sofcantrcvmore(struct socket *so); static void sofcantsendmore(struct socket *so); @@ -91,31 +91,21 @@ sofree(so) free(so); } -/* - * Read from so's socket into sb_snd, updating all relevant sbuf fields - * NOTE: This will only be called if it is select()ed for reading, so - * a read() of 0 (or less) means it's disconnected - */ -int -soread(so) - struct socket *so; +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) { - int n, nn, lss, total; + int n, lss, total; struct sbuf *sb = &so->so_snd; int len = sb->sb_datalen - sb->sb_cc; - struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; - DEBUG_CALL("soread"); + DEBUG_CALL("sopreprbuf"); DEBUG_ARG("so = %lx", (long )so); - /* - * No need to check if there's enough room to read. - * soread wouldn't have been called if there weren't - */ - len = sb->sb_datalen - sb->sb_cc; + if (len <= 0) + return 0; + iov[0].iov_base = sb->sb_wptr; iov[1].iov_base = NULL; iov[1].iov_len = 0; @@ -156,6 +146,33 @@ soread(so) n = 1; } } + if (np) + *np = n; + + return iov[0].iov_len + (n - 1) * iov[1].iov_len; +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct socket *so; +{ + int n, nn; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2]; + + DEBUG_CALL("soread"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + sopreprbuf(so, iov, &n); #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); @@ -202,6 +219,48 @@ soread(so) return nn; } +int soreadbuf(struct socket *so, const char *buf, int size) +{ + int n, nn, copy = size; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2]; + + DEBUG_CALL("soreadbuf"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + if (sopreprbuf(so, iov, &n) < size) + goto err; + + nn = MIN(iov[0].iov_len, copy); + memcpy(iov[0].iov_base, buf, nn); + + copy -= nn; + buf += nn; + + if (copy == 0) + goto done; + + memcpy(iov[1].iov_base, buf, copy); + +done: + /* Update fields */ + sb->sb_cc += size; + sb->sb_wptr += size; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return size; +err: + + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + fprintf(stderr, "soreadbuf buffer to small"); + return -1; +} + /* * Get urgent data * @@ -255,7 +314,7 @@ sosendoob(so) if (sb->sb_rptr < sb->sb_wptr) { /* We can send it directly */ - n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); @@ -276,7 +335,7 @@ sosendoob(so) so->so_urgc -= n; len += n; } - n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); @@ -348,7 +407,7 @@ sowrite(so) DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else - nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); + nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) @@ -365,7 +424,7 @@ sowrite(so) #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) { int ret; - ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } diff --git a/slirp/socket.h b/slirp/socket.h index 5edea90c93..72b473d639 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); +int soreadbuf(struct socket *so, const char *buf, int size); #endif /* _SOCKET_H_ */ diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 17a9387f04..f324adb1d9 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -71,7 +71,7 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ #ifdef TCP_ACK_HACK #define TCP_REASS(tp, ti, m, so, flags) {\ if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + tcpfrag_list_empty(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) {\ if (ti->ti_flags & TH_PUSH) \ tp->t_flags |= TF_ACKNOW; \ @@ -94,7 +94,7 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ #else #define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + tcpfrag_list_empty(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ @@ -134,8 +134,8 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti, /* * Find a segment which begins after this one does. */ - for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; - q = (struct tcpiphdr *)q->ti_next) + for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp); + q = tcpiphdr_next(q)) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; @@ -144,9 +144,9 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti, * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ - if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + if (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) { register int i; - q = (struct tcpiphdr *)q->ti_prev; + q = tcpiphdr_prev(q); /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { @@ -166,36 +166,36 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti, ti->ti_len -= i; ti->ti_seq += i; } - q = (struct tcpiphdr *)(q->ti_next); + q = tcpiphdr_next(q); } STAT(tcpstat.tcps_rcvoopack++); STAT(tcpstat.tcps_rcvoobyte += ti->ti_len); - REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + ti->ti_mbuf = m; /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - while (q != (struct tcpiphdr *)tp) { + while (!tcpfrag_list_end(q, tp)) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; - m_adj((struct mbuf *) REASS_MBUF(q), i); + m_adj(q->ti_mbuf, i); break; } - q = (struct tcpiphdr *)q->ti_next; - m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); - remque_32((void *)(q->ti_prev)); + q = tcpiphdr_next(q); + m = tcpiphdr_prev(q)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(q))); m_freem(m); } /* * Stick new segment in its place. */ - insque_32(ti, (void *)(q->ti_prev)); + insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q))); present: /* @@ -204,17 +204,17 @@ present: */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); - ti = (struct tcpiphdr *) tp->seg_next; - if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + ti = tcpfrag_list_first(tp); + if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; - remque_32(ti); - m = (struct mbuf *) REASS_MBUF(ti); /* XXX */ - ti = (struct tcpiphdr *)ti->ti_next; + remque(tcpiphdr2qlink(ti)); + m = ti->ti_mbuf; + ti = tcpiphdr_next(ti); /* if (so->so_state & SS_FCANTRCVMORE) */ if (so->so_state & SS_FCANTSENDMORE) m_freem(m); @@ -253,6 +253,7 @@ tcp_input(m, iphlen, inso) u_long tiwin; int ret; /* int ts_present = 0; */ + struct ex_list *ex_ptr; DEBUG_CALL("tcp_input"); DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", @@ -301,7 +302,8 @@ tcp_input(m, iphlen, inso) * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; - ti->ti_next = ti->ti_prev = 0; + tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = 0; + memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr)); ti->ti_x1 = 0; ti->ti_len = htons((u_int16_t)tlen); len = sizeof(struct ip ) + tlen; @@ -363,6 +365,15 @@ tcp_input(m, iphlen, inso) m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + if (slirp_restrict) { + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_fport == ti->ti_dport && + (ntohl(ti->ti_dst.s_addr) & 0xff) == ex_ptr->ex_addr) + break; + + if (!ex_ptr) + goto drop; + } /* * Locate pcb for segment. */ @@ -550,7 +561,7 @@ findso: return; } } else if (ti->ti_ack == tp->snd_una && - tp->seg_next == (tcpiphdrp_32)tp && + tcpfrag_list_empty(tp) && ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet @@ -646,7 +657,6 @@ findso: #endif { /* May be an add exec */ - struct ex_list *ex_ptr; for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if(ex_ptr->ex_fport == so->so_fport && lastbyte == ex_ptr->ex_addr) { diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index bce07a6cbd..497b988221 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -73,7 +73,7 @@ tcp_template(tp) struct socket *so = tp->t_socket; register struct tcpiphdr *n = &tp->t_template; - n->ti_next = n->ti_prev = 0; + n->ti_mbuf = NULL; n->ti_x1 = 0; n->ti_pr = IPPROTO_TCP; n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); @@ -156,7 +156,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) tlen += sizeof (struct tcpiphdr); m->m_len = tlen; - ti->ti_next = ti->ti_prev = 0; + ti->ti_mbuf = 0; ti->ti_x1 = 0; ti->ti_seq = htonl(seq); ti->ti_ack = htonl(ack); @@ -196,7 +196,7 @@ tcp_newtcpcb(so) return ((struct tcpcb *)0); memset((char *) tp, 0, sizeof(struct tcpcb)); - tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; + tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp; tp->t_maxseg = TCP_MSS; tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; @@ -272,11 +272,11 @@ tcp_close(tp) DEBUG_ARG("tp = %lx", (long )tp); /* free the reassembly queue, if any */ - t = (struct tcpiphdr *) tp->seg_next; - while (t != (struct tcpiphdr *)tp) { - t = (struct tcpiphdr *)t->ti_next; - m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); - remque_32((struct tcpiphdr *) t->ti_prev); + t = tcpfrag_list_first(tp); + while (!tcpfrag_list_end(t, tp)) { + t = tcpiphdr_next(t); + m = tcpiphdr_prev(t)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(t))); m_freem(m); } /* It's static */ @@ -1281,6 +1281,11 @@ tcp_ctl(so) for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_fport == so->so_fport && command == ex_ptr->ex_addr) { + if (ex_ptr->ex_pty == 3) { + so->s = -1; + so->extra = (void *)ex_ptr->ex_exec; + return 1; + } do_pty = ex_ptr->ex_pty; goto do_exec; } diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h index 82380f9365..99d18fdf1f 100644 --- a/slirp/tcp_var.h +++ b/slirp/tcp_var.h @@ -40,18 +40,12 @@ #include "tcpip.h" #include "tcp_timer.h" -#if SIZEOF_CHAR_P == 4 - typedef struct tcpiphdr *tcpiphdrp_32; -#else - typedef u_int32_t tcpiphdrp_32; -#endif - /* * Tcp control block, one per tcp; fields: */ struct tcpcb { - tcpiphdrp_32 seg_next; /* sequencing queue */ - tcpiphdrp_32 seg_prev; + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *seg_prev; short t_state; /* state of this connection */ short t_timer[TCPT_NTIMERS]; /* tcp timers */ short t_rxtshift; /* log(2) of rexmt exp. backoff */ @@ -170,21 +164,6 @@ struct tcpcb { #define TCP_REXMTVAL(tp) \ (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) -/* XXX - * We want to avoid doing m_pullup on incoming packets but that - * means avoiding dtom on the tcp reassembly code. That in turn means - * keeping an mbuf pointer in the reassembly queue (since we might - * have a cluster). As a quick hack, the source & destination - * port numbers (which are no longer needed once we've located the - * tcpcb) are overlayed with an mbuf pointer. - */ -#if SIZEOF_CHAR_P == 4 -typedef struct mbuf *mbufp_32; -#else -typedef u_int32_t mbufp_32; -#endif -#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) - #ifdef LOG_ENABLED /* * TCP statistics. diff --git a/slirp/tcpip.h b/slirp/tcpip.h index 82708b09c5..b98cdb30db 100644 --- a/slirp/tcpip.h +++ b/slirp/tcpip.h @@ -44,8 +44,7 @@ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ struct tcphdr ti_t; /* tcp header */ }; -#define ti_next ti_i.ih_next -#define ti_prev ti_i.ih_prev +#define ti_mbuf ti_i.ih_mbuf.mptr #define ti_x1 ti_i.ih_x1 #define ti_pr ti_i.ih_pr #define ti_len ti_i.ih_len @@ -62,6 +61,14 @@ struct tcpiphdr { #define ti_sum ti_t.th_sum #define ti_urp ti_t.th_urp +#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink))) +#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink))) +#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next) +#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev) +#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next) +#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T)) +#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T)) + /* * Just a clean way to get to the first byte * of the packet diff --git a/slirp/udp.c b/slirp/udp.c index 8030326ad6..c9926181ac 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -136,8 +136,7 @@ udp_input(m, iphlen) * Checksum extended UDP header and data. */ if (UDPCKSUM && uh->uh_sum) { - ((struct ipovly *)ip)->ih_next = 0; - ((struct ipovly *)ip)->ih_prev = 0; + memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr)); ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; /* keep uh_sum for ICMP reply @@ -158,6 +157,9 @@ udp_input(m, iphlen) goto bad; } + if (slirp_restrict) + goto bad; + /* * handle TFTP */ @@ -280,7 +282,7 @@ int udp_output2(struct socket *so, struct mbuf *m, * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); - ui->ui_next = ui->ui_prev = 0; + memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr)); ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ diff --git a/slirp/udp.h b/slirp/udp.h index 4f69b098c3..e2ca54645a 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -60,8 +60,7 @@ struct udpiphdr { struct ipovly ui_i; /* overlaid ip structure */ struct udphdr ui_u; /* udp header */ }; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev +#define ui_mbuf ui_i.ih_mbuf.mptr #define ui_x1 ui_i.ih_x1 #define ui_pr ui_i.ih_pr #define ui_len ui_i.ih_len diff --git a/target-mips/helper.c b/target-mips/helper.c index 0a3b913f19..c4fd9574e6 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -100,6 +100,7 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, return TLBRET_NOMATCH; } +#if !defined(CONFIG_USER_ONLY) static int get_physical_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) @@ -205,26 +206,29 @@ static int get_physical_address (CPUState *env, target_ulong *physical, return ret; } +#endif target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - if (env->user_mode_only) - return addr; - else { - target_ulong phys_addr; - int prot; +#if defined(CONFIG_USER_ONLY) + return addr; +#else + target_ulong phys_addr; + int prot; - if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) - return -1; - return phys_addr; - } + if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + return -1; + return phys_addr; +#endif } int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { +#if !defined(CONFIG_USER_ONLY) target_ulong physical; int prot; +#endif int exception = 0, error_code = 0; int access_type; int ret = 0; @@ -243,11 +247,9 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* XXX: put correct access by using cpu_restore_state() correctly */ access_type = ACCESS_INT; - if (env->user_mode_only) { - /* user mode only emulation */ - ret = TLBRET_NOMATCH; - goto do_fault; - } +#if defined(CONFIG_USER_ONLY) + ret = TLBRET_NOMATCH; +#else ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (logfile) { @@ -258,8 +260,9 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ret = tlb_set_page(env, address & TARGET_PAGE_MASK, physical & TARGET_PAGE_MASK, prot, mmu_idx, is_softmmu); - } else if (ret < 0) { - do_fault: + } else if (ret < 0) +#endif + { switch (ret) { default: case TLBRET_BADADDR: @@ -349,227 +352,227 @@ static const char * const excp_names[EXCP_LAST + 1] = { void do_interrupt (CPUState *env) { - if (!env->user_mode_only) { - target_ulong offset; - int cause = -1; - const char *name; +#if !defined(CONFIG_USER_ONLY) + target_ulong offset; + int cause = -1; + const char *name; - if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - if (env->exception_index < 0 || env->exception_index > EXCP_LAST) - name = "unknown"; - else - name = excp_names[env->exception_index]; + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + if (env->exception_index < 0 || env->exception_index > EXCP_LAST) + name = "unknown"; + else + name = excp_names[env->exception_index]; - fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", - __func__, env->active_tc.PC, env->CP0_EPC, name); - } - 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). */ + fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", + __func__, env->active_tc.PC, env->CP0_EPC, name); + } + 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->active_tc.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; + set_DEPC: + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_DEPC = env->active_tc.PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { env->CP0_DEPC = env->active_tc.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; - set_DEPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_DEPC = env->active_tc.PC - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; - } else { - env->CP0_DEPC = env->active_tc.PC; - } + } enter_debug_mode: - env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_KSU); - /* EJTAG probe trap enable is not implemented... */ - if (!(env->CP0_Status & (1 << CP0St_EXL))) - env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->active_tc.PC = (int32_t)0xBFC00480; - break; - case EXCP_RESET: - cpu_reset(env); - break; - case EXCP_SRESET: - env->CP0_Status |= (1 << CP0St_SR); - memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo)); - goto set_error_EPC; - case EXCP_NMI: - env->CP0_Status |= (1 << CP0St_NMI); + env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + env->hflags &= ~(MIPS_HFLAG_KSU); + /* EJTAG probe trap enable is not implemented... */ + if (!(env->CP0_Status & (1 << CP0St_EXL))) + env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->active_tc.PC = (int32_t)0xBFC00480; + break; + case EXCP_RESET: + cpu_reset(env); + break; + case EXCP_SRESET: + env->CP0_Status |= (1 << CP0St_SR); + memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo)); + goto set_error_EPC; + case EXCP_NMI: + env->CP0_Status |= (1 << CP0St_NMI); set_error_EPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_ErrorEPC = env->active_tc.PC - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; - } else { - env->CP0_ErrorEPC = env->active_tc.PC; - } - env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_KSU); - if (!(env->CP0_Status & (1 << CP0St_EXL))) - env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->active_tc.PC = (int32_t)0xBFC00000; - break; - case EXCP_EXT_INTERRUPT: - cause = 0; - if (env->CP0_Cause & (1 << CP0Ca_IV)) - offset = 0x200; - goto set_EPC; - case EXCP_LTLBL: - cause = 1; - goto set_EPC; - case EXCP_TLBL: - cause = 2; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_ErrorEPC = env->active_tc.PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { + env->CP0_ErrorEPC = env->active_tc.PC; + } + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + env->hflags &= ~(MIPS_HFLAG_KSU); + if (!(env->CP0_Status & (1 << CP0St_EXL))) + env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->active_tc.PC = (int32_t)0xBFC00000; + break; + case EXCP_EXT_INTERRUPT: + cause = 0; + if (env->CP0_Cause & (1 << CP0Ca_IV)) + offset = 0x200; + goto set_EPC; + case EXCP_LTLBL: + cause = 1; + goto set_EPC; + case EXCP_TLBL: + cause = 2; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { #if defined(TARGET_MIPS64) - int R = env->CP0_BadVAddr >> 62; - int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; - int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; - int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) - offset = 0x080; - else + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else #endif - offset = 0x000; - } - goto set_EPC; - case EXCP_TLBS: - cause = 3; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { + offset = 0x000; + } + goto set_EPC; + case EXCP_TLBS: + cause = 3; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { #if defined(TARGET_MIPS64) - int R = env->CP0_BadVAddr >> 62; - int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; - int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; - int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) - offset = 0x080; - else + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else #endif - offset = 0x000; - } - goto set_EPC; - case EXCP_AdEL: - cause = 4; - goto set_EPC; - case EXCP_AdES: - cause = 5; - 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; - env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | - (env->error_code << CP0Ca_CE); - goto set_EPC; - case EXCP_OVERFLOW: - cause = 12; - goto set_EPC; - case EXCP_TRAP: - cause = 13; - goto set_EPC; - case EXCP_FPE: - cause = 15; - goto set_EPC; - case EXCP_C2E: - cause = 18; - goto set_EPC; - case EXCP_MDMX: - cause = 22; - goto set_EPC; - case EXCP_DWATCH: - cause = 23; - /* XXX: TODO: manage defered watch exceptions */ - goto set_EPC; - case EXCP_MCHECK: - cause = 24; - goto set_EPC; - case EXCP_THREAD: - cause = 25; - goto set_EPC; - case EXCP_CACHE: - cause = 30; - if (env->CP0_Status & (1 << CP0St_BEV)) { - offset = 0x100; - } else { - offset = 0x20000100; - } + offset = 0x000; + } + goto set_EPC; + case EXCP_AdEL: + cause = 4; + goto set_EPC; + case EXCP_AdES: + cause = 5; + 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; + env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | + (env->error_code << CP0Ca_CE); + goto set_EPC; + case EXCP_OVERFLOW: + cause = 12; + goto set_EPC; + case EXCP_TRAP: + cause = 13; + goto set_EPC; + case EXCP_FPE: + cause = 15; + goto set_EPC; + case EXCP_C2E: + cause = 18; + goto set_EPC; + case EXCP_MDMX: + cause = 22; + goto set_EPC; + case EXCP_DWATCH: + cause = 23; + /* XXX: TODO: manage defered watch exceptions */ + goto set_EPC; + case EXCP_MCHECK: + cause = 24; + goto set_EPC; + case EXCP_THREAD: + cause = 25; + goto set_EPC; + case EXCP_CACHE: + cause = 30; + if (env->CP0_Status & (1 << CP0St_BEV)) { + offset = 0x100; + } else { + offset = 0x20000100; + } set_EPC: - if (!(env->CP0_Status & (1 << CP0St_EXL))) { - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_EPC = env->active_tc.PC - 4; - env->CP0_Cause |= (1 << CP0Ca_BD); - } else { - env->CP0_EPC = env->active_tc.PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); - } - env->CP0_Status |= (1 << CP0St_EXL); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_KSU); - } - env->hflags &= ~MIPS_HFLAG_BMASK; - if (env->CP0_Status & (1 << CP0St_BEV)) { - env->active_tc.PC = (int32_t)0xBFC00200; + if (!(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_EPC = env->active_tc.PC - 4; + env->CP0_Cause |= (1 << CP0Ca_BD); } else { - env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff); - } - env->active_tc.PC += offset; - env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); - break; - default: - if (logfile) { - fprintf(logfile, "Invalid MIPS exception %d. Exiting\n", - env->exception_index); + env->CP0_EPC = env->active_tc.PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); } - printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); - exit(1); + env->CP0_Status |= (1 << CP0St_EXL); + env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + env->hflags &= ~(MIPS_HFLAG_KSU); } - if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n" - " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", - __func__, env->active_tc.PC, env->CP0_EPC, cause, - env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, - env->CP0_DEPC); + env->hflags &= ~MIPS_HFLAG_BMASK; + if (env->CP0_Status & (1 << CP0St_BEV)) { + env->active_tc.PC = (int32_t)0xBFC00200; + } else { + env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff); } + env->active_tc.PC += offset; + env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); + 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); + } + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n" + " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", + __func__, env->active_tc.PC, env->CP0_EPC, cause, + env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, + env->CP0_DEPC); } +#endif env->exception_index = EXCP_NONE; } diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 2d0c1383dd..d5d1a4cbaf 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -15,7 +15,14 @@ #endif /* Even MIPS32 can have 36 bits physical address space. */ +//#define TARGET_PHYS_ADDR_BITS 64 +/*Set TARGET_PHYS_ADDR_BITS will confuse the TARGET_FMT_plx macro */ +#if defined(TARGET_MIPS64) #define TARGET_PHYS_ADDR_BITS 64 +#else +#define TARGET_PHYS_ADDR_BITS 32 +#endif + /* Masks used to mark instructions to indicate which ISA level they were introduced in. */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 7bca5bc91e..4a1861f7ee 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -7859,13 +7859,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_helper_rdhwr_ccres(t0); break; case 29: - if (env->user_mode_only) { - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value)); - break; - } else { - /* XXX: Some CPUs implement this in hardware. - Not supported yet. */ - } +#if defined(CONFIG_USER_ONLY) + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value)); + break; +#else + /* XXX: Some CPUs implement this in hardware. + Not supported yet. */ +#endif default: /* Invalid */ MIPS_INVAL("rdhwr"); generate_exception(ctx, EXCP_RI); @@ -7953,19 +7953,17 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DMTC0: #endif #ifndef CONFIG_USER_ONLY - if (!env->user_mode_only) - gen_cp0(env, ctx, op1, rt, rd); + gen_cp0(env, ctx, op1, rt, rd); #endif /* !CONFIG_USER_ONLY */ break; case OPC_C0_FIRST ... OPC_C0_LAST: #ifndef CONFIG_USER_ONLY - if (!env->user_mode_only) - gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); + gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); #endif /* !CONFIG_USER_ONLY */ break; case OPC_MFMC0: #ifndef CONFIG_USER_ONLY - if (!env->user_mode_only) { + { TCGv t0 = tcg_temp_local_new(); op2 = MASK_MFMC0(ctx->opcode); @@ -8264,10 +8262,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); - if (env->user_mode_only) +#ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; - else +#else ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; +#endif num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) @@ -8583,40 +8582,37 @@ void cpu_reset (CPUMIPSState *env) /* Minimal init */ #if defined(CONFIG_USER_ONLY) - env->user_mode_only = 1; -#endif - if (env->user_mode_only) { - env->hflags = MIPS_HFLAG_UM; + env->hflags = MIPS_HFLAG_UM; +#else + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_ErrorEPC = env->active_tc.PC - 4; } else { - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_ErrorEPC = env->active_tc.PC - 4; - } else { - env->CP0_ErrorEPC = env->active_tc.PC; - } - env->active_tc.PC = (int32_t)0xBFC00000; - env->CP0_Wired = 0; - /* SMP not implemented */ - env->CP0_EBase = 0x80000000; - env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); - /* vectored interrupts not implemented, timer on int 7, - no performance counters. */ - env->CP0_IntCtl = 0xe0000000; - { - int i; - - for (i = 0; i < 7; i++) { - env->CP0_WatchLo[i] = 0; - env->CP0_WatchHi[i] = 0x80000000; - } - env->CP0_WatchLo[7] = 0; - env->CP0_WatchHi[7] = 0; + env->CP0_ErrorEPC = env->active_tc.PC; + } + env->active_tc.PC = (int32_t)0xBFC00000; + env->CP0_Wired = 0; + /* SMP not implemented */ + env->CP0_EBase = 0x80000000; + env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); + /* vectored interrupts not implemented, timer on int 7, + no performance counters. */ + env->CP0_IntCtl = 0xe0000000; + { + int i; + + for (i = 0; i < 7; i++) { + env->CP0_WatchLo[i] = 0; + env->CP0_WatchHi[i] = 0x80000000; } - /* Count register increments in debug mode, EJTAG version 1 */ - env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); - env->hflags = MIPS_HFLAG_CP0; + env->CP0_WatchLo[7] = 0; + env->CP0_WatchHi[7] = 0; } + /* Count register increments in debug mode, EJTAG version 1 */ + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); + env->hflags = MIPS_HFLAG_CP0; +#endif env->exception_index = EXCP_NONE; cpu_mips_register(env, env->cpu_model); } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 249fc93610..6fe3214987 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -509,14 +509,14 @@ static void fpu_init (CPUMIPSState *env, const mips_def_t *def) env->fpus[i].fcr0 = def->CP1_fcr0; memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); - if (env->user_mode_only) { - if (env->CP0_Config1 & (1 << CP0C1_FP)) - env->hflags |= MIPS_HFLAG_FPU; +#if defined(CONFIG_USER_ONLY) + if (env->CP0_Config1 & (1 << CP0C1_FP)) + env->hflags |= MIPS_HFLAG_FPU; #ifdef TARGET_MIPS64 - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) - env->hflags |= MIPS_HFLAG_F64; + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) + env->hflags |= MIPS_HFLAG_F64; +#endif #endif - } } static void mvp_init (CPUMIPSState *env, const mips_def_t *def) @@ -534,9 +534,10 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def) // (0x04 << CP0MVPC0_PTC); (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) | (0x04 << CP0MVPC0_PTC); +#if !defined(CONFIG_USER_ONLY) /* Usermode has no TLB support */ - if (!env->user_mode_only) - env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE); + env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE); +#endif /* Allocatable CP1 have media extensions, allocatable CP1 have FP support, no UDI implemented, no CP2 implemented, 1 CP1 implemented. */ @@ -586,8 +587,7 @@ static int cpu_mips_register (CPUMIPSState *env, const mips_def_t *def) env->insn_flags = def->insn_flags; #ifndef CONFIG_USER_ONLY - if (!env->user_mode_only) - mmu_init(env, def); + mmu_init(env, def); #endif fpu_init(env, def); mvp_init(env, def); diff --git a/target-ppc/helper.h b/target-ppc/helper.h index f319fdb5e1..755bfbae48 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -123,6 +123,24 @@ DEF_HELPER_3(vminuw, void, avr, avr, avr) DEF_HELPER_3(vmaxub, void, avr, avr, avr) DEF_HELPER_3(vmaxuh, void, avr, avr, avr) DEF_HELPER_3(vmaxuw, void, avr, avr, avr) +DEF_HELPER_3(vcmpequb, void, avr, avr, avr) +DEF_HELPER_3(vcmpequh, void, avr, avr, avr) +DEF_HELPER_3(vcmpequw, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtub, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtuh, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtuw, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsb, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsh, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsw, void, avr, avr, avr) +DEF_HELPER_3(vcmpequb_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpequh_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpequw_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtub_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtuh_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtuw_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsb_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsh_dot, void, avr, avr, avr) +DEF_HELPER_3(vcmpgtsw_dot, void, avr, avr, avr) DEF_HELPER_3(vmrglb, void, avr, avr, avr) DEF_HELPER_3(vmrglh, void, avr, avr, avr) DEF_HELPER_3(vmrglw, void, avr, avr, avr) @@ -152,10 +170,27 @@ DEF_HELPER_3(vaddcuw, void, avr, avr, avr) DEF_HELPER_3(vsubcuw, void, avr, avr, avr) DEF_HELPER_2(lvsl, void, avr, tl); DEF_HELPER_2(lvsr, void, avr, tl); +DEF_HELPER_3(vaddsbs, void, avr, avr, avr) +DEF_HELPER_3(vaddshs, void, avr, avr, avr) +DEF_HELPER_3(vaddsws, void, avr, avr, avr) +DEF_HELPER_3(vsubsbs, void, avr, avr, avr) +DEF_HELPER_3(vsubshs, void, avr, avr, avr) +DEF_HELPER_3(vsubsws, void, avr, avr, avr) +DEF_HELPER_3(vaddubs, void, avr, avr, avr) +DEF_HELPER_3(vadduhs, void, avr, avr, avr) +DEF_HELPER_3(vadduws, void, avr, avr, avr) +DEF_HELPER_3(vsububs, void, avr, avr, avr) +DEF_HELPER_3(vsubuhs, void, avr, avr, avr) +DEF_HELPER_3(vsubuws, void, avr, avr, avr) DEF_HELPER_3(vrlb, void, avr, avr, avr) DEF_HELPER_3(vrlh, void, avr, avr, avr) DEF_HELPER_3(vrlw, void, avr, avr, avr) +DEF_HELPER_3(vsl, void, avr, avr, avr) +DEF_HELPER_3(vsr, void, avr, avr, avr) DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32) +DEF_HELPER_2(vspltisb, void, avr, i32) +DEF_HELPER_2(vspltish, void, avr, i32) +DEF_HELPER_2(vspltisw, void, avr, i32) DEF_HELPER_3(vspltb, void, avr, avr, i32) DEF_HELPER_3(vsplth, void, avr, avr, i32) DEF_HELPER_3(vspltw, void, avr, avr, i32) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5e40e42ea1..c931adbd98 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2082,6 +2082,45 @@ VARITH(uwm, u32) #undef VARITH_DO #undef VARITH +#define VARITHSAT_CASE(type, op, cvt, element) \ + { \ + type result = (type)a->element[i] op (type)b->element[i]; \ + r->element[i] = cvt(result, &sat); \ + } + +#define VARITHSAT_DO(name, op, optype, cvt, element) \ + void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int sat = 0; \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + switch (sizeof(r->element[0])) { \ + case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \ + case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \ + case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \ + } \ + } \ + if (sat) { \ + env->vscr |= (1 << VSCR_SAT); \ + } \ + } +#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \ + VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element) +#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \ + VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \ + VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element) +VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb) +VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh) +VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw) +VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub) +VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh) +VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) +#undef VARITHSAT_CASE +#undef VARITHSAT_DO +#undef VARITHSAT_SIGNED +#undef VARITHSAT_UNSIGNED + #define VAVG_DO(name, element, etype) \ void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ @@ -2101,6 +2140,42 @@ VAVG(w, s32, int64_t, u32, uint64_t) #undef VAVG_DO #undef VAVG +#define VCMP_DO(suffix, compare, element, record) \ + void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + uint32_t ones = (uint32_t)-1; \ + uint32_t all = ones; \ + uint32_t none = 0; \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \ + switch (sizeof (a->element[0])) { \ + case 4: r->u32[i] = result; break; \ + case 2: r->u16[i] = result; break; \ + case 1: r->u8[i] = result; break; \ + } \ + all &= result; \ + none |= result; \ + } \ + if (record) { \ + env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \ + } \ + } +#define VCMP(suffix, compare, element) \ + VCMP_DO(suffix, compare, element, 0) \ + VCMP_DO(suffix##_dot, compare, element, 1) +VCMP(equb, ==, u8) +VCMP(equh, ==, u16) +VCMP(equw, ==, u32) +VCMP(gtub, >, u8) +VCMP(gtuh, >, u16) +VCMP(gtuw, >, u32) +VCMP(gtsb, >, s8) +VCMP(gtsh, >, s16) +VCMP(gtsw, >, s32) +#undef VCMP_DO +#undef VCMP + void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; @@ -2416,6 +2491,45 @@ void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]); } +#if defined(WORDS_BIGENDIAN) +#define LEFT 0 +#define RIGHT 1 +#else +#define LEFT 1 +#define RIGHT 0 +#endif +/* The specification says that the results are undefined if all of the + * shift counts are not identical. We check to make sure that they are + * to conform to what real hardware appears to do. */ +#define VSHIFT(suffix, leftp) \ + void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ + { \ + int shift = b->u8[LO_IDX*0x15] & 0x7; \ + int doit = 1; \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \ + doit = doit && ((b->u8[i] & 0x7) == shift); \ + } \ + if (doit) { \ + if (shift == 0) { \ + *r = *a; \ + } else if (leftp) { \ + uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \ + r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \ + r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \ + } else { \ + uint64_t carry = a->u64[HI_IDX] << (64 - shift); \ + r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \ + r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \ + } \ + } \ + } +VSHIFT(l, LEFT) +VSHIFT(r, RIGHT) +#undef VSHIFT +#undef LEFT +#undef RIGHT + #define VSL(suffix, element) \ void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ @@ -2495,6 +2609,20 @@ VSPLT(w, u32) #undef SPLAT_ELEMENT #undef _SPLAT_MASKED +#define VSPLTI(suffix, element, splat_type) \ + void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \ + { \ + splat_type x = (int8_t)(splat << 3) >> 3; \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + r->element[i] = x; \ + } \ + } +VSPLTI(b, s8, int8_t) +VSPLTI(h, s16, int16_t) +VSPLTI(w, s32, int32_t) +#undef VSPLTI + #define VSR(suffix, element) \ void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ { \ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 03dac58e76..0cfcc0872d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4152,6 +4152,33 @@ GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) tcg_temp_free(t0); } +/* dst / dstt */ +GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC) +{ + if (rA(ctx->opcode) == 0) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); + } else { + /* interpreted as no-op */ + } +} + +/* dstst /dststt */ +GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC) +{ + if (rA(ctx->opcode) == 0) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX); + } else { + /* interpreted as no-op */ + } + +} + +/* dss / dssall */ +GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC) +{ + /* interpreted as no-op */ +} + /* icbi */ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI) { @@ -6341,9 +6368,23 @@ GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); GEN_VXFORM(vaddcuw, 0, 6); GEN_VXFORM(vsubcuw, 0, 22); +GEN_VXFORM(vaddubs, 0, 8); +GEN_VXFORM(vadduhs, 0, 9); +GEN_VXFORM(vadduws, 0, 10); +GEN_VXFORM(vaddsbs, 0, 12); +GEN_VXFORM(vaddshs, 0, 13); +GEN_VXFORM(vaddsws, 0, 14); +GEN_VXFORM(vsububs, 0, 24); +GEN_VXFORM(vsubuhs, 0, 25); +GEN_VXFORM(vsubuws, 0, 26); +GEN_VXFORM(vsubsbs, 0, 28); +GEN_VXFORM(vsubshs, 0, 29); +GEN_VXFORM(vsubsws, 0, 30); GEN_VXFORM(vrlb, 2, 0); GEN_VXFORM(vrlh, 2, 1); GEN_VXFORM(vrlw, 2, 2); +GEN_VXFORM(vsl, 2, 7); +GEN_VXFORM(vsr, 2, 11); GEN_VXFORM(vpkuhum, 7, 0); GEN_VXFORM(vpkuwum, 7, 1); GEN_VXFORM(vpkuhus, 7, 2); @@ -6359,6 +6400,57 @@ GEN_VXFORM(vsum4shs, 4, 25); GEN_VXFORM(vsum2sws, 4, 26); GEN_VXFORM(vsumsws, 4, 30); +#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ + GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC) \ + { \ + TCGv_ptr ra, rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + ra = gen_avr_ptr(rA(ctx->opcode)); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##opname (rd, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + +#define GEN_VXRFORM(name, opc2, opc3) \ + GEN_VXRFORM1(name, name, #name, opc2, opc3) \ + GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) + +GEN_VXRFORM(vcmpequb, 3, 0) +GEN_VXRFORM(vcmpequh, 3, 1) +GEN_VXRFORM(vcmpequw, 3, 2) +GEN_VXRFORM(vcmpgtsb, 3, 12) +GEN_VXRFORM(vcmpgtsh, 3, 13) +GEN_VXRFORM(vcmpgtsw, 3, 14) +GEN_VXRFORM(vcmpgtub, 3, 8) +GEN_VXRFORM(vcmpgtuh, 3, 9) +GEN_VXRFORM(vcmpgtuw, 3, 10) + +#define GEN_VXFORM_SIMM(name, opc2, opc3) \ + GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) \ + { \ + TCGv_ptr rd; \ + TCGv_i32 simm; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + simm = tcg_const_i32(SIMM5(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name (rd, simm); \ + tcg_temp_free_i32(simm); \ + tcg_temp_free_ptr(rd); \ + } + +GEN_VXFORM_SIMM(vspltisb, 6, 12); +GEN_VXFORM_SIMM(vspltish, 6, 13); +GEN_VXFORM_SIMM(vspltisw, 6, 14); + #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) \ { \ diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 7943e12bf4..d2865ee7d5 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -402,12 +402,12 @@ static int get_physical_address_data(CPUState *env, mask = 0xffffffffffc00000ULL; break; } - // ctx match, vaddr match? + // ctx match, vaddr match, valid? if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && - (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { - // valid, access ok? - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 || - ((env->dtlb_tte[i] & 0x4) && is_user) || + (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL) && + (env->dtlb_tte[i] & 0x8000000000000000ULL)) { + // access ok? + if (((env->dtlb_tte[i] & 0x4) && is_user) || (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { if (env->dmmuregs[3]) /* Fault status register */ env->dmmuregs[3] = 2; /* overflow (not read before @@ -465,12 +465,12 @@ static int get_physical_address_code(CPUState *env, mask = 0xffffffffffc00000ULL; break; } - // ctx match, vaddr match? + // ctx match, vaddr match, valid? if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) && - (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { - // valid, access ok? - if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || - ((env->itlb_tte[i] & 0x4) && is_user)) { + (address & mask) == (env->itlb_tag[i] & ~0x1fffULL) && + (env->itlb_tte[i] & 0x8000000000000000ULL)) { + // access ok? + if ((env->itlb_tte[i] & 0x4) && is_user) { if (env->immuregs[3]) /* Fault status register */ env->immuregs[3] = 2; /* overflow (not read before another fault) */ diff --git a/vl.c b/vl.c index 959be628c9..e29072b5f9 100644 --- a/vl.c +++ b/vl.c @@ -4266,6 +4266,8 @@ struct soundhw soundhw[] = { { .init_isa = pcspk_audio_init } }, #endif + +#ifdef CONFIG_SB16 { "sb16", "Creative Sound Blaster 16", @@ -4273,6 +4275,7 @@ struct soundhw soundhw[] = { 1, { .init_isa = SB16_init } }, +#endif #ifdef CONFIG_CS4231A { @@ -4318,6 +4321,7 @@ struct soundhw soundhw[] = { }, #endif +#ifdef CONFIG_ES1370 { "es1370", "ENSONIQ AudioPCI ES1370", @@ -4327,6 +4331,8 @@ struct soundhw soundhw[] = { }, #endif +#endif /* HAS_AUDIO_CHOICE */ + { NULL, NULL, 0, 0, { NULL } } };