@@ -151,4 +151,16 @@ struct cpuid {
uint64_t reserved : 15;
};
+static inline int tprot(unsigned long addr)
+{
+ int cc;
+
+ asm volatile(
+ " tprot 0(%1),0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc) : "a" (addr) : "cc");
+ return cc;
+}
+
#endif
@@ -13,6 +13,7 @@
void handle_pgm_int(void);
void expect_pgm_int(void);
+uint16_t clear_pgm_int(void);
void check_pgm_int_code(uint16_t code);
/* Activate low-address protection */
@@ -23,6 +23,17 @@ void expect_pgm_int(void)
mb();
}
+uint16_t clear_pgm_int(void)
+{
+ uint16_t code;
+
+ mb();
+ code = lc->pgm_int_code;
+ lc->pgm_int_code = 0;
+ pgm_int_expected = false;
+ return code;
+}
+
void check_pgm_int_code(uint16_t code)
{
mb();
@@ -43,6 +43,7 @@ void setup()
setup_args_progname(ipl_args);
setup_facilities();
sclp_ascii_setup();
+ sclp_memory_setup();
}
void exit(int code)
new file mode 100644
@@ -0,0 +1,58 @@
+/*
+ * s390x SCLP driver
+ *
+ * Copyright (c) 2017 Red Hat Inc
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+
+#include <libcflat.h>
+#include <asm/page.h>
+#include <asm/arch_def.h>
+#include <asm/interrupt.h>
+#include "sclp.h"
+
+static uint64_t storage_increment_size;
+static uint64_t max_ram_size;
+static uint64_t ram_size;
+
+void sclp_memory_setup(void)
+{
+ ReadInfo *ri = (void *)_sccb;
+ uint64_t rnmax, rnsize;
+ int cc;
+
+ ri->h.length = SCCB_SIZE;
+ sclp_service_call(SCLP_CMDW_READ_SCP_INFO_FORCED, ri);
+
+ /* calculate the storage increment size */
+ rnsize = ri->rnsize;
+ if (!rnsize) {
+ rnsize = ri->rnsize2;
+ }
+ storage_increment_size = rnsize << 20;
+
+ /* calculate the maximum memory size */
+ rnmax = ri->rnmax;
+ if (!rnmax) {
+ rnmax = ri->rnmax2;
+ }
+ max_ram_size = rnmax * storage_increment_size;
+
+ /* lowcore is always accessible, so the first increment is accessible */
+ ram_size = storage_increment_size;
+
+ /* probe for r/w memory up to max memory size */
+ while (ram_size < max_ram_size) {
+ expect_pgm_int();
+ cc = tprot(ram_size + storage_increment_size - 1);
+ /* stop once we receive an exception or have protected memory */
+ if (clear_pgm_int() || cc != 0)
+ break;
+ ram_size += storage_increment_size;
+ }
+}
@@ -211,5 +211,6 @@ void sclp_ascii_setup(void);
void sclp_print(const char *str);
extern char _sccb[];
int sclp_service_call(unsigned int command, void *sccb);
+void sclp_memory_setup(void);
#endif /* SCLP_H */
@@ -24,6 +24,7 @@ cflatobjs += lib/util.o
cflatobjs += lib/alloc_phys.o
cflatobjs += lib/s390x/io.o
cflatobjs += lib/s390x/stack.o
+cflatobjs += lib/s390x/sclp.o
cflatobjs += lib/s390x/sclp-ascii.o
cflatobjs += lib/s390x/interrupt.o
Unfortunately, there is no easy way to simply read out the amount of installed memory. We have to probe (via TEST PROTECTION) for installed memory in a given range. Signed-off-by: David Hildenbrand <david@redhat.com> --- lib/s390x/asm/arch_def.h | 12 ++++++++++ lib/s390x/asm/interrupt.h | 1 + lib/s390x/interrupt.c | 11 +++++++++ lib/s390x/io.c | 1 + lib/s390x/sclp.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ lib/s390x/sclp.h | 1 + s390x/Makefile | 1 + 7 files changed, 85 insertions(+) create mode 100644 lib/s390x/sclp.c