[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 18/38] arm: implement vpl011 (UART) emulator.
This is not interended to provide a full emulation, but rather just enough to satisfy the use made by Linux' boot time decompressor code (which is too early for DT etc) Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> --- xen/arch/arm/Makefile | 1 + xen/arch/arm/domain.c | 4 + xen/arch/arm/io.c | 1 + xen/arch/arm/io.h | 1 + xen/arch/arm/vpl011.c | 155 ++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/vpl011.h | 34 +++++++++ xen/include/asm-arm/domain.h | 8 ++ 7 files changed, 204 insertions(+), 0 deletions(-) create mode 100644 xen/arch/arm/vpl011.c create mode 100644 xen/arch/arm/vpl011.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 9440a21..5a87ba6 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -25,6 +25,7 @@ obj-y += shutdown.o obj-y += traps.o obj-y += vgic.o obj-y += vtimer.o +obj-y += vpl011.o #obj-bin-y += ....o diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index e867cb2..d830980 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -13,6 +13,7 @@ #include "gic.h" #include "vtimer.h" +#include "vpl011.h" DEFINE_PER_CPU(struct vcpu *, curr_vcpu); @@ -201,6 +202,9 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) if ( (rc = domain_vgic_init(d)) != 0 ) goto fail; + if ( (rc = domain_uart0_init(d)) != 0 ) + goto fail; + if ( !is_idle_domain(d) ) { rc = -ENOMEM; diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c index 4461225..18f6164 100644 --- a/xen/arch/arm/io.c +++ b/xen/arch/arm/io.c @@ -25,6 +25,7 @@ static const struct mmio_handler *const mmio_handlers[] = { &vgic_distr_mmio_handler, + &uart0_mmio_handler, }; #define MMIO_HANDLER_NR ARRAY_SIZE(mmio_handlers) diff --git a/xen/arch/arm/io.h b/xen/arch/arm/io.h index 8cc5ca7..9a507f5 100644 --- a/xen/arch/arm/io.h +++ b/xen/arch/arm/io.h @@ -40,6 +40,7 @@ struct mmio_handler { }; extern const struct mmio_handler vgic_distr_mmio_handler; +extern const struct mmio_handler uart0_mmio_handler; extern int handle_mmio(mmio_info_t *info); diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c new file mode 100644 index 0000000..1491dcc --- /dev/null +++ b/xen/arch/arm/vpl011.c @@ -0,0 +1,155 @@ +/* + * xen/arch/arm/vpl011.c + * + * ARM PL011 UART Emulator (DEBUG) + * + * Ian Campbell <ian.campbell@xxxxxxxxxx> + * Copyright (c) 2012 Citrix Systems. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * This is not intended to be a full emulation of a PL011 + * device. Rather it is intended to provide a sufficient veneer of one + * that early code (such as Linux's boot time decompressor) which + * hardcodes output directly to such a device are able to make progress. + * + * This device is not intended to be enumerable or exposed to the OS + * (e.g. via Device Tree). + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/sched.h> +#include <xen/errno.h> +#include <xen/ctype.h> + +#include "io.h" + +#define UART0_BASE_ADDRESS 0x1c090000 + +#define UARTDR 0x000 +#define UARTFR 0x018 + +int domain_uart0_init(struct domain *d) +{ + int rc; + if ( d->domain_id == 0 ) + return 0; + + spin_lock_init(&d->arch.uart0.lock); + d->arch.uart0.idx = 0; + + rc = -ENOMEM; + d->arch.uart0.buf = xzalloc_array(char, VPL011_BUF_SIZE); + if ( !d->arch.uart0.buf ) + goto out; + + rc = 0; +out: + return rc; +} + +static void uart0_print_char(char c) +{ + struct vpl011 *uart = ¤t->domain->arch.uart0; + + /* Accept only printable characters, newline, and horizontal tab. */ + if ( !isprint(c) && (c != '\n') && (c != '\t') ) + return ; + + spin_lock(&uart->lock); + uart->buf[uart->idx++] = c; + if ( (uart->idx == (VPL011_BUF_SIZE - 2)) || (c == '\n') ) + { + if ( c != '\n' ) + uart->buf[uart->idx++] = '\n'; + uart->buf[uart->idx] = '\0'; + printk(XENLOG_G_DEBUG "DOM%u: %s", + current->domain->domain_id, uart->buf); + uart->idx = 0; + } + spin_unlock(&uart->lock); +} + +static int uart0_mmio_check(struct vcpu *v, paddr_t addr) +{ + return v->domain->domain_id && addr >= UART0_BASE_ADDRESS && addr < (UART0_BASE_ADDRESS+65536); +} + +static int uart0_mmio_read(struct vcpu *v, mmio_info_t *info) +{ + struct hsr_dabt dabt = info->dabt; + struct cpu_user_regs *regs = guest_cpu_user_regs(); + uint32_t *r = ®s->r0 + dabt.reg; + int offset = (int)(info->gpa - UART0_BASE_ADDRESS); + + switch ( offset ) + { + case UARTDR: + *r = 0; + return 1; + case UARTFR: + *r = 0x87; /* All holding registers empty, ready to send etc */ + return 1; + default: + printk("VPL011: unhandled read r%d offset %#08x\n", + dabt.reg, offset); + domain_crash_synchronous(); + } +} + +static int uart0_mmio_write(struct vcpu *v, mmio_info_t *info) +{ + struct hsr_dabt dabt = info->dabt; + struct cpu_user_regs *regs = guest_cpu_user_regs(); + uint32_t *r = ®s->r0 + dabt.reg; + int offset = (int)(info->gpa - UART0_BASE_ADDRESS); + int val = (int)((*r) & 0xFF); + + if ( dabt.size != 0 ) + { + printk("VPL011: Invalid %d-byte write to offset %#x\n", + 1<<dabt.size, offset); + domain_crash_synchronous(); + } + + switch ( offset ) + { + case UARTDR: + uart0_print_char(val); + return 1; + case UARTFR: + /* Silently ignore */ + return 1; + default: + printk("VPL011: unhandled write r%d=%"PRIx32" offset %#08x\n", + dabt.reg, *r, offset); + domain_crash_synchronous(); + } +} + +const struct mmio_handler uart0_mmio_handler = { + .check_handler = uart0_mmio_check, + .read_handler = uart0_mmio_read, + .write_handler = uart0_mmio_write, +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/arch/arm/vpl011.h b/xen/arch/arm/vpl011.h new file mode 100644 index 0000000..952d812 --- /dev/null +++ b/xen/arch/arm/vpl011.h @@ -0,0 +1,34 @@ +/* + * xen/arch/arm/vpl011.h + * + * ARM PL011 Emulation Support + * + * Ian Campbell <ian.campbell@xxxxxxxxxx> + * Copyright (c) 2012 Citrix Systems. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ARCH_ARM_VPL011_H__ +#define __ARCH_ARM_VPL011_H__ + +extern int domain_uart0_init(struct domain *d); + +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 10ed540..f295a82 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -48,6 +48,14 @@ struct arch_domain struct vgic_irq_rank *shared_irqs; struct pending_irq *pending_irqs; } vgic; + + struct vpl011 { +#define VPL011_BUF_SIZE 128 + char *buf; + int idx; + spinlock_t lock; + } uart0; + } __cacheline_aligned; struct arch_vcpu -- 1.7.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |