[RFC,2/8] Add pef memory ranges to device tree
diff mbox series

Message ID 20190905132919.8765-3-grimm@linux.ibm.com
State New
Headers show
Series
  • PEF support in Skiboot
Related show

Checks

Context Check Description
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot fail Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (7b12d5489fcfd73ef7ec0cb27eff7f8a5f13b238)

Commit Message

Ryan Grimm Sept. 5, 2019, 1:29 p.m. UTC
From: Santosh Sivaraj <santosh@fossix.org>

Protected execution facility in Power 9 uses special memory areas
designated as secure memory, which can be accessed only in the ultravisor
mode. This protection is provided by the hardware. These designated memory
areas are used by the guests running as secure virtual machines.

The secure memory ranges are provided by the hostboot through HDATA. Get
secure memory ranges from HDATA and add to device tree for ultravisor
firmware.

Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
[ grimm: Fix secure-memory-ranges for multiple ranges ]
[ grimm: hdata: Dont ignore range if SMF is enbaled ]
[ grimm: use cleanup_addr on secure mem ranges ]
[ grimm: ret code checks, various cleanups for BML ]
Signed-off-by: Ryan Grimm <grimm@linux.vnet.ibm.com>
---
 hdata/memory.c       |  17 +++++-
 hw/Makefile.inc      |   1 +
 hw/ultravisor.c      | 133 +++++++++++++++++++++++++++++++++++++++++++
 include/ultravisor.h |   5 ++
 4 files changed, 154 insertions(+), 2 deletions(-)
 create mode 100644 hw/ultravisor.c

Patch
diff mbox series

diff --git a/hdata/memory.c b/hdata/memory.c
index 9af7ae71..25b8088d 100644
--- a/hdata/memory.c
+++ b/hdata/memory.c
@@ -10,6 +10,7 @@ 
 #include <types.h>
 #include <inttypes.h>
 #include <processor.h>
+#include <ultravisor.h>
 
 #include "spira.h"
 #include "hdata.h"
@@ -59,6 +60,8 @@  struct HDIF_ms_area_address_range {
 #define MS_CONTROLLER_MCS_ID(id)	GETFIELD(PPC_BITMASK32(4, 7), id)
 #define MS_CONTROLLER_MCA_ID(id)	GETFIELD(PPC_BITMASK32(8, 15), id)
 
+#define MS_ATTR_SMF			(PPC_BIT32(23))
+
 struct HDIF_ms_area_id {
 	__be16 id;
 #define MS_PTYPE_RISER_CARD	0x8000
@@ -163,6 +166,16 @@  static bool add_address_range(struct dt_node *root,
 		return false;
 	}
 
+	if (arange->mirror_attr & MS_ATTR_SMF) {
+		prlog(PR_DEBUG, "Found secure memory");
+		if (!uv_add_mem_range(reg[0], cleanup_addr(be64_to_cpu(arange->end)))) {
+			prlog(PR_INFO, "Failed to add secure memory range to DT\n");
+			mem_reserve_fw(name, reg[0], reg[1]);
+			return false;
+		} else
+			return true;
+	}
+
 	if (be16_to_cpu(id->flags) & MS_AREA_SHARED) {
 		mem = dt_find_by_name_addr(dt_root, name, reg[0]);
 		if (mem) {
@@ -676,9 +689,9 @@  static void get_hb_reserved_mem(struct HDIF_common_hdr *ms_vpd)
 
 		/*
 		 * Workaround broken HDAT reserve regions which are
-		 * bigger than 512MB
+		 * bigger than 512MB and not secure memory
 		 */
-		if ((end_addr - start_addr) > 0x20000000) {
+		if (((end_addr - start_addr) > 0x20000000) && !(start_addr & UV_SECURE_MEM_BIT)) {
 			prlog(PR_ERR, "MEM: Ignoring Bad HDAT reserve: too big\n");
 			continue;
 		}
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index b708bdfe..848898b9 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -9,6 +9,7 @@  HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o
 HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o
 HW_OBJS += occ-sensor.o vas.o sbe-p8.o dio-p9.o lpc-port80h.o cache-p9.o
 HW_OBJS += npu-opal.o npu3.o npu3-nvlink.o npu3-hw-procedures.o
+HW_OBJS += ultravisor.o
 HW=hw/built-in.a
 
 include $(SRC)/hw/fsp/Makefile.inc
diff --git a/hw/ultravisor.c b/hw/ultravisor.c
new file mode 100644
index 00000000..f79699ef
--- /dev/null
+++ b/hw/ultravisor.c
@@ -0,0 +1,133 @@ 
+/* Copyright 2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <xscom.h>
+#include <chip.h>
+#include <device.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <ultravisor.h>
+
+static struct dt_node *add_uv_dt_node(void)
+{
+	struct dt_node *dev, *uv;
+
+	dev = dt_new_check(dt_root, "ibm,ultravisor");
+	if (!dev)
+		return NULL;
+
+	dt_add_property_string(dev, "compatible", "ibm,ultravisor");
+	uv = dt_new_check(dev, "ibm,uv-firmware");
+	if (!uv) {
+		dt_free(dev);
+		return NULL;
+	}
+
+	dt_add_property_string(uv, "compatible", "ibm,uv-firmware");
+	return dev;
+}
+
+static struct dt_node *find_uv_node(void)
+{
+	struct dt_node *uv_node, *dt;
+
+	uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware");
+	if (!uv_node) {
+		prlog(PR_DEBUG, "UV node not found, creating");
+		dt = add_uv_dt_node();
+		if (!dt)
+			return NULL;
+		uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware");
+	}
+
+	return uv_node;
+}
+
+static bool dt_append_memory_range(struct dt_node *node, __be64 start,
+				   __be64 len)
+{
+	const struct dt_property *ranges;
+	size_t size;
+	u32 *new_ranges;
+	int i;
+
+	/* for Cronus boot the BML script creates secure-memory-ranges
+	 * for Mambo boot the ultra.tcl script create secure-memory ranges
+	 * for HostBoot, skiboot parses HDAT in hdata/memory.c and creates it here */
+	ranges = dt_find_property(node, "secure-memory-ranges");
+	if (!ranges) {
+		prlog(PR_DEBUG, "Creating secure-memory-ranges.\n");
+		ranges = dt_add_property_cells(node, "secure-memory-ranges",
+					       hi32(start), lo32(start),
+					       hi32(len), lo32(len));
+		return true;
+	}
+
+	prlog(PR_DEBUG, "Adding secure memory range range at 0x%llx of size: 0x%llx\n", start, len);
+	/* Calculate the total size in bytes of the new property */
+	size = ranges->len + 16;
+	new_ranges = (u32 *)malloc(size);
+	memcpy(new_ranges, ranges->prop, ranges->len);
+
+	i = ranges->len / 4;
+	/* The ranges property will be of type <addr size ...> */
+	new_ranges[i++] = hi32(start);
+	new_ranges[i++] = lo32(start);
+	new_ranges[i++] = hi32(len);
+	new_ranges[i] = lo32(len);
+
+	/* Update our node with the new set of ranges */
+	dt_del_property(node, (struct dt_property *)ranges);
+	dt_add_property(node, "secure-memory-ranges", (void *)new_ranges, size);
+
+	return true;
+}
+
+/*
+ * This code returns false on invalid memory ranges and in no-secure mode.
+ * It is the caller's responsibility of moving the memory to appropriate
+ * reserved areas.
+ */
+bool uv_add_mem_range(__be64 start, __be64 end)
+{
+	struct dt_node *uv_node;
+	bool ret = false;
+
+	if (!is_msr_bit_set(MSR_S))
+		return ret;
+
+	/* Check if address range is secure */
+	if (!((start & UV_SECURE_MEM_BIT) && (end & UV_SECURE_MEM_BIT))) {
+		prlog(PR_DEBUG, "Invalid SMF address range.\n");
+		return ret;
+	}
+
+	uv_node = find_uv_node();
+	if (!uv_node) {
+		prlog(PR_ERR, "Could not create uv node\n");
+		return false;
+	}
+
+	ret = dt_append_memory_range(uv_node, start, end - start + 1);
+
+	if (ret)
+		prlog(PR_NOTICE, "SMF memory range added [0x%016llx..0x%015llx]\n", start, end);
+
+	return ret;
+}
diff --git a/include/ultravisor.h b/include/ultravisor.h
index 9473319c..d038d42b 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -17,6 +17,11 @@ 
 #ifndef __ULTRAVISOR_H
 #define __ULTRAVISOR_H
 
+/* Bit 15 of an address should be set for it to be used as a secure memory area
+ * for the secure virtual machines */
+#define UV_SECURE_MEM_BIT              (PPC_BIT(15))
+
 extern int start_uv(uint64_t entry, void *ptr);
+extern bool uv_add_mem_range(__be64 start, __be64 end);
 
 #endif /* __ULTRAVISOR_H */