[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 16/27] Implement hcall based RTAS for pSeries machin
From: |
David Gibson |
Subject: |
[Qemu-devel] [PATCH 16/27] Implement hcall based RTAS for pSeries machines |
Date: |
Fri, 25 Mar 2011 14:21:21 +1100 |
On pSeries machines, operating systems can instantiate "RTAS" (Run-Time
Abstraction Services), a runtime component of the firmware which implements
a number of low-level, infrequently used operations. On logical partitions
under a hypervisor, many of the RTAS functions require hypervisor
privilege. For simplicity, therefore, hypervisor systems typically
implement the in-partition RTAS as just a tiny wrapper around a hypercall
which actually implements the various RTAS functions.
This patch implements such a hypercall based RTAS for our emulated pSeries
machine. A tiny in-partition "firmware" calls a new hypercall, which
looks up available RTAS services in a table.
Signed-off-by: David Gibson <address@hidden>
---
Makefile | 3 +-
Makefile.target | 2 +-
configure | 4 +-
hw/spapr.c | 26 +++++++-
hw/spapr.h | 22 +++++++
hw/spapr_hcall.c | 15 +++++
hw/spapr_rtas.c | 131 +++++++++++++++++++++++++++++++++++++++
pc-bios/spapr-rtas.bin | Bin 0 -> 20 bytes
pc-bios/spapr-rtas/Makefile | 24 +++++++
pc-bios/spapr-rtas/spapr-rtas.S | 36 +++++++++++
10 files changed, 257 insertions(+), 6 deletions(-)
create mode 100644 hw/spapr_rtas.c
create mode 100644 pc-bios/spapr-rtas.bin
create mode 100644 pc-bios/spapr-rtas/Makefile
create mode 100644 pc-bios/spapr-rtas/spapr-rtas.S
diff --git a/Makefile b/Makefile
index 89e88b4..e0b3fea 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin \
-s390-zipl.rom
+s390-zipl.rom \
+spapr-rtas.bin
else
BLOBS=
endif
diff --git a/Makefile.target b/Makefile.target
index cf12691..a53d99f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-ppc-y += ppc_oldworld.o
obj-ppc-y += ppc_newworld.o
# IBM pSeries (sPAPR)
ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
-obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o
+obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
obj-ppc-y += spapr_vty.o
endif
# PowerPC 4xx boards
diff --git a/configure b/configure
index 5a5827f..7d8d890 100755
--- a/configure
+++ b/configure
@@ -2461,7 +2461,9 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
"$softmmu" = yes ; then
roms="optionrom"
fi
-
+if test "$cpu" = "ppc64" ; then
+ roms="$roms spapr-rtas"
+fi
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $datadir`"
diff --git a/hw/spapr.c b/hw/spapr.c
index cd05d3f..ff1eb3b 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -40,6 +40,7 @@
#define KERNEL_LOAD_ADDR 0x00000000
#define INITRD_LOAD_ADDR 0x02800000
#define FDT_MAX_SIZE 0x10000
+#define RTAS_MAX_SIZE 0x10000
#define TIMEBASE_FREQ 512000000ULL
@@ -53,6 +54,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t
ramsize,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
const char *kernel_cmdline,
+ target_phys_addr_t rtas_addr,
+ target_phys_addr_t rtas_size,
long hash_shift)
{
void *fdt;
@@ -195,6 +198,12 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t
ramsize,
exit(1);
}
+ /* RTAS */
+ ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
+ }
+
_FDT((fdt_pack(fdt)));
*fdt_size = fdt_totalsize(fdt);
@@ -224,11 +233,12 @@ static void ppc_spapr_init(ram_addr_t ram_size,
void *fdt, *htab;
int i;
ram_addr_t ram_offset;
- target_phys_addr_t fdt_addr;
+ target_phys_addr_t fdt_addr, rtas_addr;
uint32_t kernel_base, initrd_base;
- long kernel_size, initrd_size, htab_size;
+ long kernel_size, initrd_size, htab_size, rtas_size;
long pteg_shift = 17;
int fdt_size;
+ char *filename;
spapr = qemu_malloc(sizeof(*spapr));
cpu_ppc_hypercall = emulate_spapr_hypercall;
@@ -237,6 +247,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
* 2GB, so that it can be processed with 32-bit code if
* necessary */
fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
+ /* RTAS goes just below that */
+ rtas_addr = fdt_addr - RTAS_MAX_SIZE;
/* init CPUs */
if (cpu_model == NULL) {
@@ -276,6 +288,14 @@ static void ppc_spapr_init(ram_addr_t ram_size,
envs[i]->htab_mask = htab_size - 1;
}
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
+ rtas_size = load_image_targphys(filename, rtas_addr, ram_size - rtas_addr);
+ if (rtas_size < 0) {
+ hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+ exit(1);
+ }
+ qemu_free(filename);
+
spapr->vio_bus = spapr_vio_bus_init();
for (i = 0; i < MAX_SERIAL_PORTS; i++) {
@@ -323,7 +343,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
/* Prepare the device tree */
fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr,
initrd_base, initrd_size, kernel_cmdline,
- pteg_shift + 7);
+ rtas_addr, rtas_size, pteg_shift + 7);
assert(fdt != NULL);
cpu_physical_memory_write(fdt_addr, fdt, fdt_size);
diff --git a/hw/spapr.h b/hw/spapr.h
index 06cca15..62a040f 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -237,6 +237,8 @@ typedef struct sPAPREnvironment {
#define H_GET_MPP 0x2D4
#define MAX_HCALL_OPCODE H_GET_MPP
+#define H_RTAS 0x72746173
+
extern sPAPREnvironment *spapr;
/*#define DEBUG_SPAPR_HCALLS*/
@@ -257,4 +259,24 @@ void spapr_register_hypercall(target_ulong opcode,
spapr_hcall_fn fn);
target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
target_ulong *args);
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+ return ldl_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+ stl_phys(phys + 4*n, val);
+}
+
+typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
+ uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets);
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+ target_phys_addr_t rtas_size);
+
#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 5c2dd88..594e27d 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -248,6 +248,16 @@ static target_ulong h_protect(CPUState *env,
sPAPREnvironment *spapr,
return H_SUCCESS;
}
+static target_ulong h_rtas(sPAPREnvironment *spapr, target_ulong rtas_r3)
+{
+ uint32_t token = ldl_phys(rtas_r3);
+ uint32_t nargs = ldl_phys(rtas_r3 + 4);
+ uint32_t nret = ldl_phys(rtas_r3 + 8);
+
+ return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+ nret, rtas_r3 + 12 + 4*nargs);
+}
+
struct hypercall {
spapr_hcall_fn fn;
} hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
@@ -283,6 +293,11 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong
opcode,
}
}
+ if (opcode == H_RTAS) {
+ /* H_RTAS is a special case outside the normal range */
+ return h_rtas(spapr, args[0]);
+ }
+
hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
return H_FUNCTION;
}
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
new file mode 100644
index 0000000..3f090f5
--- /dev/null
+++ b/hw/spapr_rtas.c
@@ -0,0 +1,131 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Hypercall based emulated RTAS
+ *
+ * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
+ *
+ * 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 "cpu.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "hw/qdev.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define TOKEN_BASE 0x2000
+#define TOKEN_MAX 0x100
+
+static struct rtas_call {
+ const char *name;
+ spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ if ((token >= TOKEN_BASE)
+ && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+ struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+ if (call->fn) {
+ call->fn(spapr, token, nargs, args, nret, rets);
+ return H_SUCCESS;
+ }
+ }
+
+ hcall_dprintf("Unknown RTAS token 0x%x\n", token);
+ rtas_st(rets, 0, -3);
+ return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+ assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+ rtas_next->name = name;
+ rtas_next->fn = fn;
+
+ rtas_next++;
+}
+
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+ target_phys_addr_t rtas_size)
+{
+ int ret;
+ int i;
+
+ ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base",
+ rtas_addr);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
+ rtas_addr);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size",
+ rtas_size);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't add rtas-size property: %s\n",
+ fdt_strerror(ret));
+ return ret;
+ }
+
+ for (i = 0; i < TOKEN_MAX; i++) {
+ struct rtas_call *call = &rtas_table[i];
+
+ if (!call->fn) {
+ continue;
+ }
+
+ ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name,
+ i + TOKEN_BASE);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
+ call->name, fdt_strerror(ret));
+ return ret;
+ }
+
+ }
+ return 0;
+}
diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin
new file mode 100644
index
0000000000000000000000000000000000000000..eade9c0e8ff0fd3071e3a6638a11c1a2e9a47152
GIT binary patch
literal 20
bcmb<address@hidden)vPAqm|U{LaFU{C-6M#cr<
literal 0
HcmV?d00001
diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile
new file mode 100644
index 0000000..dc8b23e
--- /dev/null
+++ b/pc-bios/spapr-rtas/Makefile
@@ -0,0 +1,24 @@
+all: build-all
+# Dummy command so that make thinks it has done something
+ @true
+
+include ../../config-host.mak
+include $(SRC_PATH)/rules.mak
+
+$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas)
+
+.PHONY : all clean build-all
+
+#CFLAGS += -I$(SRC_PATH)
+#QEMU_CFLAGS = $(CFLAGS)
+
+build-all: spapr-rtas.bin
+
+%.img: %.o
+ $(call quiet-command,$(CC) -nostdlib -o $@ $<," Building
$(TARGET_DIR)$@")
+
+%.bin: %.img
+ $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building
$(TARGET_DIR)$@")
+
+clean:
+ rm -f *.o *.d *.img *.bin *~
diff --git a/pc-bios/spapr-rtas/spapr-rtas.S b/pc-bios/spapr-rtas/spapr-rtas.S
new file mode 100644
index 0000000..71a8554
--- /dev/null
+++ b/pc-bios/spapr-rtas/spapr-rtas.S
@@ -0,0 +1,36 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Trivial in-partition RTAS implementation, based on a hypercall
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+
+#define H_RTAS 0x72746173
+
+.globl _start
+_start:
+ mr 4,3
+ lis 3,address@hidden
+ ori 3,3,address@hidden
+ sc 1
+ blr
--
1.7.1
- [Qemu-devel] [PATCH 07/27] Clean up slb_lookup() function, (continued)
- [Qemu-devel] [PATCH 07/27] Clean up slb_lookup() function, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 08/27] Parse SDR1 on mtspr instead of at translate time, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 04/27] Implement PowerPC slbmfee and slbmfev instructions, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 10/27] Better factor the ppc hash translation path, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 09/27] Use "hash" more consistently in ppc mmu code, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 11/27] Support 1T segments on ppc, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 12/27] Add POWER7 support for ppc, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 02/27] Allow qemu_devtree_setprop() to take arbitrary values, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 13/27] Start implementing pSeries logical partition machine, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 14/27] Implement the bus structure for PAPR virtual IO, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 16/27] Implement hcall based RTAS for pSeries machines,
David Gibson <=
- [Qemu-devel] [PATCH 20/27] Add (virtual) interrupt to PAPR virtual tty device, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 19/27] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 15/27] Virtual hash page table handling on pSeries machine, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 21/27] Implement TCE translation for sPAPR VIO, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 17/27] Implement assorted pSeries hcalls and RTAS methods, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 26/27] Implement PAPR VPA functions for pSeries shared processor partitions, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 25/27] Add a PAPR TCE-bypass mechanism for the pSeries machine, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 22/27] Implement sPAPR Virtual LAN (ibmveth), David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 23/27] Implement PAPR CRQ hypercalls, David Gibson, 2011/03/24
- [Qemu-devel] [PATCH 24/27] Implement PAPR virtual SCSI interface (ibmvscsi), David Gibson, 2011/03/24