@@ -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;
}
@@ -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
new file mode 100644
@@ -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;
+}
@@ -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 */