[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Int
From: |
Sagar Karandikar |
Subject: |
[Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices |
Date: |
Mon, 26 Sep 2016 03:56:47 -0700 |
HTIF devices are currently used for the console and signaling test
completion for tests in riscv-tests. These are not part of any
RISC-V standard and will be phased out once better device support is
available.
Signed-off-by: Sagar Karandikar <address@hidden>
---
hw/riscv/Makefile.objs | 2 +
hw/riscv/htif/elf_symb.c | 286 +++++++++++++++++++++++++++++
hw/riscv/htif/elf_symb.h | 80 ++++++++
hw/riscv/htif/htif.c | 423 +++++++++++++++++++++++++++++++++++++++++++
include/hw/riscv/htif/htif.h | 61 +++++++
5 files changed, 852 insertions(+)
create mode 100644 hw/riscv/htif/elf_symb.c
create mode 100644 hw/riscv/htif/elf_symb.h
create mode 100644 hw/riscv/htif/htif.c
create mode 100644 include/hw/riscv/htif/htif.h
diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
index 79b4553..d830e5d 100644
--- a/hw/riscv/Makefile.objs
+++ b/hw/riscv/Makefile.objs
@@ -1 +1,3 @@
obj-y += riscv_rtc.o
+obj-y += htif/elf_symb.o
+obj-y += htif/htif.o
diff --git a/hw/riscv/htif/elf_symb.c b/hw/riscv/htif/elf_symb.c
new file mode 100644
index 0000000..dc8efd6
--- /dev/null
+++ b/hw/riscv/htif/elf_symb.c
@@ -0,0 +1,286 @@
+/*
+ * elf.c - A simple package for manipulating symbol tables in elf binaries.
+ *
+ * Taken from
+ * https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15213-f03/www/
+ * ftrace/elf.c
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "elf_symb.h"
+
+/*
+ * elf_open - Map a binary into the address space and extract the
+ * locations of the static and dynamic symbol tables and their string
+ * tables. Return this information in a Elf object file handle that will
+ * be passed to all of the other elf functions.
+ */
+Elf_obj *elf_open(const char *filename)
+{
+ int i, fd;
+ struct stat sbuf;
+ Elf_obj *ep;
+ Elf64_Shdr *shdr;
+
+ ep = g_new(Elf_obj, 1);
+
+ /* Do some consistency checks on the binary */
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Can't open \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (fstat(fd, &sbuf) == -1) {
+ fprintf(stderr, "Can't stat \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (sbuf.st_size < sizeof(Elf64_Ehdr)) {
+ fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+ exit(1);
+ }
+
+ /* It looks OK, so map the Elf binary into our address space */
+ ep->mlen = sbuf.st_size;
+ ep->maddr = mmap(NULL, ep->mlen, PROT_READ, MAP_SHARED, fd, 0);
+ if (ep->maddr == (void *)-1) {
+ fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ close(fd);
+
+ /* The Elf binary begins with the Elf header */
+ ep->ehdr = ep->maddr;
+
+ /* Make sure that this is an Elf binary */
+ /* if (strncmp(ep->ehdr->e_ident, ELFMAG, SELFMAG)) {
+ fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+ exit(1);
+ }*/
+
+ /*
+ * Find the static and dynamic symbol tables and their string
+ * tables in the the mapped binary. The sh_link field in symbol
+ * table section headers gives the section index of the string
+ * table for that symbol table.
+ */
+ shdr = (Elf64_Shdr *)(ep->maddr + ep->ehdr->e_shoff);
+ for (i = 0; i < ep->ehdr->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) { /* Static symbol table */
+ ep->symtab = (Elf64_Sym *)(ep->maddr + shdr[i].sh_offset);
+ ep->symtab_end = (Elf64_Sym *)((char *)ep->symtab +
+ shdr[i].sh_size);
+ ep->strtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+ }
+ if (shdr[i].sh_type == SHT_DYNSYM) { /* Dynamic symbol table */
+ ep->dsymtab = (Elf64_Sym *)(ep->maddr + shdr[i].sh_offset);
+ ep->dsymtab_end = (Elf64_Sym *)((char *)ep->dsymtab +
+ shdr[i].sh_size);
+ ep->dstrtab = (char *)(ep->maddr +
shdr[shdr[i].sh_link].sh_offset);
+ }
+ }
+ return ep;
+}
+
+/*
+ * elf_open - Map a binary into the address space and extract the
+ * locations of the static and dynamic symbol tables and their string
+ * tables. Return this information in a Elf object file handle that will
+ * be passed to all of the other elf functions.
+ */
+Elf_obj32 *elf_open32(const char *filename)
+{
+ int i, fd;
+ struct stat sbuf;
+ Elf_obj32 *ep;
+ Elf32_Shdr *shdr;
+
+ ep = g_new(Elf_obj32, 1);
+
+ /* Do some consistency checks on the binary */
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Can't open \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (fstat(fd, &sbuf) == -1) {
+ fprintf(stderr, "Can't stat \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
+ fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+ exit(1);
+ }
+
+ /* It looks OK, so map the Elf binary into our address space */
+ ep->mlen = sbuf.st_size;
+ ep->maddr = mmap(NULL, ep->mlen, PROT_READ, MAP_SHARED, fd, 0);
+ if (ep->maddr == (void *)-1) {
+ fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ close(fd);
+
+ /* The Elf binary begins with the Elf header */
+ ep->ehdr = ep->maddr;
+
+ /* Make sure that this is an Elf binary */
+/* if (strncmp(ep->ehdr->e_ident, ELFMAG, SELFMAG)) {
+ fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
+ exit(1);
+ }*/
+
+ /*
+ * Find the static and dynamic symbol tables and their string
+ * tables in the the mapped binary. The sh_link field in symbol
+ * table section headers gives the section index of the string
+ * table for that symbol table.
+ */
+ shdr = (Elf32_Shdr *)(ep->maddr + ep->ehdr->e_shoff);
+ for (i = 0; i < ep->ehdr->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) { /* Static symbol table */
+ ep->symtab = (Elf32_Sym *)(ep->maddr + shdr[i].sh_offset);
+ ep->symtab_end = (Elf32_Sym *)((char *)ep->symtab +
+ shdr[i].sh_size);
+ ep->strtab = (char *)(ep->maddr + shdr[shdr[i].sh_link].sh_offset);
+ }
+ if (shdr[i].sh_type == SHT_DYNSYM) { /* Dynamic symbol table */
+ ep->dsymtab = (Elf32_Sym *)(ep->maddr + shdr[i].sh_offset);
+ ep->dsymtab_end = (Elf32_Sym *)((char *)ep->dsymtab +
+ shdr[i].sh_size);
+ ep->dstrtab = (char *)(ep->maddr +
shdr[shdr[i].sh_link].sh_offset);
+ }
+ }
+ return ep;
+}
+
+/*
+ * elf_close - Free up the resources of an elf object
+ */
+void elf_close(Elf_obj *ep)
+{
+ if (munmap(ep->maddr, ep->mlen) < 0) {
+ perror("munmap");
+ exit(1);
+ }
+ free(ep);
+}
+
+/*
+ * elf_symname - Return ASCII name of a static symbol
+ */
+char *elf_symname(Elf_obj *ep, Elf64_Sym *sym)
+{
+ return &ep->strtab[sym->st_name];
+}
+
+/*
+ * elf_symname - Return ASCII name of a static symbol
+ */
+char *elf_symname32(Elf_obj32 *ep, Elf32_Sym *sym)
+{
+ return &ep->strtab[sym->st_name];
+}
+
+
+/*
+ * elf_dsymname - Return ASCII name of a dynamic symbol
+ */
+char *elf_dsymname(Elf_obj *ep, Elf64_Sym *sym)
+{
+ return &ep->dstrtab[sym->st_name];
+}
+
+/*
+ * elf_firstsym - Return ptr to first symbol in static symbol table
+ */
+Elf64_Sym *elf_firstsym(Elf_obj *ep)
+{
+ return ep->symtab;
+}
+
+/*
+ * elf_firstsym - Return ptr to first symbol in static symbol table
+ */
+Elf32_Sym *elf_firstsym32(Elf_obj32 *ep)
+{
+ return ep->symtab;
+}
+
+
+/*
+ * elf_nextsym - Return ptr to next symbol in static symbol table,
+ * or NULL if no more symbols.
+ */
+Elf64_Sym *elf_nextsym(Elf_obj *ep, Elf64_Sym *sym)
+{
+ sym++;
+ if (sym < ep->symtab_end) {
+ return sym;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * elf_nextsym - Return ptr to next symbol in static symbol table,
+ * or NULL if no more symbols.
+ */
+Elf32_Sym *elf_nextsym32(Elf_obj32 *ep, Elf32_Sym *sym)
+{
+ sym++;
+ if (sym < ep->symtab_end) {
+ return sym;
+ } else {
+ return NULL;
+ }
+}
+
+
+/*
+ * elf_firstdsym - Return ptr to first symbol in dynamic symbol table
+ */
+Elf64_Sym *elf_firstdsym(Elf_obj *ep)
+{
+ return ep->dsymtab;
+}
+
+/*
+ * elf_nextdsym - Return ptr to next symbol in dynamic symbol table,
+ * of NULL if no more symbols.
+ */
+Elf64_Sym *elf_nextdsym(Elf_obj *ep, Elf64_Sym *sym)
+{
+ sym++;
+ if (sym < ep->dsymtab_end) {
+ return sym;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * elf_isfunc - Return true if symbol is a static function
+ */
+int elf_isfunc(Elf_obj *ep, Elf64_Sym *sym)
+{
+ return ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC) &&
+ (sym->st_shndx != SHT_NULL));
+}
+
+/*
+ * elf_isdfunc - Return true if symbol is a dynamic function
+ */
+int elf_isdfunc(Elf_obj *ep, Elf64_Sym *sym)
+{
+ return ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC));
+}
diff --git a/hw/riscv/htif/elf_symb.h b/hw/riscv/htif/elf_symb.h
new file mode 100644
index 0000000..a438c60
--- /dev/null
+++ b/hw/riscv/htif/elf_symb.h
@@ -0,0 +1,80 @@
+/*
+ * elf.h - A package for manipulating Elf binaries
+ *
+ * Taken from:
+ * https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15213-f03/www/ftrace/
+ * elf.h
+ *
+ */
+
+#ifndef ELF_H
+#define ELF_H
+
+#include <stdint.h>
+#include <elf.h>
+
+/*
+ * This is a handle that is created by elf_open and then used by every
+ * other function in the elf package
+*/
+typedef struct {
+ void *maddr; /* Start of mapped Elf binary segment in memory */
+ int mlen; /* Length in bytes of the mapped Elf segment */
+ Elf64_Ehdr *ehdr; /* Start of main Elf header (same as maddr) */
+ Elf64_Sym *symtab; /* Start of symbol table */
+ Elf64_Sym *symtab_end; /* End of symbol table (symtab + size) */
+ char *strtab; /* Address of string table */
+ Elf64_Sym *dsymtab; /* Start of dynamic symbol table */
+ Elf64_Sym *dsymtab_end; /* End of dynamic symbol table (dsymtab + size) */
+ char *dstrtab; /* Address of dynamic string table */
+} Elf_obj;
+
+typedef struct {
+ void *maddr; /* Start of mapped Elf binary segment in memory */
+ int mlen; /* Length in bytes of the mapped Elf segment */
+ Elf32_Ehdr *ehdr; /* Start of main Elf header (same as maddr) */
+ Elf32_Sym *symtab; /* Start of symbol table */
+ Elf32_Sym *symtab_end; /* End of symbol table (symtab + size) */
+ char *strtab; /* Address of string table */
+ Elf32_Sym *dsymtab; /* Start of dynamic symbol table */
+ Elf32_Sym *dsymtab_end; /* End of dynamic symbol table (dsymtab + size) */
+ char *dstrtab; /* Address of dynamic string table */
+} Elf_obj32;
+
+/*
+ * Create and destroy Elf object handles
+ */
+Elf_obj *elf_open(const char *filename);
+Elf_obj32 *elf_open32(const char *filename);
+
+void elf_close(Elf_obj *ep);
+
+/*
+ * Functions for manipulating static symbols
+ */
+
+/* Returns pointer to the first symbol */
+Elf64_Sym *elf_firstsym(Elf_obj *ep);
+Elf32_Sym *elf_firstsym32(Elf_obj32 *ep);
+
+/* Returns pointer to the next symbol, or NULL if no more symbols */
+Elf64_Sym *elf_nextsym(Elf_obj *ep, Elf64_Sym *sym);
+Elf32_Sym *elf_nextsym32(Elf_obj32 *ep, Elf32_Sym *sym);
+
+/* Return symbol string name */
+char *elf_symname(Elf_obj *ep, Elf64_Sym *sym);
+char *elf_symname32(Elf_obj32 *ep, Elf32_Sym *sym);
+
+/* True if symbol is a function */
+int elf_isfunc(Elf_obj *ep, Elf64_Sym *sym);
+
+/*
+ * Corresponding functions for manipulating dynamic symbols
+ */
+Elf64_Sym *elf_firstdsym(Elf_obj *ep);
+Elf64_Sym *elf_nextdsym(Elf_obj *ep, Elf64_Sym *sym);
+char *elf_dsymname(Elf_obj *ep, Elf64_Sym *sym);
+int elf_isdfunc(Elf_obj *ep, Elf64_Sym *sym);
+
+
+#endif
diff --git a/hw/riscv/htif/htif.c b/hw/riscv/htif/htif.c
new file mode 100644
index 0000000..6093ebd
--- /dev/null
+++ b/hw/riscv/htif/htif.c
@@ -0,0 +1,423 @@
+/*
+ * QEMU RISC-V Host Target Interface (HTIF) Emulation
+ *
+ * Author: Sagar Karandikar, address@hidden
+ *
+ * This provides HTIF device emulation for QEMU. At the moment this allows
+ * for identical copies of bbl/linux to run on both spike and QEMU.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/serial.h"
+#include "sysemu/char.h"
+#include "hw/riscv/htif/htif.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include "elf_symb.h"
+
+#define ENABLE_CHARDEV
+/*#define DEBUG_CHARDEV */
+/*#define DEBUG_HTIF */
+
+#ifdef ENABLE_CHARDEV
+/*
+ * Called by the char dev to see if HTIF is ready to accept input.
+ */
+static int htif_can_recv(void *opaque)
+{
+ return 1;
+}
+
+/*
+ * Called by the char dev to supply input to HTIF console.
+ * We assume that we will receive one character at a time.
+ */
+static void htif_recv(void *opaque, const uint8_t *buf, int size)
+{
+ if (size != 1) {
+ return;
+ }
+
+ HTIFState *htifstate = opaque;
+
+ #ifdef DEBUG_CHARDEV
+ if (htifstate->env->mfromhost != 0x0) {
+ fprintf(stderr, "recv handler: fromhost was not ready to \
+ accept input\n");
+ fprintf(stderr, "recv handler: prev value was: %016lx\n",
+ htifstate->env->mfromhost);
+ }
+ #endif
+
+ uint64_t val_written = htifstate->pending_read;
+ uint64_t resp = 0x100 | *buf;
+
+ htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
+ qemu_irq_raise(htifstate->irq);
+}
+
+/*
+ * Called by the char dev to supply special events to the HTIF console.
+ * Not used for HTIF.
+ */
+static void htif_event(void *opaque, int event)
+{
+ #ifdef DEBUG_CHARDEV
+ fprintf(stderr, "GOT EVENT: %d\n", event);
+ #endif
+}
+#endif
+
+static void htif_pre_save(void *opaque)
+{
+ return;
+}
+
+static int htif_post_load(void *opaque, int version_id)
+{
+ return 0;
+}
+
+const VMStateDescription vmstate_htif = {
+ .name = "htif",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = htif_pre_save,
+ .post_load = htif_post_load,
+ .fields = (VMStateField []) { /* TODO what */
+ VMSTATE_UINT64(tohost_offset, HTIFState),
+ VMSTATE_UINT64(fromhost_offset, HTIFState),
+ VMSTATE_UINT64(tohost_size, HTIFState),
+ VMSTATE_UINT64(fromhost_size, HTIFState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void dma_strcopy(HTIFState *htifstate, char *str, hwaddr phys_addr)
+{
+ int i = 0;
+ void *base_copy_addr = htifstate->main_mem_ram_ptr + phys_addr;
+ while (*(str + i)) {
+ stb_p((void *)(base_copy_addr + i), *(str + i));
+ i++;
+ }
+ stb_p((void *)(base_copy_addr + i), 0); /* store null term */
+}
+
+static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t
val_written)
+{
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "TOHOST WRITE WITH val 0x%016lx\n", val_written);
+ #endif
+
+ uint8_t device = val_written >> 56;
+ uint8_t cmd = val_written >> 48;
+ uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
+
+ uint64_t addr = payload >> 8;
+ hwaddr real_addr = (hwaddr)addr;
+ uint8_t what = payload & 0xFF;
+ int resp;
+
+ resp = 0; /* stop gcc complaining */
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "mtohost write:\n-device: %d\n-cmd: %d\n-what: %02lx\n\
+ -payload: %016lx\n", device, cmd, payload & 0xFF,
payload);
+ #endif
+
+ /*
+ * Currently, there is a fixed mapping of devices:
+ * 0: riscv-tests Pass/Fail Reporting Only (no syscall proxy)
+ * 1: Console
+ */
+ if (unlikely(device == 0x0)) {
+ /* frontend syscall handler, only test pass/fail support */
+ if (cmd == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "frontend syscall handler\n");
+ #endif
+ if (payload & 0x1) {
+ /* test result */
+ if (payload >> 1) {
+ printf("*** FAILED *** (exitcode = %016lx)\n",
+ payload >> 1);
+ } else {
+ printf("TEST PASSED\n");
+ }
+ exit(payload >> 1);
+ }
+ fprintf(stderr, "pk syscall proxy not supported\n");
+ } else if (cmd == 0xFF) {
+ /* use what */
+ if (what == 0xFF) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering name\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"syscall_proxy", real_addr);
+ } else if (what == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering syscall cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"syscall", real_addr);
+ } else {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering end of cmds list\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"", real_addr);
+ }
+ resp = 0x1; /* write to indicate device name placed */
+ } else {
+ fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+ exit(1);
+ }
+ } else if (likely(device == 0x1)) {
+ /* HTIF Console */
+ if (cmd == 0x0) {
+ /* this should be a queue, but not yet implemented as such */
+ htifstate->pending_read = val_written;
+ htifstate->env->mtohost = 0; /* clear to indicate we read */
+ return;
+ } else if (cmd == 0x1) {
+ #ifdef ENABLE_CHARDEV
+ qemu_chr_fe_write(htifstate->chr, (uint8_t *)&payload, 1);
+ #endif
+ resp = 0x100 | (uint8_t)payload;
+ } else if (cmd == 0xFF) {
+ /* use what */
+ if (what == 0xFF) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering name\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"bcd", real_addr);
+ } else if (what == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering read cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"read", real_addr);
+ } else if (what == 0x1) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering write cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"write", real_addr);
+ } else {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering end of cmds list\n");
+ #endif
+ dma_strcopy(htifstate, (char *)"", real_addr);
+ }
+ resp = 0x1; /* write to indicate device name placed */
+ } else {
+ fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+ exit(1);
+ }
+ /* all other devices */
+ } else if (device == 0x2 && cmd == 0xFF && what == 0xFF) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering no device as last\n");
+ #endif
+ stb_p((void *)(htifstate->main_mem_ram_ptr + real_addr), 0);
+ resp = 0x1; /* write to indicate device name placed */
+ } else {
+ fprintf(stderr, "HTIF UNKNOWN DEVICE OR COMMAND!\n");
+ fprintf(stderr, "-device: %d\n-cmd: %d\n-what: %02lx\n-payload: \
+ %016lx\n", device, cmd, payload & 0xFF, payload);
+ exit(1);
+ }
+ while (!htifstate->fromhost_inprogress &&
+ htifstate->env->mfromhost != 0x0) {
+ /* wait */
+ }
+ htifstate->env->mfromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
+ htifstate->env->mtohost = 0; /* clear to indicate we read */
+ if (htifstate->env->mfromhost != 0) {
+ /* raise HTIF interrupt */
+ qemu_irq_raise(htifstate->irq);
+ }
+}
+
+#define TOHOST_OFFSET1 (htifstate->tohost_offset)
+#define TOHOST_OFFSET2 (htifstate->tohost_offset + 4)
+#define FROMHOST_OFFSET1 (htifstate->fromhost_offset)
+#define FROMHOST_OFFSET2 (htifstate->fromhost_offset + 4)
+
+/* CPU wants to read an HTIF register */
+static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ HTIFState *htifstate = opaque;
+ if (addr == TOHOST_OFFSET1) {
+ return htifstate->env->mtohost & 0xFFFFFFFF;
+ } else if (addr == TOHOST_OFFSET2) {
+ return (htifstate->env->mtohost >> 32) & 0xFFFFFFFF;
+ } else if (addr == FROMHOST_OFFSET1) {
+ return htifstate->env->mfromhost & 0xFFFFFFFF;
+ } else if (addr == FROMHOST_OFFSET2) {
+ return (htifstate->env->mfromhost >> 32) & 0xFFFFFFFF;
+ } else {
+ printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+ exit(1);
+ }
+}
+
+/* CPU wrote to an HTIF register */
+static void htif_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ HTIFState *htifstate = opaque;
+ if (addr == TOHOST_OFFSET1) {
+ if (htifstate->env->mtohost == 0x0) {
+ htifstate->allow_tohost = 1;
+ htifstate->env->mtohost = value & 0xFFFFFFFF;
+ if (unlikely(htifstate->tohost_size != 8)) {
+#ifdef DEBUG_HTIF
+ fprintf(stderr, "Using non-8 htif width\n");
+#endif
+ /* tests have a zero tohost size in elf symb tab and they
+ use sw to write to mm_write, so TOHOST_OFFSET2 will never
+ be written to. Thus, initiate side effects here. */
+ htif_handle_tohost_write(htifstate, htifstate->env->mtohost);
+ }
+ } else {
+ htifstate->allow_tohost = 0;
+ }
+ } else if (addr == TOHOST_OFFSET2) {
+ if (htifstate->allow_tohost) {
+ htifstate->env->mtohost |= value << 32;
+ htif_handle_tohost_write(htifstate, htifstate->env->mtohost);
+ }
+ } else if (addr == FROMHOST_OFFSET1) {
+ htifstate->fromhost_inprogress = 1;
+ htifstate->env->mfromhost = value & 0xFFFFFFFF;
+ } else if (addr == FROMHOST_OFFSET2) {
+ htifstate->env->mfromhost |= value << 32;
+ if (htifstate->env->mfromhost == 0x0) {
+ qemu_irq_lower(htifstate->irq);
+ }
+ htifstate->fromhost_inprogress = 0;
+ } else {
+ printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+ exit(1);
+ }
+}
+
+static const MemoryRegionOps htif_mm_ops[3] = {
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = htif_mm_read,
+ .write = htif_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ },
+};
+
+HTIFState *htif_mm_init(MemoryRegion *address_space,
+ const char *kernel_filename, qemu_irq irq, MemoryRegion *main_mem,
+ CPURISCVState *env, CharDriverState *chr)
+{
+ uint64_t fromhost_addr = 0;
+ uint64_t fromhost_size = 0; /* for pk vs tests */
+ uint64_t tohost_addr = 0;
+ uint64_t tohost_size = 0; /* for pk vs tests */
+
+ /* get fromhost/tohost addresses from the ELF, as spike/fesvr do */
+ if (NULL != kernel_filename) {
+#if defined(TARGET_RISCV64)
+ Elf_obj *e = elf_open(kernel_filename);
+#else
+ Elf_obj32 *e = elf_open32(kernel_filename);
+#endif
+
+ const char *fromhost = "fromhost";
+ const char *tohost = "tohost";
+
+#if defined(TARGET_RISCV64)
+ Elf64_Sym *curr_sym = elf_firstsym(e);
+#else
+ Elf32_Sym *curr_sym = elf_firstsym32(e);
+#endif
+ while (curr_sym) {
+#if defined(TARGET_RISCV64)
+ char *symname = elf_symname(e, curr_sym);
+#else
+ char *symname = elf_symname32(e, curr_sym);
+#endif
+
+ if (strcmp(fromhost, symname) == 0) {
+ /* get fromhost addr */
+ fromhost_addr = curr_sym->st_value;
+ fromhost_size = curr_sym->st_size; /* this is correctly set to
8
+ by pk */
+ } else if (strcmp(tohost, symname) == 0) {
+ /* get tohost addr */
+ tohost_addr = curr_sym->st_value;
+ tohost_size = curr_sym->st_size; /* this is correctly set to 8
+ by pk */
+ }
+#if defined(TARGET_RISCV64)
+ curr_sym = elf_nextsym(e, curr_sym);
+#else
+ curr_sym = elf_nextsym32(e, curr_sym);
+#endif
+ }
+ }
+
+ /* now setup HTIF device */
+ HTIFState *htifstate;
+
+ htifstate = g_malloc0(sizeof(HTIFState));
+ htifstate->irq = irq;
+ htifstate->address_space = address_space;
+ htifstate->main_mem = main_mem;
+ htifstate->main_mem_ram_ptr = memory_region_get_ram_ptr(main_mem);
+ htifstate->env = env;
+ htifstate->chr = chr;
+ htifstate->pending_read = 0;
+ htifstate->allow_tohost = 0;
+ htifstate->fromhost_inprogress = 0;
+ htifstate->fromhost_size = fromhost_size;
+ htifstate->tohost_size = tohost_size;
+
+#ifdef ENABLE_CHARDEV
+ qemu_chr_add_handlers(htifstate->chr, htif_can_recv, htif_recv, htif_event,
+ htifstate);
+#endif
+
+ uint64_t base = tohost_addr < fromhost_addr ? tohost_addr : fromhost_addr;
+ uint64_t second = tohost_addr < fromhost_addr ? fromhost_addr :
tohost_addr;
+ uint64_t regionwidth = second - base + 8;
+
+ htifstate->tohost_offset = base == tohost_addr ? 0 : tohost_addr -
+ fromhost_addr;
+ htifstate->fromhost_offset = base == fromhost_addr ? 0 : fromhost_addr -
+ tohost_addr;
+
+ vmstate_register(NULL, base, &vmstate_htif, htifstate);
+
+ memory_region_init_io(&htifstate->io, NULL,
+ &htif_mm_ops[DEVICE_LITTLE_ENDIAN],
+ htifstate, "htif", regionwidth);
+ memory_region_add_subregion(address_space, base, &htifstate->io);
+
+ return htifstate;
+}
diff --git a/include/hw/riscv/htif/htif.h b/include/hw/riscv/htif/htif.h
new file mode 100644
index 0000000..3499947
--- /dev/null
+++ b/include/hw/riscv/htif/htif.h
@@ -0,0 +1,61 @@
+/*
+ * QEMU RISCV Host Target Interface (HTIF) Emulation
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HW_RISCV_HTIF_H
+#define HW_RISCV_HTIF_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+#include "target-riscv/cpu.h"
+
+typedef struct HTIFState HTIFState;
+
+struct HTIFState {
+ int allow_tohost;
+ int fromhost_inprogress;
+
+ hwaddr tohost_offset;
+ hwaddr fromhost_offset;
+ uint64_t tohost_size;
+ uint64_t fromhost_size;
+ qemu_irq irq; /* host interrupt line */
+ MemoryRegion io;
+ MemoryRegion *address_space;
+ MemoryRegion *main_mem;
+ void *main_mem_ram_ptr;
+
+ CPURISCVState *env;
+ CharDriverState *chr;
+ uint64_t pending_read;
+};
+
+extern const VMStateDescription vmstate_htif;
+extern const MemoryRegionOps htif_io_ops;
+
+/* legacy pre qom */
+HTIFState *htif_mm_init(MemoryRegion *address_space,
+ const char *kernel_filename, qemu_irq irq,
+ MemoryRegion *main_mem,
+ CPURISCVState *env, CharDriverState *chr);
+
+#endif
--
2.9.3
- [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target, (continued)
- [Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target, Sagar Karandikar, 2016/09/26
- [Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions, Sagar Karandikar, 2016/09/26
- [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions, Sagar Karandikar, 2016/09/26
- [Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode, Sagar Karandikar, 2016/09/26
- [Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/, Sagar Karandikar, 2016/09/26
- [Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices,
Sagar Karandikar <=
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Paolo Bonzini, 2016/09/26
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Richard Henderson, 2016/09/26
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Andreas Färber, 2016/09/26
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Paolo Bonzini, 2016/09/26
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Andreas Färber, 2016/09/26
- Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Paolo Bonzini, 2016/09/26