diff options
93 files changed, 1749 insertions, 1286 deletions
@@ -225,8 +225,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 BLOBS += extboot.bin else BLOBS= @@ -360,6 +361,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 c3542b11b..2b1aa37c9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -646,10 +646,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 @@ -732,7 +729,7 @@ OBJS+= cirrus_vga.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 @@ -779,7 +776,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 1fecf3078..91c53b1b8 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 707109e44..9aa7261e3 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 7c98144ae..73a824a07 100644 --- a/cache-utils.c +++ b/cache-utils.c @@ -1,6 +1,6 @@ #include "cache-utils.h" -#ifdef __powerpc__ +#ifdef HOST_PPC 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 */ diff --git a/cache-utils.h b/cache-utils.h index 0598b96eb..19b24ab4e 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" + +#ifdef HOST_PPC struct qemu_cache_conf { unsigned long dcache_bsize; unsigned long icache_bsize; @@ -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" @@ -537,8 +538,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" @@ -1014,6 +1015,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 @@ -695,7 +695,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 @@ -729,7 +729,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 70d4af6b2..151f3c2ab 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 d84788854..f222f3c0e 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 f7bdd1465..066b96944 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/device-hotplug.c b/hw/device-hotplug.c index 0bcac601b..56172e114 100644 --- a/hw/device-hotplug.c +++ b/hw/device-hotplug.c @@ -26,7 +26,7 @@ static PCIDevice *qemu_system_hot_add_nic(const char *opts, int bus_nr) ret = net_client_init ("nic", opts); if (ret < 0 || !nd_table[ret].model) return NULL; - return pci_nic_init (pci_bus, &nd_table[ret], -1); + return pci_nic_init (pci_bus, &nd_table[ret], -1, "rtl8139"); } #ifdef USE_KVM_DEVICE_ASSIGNMENT diff --git a/hw/e1000.c b/hw/e1000.c index 9de057d5f..eaed351f1 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -571,6 +571,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) { @@ -1087,6 +1102,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 index 1028ed944..d68f90b54 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,36 +706,39 @@ 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 irq, 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; @@ -735,6 +746,7 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, 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 +754,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 +901,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 +909,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 +924,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 000000000..2f3ae3116 --- /dev/null +++ b/hw/escc.h @@ -0,0 +1,7 @@ +/* escc.c */ +#define ESCC_SIZE 4 +int escc_init(target_phys_addr_t base, qemu_irq irq, 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 01b5a6e6f..e409a94e2 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 0c9fdbb60..17dca29a4 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 239e0d872..cce89178a 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: @@ -956,7 +956,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); @@ -1068,7 +1068,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); @@ -2468,7 +2468,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; @@ -3186,9 +3187,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 a2d3d4306..fdbfe202f 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 7f0d9f791..2a98dfb31 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 71ba3fb0a..f06c25a54 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 49ae69bd5..413c5694d 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_malta.c b/hw/mips_malta.c index dea9b589f..3ca036bba 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -487,21 +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 */ - if (!pci_nic_init(pci_bus, nd, 88)) - exit(1); - } else { - if (!pci_nic_init(pci_bus, nd, -1)) - exit(1); - } + devfn = 88; + + pci_nic_init(pci_bus, nd, devfn, "pcnet"); } } diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index dc62f696a..83f1a63e5 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_r4k.c b/hw/mips_r4k.c index 6551b02e0..c12ab54b0 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 13217b2da..67b873511 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 0eb4c1ed1..04ce32287 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 1c932ec3f..f64bb1c89 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 a6d0eecae..7c000176f 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; @@ -814,7 +814,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; @@ -1062,28 +1061,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 = "rtl8139"; - } 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"); - if (!pci_nic_init(pci_bus, nd, -1)) - exit(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, "rtl8139"); } qemu_system_hot_add_init(cpu_model); @@ -715,43 +715,51 @@ 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 PCIDevice *(*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. */ -PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) +PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn, + const char *default_model) { PCIDevice *pci_dev; + int i; - if (strcmp(nd->model, "ne2k_pci") == 0) { - pci_dev = pci_ne2000_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82551") == 0) { - pci_dev = pci_i82551_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82557b") == 0) { - pci_dev = pci_i82557b_init(bus, nd, devfn); - } else if (strcmp(nd->model, "i82559er") == 0) { - pci_dev = pci_i82559er_init(bus, nd, devfn); - } else if (strcmp(nd->model, "rtl8139") == 0) { - pci_dev = pci_rtl8139_init(bus, nd, devfn); - } else if (strcmp(nd->model, "e1000") == 0) { - pci_dev = pci_e1000_init(bus, nd, devfn); - } else if (strcmp(nd->model, "pcnet") == 0) { - pci_dev = pci_pcnet_init(bus, nd, devfn); - } else if (strcmp(nd->model, "virtio") == 0) { - pci_dev = 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"); - return NULL; - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); - return NULL; - } + qemu_check_nic_model_list(nd, pci_nic_models, default_model); - if (!pci_dev) { - fprintf(stderr, "qemu: Unable to initialze NIC: %s\n", nd->model); - return NULL; - } + for (i = 0; pci_nic_models[i]; i++) + if (strcmp(nd->model, pci_nic_models[i]) == 0) { + pci_dev = pci_nic_init_fns[i](bus, nd, devfn); + if (pci_dev) { + nd->devfn = pci_dev->devfn; + } + return pci_dev; + } - nd->devfn = pci_dev->devfn; - return pci_dev; + return NULL; } typedef struct { @@ -126,7 +126,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); -PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); +PCIDevice *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); @@ -178,8 +179,9 @@ PCIDevice *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 e2e428a27..c4f42a40e 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 e92960a95..f5bf15d64 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2090,6 +2090,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; @@ -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 a6fc75823..bc8a47b46 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 daa3aeb95..7625cd131 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,14 +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"; - if (!pci_nic_init(pci_bus, &nd_table[i], -1)) - exit(1); - } + escc_mem_index = escc_init(0x80013000, dummy_irq[4], 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); @@ -296,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 c833d1758..cc70fb7dc 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 1d5e9d67f..cf8b24f58 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; @@ -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[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 e315028a5..6c0d8fe7c 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -671,12 +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 { - if (!pci_nic_init(pci_bus, &nd_table[i], -1)) - exit(1); + pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); } } @@ -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 eb98099c0..e28533800 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -121,13 +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 { - if (!pci_nic_init(pci_bus, nd, -1)) - exit(1); + pci_nic_init(pci_bus, nd, -1, "rtl8139"); } } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 687667a64..2527d9bfb 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; } @@ -3450,7 +3464,7 @@ PCIDevice *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 27a3158f9..f5b29a704 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 703ef7e42..7069518bd 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 a5cd16389..88c56204e 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 e6a538a9f..eb6733c0c 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], 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], 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,17 @@ 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], 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 f6d822ee3..c9601ed32 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 0c1e1a24c..91e7538da 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,12 +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"; - if (!pci_nic_init(pci_bus, &nd_table[i], -1)) - exit(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 527f65eff..267aa42d6 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -194,13 +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 { - if (!pci_nic_init(pci_bus, nd, -1)) - exit(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 1f9dc16bf..28337c3a3 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -25,6 +25,7 @@ typedef struct VirtIONet { VirtIODevice vdev; uint8_t mac[6]; + uint16_t status; VirtQueue *rx_vq; VirtQueue *tx_vq; VLANClientState *vc; @@ -47,13 +48,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); #ifdef TAP_VNET_HDR VirtIONet *n = to_virtio_net(vdev); VLANClientState *host = n->vc->vlan->first_client; @@ -393,7 +409,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; @@ -401,9 +417,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; @@ -411,8 +428,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); @@ -422,6 +441,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 0d9f71ba1..148ec4712 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 @@ -1543,6 +1543,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]" }, { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu state" }, #if defined(TARGET_I386) || defined(TARGET_X86_64) { "drive_add", "iss", drive_hot_add, "pcibus pcidevfn [file=file][,if=type][,bus=n]\n" @@ -301,7 +301,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]); } @@ -389,12 +390,15 @@ int qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) VLANClientState *vc; int ret = -EAGAIN; + 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) { if (!vc->fd_can_read || vc->fd_can_read(vc->opaque)) { vc->fd_read(vc->opaque, buf, size); ret = 0; @@ -453,6 +457,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) @@ -489,7 +495,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); @@ -507,7 +513,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; @@ -593,7 +599,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 */ @@ -673,6 +679,7 @@ typedef struct TAPState { VLANClientState *vc; int fd; char down_script[1024]; + char down_script_arg[128]; char buf[TAP_BUFSIZE]; int size; unsigned int has_vnet_hdr : 1; @@ -1155,8 +1162,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; } @@ -1674,6 +1683,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]; @@ -1736,6 +1779,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 @@ -1875,6 +1924,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; @@ -1886,13 +1965,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) { @@ -9,6 +9,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); typedef struct VLANClientState VLANClientState; +typedef void (LinkStatusChanged)(VLANClientState *); typedef void (SetOffload)(VLANClientState *, int, int, int, int); struct VLANClientState { @@ -17,6 +18,8 @@ struct VLANClientState { /* 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; SetOffload *set_offload; void *opaque; struct VLANClientState *next; @@ -46,9 +49,13 @@ ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); int 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); int tap_has_vnet_hdr(void *opaque); void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr); diff --git a/pc-bios/README b/pc-bios/README index 665bd7d59..1fabe0e84 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 373. - 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 2886e8566..000000000 --- a/pc-bios/bios-pq/0002_e820-high-mem.patch +++ /dev/null @@ -1,129 +0,0 @@ -From: Izik Eidus <izike@qumranet.com> - -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 cd1a3ff03..000000000 --- a/pc-bios/bios-pq/0003_smp-startup-poll.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Avi Kivity <avi@qumranet.com> - -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 9347cb501..000000000 --- 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 <eak@us.ibm.com> - -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 928a2334b..1f604ae82 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 0e7558c47..556c0e48d 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/openbios-ppc b/pc-bios/openbios-ppc Binary files differnew file mode 100644 index 000000000..e597269dd --- /dev/null +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex 7c5d0127b..8f4170b55 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 99e0d790e..e00c5ddbb 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 92ec23457..c919e3b22 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 2ebc5dbf8..bd3a7f1f0 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 ed64b6b2d..59bd2f14f 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 750fae3d0..bf704abf5 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 a8cdb0d3f..3079f90f9 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 <sys/types32.h> -#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 b04684027..116ee4565 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -43,6 +43,7 @@ */ #include <slirp.h> +#include <osdep.h> #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 7e4cfa98a..6c5db54c9 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 c01addac4..ed5138559 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 9ff317639..f558b3c0f 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 b0e083840..2e6e2b214 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 17b40e249..0394496ab 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 3002e0bb0..d57fb1236 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 <netdb.h> #endif diff --git a/slirp/socket.c b/slirp/socket.c index 00694e2c7..9def541da 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 <slirp.h> #include "ip_icmp.h" #ifdef __sun__ #include <sys/filio.h> #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 5edea90c9..72b473d63 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 17a9387f0..f324adb1d 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 bce07a6cb..497b98822 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 82380f936..99d18fdf1 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 82708b09c..b98cdb30d 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 8030326ad..c9926181a 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 4f69b098c..e2ca54645 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 0a3b913f1..c4fd9574e 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/translate.c b/target-mips/translate.c index 7bca5bc91..4a1861f7e 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 7ec82b0d2..d0243aa1d 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -495,14 +495,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) @@ -520,9 +520,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. */ @@ -572,8 +573,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 f319fdb5e..755bfbae4 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 5e40e42ea..c931adbd9 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 03dac58e7..0cfcc0872 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 7943e12bf..d2865ee7d 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) */ @@ -4435,6 +4435,8 @@ struct soundhw soundhw[] = { { .init_isa = pcspk_audio_init } }, #endif + +#ifdef CONFIG_SB16 { "sb16", "Creative Sound Blaster 16", @@ -4442,6 +4444,7 @@ struct soundhw soundhw[] = { 1, { .init_isa = SB16_init } }, +#endif #ifdef CONFIG_CS4231A { @@ -4487,6 +4490,7 @@ struct soundhw soundhw[] = { }, #endif +#ifdef CONFIG_ES1370 { "es1370", "ENSONIQ AudioPCI ES1370", @@ -4496,6 +4500,8 @@ struct soundhw soundhw[] = { }, #endif +#endif /* HAS_AUDIO_CHOICE */ + { NULL, NULL, 0, 0, { NULL } } }; |