diff options
author | Miodrag Dinic <miodrag.dinic@imgtec.com> | 2015-06-16 17:24:06 +0200 |
---|---|---|
committer | Miodrag Dinic <miodrag.dinic@imgtec.com> | 2015-06-23 12:31:10 +0200 |
commit | 7673fd2cd207de3774cbf2e0bea9f1f99bab7c87 (patch) | |
tree | 51a6507d255f560acbbf0ddd8c20a69078ea6900 | |
parent | 5e29087a9444d323bbab1ed7c7120ea7ef3739f2 (diff) | |
download | qemu-android-master.tar.gz |
goldfish_tty.c: Use physical addresses instead of virtualHEADstudio-master-dev_before_26911779studio-1.5studio-1.4gradle_1.5.0studio-master-devmastermain
Re-implement Goldfish TTY device to work directly with
physical addresses instead of virtual. Main idea behind
this approach is to move away from using
cpu_memory_rw_debug() -> cpu_phys_page_debug() path
for VA-PA translation, which does not guarantee that it
will return a valid mapping. Using physical addresses
is the correct way to go, ensures less overhead and
faster serial communication.
Change-Id: Ib31f3cb33ac6630816f901a39834c87188ac09aa
-rw-r--r-- | hw/char/goldfish_tty.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c index 5525e3f3d6..7223c604d7 100644 --- a/hw/char/goldfish_tty.c +++ b/hw/char/goldfish_tty.c @@ -17,6 +17,8 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" +#define TTY_DEVICE_VERSION 1 + enum { TTY_PUT_CHAR = 0x00, TTY_BYTES_READY = 0x04, @@ -26,6 +28,8 @@ enum { TTY_DATA_LEN = 0x14, TTY_DATA_PTR_HIGH = 0x18, + TTY_VERSION = 0x20, + TTY_CMD_INT_DISABLE = 0, TTY_CMD_INT_ENABLE = 1, TTY_CMD_WRITE_BUFFER = 2, @@ -96,6 +100,8 @@ static uint64_t goldfish_tty_read(void *opaque, hwaddr offset, unsigned size) switch (offset) { case TTY_BYTES_READY: return s->data_count; + case TTY_VERSION: + return TTY_DEVICE_VERSION; default: cpu_abort(current_cpu, "goldfish_tty_read: Bad offset %" HWADDR_PRIx "\n", @@ -104,7 +110,8 @@ static uint64_t goldfish_tty_read(void *opaque, hwaddr offset, unsigned size) } } -static void goldfish_tty_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +static void goldfish_tty_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) { struct tty_state *s = (struct tty_state *)opaque; @@ -135,39 +142,42 @@ static void goldfish_tty_write(void *opaque, hwaddr offset, uint64_t value, unsi case TTY_CMD_WRITE_BUFFER: if(s->cs) { - int len; - target_ulong buf; - - buf = s->ptr; - len = s->ptr_len; - - while (len) { - char temp[64]; - int to_write = sizeof(temp); - if (to_write > len) - to_write = len; - - cpu_memory_rw_debug(current_cpu, buf, (uint8_t*)temp, to_write, 0); - qemu_chr_fe_write(s->cs, (const uint8_t*)temp, to_write); - buf += to_write; - len -= to_write; - } + hwaddr l = s->ptr_len; + void *ptr; + + ptr = cpu_physical_memory_map(s->ptr, &l, 0); + qemu_chr_fe_write(s->cs, (const uint8_t*)ptr, l); + cpu_physical_memory_unmap(ptr, l, 0, 0); } break; case TTY_CMD_READ_BUFFER: - if(s->ptr_len > s->data_count) - cpu_abort(current_cpu, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count); - cpu_memory_rw_debug(current_cpu, s->ptr, s->data, s->ptr_len,1); - if(s->data_count > s->ptr_len) - memmove(s->data, s->data + s->ptr_len, s->data_count - s->ptr_len); - s->data_count -= s->ptr_len; - if(s->data_count == 0 && s->ready) - qemu_set_irq(s->irq, 0); + { + hwaddr l = s->ptr_len; + void *ptr; + + if(s->ptr_len > s->data_count) + cpu_abort(current_cpu, + "goldfish_tty_write: reading" + " more data than available %d %d\n", + s->ptr_len, s->data_count); + + ptr = cpu_physical_memory_map(s->ptr, &l, 1); + memcpy(ptr, s->data, l); + cpu_physical_memory_unmap(ptr, l, 1, l); + + if(s->data_count > l) + memmove(s->data, s->data + l, s->data_count - l); + s->data_count -= l; + if(s->data_count == 0 && s->ready) + qemu_set_irq(s->irq, 0); + } break; default: - cpu_abort(current_cpu, "goldfish_tty_write: Bad command %" PRIx64 "\n", value); + cpu_abort(current_cpu, + "goldfish_tty_write: Bad command %" PRIx64 "\n", + value); }; break; @@ -224,7 +234,9 @@ static void goldfish_tty_realize(DeviceState *dev, Error **errp) int i; if ((instance_id + 1) == MAX_SERIAL_PORTS) { - cpu_abort(current_cpu, "goldfish_tty: MAX_SERIAL_PORTS(%d) reached\n", MAX_SERIAL_PORTS); + cpu_abort(current_cpu, + "goldfish_tty: MAX_SERIAL_PORTS(%d) reached\n", + MAX_SERIAL_PORTS); } memory_region_init_io(&s->iomem, OBJECT(s), &mips_qemu_ops, s, @@ -235,7 +247,8 @@ static void goldfish_tty_realize(DeviceState *dev, Error **errp) for(i = 0; i < MAX_SERIAL_PORTS; i++) { if(serial_hds[i]) { s->cs = serial_hds[i]; - qemu_chr_add_handlers(serial_hds[i], tty_can_receive, tty_receive, NULL, s); + qemu_chr_add_handlers(serial_hds[i], tty_can_receive, + tty_receive, NULL, s); break; } } |