diff options
author | Avi Kivity <avi@redhat.com> | 2009-12-02 12:48:32 +0200 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-02 12:48:32 +0200 |
commit | 2e88035e52dee6b6efac71fbd1432ed1c117eab8 (patch) | |
tree | 943ab9665347abb29fdf6eb3a47205f4adbb3a2f | |
parent | kvm_handle_internal_error should return 1 (diff) | |
parent | Update SeaBIOS (diff) | |
download | qemu-kvm-2e88035e52dee6b6efac71fbd1432ed1c117eab8.tar.gz qemu-kvm-2e88035e52dee6b6efac71fbd1432ed1c117eab8.tar.bz2 qemu-kvm-2e88035e52dee6b6efac71fbd1432ed1c117eab8.zip |
Merge commit 'b0293e54af32bcf08f4b4e5b4b472534de343972' into upstream-merge
* commit 'b0293e54af32bcf08f4b4e5b4b472534de343972':
Update SeaBIOS
ARM atomic ops rewrite
ARM RealView I2C
GPIO I2C rework
DS1338 RTC
BCD cleanup
Makefile dependencies for device configs
target-mips: fix physical address type in MMU functions
[WIN32] Enable -k option on Windows too
target-mips: make CP0_LLAddr register CPU dependent
target-mips: rename CP0_LLAddr into lladdr
Conflicts:
pc-bios/bios.bin (pick upstream's)
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | Makefile.target | 2 | ||||
-rw-r--r-- | config.h | 11 | ||||
-rwxr-xr-x | configure | 4 | ||||
-rw-r--r-- | default-configs/arm-softmmu.mak | 1 | ||||
-rw-r--r-- | hw/bitbang_i2c.c | 245 | ||||
-rw-r--r-- | hw/bitbang_i2c.h | 14 | ||||
-rw-r--r-- | hw/ds1338.c | 132 | ||||
-rw-r--r-- | hw/m48t59.c | 50 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 36 | ||||
-rw-r--r-- | hw/musicpal.c | 2 | ||||
-rw-r--r-- | hw/omap1.c | 70 | ||||
-rw-r--r-- | hw/realview.c | 86 | ||||
-rw-r--r-- | hw/twl92230.c | 10 | ||||
-rw-r--r-- | linux-user/main.c | 84 | ||||
-rw-r--r-- | pc-bios/bios.bin | bin | 131072 -> 131072 bytes | |||
-rw-r--r-- | qemu-common.h | 11 | ||||
m--------- | roms/seabios | 0 | ||||
-rw-r--r-- | target-arm/cpu.h | 9 | ||||
-rw-r--r-- | target-arm/helper.c | 84 | ||||
-rw-r--r-- | target-arm/helpers.h | 4 | ||||
-rw-r--r-- | target-arm/translate.c | 250 | ||||
-rw-r--r-- | target-mips/cpu.h | 12 | ||||
-rw-r--r-- | target-mips/helper.c | 14 | ||||
-rw-r--r-- | target-mips/helper.h | 1 | ||||
-rw-r--r-- | target-mips/machine.c | 4 | ||||
-rw-r--r-- | target-mips/op_helper.c | 21 | ||||
-rw-r--r-- | target-mips/translate.c | 19 | ||||
-rw-r--r-- | target-mips/translate_init.c | 32 | ||||
-rw-r--r-- | vl.c | 2 |
30 files changed, 802 insertions, 429 deletions
@@ -1,7 +1,7 @@ # Makefile for QEMU. # This needs to be defined before rules.mak -GENERATED_HEADERS = config-host.h config-all-devices.h +GENERATED_HEADERS = config-host.h ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -41,6 +41,19 @@ SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) config-all-devices.mak: $(SUBDIR_DEVICES_MAK) $(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep "=y$$" | sort -u > $@," GEN $@") +%/config-devices.mak: default-configs/%.mak + $(call quiet-command,cat $< > $@.tmp, " GEN $@") + @if test -f $@ ; then \ + echo "WARNING: $@ out of date." ;\ + echo "Run \"make defconfing\" to regenerate." ; \ + rm $@.tmp ; \ + else \ + mv $@.tmp $@ ; \ + fi + +defconfig: + rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK) + -include config-all-devices.mak build-all: $(DOCS) $(TOOLS) recurse-all @@ -48,9 +61,6 @@ build-all: $(DOCS) $(TOOLS) recurse-all config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak -config-all-devices.h: config-all-devices.h-timestamp -config-all-devices.h-timestamp: config-all-devices.mak - SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) ifeq ($(KVM_KMOD),yes) @@ -135,6 +145,7 @@ obj-$(CONFIG_SSD0303) += ssd0303.o obj-$(CONFIG_SSD0323) += ssd0323.o obj-$(CONFIG_ADS7846) += ads7846.o obj-$(CONFIG_MAX111X) += max111x.o +obj-$(CONFIG_DS1338) += ds1338.o obj-y += i2c.o smbus.o smbus_eeprom.o obj-y += eeprom93xx.o obj-y += scsi-disk.o cdrom.o @@ -259,7 +270,7 @@ clean: distclean: clean rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi - rm -f config-all-devices.mak config-all-devices.h* + rm -f config-all-devices.mak rm -f roms/seabios/config.mak roms/vgabios/config.mak rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr} for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \ diff --git a/Makefile.target b/Makefile.target index 9527404b5..cba0f4cf0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,7 +1,7 @@ # -*- Mode: makefile -*- # This needs to be defined before rules.mak -GENERATED_HEADERS = config-target.h config-devices.h +GENERATED_HEADERS = config-target.h include ../config-host.mak include config-devices.mak @@ -1,13 +1,2 @@ - #include "config-host.h" #include "config-target.h" - -/* We want to include different config files for specific targets - And for the common library. They need a different name because - we don't want to rely in paths */ - -#if defined(NEED_CPU_H) -#include "config-devices.h" -#else -#include "config-all-devices.h" -#endif @@ -2375,10 +2375,6 @@ if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$targ mkdir -p $target_dir/nwfpe fi -if test ! -f $target_dir/config-devices.mak ; then - cp $source_path/default-configs/${target}.mak $target_dir/config-devices.mak -fi - # # don't use ln -sf as not all "ln -sf" over write the file/link # diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 35d2cb9c9..c1b7496c0 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -22,3 +22,4 @@ CONFIG_SSI=y CONFIG_SSI_SD=y CONFIG_LAN9118=y CONFIG_SMC91C111=y +CONFIG_DS1338=y diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 443ddb2b0..4ee99a18b 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -7,12 +7,20 @@ * This code is licenced under the GNU GPL v2. */ #include "hw.h" -#include "i2c.h" +#include "bitbang_i2c.h" #include "sysbus.h" +//#define DEBUG_BITBANG_I2C + +#ifdef DEBUG_BITBANG_I2C +#define DPRINTF(fmt, ...) \ +do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do {} while(0) +#endif + typedef enum bitbang_i2c_state { STOPPED = 0, - INITIALIZING, SENDING_BIT7, SENDING_BIT6, SENDING_BIT5, @@ -33,138 +41,171 @@ typedef enum bitbang_i2c_state { SENDING_ACK } bitbang_i2c_state; -typedef struct bitbang_i2c_interface { - SysBusDevice busdev; +struct bitbang_i2c_interface { i2c_bus *bus; bitbang_i2c_state state; int last_data; int last_clock; + int device_out; uint8_t buffer; int current_addr; - qemu_irq out; -} bitbang_i2c_interface; +}; static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) { + DPRINTF("STOP\n"); if (i2c->current_addr >= 0) i2c_end_transfer(i2c->bus); i2c->current_addr = -1; i2c->state = STOPPED; } -static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) +/* Set device data pin. */ +static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level) +{ + i2c->device_out = level; + //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out); + return level & i2c->last_data; +} + +/* Leave device data pin unodified. */ +static int bitbang_i2c_nop(bitbang_i2c_interface *i2c) +{ + return bitbang_i2c_ret(i2c, i2c->device_out); +} + +/* Returns data line level. */ +int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) { - bitbang_i2c_interface *i2c = opaque; int data; - int clock; - int data_goes_up; - int data_goes_down; - int clock_goes_up; - int clock_goes_down; - - /* get pins states */ - data = i2c->last_data; - clock = i2c->last_clock; - - if (irq == 0) - data = level; - if (irq == 1) - clock = level; - - /* compute pins changes */ - data_goes_up = data == 1 && i2c->last_data == 0; - data_goes_down = data == 0 && i2c->last_data == 1; - clock_goes_up = clock == 1 && i2c->last_clock == 0; - clock_goes_down = clock == 0 && i2c->last_clock == 1; - - if (data_goes_up == 0 && data_goes_down == 0 && - clock_goes_up == 0 && clock_goes_down == 0) - return; - - if (!i2c) - return; - - if ((RECEIVING_BIT7 > i2c->state && i2c->state > RECEIVING_BIT0) - || i2c->state == WAITING_FOR_ACK) - qemu_set_irq(i2c->out, 0); - switch (i2c->state) { - case STOPPED: - if (data_goes_down && clock == 1) - i2c->state = INITIALIZING; - break; + if (level != 0 && level != 1) { + abort(); + } - case INITIALIZING: - if (clock_goes_down && data == 0) + if (line == BITBANG_I2C_SDA) { + if (level == i2c->last_data) { + return bitbang_i2c_nop(i2c); + } + i2c->last_data = level; + if (i2c->last_clock == 0) { + return bitbang_i2c_nop(i2c); + } + if (level == 0) { + DPRINTF("START\n"); + /* START condition. */ i2c->state = SENDING_BIT7; - else + i2c->current_addr = -1; + } else { + /* STOP condition. */ bitbang_i2c_enter_stop(i2c); - break; + } + return bitbang_i2c_ret(i2c, 1); + } + + data = i2c->last_data; + if (i2c->last_clock == level) { + return bitbang_i2c_nop(i2c); + } + i2c->last_clock = level; + if (level == 0) { + /* State is set/read at the start of the clock pulse. + release the data line at the end. */ + return bitbang_i2c_ret(i2c, 1); + } + switch (i2c->state) { + case STOPPED: + return bitbang_i2c_ret(i2c, 1); case SENDING_BIT7 ... SENDING_BIT0: - if (clock_goes_down) { - i2c->buffer = (i2c->buffer << 1) | data; - /* will end up in WAITING_FOR_ACK */ - i2c->state++; - } else if (data_goes_up && clock == 1) - bitbang_i2c_enter_stop(i2c); - break; + i2c->buffer = (i2c->buffer << 1) | data; + /* will end up in WAITING_FOR_ACK */ + i2c->state++; + return bitbang_i2c_ret(i2c, 1); case WAITING_FOR_ACK: - if (clock_goes_down) { - if (i2c->current_addr < 0) { - i2c->current_addr = i2c->buffer; - i2c_start_transfer(i2c->bus, (i2c->current_addr & 0xfe) / 2, - i2c->buffer & 1); - } else - i2c_send(i2c->bus, i2c->buffer); - if (i2c->current_addr & 1) { - i2c->state = RECEIVING_BIT7; - i2c->buffer = i2c_recv(i2c->bus); - } else - i2c->state = SENDING_BIT7; - } else if (data_goes_up && clock == 1) - bitbang_i2c_enter_stop(i2c); - break; - - case RECEIVING_BIT7 ... RECEIVING_BIT0: - qemu_set_irq(i2c->out, i2c->buffer >> 7); - if (clock_goes_down) { - /* will end up in SENDING_ACK */ - i2c->state++; - i2c->buffer <<= 1; - } else if (data_goes_up && clock == 1) - bitbang_i2c_enter_stop(i2c); - break; + if (i2c->current_addr < 0) { + i2c->current_addr = i2c->buffer; + DPRINTF("Address 0x%02x\n", i2c->current_addr); + i2c_start_transfer(i2c->bus, i2c->current_addr >> 1, + i2c->current_addr & 1); + } else { + DPRINTF("Sent 0x%02x\n", i2c->buffer); + i2c_send(i2c->bus, i2c->buffer); + } + if (i2c->current_addr & 1) { + i2c->state = RECEIVING_BIT7; + } else { + i2c->state = SENDING_BIT7; + } + return bitbang_i2c_ret(i2c, 0); + + case RECEIVING_BIT7: + i2c->buffer = i2c_recv(i2c->bus); + DPRINTF("RX byte 0x%02x\n", i2c->buffer); + /* Fall through... */ + case RECEIVING_BIT6 ... RECEIVING_BIT0: + data = i2c->buffer >> 7; + /* will end up in SENDING_ACK */ + i2c->state++; + i2c->buffer <<= 1; + return bitbang_i2c_ret(i2c, data); case SENDING_ACK: - if (clock_goes_down) { - i2c->state = RECEIVING_BIT7; - if (data == 0) - i2c->buffer = i2c_recv(i2c->bus); - else - i2c_nack(i2c->bus); - } else if (data_goes_up && clock == 1) - bitbang_i2c_enter_stop(i2c); - break; + i2c->state = RECEIVING_BIT7; + if (data != 0) { + DPRINTF("NACKED\n"); + i2c_nack(i2c->bus); + } else { + DPRINTF("ACKED\n"); + } + return bitbang_i2c_ret(i2c, 1); } + abort(); +} + +bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus) +{ + bitbang_i2c_interface *s; + + s = qemu_mallocz(sizeof(bitbang_i2c_interface)); + + s->bus = bus; + s->last_data = 1; + s->last_clock = 1; + s->device_out = 1; + + return s; +} - i2c->last_data = data; - i2c->last_clock = clock; +/* GPIO interface. */ +typedef struct { + SysBusDevice busdev; + bitbang_i2c_interface *bitbang; + int last_level; + qemu_irq out; +} GPIOI2CState; + +static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) +{ + GPIOI2CState *s = opaque; + + level = bitbang_i2c_set(s->bitbang, irq, level); + if (level != s->last_level) { + s->last_level = level; + qemu_set_irq(s->out, level); + } } -static int bitbang_i2c_init(SysBusDevice *dev) +static int gpio_i2c_init(SysBusDevice *dev) { - bitbang_i2c_interface *s = FROM_SYSBUS(bitbang_i2c_interface, dev); + GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev); i2c_bus *bus; sysbus_init_mmio(dev, 0x0, 0); bus = i2c_init_bus(&dev->qdev, "i2c"); - s->bus = bus; - - s->last_data = 1; - s->last_clock = 1; + s->bitbang = bitbang_i2c_init(bus); qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2); qdev_init_gpio_out(&dev->qdev, &s->out, 1); @@ -172,10 +213,16 @@ static int bitbang_i2c_init(SysBusDevice *dev) return 0; } +static SysBusDeviceInfo gpio_i2c_info = { + .init = gpio_i2c_init, + .qdev.name = "gpio_i2c", + .qdev.desc = "Virtual GPIO to I2C bridge", + .qdev.size = sizeof(GPIOI2CState), +}; + static void bitbang_i2c_register(void) { - sysbus_register_dev("bitbang_i2c", - sizeof(bitbang_i2c_interface), bitbang_i2c_init); + sysbus_register_withprop(&gpio_i2c_info); } device_init(bitbang_i2c_register) diff --git a/hw/bitbang_i2c.h b/hw/bitbang_i2c.h new file mode 100644 index 000000000..519d2dc22 --- /dev/null +++ b/hw/bitbang_i2c.h @@ -0,0 +1,14 @@ +#ifndef BITBANG_I2C_H +#define BITBANG_I2C_H + +#include "i2c.h" + +typedef struct bitbang_i2c_interface bitbang_i2c_interface; + +#define BITBANG_I2C_SDA 0 +#define BITBANG_I2C_SCL 1 + +bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus); +int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level); + +#endif diff --git a/hw/ds1338.c b/hw/ds1338.c new file mode 100644 index 000000000..6f5ae5e6c --- /dev/null +++ b/hw/ds1338.c @@ -0,0 +1,132 @@ +/* + * MAXIM DS1338 I2C RTC+NVRAM + * + * Copyright (c) 2009 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GNU GPL v2. + */ + +#include "i2c.h" + +typedef struct { + i2c_slave i2c; + time_t offset; + struct tm now; + uint8_t nvram[56]; + int ptr; + int addr_byte; +} DS1338State; + +static void ds1338_event(i2c_slave *i2c, enum i2c_event event) +{ + DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); + + switch (event) { + case I2C_START_RECV: + qemu_get_timedate(&s->now, s->offset); + s->nvram[0] = to_bcd(s->now.tm_sec); + s->nvram[1] = to_bcd(s->now.tm_min); + if (s->nvram[2] & 0x40) { + s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40; + if (s->now.tm_hour >= 12) { + s->nvram[2] |= 0x20; + } + } else { + s->nvram[2] = to_bcd(s->now.tm_hour); + } + s->nvram[3] = to_bcd(s->now.tm_wday) + 1; + s->nvram[4] = to_bcd(s->now.tm_mday); + s->nvram[5] = to_bcd(s->now.tm_mon) + 1; + s->nvram[6] = to_bcd(s->now.tm_year - 100); + break; + case I2C_START_SEND: + s->addr_byte = 1; + break; + default: + break; + } +} + +static int ds1338_recv(i2c_slave *i2c) +{ + DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); + uint8_t res; + + res = s->nvram[s->ptr]; + s->ptr = (s->ptr + 1) & 0xff; + return res; +} + +static int ds1338_send(i2c_slave *i2c, uint8_t data) +{ + DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); + if (s->addr_byte) { + s->ptr = data; + s->addr_byte = 0; + return 0; + } + s->nvram[s->ptr - 8] = data; + if (data < 8) { + qemu_get_timedate(&s->now, s->offset); + switch(data) { + case 0: + /* TODO: Implement CH (stop) bit. */ + s->now.tm_sec = from_bcd(data & 0x7f); + break; + case 1: + s->now.tm_min = from_bcd(data & 0x7f); + break; + case 2: + if (data & 0x40) { + if (data & 0x20) { + data = from_bcd(data & 0x4f) + 11; + } else { + data = from_bcd(data & 0x1f) - 1; + } + } else { + data = from_bcd(data); + } + s->now.tm_hour = data; + break; + case 3: + s->now.tm_wday = from_bcd(data & 7) - 1; + break; + case 4: + s->now.tm_mday = from_bcd(data & 0x3f); + break; + case 5: + s->now.tm_mon = from_bcd(data & 0x1f) - 1; + case 6: + s->now.tm_year = from_bcd(data) + 100; + break; + case 7: + /* Control register. Currently ignored. */ + break; + } + s->offset = qemu_timedate_diff(&s->now); + } + s->ptr = (s->ptr + 1) & 0xff; + return 0; +} + +static int ds1338_init(i2c_slave *i2c) +{ + return 0; +} + +static I2CSlaveInfo ds1338_info = { + .qdev.name = "ds1338", + .qdev.size = sizeof(DS1338State), + .init = ds1338_init, + .event = ds1338_event, + .recv = ds1338_recv, + .send = ds1338_send, +}; + +static void ds1338_register_devices(void) +{ + i2c_register_slave(&ds1338_info); +} + +device_init(ds1338_register_devices) diff --git a/hw/m48t59.c b/hw/m48t59.c index bb58419d2..ce38f8b6e 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -80,16 +80,6 @@ typedef struct M48t59SysBusState { } M48t59SysBusState; /* Fake timer functions */ -/* Generic helpers for BCD */ -static inline uint8_t toBCD (uint8_t value) -{ - return (((value / 10) % 10) << 4) | (value % 10); -} - -static inline uint8_t fromBCD (uint8_t BCD) -{ - return ((BCD >> 4) * 10) + (BCD & 0x0F); -} /* Alarm management */ static void alarm_cb (void *opaque) @@ -219,7 +209,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) break; case 0x1FF2: /* alarm seconds */ - tmp = fromBCD(val & 0x7F); + tmp = from_bcd(val & 0x7F); if (tmp >= 0 && tmp <= 59) { NVRAM->alarm.tm_sec = tmp; NVRAM->buffer[0x1FF2] = val; @@ -228,7 +218,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) break; case 0x1FF3: /* alarm minutes */ - tmp = fromBCD(val & 0x7F); + tmp = from_bcd(val & 0x7F); if (tmp >= 0 && tmp <= 59) { NVRAM->alarm.tm_min = tmp; NVRAM->buffer[0x1FF3] = val; @@ -237,7 +227,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) break; case 0x1FF4: /* alarm hours */ - tmp = fromBCD(val & 0x3F); + tmp = from_bcd(val & 0x3F); if (tmp >= 0 && tmp <= 23) { NVRAM->alarm.tm_hour = tmp; NVRAM->buffer[0x1FF4] = val; @@ -246,7 +236,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) break; case 0x1FF5: /* alarm date */ - tmp = fromBCD(val & 0x1F); + tmp = from_bcd(val & 0x1F); if (tmp != 0) { NVRAM->alarm.tm_mday = tmp; NVRAM->buffer[0x1FF5] = val; @@ -270,7 +260,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FF9: case 0x07F9: /* seconds (BCD) */ - tmp = fromBCD(val & 0x7F); + tmp = from_bcd(val & 0x7F); if (tmp >= 0 && tmp <= 59) { get_time(NVRAM, &tm); tm.tm_sec = tmp; @@ -289,7 +279,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFA: case 0x07FA: /* minutes (BCD) */ - tmp = fromBCD(val & 0x7F); + tmp = from_bcd(val & 0x7F); if (tmp >= 0 && tmp <= 59) { get_time(NVRAM, &tm); tm.tm_min = tmp; @@ -299,7 +289,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFB: case 0x07FB: /* hours (BCD) */ - tmp = fromBCD(val & 0x3F); + tmp = from_bcd(val & 0x3F); if (tmp >= 0 && tmp <= 23) { get_time(NVRAM, &tm); tm.tm_hour = tmp; @@ -309,7 +299,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFC: case 0x07FC: /* day of the week / century */ - tmp = fromBCD(val & 0x07); + tmp = from_bcd(val & 0x07); get_time(NVRAM, &tm); tm.tm_wday = tmp; set_time(NVRAM, &tm); @@ -318,7 +308,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFD: case 0x07FD: /* date */ - tmp = fromBCD(val & 0x1F); + tmp = from_bcd(val & 0x1F); if (tmp != 0) { get_time(NVRAM, &tm); tm.tm_mday = tmp; @@ -328,7 +318,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFE: case 0x07FE: /* month */ - tmp = fromBCD(val & 0x1F); + tmp = from_bcd(val & 0x1F); if (tmp >= 1 && tmp <= 12) { get_time(NVRAM, &tm); tm.tm_mon = tmp - 1; @@ -338,13 +328,13 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) case 0x1FFF: case 0x07FF: /* year */ - tmp = fromBCD(val); + tmp = from_bcd(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); if (NVRAM->type == 8) - tm.tm_year = fromBCD(val) + 68; // Base year is 1968 + tm.tm_year = from_bcd(val) + 68; // Base year is 1968 else - tm.tm_year = fromBCD(val); + tm.tm_year = from_bcd(val); set_time(NVRAM, &tm); } break; @@ -410,19 +400,19 @@ uint32_t m48t59_read (void *opaque, uint32_t addr) case 0x07F9: /* seconds (BCD) */ get_time(NVRAM, &tm); - retval = (NVRAM->buffer[addr] & 0x80) | toBCD(tm.tm_sec); + retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec); break; case 0x1FFA: case 0x07FA: /* minutes (BCD) */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_min); + retval = to_bcd(tm.tm_min); break; case 0x1FFB: case 0x07FB: /* hours (BCD) */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_hour); + retval = to_bcd(tm.tm_hour); break; case 0x1FFC: case 0x07FC: @@ -434,22 +424,22 @@ uint32_t m48t59_read (void *opaque, uint32_t addr) case 0x07FD: /* date */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mday); + retval = to_bcd(tm.tm_mday); break; case 0x1FFE: case 0x07FE: /* month */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mon + 1); + retval = to_bcd(tm.tm_mon + 1); break; case 0x1FFF: case 0x07FF: /* year */ get_time(NVRAM, &tm); if (NVRAM->type == 8) - retval = toBCD(tm.tm_year - 68); // Base year is 1968 + retval = to_bcd(tm.tm_year - 68); // Base year is 1968 else - retval = toBCD(tm.tm_year); + retval = to_bcd(tm.tm_year); break; default: /* Check lock registers state */ diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 61ddf0b35..b8c7b0c1b 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -259,7 +259,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } } -static inline int to_bcd(RTCState *s, int a) +static inline int rtc_to_bcd(RTCState *s, int a) { if (s->cmos_data[RTC_REG_B] & REG_B_DM) { return a; @@ -268,7 +268,7 @@ static inline int to_bcd(RTCState *s, int a) } } -static inline int from_bcd(RTCState *s, int a) +static inline int rtc_from_bcd(RTCState *s, int a) { if (s->cmos_data[RTC_REG_B] & REG_B_DM) { return a; @@ -281,17 +281,17 @@ static void rtc_set_time(RTCState *s) { struct tm *tm = &s->current_tm; - tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]); - tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]); - tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); + tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); + tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); + tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); if (!(s->cmos_data[RTC_REG_B] & 0x02) && (s->cmos_data[RTC_HOURS] & 0x80)) { tm->tm_hour += 12; } - tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; - tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); - tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; - tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; + tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; + tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); + tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; + tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; } static void rtc_copy_date(RTCState *s) @@ -299,24 +299,24 @@ static void rtc_copy_date(RTCState *s) const struct tm *tm = &s->current_tm; int year; - s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); - s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); + s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec); + s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min); if (s->cmos_data[RTC_REG_B] & 0x02) { /* 24 hour format */ - s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); + s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour); } else { /* 12 hour format */ - s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); + s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour % 12); if (tm->tm_hour >= 12) s->cmos_data[RTC_HOURS] |= 0x80; } - s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday + 1); - s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); - s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); + s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1); + s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday); + s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1); year = (tm->tm_year - s->base_year) % 100; if (year < 0) year += 100; - s->cmos_data[RTC_YEAR] = to_bcd(s, year); + s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year); } /* month is between 0 and 11. */ @@ -497,7 +497,7 @@ static void rtc_set_date_from_host(RTCState *s) qemu_get_timedate(&tm, 0); rtc_set_date(s, &tm); - val = to_bcd(s, (tm.tm_year / 100) + 19); + val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); } diff --git a/hw/musicpal.c b/hw/musicpal.c index 0d21f1778..264669f61 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1565,7 +1565,7 @@ static void musicpal_init(ram_addr_t ram_size, musicpal_misc_init(); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); - i2c_dev = sysbus_create_simple("bitbang_i2c", 0, NULL); + i2c_dev = sysbus_create_simple("gpio_i2c", 0, NULL); i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); diff --git a/hw/omap1.c b/hw/omap1.c index e9676ecc8..b5d78cd91 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -3358,16 +3358,6 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s) printf("%s: conversion failed\n", __FUNCTION__); } -static inline uint8_t omap_rtc_bcd(int num) -{ - return ((num / 10) << 4) | (num % 10); -} - -static inline int omap_rtc_bin(uint8_t num) -{ - return (num & 15) + 10 * (num >> 4); -} - static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; @@ -3376,51 +3366,51 @@ static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) switch (offset) { case 0x00: /* SECONDS_REG */ - return omap_rtc_bcd(s->current_tm.tm_sec); + return to_bcd(s->current_tm.tm_sec); case 0x04: /* MINUTES_REG */ - return omap_rtc_bcd(s->current_tm.tm_min); + return to_bcd(s->current_tm.tm_min); case 0x08: /* HOURS_REG */ if (s->pm_am) return ((s->current_tm.tm_hour > 11) << 7) | - omap_rtc_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); + to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); else - return omap_rtc_bcd(s->current_tm.tm_hour); + return to_bcd(s->current_tm.tm_hour); case 0x0c: /* DAYS_REG */ - return omap_rtc_bcd(s->current_tm.tm_mday); + return to_bcd(s->current_tm.tm_mday); case 0x10: /* MONTHS_REG */ - return omap_rtc_bcd(s->current_tm.tm_mon + 1); + return to_bcd(s->current_tm.tm_mon + 1); case 0x14: /* YEARS_REG */ - return omap_rtc_bcd(s->current_tm.tm_year % 100); + return to_bcd(s->current_tm.tm_year % 100); case 0x18: /* WEEK_REG */ return s->current_tm.tm_wday; case 0x20: /* ALARM_SECONDS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_sec); + return to_bcd(s->alarm_tm.tm_sec); case 0x24: /* ALARM_MINUTES_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_min); + return to_bcd(s->alarm_tm.tm_min); case 0x28: /* ALARM_HOURS_REG */ if (s->pm_am) return ((s->alarm_tm.tm_hour > 11) << 7) | - omap_rtc_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); + to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); else - return omap_rtc_bcd(s->alarm_tm.tm_hour); + return to_bcd(s->alarm_tm.tm_hour); case 0x2c: /* ALARM_DAYS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_mday); + return to_bcd(s->alarm_tm.tm_mday); case 0x30: /* ALARM_MONTHS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_mon + 1); + return to_bcd(s->alarm_tm.tm_mon + 1); case 0x34: /* ALARM_YEARS_REG */ - return omap_rtc_bcd(s->alarm_tm.tm_year % 100); + return to_bcd(s->alarm_tm.tm_year % 100); case 0x40: /* RTC_CTRL_REG */ return (s->pm_am << 3) | (s->auto_comp << 2) | @@ -3459,7 +3449,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, printf("RTC SEC_REG <-- %02x\n", value); #endif s->ti -= s->current_tm.tm_sec; - s->ti += omap_rtc_bin(value); + s->ti += from_bcd(value); return; case 0x04: /* MINUTES_REG */ @@ -3467,7 +3457,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, printf("RTC MIN_REG <-- %02x\n", value); #endif s->ti -= s->current_tm.tm_min * 60; - s->ti += omap_rtc_bin(value) * 60; + s->ti += from_bcd(value) * 60; return; case 0x08: /* HOURS_REG */ @@ -3476,10 +3466,10 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #endif s->ti -= s->current_tm.tm_hour * 3600; if (s->pm_am) { - s->ti += (omap_rtc_bin(value & 0x3f) & 12) * 3600; + s->ti += (from_bcd(value & 0x3f) & 12) * 3600; s->ti += ((value >> 7) & 1) * 43200; } else - s->ti += omap_rtc_bin(value & 0x3f) * 3600; + s->ti += from_bcd(value & 0x3f) * 3600; return; case 0x0c: /* DAYS_REG */ @@ -3487,7 +3477,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, printf("RTC DAY_REG <-- %02x\n", value); #endif s->ti -= s->current_tm.tm_mday * 86400; - s->ti += omap_rtc_bin(value) * 86400; + s->ti += from_bcd(value) * 86400; return; case 0x10: /* MONTHS_REG */ @@ -3495,7 +3485,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, printf("RTC MTH_REG <-- %02x\n", value); #endif memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_mon = omap_rtc_bin(value); + new_tm.tm_mon = from_bcd(value); ti[0] = mktimegm(&s->current_tm); ti[1] = mktimegm(&new_tm); @@ -3505,7 +3495,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, } else { /* A less accurate version */ s->ti -= s->current_tm.tm_mon * 2592000; - s->ti += omap_rtc_bin(value) * 2592000; + s->ti += from_bcd(value) * 2592000; } return; @@ -3514,7 +3504,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, printf("RTC YRS_REG <-- %02x\n", value); #endif memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); - new_tm.tm_year += omap_rtc_bin(value) - (new_tm.tm_year % 100); + new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100); ti[0] = mktimegm(&s->current_tm); ti[1] = mktimegm(&new_tm); @@ -3524,7 +3514,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, } else { /* A less accurate version */ s->ti -= (s->current_tm.tm_year % 100) * 31536000; - s->ti += omap_rtc_bin(value) * 31536000; + s->ti += from_bcd(value) * 31536000; } return; @@ -3535,7 +3525,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #ifdef ALMDEBUG printf("ALM SEC_REG <-- %02x\n", value); #endif - s->alarm_tm.tm_sec = omap_rtc_bin(value); + s->alarm_tm.tm_sec = from_bcd(value); omap_rtc_alarm_update(s); return; @@ -3543,7 +3533,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #ifdef ALMDEBUG printf("ALM MIN_REG <-- %02x\n", value); #endif - s->alarm_tm.tm_min = omap_rtc_bin(value); + s->alarm_tm.tm_min = from_bcd(value); omap_rtc_alarm_update(s); return; @@ -3553,10 +3543,10 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #endif if (s->pm_am) s->alarm_tm.tm_hour = - ((omap_rtc_bin(value & 0x3f)) % 12) + + ((from_bcd(value & 0x3f)) % 12) + ((value >> 7) & 1) * 12; else - s->alarm_tm.tm_hour = omap_rtc_bin(value); + s->alarm_tm.tm_hour = from_bcd(value); omap_rtc_alarm_update(s); return; @@ -3564,7 +3554,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #ifdef ALMDEBUG printf("ALM DAY_REG <-- %02x\n", value); #endif - s->alarm_tm.tm_mday = omap_rtc_bin(value); + s->alarm_tm.tm_mday = from_bcd(value); omap_rtc_alarm_update(s); return; @@ -3572,7 +3562,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #ifdef ALMDEBUG printf("ALM MON_REG <-- %02x\n", value); #endif - s->alarm_tm.tm_mon = omap_rtc_bin(value); + s->alarm_tm.tm_mon = from_bcd(value); omap_rtc_alarm_update(s); return; @@ -3580,7 +3570,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, #ifdef ALMDEBUG printf("ALM YRS_REG <-- %02x\n", value); #endif - s->alarm_tm.tm_year = omap_rtc_bin(value); + s->alarm_tm.tm_year = from_bcd(value); omap_rtc_alarm_update(s); return; diff --git a/hw/realview.c b/hw/realview.c index 7aa127ee2..f0b834734 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -15,8 +15,86 @@ #include "net.h" #include "sysemu.h" #include "boards.h" +#include "bitbang_i2c.h" +#include "sysbus.h" #define SMP_BOOT_ADDR 0xe0000000 + +typedef struct { + SysBusDevice busdev; + bitbang_i2c_interface *bitbang; + int out; + int in; +} RealViewI2CState; + +static uint32_t realview_i2c_read(void *opaque, target_phys_addr_t offset) +{ + RealViewI2CState *s = (RealViewI2CState *)opaque; + + if (offset == 0) { + return (s->out & 1) | (s->in << 1); + } else { + hw_error("realview_i2c_read: Bad offset 0x%x\n", (int)offset); + return -1; + } +} + +static void realview_i2c_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + RealViewI2CState *s = (RealViewI2CState *)opaque; + + switch (offset) { + case 0: + s->out |= value & 3; + break; + case 4: + s->out &= ~value; + break; + default: + hw_error("realview_i2c_write: Bad offset 0x%x\n", (int)offset); + } + bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0); + s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); +} + +static CPUReadMemoryFunc * const realview_i2c_readfn[] = { + realview_i2c_read, + realview_i2c_read, + realview_i2c_read +}; + +static CPUWriteMemoryFunc * const realview_i2c_writefn[] = { + realview_i2c_write, + realview_i2c_write, + realview_i2c_write +}; + +static int realview_i2c_init(SysBusDevice *dev) +{ + RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev); + i2c_bus *bus; + int iomemtype; + + bus = i2c_init_bus(&dev->qdev, "i2c"); + s->bitbang = bitbang_i2c_init(bus); + iomemtype = cpu_register_io_memory(realview_i2c_readfn, + realview_i2c_writefn, s); + sysbus_init_mmio(dev, 0x1000, iomemtype); + return 0; +} + +static SysBusDeviceInfo realview_i2c_info = { + .init = realview_i2c_init, + .qdev.name = "realview_i2c", + .qdev.size = sizeof(RealViewI2CState), +}; + +static void realview_register_devices(void) +{ + sysbus_register_withprop(&realview_i2c_info); +} + /* Board init. */ static struct arm_boot_info realview_binfo = { @@ -63,6 +141,7 @@ static void realview_init(ram_addr_t ram_size, qemu_irq pic[64]; PCIBus *pci_bus; NICInfo *nd; + i2c_bus *i2c; int n; int done_nic = 0; qemu_irq cpu_irq[4]; @@ -202,10 +281,14 @@ static void realview_init(ram_addr_t ram_size, } } + dev = sysbus_create_simple("realview_i2c", 0x10002000, NULL); + i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); + i2c_create_slave(i2c, "ds1338", 0x68); + /* Memory map for RealView Emulation Baseboard: */ /* 0x10000000 System registers. */ /* 0x10001000 System controller. */ - /* 0x10002000 Two-Wire Serial Bus. */ + /* 0x10002000 Two-Wire Serial Bus. */ /* 0x10003000 Reserved. */ /* 0x10004000 AACI. */ /* 0x10005000 MCI. */ @@ -362,3 +445,4 @@ static void realview_machine_init(void) } machine_init(realview_machine_init); +device_init(realview_register_devices) diff --git a/hw/twl92230.c b/hw/twl92230.c index a6c60ba2b..93232da2d 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -183,16 +183,6 @@ static void menelaus_reset(i2c_slave *i2c) menelaus_update(s); } -static inline uint8_t to_bcd(int val) -{ - return ((val / 10) << 4) | (val % 10); -} - -static inline int from_bcd(uint8_t val) -{ - return ((val >> 4) * 10) + (val & 0x0f); -} - static void menelaus_gpio_set(void *opaque, int line, int level) { MenelausState *s = (MenelausState *) opaque; diff --git a/linux-user/main.c b/linux-user/main.c index bcc36f256..2b8bab1b6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -524,6 +524,81 @@ do_kernel_trap(CPUARMState *env) return 0; } +static int do_strex(CPUARMState *env) +{ + uint32_t val; + int size; + int rc = 1; + int segv = 0; + uint32_t addr; + start_exclusive(); + addr = env->exclusive_addr; + if (addr != env->exclusive_test) { + goto fail; + } + size = env->exclusive_info & 0xf; + switch (size) { + case 0: + segv = get_user_u8(val, addr); + break; + case 1: + segv = get_user_u16(val, addr); + break; + case 2: + case 3: + segv = get_user_u32(val, addr); + break; + } + if (segv) { + env->cp15.c6_data = addr; + goto done; + } + if (val != env->exclusive_val) { + goto fail; + } + if (size == 3) { + segv = get_user_u32(val, addr + 4); + if (segv) { + env->cp15.c6_data = addr + 4; + goto done; + } + if (val != env->exclusive_high) { + goto fail; + } + } + val = env->regs[(env->exclusive_info >> 8) & 0xf]; + switch (size) { + case 0: + segv = put_user_u8(val, addr); + break; + case 1: + segv = put_user_u16(val, addr); + break; + case 2: + case 3: + segv = put_user_u32(val, addr); + break; + } + if (segv) { + env->cp15.c6_data = addr; + goto done; + } + if (size == 3) { + val = env->regs[(env->exclusive_info >> 12) & 0xf]; + segv = put_user_u32(val, addr); + if (segv) { + env->cp15.c6_data = addr + 4; + goto done; + } + } + rc = 0; +fail: + env->regs[(env->exclusive_info >> 4) & 0xf] = rc; +done: + end_exclusive(); + return segv; +} + void cpu_loop(CPUARMState *env) { int trapnr; @@ -717,6 +792,11 @@ void cpu_loop(CPUARMState *env) if (do_kernel_trap(env)) goto error; break; + case EXCP_STREX: + if (do_strex(env)) { + addr = env->cp15.c6_data; + goto do_segv; + } default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", @@ -1849,7 +1929,7 @@ static int do_store_exclusive(CPUMIPSState *env) int reg; int d; - addr = env->CP0_LLAddr; + addr = env->lladdr; page_addr = addr & TARGET_PAGE_MASK; start_exclusive(); mmap_lock(); @@ -1879,7 +1959,7 @@ static int do_store_exclusive(CPUMIPSState *env) } } } - env->CP0_LLAddr = -1; + env->lladdr = -1; if (!segv) { env->active_tc.PC += 4; } diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex bba1e5c84..294958019 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/qemu-common.h b/qemu-common.h index f08a1b670..05377b173 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -256,6 +256,17 @@ void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count); struct Monitor; typedef struct Monitor Monitor; +/* Convert a byte between binary and BCD. */ +static inline uint8_t to_bcd(uint8_t val) +{ + return ((val / 10) << 4) | (val % 10); +} + +static inline uint8_t from_bcd(uint8_t val) +{ + return ((val >> 4) * 10) + (val & 0x0f); +} + #include "module.h" #endif /* dyngen-exec.h hack */ diff --git a/roms/seabios b/roms/seabios -Subproject b021a57b6af2e1f055391b1d813f7e3a94f41b5 +Subproject 42bc3940d93911e382f5e72289f043d1faa9083 diff --git a/target-arm/cpu.h b/target-arm/cpu.h index a83ce48c4..4a1c53f24 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -40,6 +40,7 @@ #define EXCP_BKPT 7 #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ #define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ +#define EXCP_STREX 10 #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 @@ -180,10 +181,12 @@ typedef struct CPUARMState { float_status fp_status; } vfp; + uint32_t exclusive_addr; + uint32_t exclusive_val; + uint32_t exclusive_high; #if defined(CONFIG_USER_ONLY) - struct mmon_state *mmon_entry; -#else - uint32_t mmon_addr; + uint32_t exclusive_test; + uint32_t exclusive_info; #endif /* iwMMXt coprocessor state. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index ffc14f032..b3aec9944 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -470,16 +470,6 @@ void do_interrupt (CPUState *env) env->exception_index = -1; } -/* Structure used to record exclusive memory locations. */ -typedef struct mmon_state { - struct mmon_state *next; - CPUARMState *cpu_env; - uint32_t addr; -} mmon_state; - -/* Chain of current locks. */ -static mmon_state* mmon_head = NULL; - int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { @@ -493,62 +483,6 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } -static void allocate_mmon_state(CPUState *env) -{ - env->mmon_entry = malloc(sizeof (mmon_state)); - memset (env->mmon_entry, 0, sizeof (mmon_state)); - env->mmon_entry->cpu_env = env; - mmon_head = env->mmon_entry; -} - -/* Flush any monitor locks for the specified address. */ -static void flush_mmon(uint32_t addr) -{ - mmon_state *mon; - - for (mon = mmon_head; mon; mon = mon->next) - { - if (mon->addr != addr) - continue; - - mon->addr = 0; - break; - } -} - -/* Mark an address for exclusive access. */ -void HELPER(mark_exclusive)(CPUState *env, uint32_t addr) -{ - if (!env->mmon_entry) - allocate_mmon_state(env); - /* Clear any previous locks. */ - flush_mmon(addr); - env->mmon_entry->addr = addr; -} - -/* Test if an exclusive address is still exclusive. Returns zero - if the address is still exclusive. */ -uint32_t HELPER(test_exclusive)(CPUState *env, uint32_t addr) -{ - int res; - - if (!env->mmon_entry) - return 1; - if (env->mmon_entry->addr == addr) - res = 0; - else - res = 1; - flush_mmon(addr); - return res; -} - -void HELPER(clrex)(CPUState *env) -{ - if (!(env->mmon_entry && env->mmon_entry->addr)) - return; - flush_mmon(env->mmon_entry->addr); -} - target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; @@ -1273,24 +1207,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return phys_addr; } -/* Not really implemented. Need to figure out a sane way of doing this. - Maybe add generic watchpoint support and use that. */ - -void HELPER(mark_exclusive)(CPUState *env, uint32_t addr) -{ - env->mmon_addr = addr; -} - -uint32_t HELPER(test_exclusive)(CPUState *env, uint32_t addr) -{ - return (env->mmon_addr != addr); -} - -void HELPER(clrex)(CPUState *env) -{ - env->mmon_addr = -1; -} - void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) { int cp_num = (insn >> 8) & 0xf; diff --git a/target-arm/helpers.h b/target-arm/helpers.h index dc25f185d..0d1bc47d0 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -68,10 +68,6 @@ DEF_HELPER_2(get_cp, i32, env, i32) DEF_HELPER_2(get_r13_banked, i32, env, i32) DEF_HELPER_3(set_r13_banked, void, env, i32, i32) -DEF_HELPER_2(mark_exclusive, void, env, i32) -DEF_HELPER_2(test_exclusive, i32, env, i32) -DEF_HELPER_1(clrex, void, env) - DEF_HELPER_1(get_user_reg, i32, i32) DEF_HELPER_2(set_user_reg, void, i32, i32) diff --git a/target-arm/translate.c b/target-arm/translate.c index a002f7e02..45bf77256 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -76,6 +76,13 @@ static TCGv_ptr cpu_env; /* We reuse the same 64-bit temporaries for efficiency. */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_exclusive_addr; +static TCGv_i32 cpu_exclusive_val; +static TCGv_i32 cpu_exclusive_high; +#ifdef CONFIG_USER_ONLY +static TCGv_i32 cpu_exclusive_test; +static TCGv_i32 cpu_exclusive_info; +#endif /* FIXME: These should be removed. */ static TCGv cpu_F0s, cpu_F1s; @@ -99,6 +106,18 @@ void arm_translate_init(void) offsetof(CPUState, regs[i]), regnames[i]); } + cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_addr), "exclusive_addr"); + cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_val), "exclusive_val"); + cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_high), "exclusive_high"); +#ifdef CONFIG_USER_ONLY + cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_test), "exclusive_test"); + cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, exclusive_info), "exclusive_info"); +#endif #define GEN_HELPER 2 #include "helpers.h" @@ -5819,6 +5838,132 @@ static void gen_logicq_cc(TCGv_i64 val) dead_tmp(tmp); } +/* Load/Store exclusive instructions are implemented by remembering + the value/address loaded, and seeing if these are the same + when the store is performed. This should be is sufficient to implement + the architecturally mandated semantics, and avoids having to monitor + regular stores. + + In system emulation mode only one CPU will be running at once, so + this sequence is effectively atomic. In user emulation mode we + throw an exception and handle the atomic operation elsewhere. */ +static void gen_load_exclusive(DisasContext *s, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_mov_i32(cpu_exclusive_val, tmp); + store_reg(s, rt, tmp); + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + tcg_gen_mov_i32(cpu_exclusive_high, tmp); + store_reg(s, rt2, tmp); + } + tcg_gen_mov_i32(cpu_exclusive_addr, addr); +} + +static void gen_clrex(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} + +#ifdef CONFIG_USER_ONLY +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + tcg_gen_mov_i32(cpu_exclusive_test, addr); + tcg_gen_movi_i32(cpu_exclusive_info, + size | (rd << 4) | (rt << 8) | (rt2 << 12)); + gen_set_condexec(s); + gen_set_pc_im(s->pc - 4); + gen_exception(EXCP_STREX); + s->is_jmp = DISAS_JUMP; +} +#else +static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, + TCGv addr, int size) +{ + TCGv tmp; + int done_label; + int fail_label; + + /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) { + [addr] = {Rt}; + {Rd} = 0; + } else { + {Rd} = 1; + } */ + fail_label = gen_new_label(); + done_label = gen_new_label(); + tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label); + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + case 3: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: + abort(); + } + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label); + dead_tmp(tmp); + if (size == 3) { + TCGv tmp2 = new_tmp(); + tcg_gen_addi_i32(tmp2, addr, 4); + tmp = gen_ld32(addr, IS_USER(s)); + dead_tmp(tmp2); + tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label); + dead_tmp(tmp); + } + tmp = load_reg(s, rt); + switch (size) { + case 0: + gen_st8(tmp, addr, IS_USER(s)); + break; + case 1: + gen_st16(tmp, addr, IS_USER(s)); + break; + case 2: + case 3: + gen_st32(tmp, addr, IS_USER(s)); + break; + default: + abort(); + } + if (size == 3) { + tcg_gen_addi_i32(addr, addr, 4); + tmp = load_reg(s, rt2); + gen_st32(tmp, addr, IS_USER(s)); + } + tcg_gen_movi_i32(cpu_R[rd], 0); + tcg_gen_br(done_label); + gen_set_label(fail_label); + tcg_gen_movi_i32(cpu_R[rd], 1); + gen_set_label(done_label); + tcg_gen_movi_i32(cpu_exclusive_addr, -1); +} +#endif + static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; @@ -5869,7 +6014,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) switch ((insn >> 4) & 0xf) { case 1: /* clrex */ ARCH(6K); - gen_helper_clrex(cpu_env); + gen_clrex(s); return; case 4: /* dsb */ case 5: /* dmb */ @@ -6454,57 +6599,40 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) addr = tcg_temp_local_new_i32(); load_reg_var(s, addr, rn); if (insn & (1 << 20)) { - gen_helper_mark_exclusive(cpu_env, addr); switch (op1) { case 0: /* ldrex */ - tmp = gen_ld32(addr, IS_USER(s)); + gen_load_exclusive(s, rd, 15, addr, 2); break; case 1: /* ldrexd */ - tmp = gen_ld32(addr, IS_USER(s)); - store_reg(s, rd, tmp); - tcg_gen_addi_i32(addr, addr, 4); - tmp = gen_ld32(addr, IS_USER(s)); - rd++; + gen_load_exclusive(s, rd, rd + 1, addr, 3); break; case 2: /* ldrexb */ - tmp = gen_ld8u(addr, IS_USER(s)); + gen_load_exclusive(s, rd, 15, addr, 0); break; case 3: /* ldrexh */ - tmp = gen_ld16u(addr, IS_USER(s)); + gen_load_exclusive(s, rd, 15, addr, 1); break; default: abort(); } - store_reg(s, rd, tmp); } else { - int label = gen_new_label(); rm = insn & 0xf; - tmp2 = tcg_temp_local_new_i32(); - gen_helper_test_exclusive(tmp2, cpu_env, addr); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp2, 0, label); - tmp = load_reg(s,rm); switch (op1) { case 0: /* strex */ - gen_st32(tmp, addr, IS_USER(s)); + gen_store_exclusive(s, rd, rm, 15, addr, 2); break; case 1: /* strexd */ - gen_st32(tmp, addr, IS_USER(s)); - tcg_gen_addi_i32(addr, addr, 4); - tmp = load_reg(s, rm + 1); - gen_st32(tmp, addr, IS_USER(s)); + gen_store_exclusive(s, rd, rm, rm + 1, addr, 2); break; case 2: /* strexb */ - gen_st8(tmp, addr, IS_USER(s)); + gen_store_exclusive(s, rd, rm, 15, addr, 0); break; case 3: /* strexh */ - gen_st16(tmp, addr, IS_USER(s)); + gen_store_exclusive(s, rd, rm, 15, addr, 1); break; default: abort(); } - gen_set_label(label); - tcg_gen_mov_i32(cpu_R[rd], tmp2); - tcg_temp_free(tmp2); } tcg_temp_free(addr); } else { @@ -7259,20 +7387,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) /* Load/store exclusive word. */ addr = tcg_temp_local_new(); load_reg_var(s, addr, rn); + tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2); if (insn & (1 << 20)) { - gen_helper_mark_exclusive(cpu_env, addr); - tmp = gen_ld32(addr, IS_USER(s)); - store_reg(s, rd, tmp); + gen_load_exclusive(s, rs, 15, addr, 2); } else { - int label = gen_new_label(); - tmp2 = tcg_temp_local_new(); - gen_helper_test_exclusive(tmp2, cpu_env, addr); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp2, 0, label); - tmp = load_reg(s, rs); - gen_st32(tmp, addr, IS_USER(s)); - gen_set_label(label); - tcg_gen_mov_i32(cpu_R[rd], tmp2); - tcg_temp_free(tmp2); + gen_store_exclusive(s, rd, rs, 15, addr, 2); } tcg_temp_free(addr); } else if ((insn & (1 << 6)) == 0) { @@ -7300,56 +7419,17 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) store_reg(s, 15, tmp); } else { /* Load/store exclusive byte/halfword/doubleword. */ - /* ??? These are not really atomic. However we know - we never have multiple CPUs running in parallel, - so it is good enough. */ + ARCH(7); op = (insn >> 4) & 0x3; + if (op == 2) { + goto illegal_op; + } addr = tcg_temp_local_new(); load_reg_var(s, addr, rn); if (insn & (1 << 20)) { - gen_helper_mark_exclusive(cpu_env, addr); - switch (op) { - case 0: - tmp = gen_ld8u(addr, IS_USER(s)); - break; - case 1: - tmp = gen_ld16u(addr, IS_USER(s)); - break; - case 3: - tmp = gen_ld32(addr, IS_USER(s)); - tcg_gen_addi_i32(addr, addr, 4); - tmp2 = gen_ld32(addr, IS_USER(s)); - store_reg(s, rd, tmp2); - break; - default: - goto illegal_op; - } - store_reg(s, rs, tmp); + gen_load_exclusive(s, rs, rd, addr, op); } else { - int label = gen_new_label(); - tmp2 = tcg_temp_local_new(); - gen_helper_test_exclusive(tmp2, cpu_env, addr); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp2, 0, label); - tmp = load_reg(s, rs); - switch (op) { - case 0: - gen_st8(tmp, addr, IS_USER(s)); - break; - case 1: - gen_st16(tmp, addr, IS_USER(s)); - break; - case 3: - gen_st32(tmp, addr, IS_USER(s)); - tcg_gen_addi_i32(addr, addr, 4); - tmp = load_reg(s, rd); - gen_st32(tmp, addr, IS_USER(s)); - break; - default: - goto illegal_op; - } - gen_set_label(label); - tcg_gen_mov_i32(cpu_R[rm], tmp2); - tcg_temp_free(tmp2); + gen_store_exclusive(s, rm, rs, rd, addr, op); } tcg_temp_free(addr); } @@ -7845,16 +7925,16 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } break; case 3: /* Special control operations. */ + ARCH(7); op = (insn >> 4) & 0xf; switch (op) { case 2: /* clrex */ - gen_helper_clrex(cpu_env); + gen_clrex(s); break; case 4: /* dsb */ case 5: /* dmb */ case 6: /* isb */ /* These execute as NOPs. */ - ARCH(7); break; default: goto illegal_op; diff --git a/target-mips/cpu.h b/target-mips/cpu.h index cefa5ae58..82f9a3816 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -40,7 +40,7 @@ typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; struct CPUMIPSTLBContext { uint32_t nb_tlb; uint32_t tlb_in_use; - int (*map_address) (struct CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); + int (*map_address) (struct CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type); void (*helper_tlbwi) (void); void (*helper_tlbwr) (void); void (*helper_tlbp) (void); @@ -372,10 +372,12 @@ struct CPUMIPSState { int32_t CP0_Config6; int32_t CP0_Config7; /* XXX: Maybe make LLAddr per-TC? */ - target_ulong CP0_LLAddr; + target_ulong lladdr; target_ulong llval; target_ulong llnewval; target_ulong llreg; + target_ulong CP0_LLAddr_rw_bitmask; + int CP0_LLAddr_shift; target_ulong CP0_WatchLo[8]; int32_t CP0_WatchHi[8]; target_ulong CP0_XContext; @@ -464,11 +466,11 @@ struct CPUMIPSState { struct QEMUTimer *timer; /* Internal timer */ }; -int no_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, +int no_mmu_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type); -int fixed_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, +int fixed_mmu_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type); -int r4k_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, +int r4k_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type); void r4k_helper_tlbwi (void); void r4k_helper_tlbwr (void); diff --git a/target-mips/helper.c b/target-mips/helper.c index 7f659ae6b..4a372777c 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -35,7 +35,7 @@ enum { }; /* no MMU emulation */ -int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, +int no_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type) { *physical = address; @@ -44,7 +44,7 @@ int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, } /* fixed mapping MMU emulation */ -int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, +int fixed_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type) { if (address <= (int32_t)0x7FFFFFFFUL) { @@ -62,7 +62,7 @@ int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, } /* MIPS32/MIPS64 R4000-style MMU emulation */ -int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, +int r4k_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type) { uint8_t ASID = env->CP0_EntryHi & 0xFF; @@ -99,7 +99,7 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, } #if !defined(CONFIG_USER_ONLY) -static int get_physical_address (CPUState *env, target_ulong *physical, +static int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type) { @@ -206,7 +206,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #if defined(CONFIG_USER_ONLY) return addr; #else - target_ulong phys_addr; + target_phys_addr_t phys_addr; int prot; if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) @@ -219,7 +219,7 @@ 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; + target_phys_addr_t physical; int prot; #endif int exception = 0, error_code = 0; @@ -243,7 +243,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #else ret = get_physical_address(env, &physical, &prot, address, rw, access_type); - qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n", + qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, physical, prot); if (ret == TLBRET_MATCH) { ret = tlb_set_page(env, address & TARGET_PAGE_MASK, diff --git a/target-mips/helper.h b/target-mips/helper.h index b8ec15eab..4f1de5193 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -122,6 +122,7 @@ DEF_HELPER_1(mtc0_cause, void, tl) DEF_HELPER_1(mtc0_ebase, void, tl) DEF_HELPER_1(mtc0_config0, void, tl) DEF_HELPER_1(mtc0_config2, void, tl) +DEF_HELPER_1(mtc0_lladdr, void, tl) DEF_HELPER_2(mtc0_watchlo, void, tl, i32) DEF_HELPER_2(mtc0_watchhi, void, tl, i32) DEF_HELPER_1(mtc0_xcontext, void, tl) diff --git a/target-mips/machine.c b/target-mips/machine.c index 451931988..9ffac711c 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -127,7 +127,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_sbe32s(f, &env->CP0_Config3); qemu_put_sbe32s(f, &env->CP0_Config6); qemu_put_sbe32s(f, &env->CP0_Config7); - qemu_put_betls(f, &env->CP0_LLAddr); + qemu_put_betls(f, &env->lladdr); for(i = 0; i < 8; i++) qemu_put_betls(f, &env->CP0_WatchLo[i]); for(i = 0; i < 8; i++) @@ -279,7 +279,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->CP0_Config3); qemu_get_sbe32s(f, &env->CP0_Config6); qemu_get_sbe32s(f, &env->CP0_Config7); - qemu_get_betls(f, &env->CP0_LLAddr); + qemu_get_betls(f, &env->lladdr); for(i = 0; i < 8; i++) qemu_get_betls(f, &env->CP0_WatchLo[i]); for(i = 0; i < 8; i++) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 83734b123..52d687d33 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -730,7 +730,7 @@ target_ulong helper_mftc0_status(void) target_ulong helper_mfc0_lladdr (void) { - return (int32_t)env->CP0_LLAddr >> 4; + return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift); } target_ulong helper_mfc0_watchlo (uint32_t sel) @@ -795,7 +795,7 @@ target_ulong helper_dmfc0_tcschefback (void) target_ulong helper_dmfc0_lladdr (void) { - return env->CP0_LLAddr >> 4; + return env->lladdr >> env->CP0_LLAddr_shift; } target_ulong helper_dmfc0_watchlo (uint32_t sel) @@ -959,7 +959,7 @@ void helper_mtc0_tcrestart (target_ulong arg1) { env->active_tc.PC = arg1; env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); - env->CP0_LLAddr = 0ULL; + env->lladdr = 0ULL; /* MIPS16 not implemented. */ } @@ -970,12 +970,12 @@ void helper_mttc0_tcrestart (target_ulong arg1) if (other_tc == env->current_tc) { env->active_tc.PC = arg1; env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); - env->CP0_LLAddr = 0ULL; + env->lladdr = 0ULL; /* MIPS16 not implemented. */ } else { env->tcs[other_tc].PC = arg1; env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS); - env->CP0_LLAddr = 0ULL; + env->lladdr = 0ULL; /* MIPS16 not implemented. */ } } @@ -1243,6 +1243,13 @@ void helper_mtc0_config2 (target_ulong arg1) env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); } +void helper_mtc0_lladdr (target_ulong arg1) +{ + target_long mask = env->CP0_LLAddr_rw_bitmask; + arg1 = arg1 << env->CP0_LLAddr_shift; + env->lladdr = (env->lladdr & ~mask) | (arg1 & mask); +} + void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel) { /* Watch exceptions for instructions, data loads, data stores @@ -1702,7 +1709,7 @@ void helper_eret (void) } compute_hflags(env); debug_post_eret(); - env->CP0_LLAddr = 1; + env->lladdr = 1; } void helper_deret (void) @@ -1712,7 +1719,7 @@ void helper_deret (void) env->hflags &= MIPS_HFLAG_DM; compute_hflags(env); debug_post_eret(); - env->CP0_LLAddr = 1; + env->lladdr = 1; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 7bae5414c..e9d92249e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -918,7 +918,7 @@ static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ TCGv t0 = tcg_temp_new(); \ tcg_gen_mov_tl(t0, arg1); \ tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, lladdr)); \ tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval)); \ tcg_temp_free(t0); \ } @@ -941,7 +941,7 @@ static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ct tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ generate_exception(ctx, EXCP_AdES); \ gen_set_label(l1); \ - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr)); \ tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg)); \ @@ -967,7 +967,7 @@ static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ct tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ generate_exception(ctx, EXCP_AdES); \ gen_set_label(l1); \ - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr)); \ tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, llval)); \ tcg_gen_qemu_##ldname(t1, arg2, ctx->mem_idx); \ @@ -3841,7 +3841,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int s case 17: switch (sel) { case 0: - /* ignored */ + gen_helper_mtc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -4998,7 +4998,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int case 17: switch (sel) { case 0: - /* ignored */ + gen_helper_mtc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -8501,8 +8501,8 @@ cpu_mips_check_sign_extensions (CPUState *env, FILE *f, if (!SIGN_EXT_P(env->CP0_EPC)) cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC); - if (!SIGN_EXT_P(env->CP0_LLAddr)) - cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->CP0_LLAddr); + if (!SIGN_EXT_P(env->lladdr)) + cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->lladdr); } #endif @@ -8526,7 +8526,7 @@ void cpu_dump_state (CPUState *env, FILE *f, cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", env->CP0_Status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", - env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); + env->CP0_Config0, env->CP0_Config1, env->lladdr); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) @@ -8633,6 +8633,9 @@ void cpu_reset (CPUMIPSState *env) env->CP0_Config3 = env->cpu_model->CP0_Config3; env->CP0_Config6 = env->cpu_model->CP0_Config6; env->CP0_Config7 = env->cpu_model->CP0_Config7; + env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask + << env->cpu_model->CP0_LLAddr_shift; + env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift; env->SYNCI_Step = env->cpu_model->SYNCI_Step; env->CCRes = env->cpu_model->CCRes; env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 088e2b4c2..c950eab1a 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -70,6 +70,8 @@ struct mips_def_t { int32_t CP0_Config3; int32_t CP0_Config6; int32_t CP0_Config7; + target_ulong CP0_LLAddr_rw_bitmask; + int CP0_LLAddr_shift; int32_t SYNCI_Step; int32_t CCRes; int32_t CP0_Status_rw_bitmask; @@ -105,6 +107,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, @@ -124,6 +128,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1258FF17, @@ -141,6 +147,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, @@ -158,6 +166,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1258FF17, @@ -176,6 +186,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, @@ -194,6 +206,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1258FF17, @@ -212,6 +226,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ @@ -231,6 +247,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ @@ -252,6 +270,8 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ @@ -294,6 +314,8 @@ static const mips_def_t mips_defs[] = .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0), /* Note: Config1 is only used internally, the R4000 has only Config0. */ .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), + .CP0_LLAddr_rw_bitmask = 0xFFFFFFFF, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 16, .CCRes = 2, .CP0_Status_rw_bitmask = 0x3678FFFF, @@ -310,6 +332,8 @@ static const mips_def_t mips_defs[] = /* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */ .CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0), .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), + .CP0_LLAddr_rw_bitmask = 0xFFFFFFFFL, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 16, .CCRes = 2, .CP0_Status_rw_bitmask = 0x3678FFFF, @@ -331,6 +355,8 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x32F8FFFF, @@ -350,6 +376,8 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x36F8FFFF, @@ -374,6 +402,8 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 1, .CP0_Status_rw_bitmask = 0x36FBFFFF, @@ -399,6 +429,8 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x36FBFFFF, @@ -5102,11 +5102,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_S: autostart = 0; break; -#ifndef _WIN32 case QEMU_OPTION_k: keyboard_layout = optarg; break; -#endif case QEMU_OPTION_localtime: rtc_utc = 0; break; |