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. Reviewed-by: Thomas Huth <thuth@xxxxxxxxxx> Signed-off-by: David Hildenbrand <david@xxxxxxxxxx> --- 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 diff --git a/lib/s390x/asm/arch_def.h b/lib/s390x/asm/arch_def.h index 72e5c60..ee4c96f 100644 --- a/lib/s390x/asm/arch_def.h +++ b/lib/s390x/asm/arch_def.h @@ -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 diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h index 41be039..3ccc8e3 100644 --- a/lib/s390x/asm/interrupt.h +++ b/lib/s390x/asm/interrupt.h @@ -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 */ diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c index 8d861a2..67d581b 100644 --- a/lib/s390x/interrupt.c +++ b/lib/s390x/interrupt.c @@ -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(); diff --git a/lib/s390x/io.c b/lib/s390x/io.c index 3121a78..eb4d171 100644 --- a/lib/s390x/io.c +++ b/lib/s390x/io.c @@ -43,6 +43,7 @@ void setup() setup_args_progname(ipl_args); setup_facilities(); sclp_ascii_setup(); + sclp_memory_setup(); } void exit(int code) diff --git a/lib/s390x/sclp.c b/lib/s390x/sclp.c new file mode 100644 index 0000000..199405c --- /dev/null +++ b/lib/s390x/sclp.c @@ -0,0 +1,58 @@ +/* + * s390x SCLP driver + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Hildenbrand <david@xxxxxxxxxx> + * + * 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; + } +} diff --git a/lib/s390x/sclp.h b/lib/s390x/sclp.h index d113cf8..21d482b 100644 --- a/lib/s390x/sclp.h +++ b/lib/s390x/sclp.h @@ -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 */ diff --git a/s390x/Makefile b/s390x/Makefile index f585faf..ce63dd1 100644 --- a/s390x/Makefile +++ b/s390x/Makefile @@ -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 -- 2.14.3