aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/core/test
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/core/test
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/core/test')
-rw-r--r--roms/skiboot/core/test/Makefile.check101
-rw-r--r--roms/skiboot/core/test/dummy-cpu.h35
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-0bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-1bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-10bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-11bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-16bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-2bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-26bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-27bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-29bin0 -> 4096 bytes
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-long2
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-nodash2
-rw-r--r--roms/skiboot/core/test/firmware-versions-input/version-trunc2
-rw-r--r--roms/skiboot/core/test/run-api-test.c40
-rw-r--r--roms/skiboot/core/test/run-bitmap.c80
-rw-r--r--roms/skiboot/core/test/run-buddy.c73
-rw-r--r--roms/skiboot/core/test/run-console-log-buf-overrun.c105
-rw-r--r--roms/skiboot/core/test/run-console-log-pr_fmt.c63
-rw-r--r--roms/skiboot/core/test/run-console-log.c63
-rw-r--r--roms/skiboot/core/test/run-cpufeatures.c144
-rw-r--r--roms/skiboot/core/test/run-device.c471
-rw-r--r--roms/skiboot/core/test/run-flash-firmware-versions.c154
-rw-r--r--roms/skiboot/core/test/run-flash-subpartition.c48
-rw-r--r--roms/skiboot/core/test/run-malloc-speed.c88
-rw-r--r--roms/skiboot/core/test/run-malloc.c174
-rw-r--r--roms/skiboot/core/test/run-mem_range_is_reserved.c207
-rw-r--r--roms/skiboot/core/test/run-mem_region.c252
-rw-r--r--roms/skiboot/core/test/run-mem_region_init.c175
-rw-r--r--roms/skiboot/core/test/run-mem_region_next.c105
-rw-r--r--roms/skiboot/core/test/run-mem_region_release_unused.c177
-rw-r--r--roms/skiboot/core/test/run-mem_region_release_unused_noalloc.c156
-rw-r--r--roms/skiboot/core/test/run-mem_region_reservations.c228
-rw-r--r--roms/skiboot/core/test/run-msg.c281
-rw-r--r--roms/skiboot/core/test/run-nvram-format.c167
-rw-r--r--roms/skiboot/core/test/run-pci-quirk.c98
-rw-r--r--roms/skiboot/core/test/run-pel.c120
-rw-r--r--roms/skiboot/core/test/run-pool.c59
-rw-r--r--roms/skiboot/core/test/run-time-utils.c52
-rw-r--r--roms/skiboot/core/test/run-timebase.c47
-rw-r--r--roms/skiboot/core/test/run-timer.c84
-rw-r--r--roms/skiboot/core/test/run-trace.c397
-rw-r--r--roms/skiboot/core/test/stubs.c101
43 files changed, 4351 insertions, 0 deletions
diff --git a/roms/skiboot/core/test/Makefile.check b/roms/skiboot/core/test/Makefile.check
new file mode 100644
index 000000000..7c347bea2
--- /dev/null
+++ b/roms/skiboot/core/test/Makefile.check
@@ -0,0 +1,101 @@
+# -*-Makefile-*-
+CORE_TEST := \
+ core/test/run-bitmap \
+ core/test/run-cpufeatures \
+ core/test/run-device \
+ core/test/run-flash-subpartition \
+ core/test/run-flash-firmware-versions \
+ core/test/run-mem_region \
+ core/test/run-malloc \
+ core/test/run-malloc-speed \
+ core/test/run-mem_region_init \
+ core/test/run-mem_region_next \
+ core/test/run-mem_region_release_unused \
+ core/test/run-mem_region_release_unused_noalloc \
+ core/test/run-mem_region_reservations \
+ core/test/run-mem_range_is_reserved \
+ core/test/run-nvram-format \
+ core/test/run-trace core/test/run-msg \
+ core/test/run-pel \
+ core/test/run-pool \
+ core/test/run-time-utils \
+ core/test/run-timebase \
+ core/test/run-timer \
+ core/test/run-buddy \
+ core/test/run-pci-quirk
+
+HOSTCFLAGS+=-I . -I include -Wno-error=attributes
+
+CORE_TEST_NOSTUB := core/test/run-console-log
+CORE_TEST_NOSTUB += core/test/run-console-log-buf-overrun
+CORE_TEST_NOSTUB += core/test/run-console-log-pr_fmt
+CORE_TEST_NOSTUB += core/test/run-api-test
+
+LCOV_EXCLUDE += $(CORE_TEST:%=%.c) core/test/stubs.c
+LCOV_EXCLUDE += $(CORE_TEST_NOSTUB:%=%.c) /usr/include/*
+
+.PHONY : core-check
+core-check: $(CORE_TEST:%=%-check) $(CORE_TEST_NOSTUB:%=%-check)
+
+.PHONY : core-coverage
+core-coverage: $(CORE_TEST:%=%-gcov-run)
+core-coverage: $(CORE_TEST_NOSTUB:%=%-gcov-run)
+
+check: core-check
+coverage: core-coverage
+
+$(CORE_TEST:%=%-gcov-run) : %-run: %
+ $(call QTEST, TEST-COVERAGE ,$< , $<)
+
+$(CORE_TEST_NOSTUB:%=%-gcov-run) : %-run: %
+ $(call QTEST, TEST-COVERAGE ,$< , $<)
+
+$(CORE_TEST:%=%-check) : %-check: %
+ $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<)
+
+$(CORE_TEST_NOSTUB:%=%-check) : %-check: %
+ $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<)
+
+core/test/stubs.o: core/test/stubs.c
+ $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -g -c -o $@ $<, $<)
+
+$(CORE_TEST) : core/test/stubs.o
+
+$(CORE_TEST) : % : %.c
+ $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -O0 -g -I include -I . -I libfdt -o $@ $< core/test/stubs.o, $<)
+
+$(CORE_TEST_NOSTUB) : % : %.c
+ $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -O0 -g -I include -I . -I libfdt -o $@ $< , $<)
+
+$(CORE_TEST:%=%-gcov): %-gcov : %.c %
+ $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< core/test/stubs.o, $<)
+
+$(CORE_TEST_NOSTUB:%=%-gcov) : %-gcov : %.c %
+ $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< , $<)
+
+core/test/run-flash-firmware-versions-gcov-run: core/test/run-flash-firmware-versions-inputs-gcov-run
+
+core/test/run-flash-firmware-versions-inputs-gcov-run: core/test/run-flash-firmware-versions-gcov
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-0 > /dev/null, $< version-0)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-1 > /dev/null, $< version-1)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-2 > /dev/null, $< version-2)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-10 > /dev/null, $< version-10)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-11 > /dev/null, $< version-11)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-16 > /dev/null, $< version-16)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-26 > /dev/null, $< version-26)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-27 > /dev/null, $< version-27)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-29 > /dev/null, $< version-29)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-trunc > /dev/null, $< version-trunc)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-long > /dev/null, $< version-long)
+ $(call Q, TEST-COVERAGE , ./core/test/run-flash-firmware-versions-gcov core/test/firmware-versions-input/version-nodash > /dev/null, $< version-nodash)
+
+
+-include $(wildcard core/test/*.d)
+
+clean: core-test-clean
+
+core-test-clean:
+ $(RM) -f core/test/*.[od] $(CORE_TEST) $(CORE_TEST:%=%-gcov)
+ $(RM) -f $(CORE_TEST_NOSTUB) $(CORE_TEST_NOSTUB:%=%-gcov)
+ $(RM) -f *.gcda *.gcno skiboot.info
+ $(RM) -rf coverage-report
diff --git a/roms/skiboot/core/test/dummy-cpu.h b/roms/skiboot/core/test/dummy-cpu.h
new file mode 100644
index 000000000..64fb71bce
--- /dev/null
+++ b/roms/skiboot/core/test/dummy-cpu.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ *
+ * A dummy cpu.h for tests.
+ * We don't want to include the real skiboot cpu.h, it's PPC-specific
+ */
+
+#ifndef __CPU_H
+#define __CPU_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+static unsigned int cpu_max_pir = 1;
+struct cpu_thread {
+ unsigned int chip_id;
+};
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+ const char *name,
+ void (*func)(void *data), void *data,
+ bool no_return);
+static inline struct cpu_job *cpu_queue_job(struct cpu_thread *cpu,
+ const char *name,
+ void (*func)(void *data),
+ void *data)
+{
+ return __cpu_queue_job(cpu, name, func, data, false);
+}
+void cpu_wait_job(struct cpu_job *job, bool free_it);
+void cpu_process_local_jobs(void);
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+ const char *name,
+ void (*func)(void *data), void *data);
+#endif /* __CPU_H */
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-0 b/roms/skiboot/core/test/firmware-versions-input/version-0
new file mode 100644
index 000000000..2ab241af5
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-0
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-1 b/roms/skiboot/core/test/firmware-versions-input/version-1
new file mode 100644
index 000000000..746327a8b
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-1
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-10 b/roms/skiboot/core/test/firmware-versions-input/version-10
new file mode 100644
index 000000000..013af6089
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-10
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-11 b/roms/skiboot/core/test/firmware-versions-input/version-11
new file mode 100644
index 000000000..55e835321
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-11
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-16 b/roms/skiboot/core/test/firmware-versions-input/version-16
new file mode 100644
index 000000000..8906af4e9
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-16
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-2 b/roms/skiboot/core/test/firmware-versions-input/version-2
new file mode 100644
index 000000000..f012ffd23
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-2
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-26 b/roms/skiboot/core/test/firmware-versions-input/version-26
new file mode 100644
index 000000000..adfd5bbcf
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-26
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-27 b/roms/skiboot/core/test/firmware-versions-input/version-27
new file mode 100644
index 000000000..d7ade9863
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-27
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-29 b/roms/skiboot/core/test/firmware-versions-input/version-29
new file mode 100644
index 000000000..b1476a3a5
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-29
Binary files differ
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-long b/roms/skiboot/core/test/firmware-versions-input/version-long
new file mode 100644
index 000000000..f814fa6f4
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-long
@@ -0,0 +1,2 @@
+open-power-whatever-v2.0-10-g1cec21d-dirty
+ Well, I wonder what a short essay here will mean for parsing everything. I hope it is all okay, but we want to get greater than 80 chars.
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-nodash b/roms/skiboot/core/test/firmware-versions-input/version-nodash
new file mode 100644
index 000000000..139aa9350
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-nodash
@@ -0,0 +1,2 @@
+no_dashes_in_version
+ this_is_wrong
diff --git a/roms/skiboot/core/test/firmware-versions-input/version-trunc b/roms/skiboot/core/test/firmware-versions-input/version-trunc
new file mode 100644
index 000000000..c9c92a01f
--- /dev/null
+++ b/roms/skiboot/core/test/firmware-versions-input/version-trunc
@@ -0,0 +1,2 @@
+open-power-SUPERMICRO-P8DTU-V2.00.GA2-20161028
+ op
diff --git a/roms/skiboot/core/test/run-api-test.c b/roms/skiboot/core/test/run-api-test.c
new file mode 100644
index 000000000..35e8135d4
--- /dev/null
+++ b/roms/skiboot/core/test/run-api-test.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2014-2016 IBM Corp.
+ *
+ * For now it just validates that addresses passed are sane and test the
+ * wrapper that validates addresses
+ *
+ * Copyright 2016 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <compiler.h>
+#include <opal-internal.h>
+
+#define __TEST__
+unsigned long top_of_ram; /* Fake it here */
+int main(void)
+{
+ unsigned long addr = 0xd000000000000000;
+
+ top_of_ram = 16ULL * 1024 * 1024 * 1024; /* 16 GB */
+ assert(opal_addr_valid((void *)addr) == false);
+
+ addr = 0xc000000000000000;
+ assert(opal_addr_valid((void *)addr) == true);
+
+ addr = 0x0;
+ assert(opal_addr_valid((void *)addr) == true);
+
+ addr = ~0;
+ assert(opal_addr_valid((void *)addr) == false);
+
+ addr = top_of_ram + 1;
+ assert(opal_addr_valid((void *)addr) == false);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-bitmap.c b/roms/skiboot/core/test/run-bitmap.c
new file mode 100644
index 000000000..e474915b8
--- /dev/null
+++ b/roms/skiboot/core/test/run-bitmap.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2017 IBM Corp.
+ */
+
+#include "../bitmap.c"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int main(void)
+{
+ bitmap_t *map = malloc(sizeof(bitmap_elem_t));
+ int i;
+ memset(map, 0, sizeof(bitmap_elem_t));
+
+ assert(BITMAP_ELEMS(16) == (BITMAP_ELEMS(8)));
+ assert(BITMAP_ELEMS(128) == (BITMAP_ELEMS(64)*2));
+
+ assert(BITMAP_BYTES(64) == 8);
+ assert(BITMAP_BYTES(128) == 16);
+
+ assert(BITMAP_BIT(1) == 0x1);
+ assert(BITMAP_BIT(2) == 0x2);
+ assert(BITMAP_BIT(3) == 0x3);
+ assert(BITMAP_BIT(8) == 0x8);
+
+ assert(BITMAP_MASK(0) == 0x1);
+ assert(BITMAP_MASK(1) == 0x2);
+ assert(BITMAP_MASK(8) == 0x100);
+ assert(BITMAP_MASK(9) == 0x200);
+
+ assert(BITMAP_ELEM(1) == 0);
+ assert(BITMAP_ELEM(128) == BITMAP_ELEMS(128));
+
+ bitmap_set_bit(*map, 0);
+ assert(*(unsigned long*)map == 0x1);
+ assert(bitmap_tst_bit(*map, 0) == true);
+ bitmap_clr_bit(*map, 0);
+ assert(*(unsigned long*)map == 0x00);
+
+ bitmap_set_bit(*map, 8);
+ assert(*(unsigned long*)map == 0x100);
+ assert(bitmap_tst_bit(*map, 0) == false);
+ assert(bitmap_tst_bit(*map, 1) == false);
+ assert(bitmap_tst_bit(*map, 2) == false);
+ assert(bitmap_tst_bit(*map, 3) == false);
+ assert(bitmap_tst_bit(*map, 4) == false);
+ assert(bitmap_tst_bit(*map, 5) == false);
+ assert(bitmap_tst_bit(*map, 6) == false);
+ assert(bitmap_tst_bit(*map, 7) == false);
+ assert(bitmap_tst_bit(*map, 8) == true);
+ assert(bitmap_tst_bit(*map, 9) == false);
+ assert(bitmap_tst_bit(*map, 10) == false);
+ assert(bitmap_tst_bit(*map, 11) == false);
+ assert(bitmap_tst_bit(*map, 12) == false);
+ assert(bitmap_tst_bit(*map, 13) == false);
+ assert(bitmap_tst_bit(*map, 14) == false);
+ assert(bitmap_tst_bit(*map, 15) == false);
+ assert(bitmap_find_one_bit(*map, 0, 16) == 8);
+ bitmap_clr_bit(*map, 8);
+ assert(bitmap_find_one_bit(*map, 0, 16) == -1);
+ assert(*(unsigned long*)map == 0x00);
+ assert(bitmap_tst_bit(*map, 8) == false);
+
+ bitmap_for_each_zero(*map, 7, i) {
+ bitmap_set_bit(*map, i);
+ }
+
+ for (i = 0; i < 7; i++)
+ assert(bitmap_tst_bit(*map, i) == true);
+
+ assert(bitmap_tst_bit(*map, 8) == false);
+
+
+ free(map);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-buddy.c b/roms/skiboot/core/test/run-buddy.c
new file mode 100644
index 000000000..8ae26cb6c
--- /dev/null
+++ b/roms/skiboot/core/test/run-buddy.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2016-2017 IBM Corp.
+ */
+
+#include <buddy.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static void *zalloc(size_t size)
+{
+ return calloc(size, 1);
+}
+
+#include "../buddy.c"
+#include "../bitmap.c"
+
+#define BUDDY_ORDER 8
+
+int main(void)
+{
+ struct buddy *b;
+ int i, a[10];
+
+ b = buddy_create(BUDDY_ORDER);
+ assert(b);
+
+ buddy_reserve(b, 127, 0);
+ buddy_reserve(b, 0, 4);
+ assert(buddy_reserve(b, 0, 4) == false);
+
+ a[0] = buddy_alloc(b, 0);
+ assert(a[0] >= 0);
+ a[1] = buddy_alloc(b, 0);
+ assert(a[1] >= 0);
+ a[2] = buddy_alloc(b, 3);
+ assert(a[2] >= 0);
+ a[3] = buddy_alloc(b, 4);
+ assert(a[3] >= 0);
+ a[4] = buddy_alloc(b, 5);
+ assert(a[4] >= 0);
+ a[5] = buddy_alloc(b, 4);
+ assert(a[5] >= 0);
+ a[6] = buddy_alloc(b, 3);
+ assert(a[6] >= 0);
+ a[7] = buddy_alloc(b, 2);
+ assert(a[7] >= 0);
+ a[8] = buddy_alloc(b, 1);
+ assert(a[8] >= 0);
+ a[9] = buddy_alloc(b, 8);
+ assert(a[9] < 0);
+
+ buddy_free(b, a[0], 0);
+ buddy_free(b, a[8], 1);
+ buddy_free(b, a[1], 0);
+ buddy_free(b, a[7], 2);
+ buddy_free(b, a[2], 3);
+ buddy_free(b, a[6], 3);
+ buddy_free(b, a[3], 4);
+ buddy_free(b, a[5], 4);
+ buddy_free(b, a[4], 5);
+
+ buddy_free(b, 127, 0);
+ buddy_free(b, 0, 4);
+
+ for (i = 2; i < buddy_map_size(b); i++)
+ assert(bitmap_tst_bit(b->map, i));
+ assert(!bitmap_tst_bit(b->map, 1));
+
+ buddy_destroy(b);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-console-log-buf-overrun.c b/roms/skiboot/core/test/run-console-log-buf-overrun.c
new file mode 100644
index 000000000..83774c4c9
--- /dev/null
+++ b/roms/skiboot/core/test/run-console-log-buf-overrun.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <compiler.h>
+
+unsigned long tb_hz = 512000000;
+
+#define __TEST__
+
+#define CHECK_BUF_ASSERT(buf, str) \
+ assert(memcmp(buf, str, strlen(str)) == 0)
+
+#define CHECK_ASSERT(str) \
+ CHECK_BUF_ASSERT(console_buffer, str)
+
+int huge_tb;
+
+static inline unsigned long mftb(void)
+{
+ /*
+ * return huge value for TB that overrun tmp[16] buffer defined
+ * in print_itoa().
+ */
+ if (huge_tb)
+ return 1223372515963611388;
+ else
+ return 42;
+}
+
+#include "../../libc/include/stdio.h"
+#include "../console-log.c"
+#include "../../libc/stdio/snprintf.c"
+#include "../../libc/stdio/vsnprintf.c"
+
+char console_buffer[4096];
+struct debug_descriptor debug_descriptor;
+
+bool flushed_to_drivers;
+
+ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count)
+{
+ flushed_to_drivers = flush_to_drivers;
+ memcpy(console_buffer, buf, count);
+ return count;
+}
+
+int main(void)
+{
+ unsigned long value = 0xffffffffffffffff;
+ char *ptr = console_buffer;
+
+ debug_descriptor.console_log_levels = 0x75;
+
+ /* Test for huge TB value. */
+ huge_tb = 1;
+
+ prlog(PR_EMERG, "Hello World");
+ CHECK_ASSERT("[2389399445.123611388,0] Hello World");
+
+ memset(console_buffer, 0, sizeof(console_buffer));
+
+ /* Test for normal TB with huge unsigned long value */
+ huge_tb = 0;
+
+ prlog(PR_EMERG, "Hello World %lu", value);
+ CHECK_ASSERT("[ 0.000000042,0] Hello World 18446744073709551615");
+
+ printf("Hello World %lu", value);
+ CHECK_ASSERT("[ 0.000000042,5] Hello World 18446744073709551615");
+
+ /*
+ * Test string of size > 320
+ *
+ * core/console-log.c:vprlog() uses buffer[320] to print message
+ * Try printing more than 320 bytes to test stack corruption.
+ * You would see Segmentation fault on stack corruption.
+ */
+ prlog(PR_EMERG, "%330s", "Hello World");
+
+ memset(console_buffer, 0, sizeof(console_buffer));
+
+ /*
+ * Test boundary condition.
+ *
+ * Print string of exact size 320. We should see string truncated
+ * with console_buffer[319] == '\0'.
+ */
+ memset(console_buffer, 0, sizeof(console_buffer));
+
+ prlog(PR_EMERG, "%300s", "Hello World");
+ assert(console_buffer[319] == 0);
+
+ /* compare truncated string */
+ ptr += 320 - strlen("Hello World");
+ CHECK_BUF_ASSERT(ptr, "Hello Worl");
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-console-log-pr_fmt.c b/roms/skiboot/core/test/run-console-log-pr_fmt.c
new file mode 100644
index 000000000..457de03fb
--- /dev/null
+++ b/roms/skiboot/core/test/run-console-log-pr_fmt.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#define __TEST__
+
+unsigned long tb_hz = 512000000;
+
+static inline unsigned long mftb(void)
+{
+ return 42;
+}
+
+#define pr_fmt(f) "PREFIX: " f
+#include "../../libc/include/stdio.h"
+#include "../console-log.c"
+#include "../../libc/stdio/snprintf.c"
+#include "../../libc/stdio/vsnprintf.c"
+
+struct debug_descriptor debug_descriptor;
+
+bool flushed_to_drivers;
+char console_buffer[4096];
+
+ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count)
+{
+ flushed_to_drivers = flush_to_drivers;
+ memcpy(console_buffer, buf, count);
+ return count;
+}
+
+int main(void)
+{
+ debug_descriptor.console_log_levels = 0x75;
+
+ prlog(PR_EMERG, "Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,0] PREFIX: Hello World") == 0);
+ assert(flushed_to_drivers==true);
+
+ memset(console_buffer, 0, sizeof(console_buffer));
+
+ // Below log level
+ prlog(PR_TRACE, "Hello World");
+ assert(console_buffer[0] == 0);
+
+ // Should not be flushed to console
+ prlog(PR_DEBUG, "Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,7] PREFIX: Hello World") == 0);
+ assert(flushed_to_drivers==false);
+
+ printf("Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,5] PREFIX: Hello World") == 0);
+ assert(flushed_to_drivers==true);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-console-log.c b/roms/skiboot/core/test/run-console-log.c
new file mode 100644
index 000000000..bec281b6e
--- /dev/null
+++ b/roms/skiboot/core/test/run-console-log.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2014-2016 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#define __TEST__
+
+#define _printf printf
+
+unsigned long tb_hz = 512000000;
+
+static inline unsigned long mftb(void)
+{
+ return 42;
+}
+
+int _printf(const char* fmt, ...);
+
+#include "../console-log.c"
+
+struct debug_descriptor debug_descriptor;
+
+bool flushed_to_drivers;
+char console_buffer[4096];
+
+ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count)
+{
+ flushed_to_drivers = flush_to_drivers;
+ memcpy(console_buffer, buf, count);
+ return count;
+}
+
+int main(void)
+{
+ debug_descriptor.console_log_levels = 0x75;
+
+ prlog(PR_EMERG, "Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,0] Hello World") == 0);
+ assert(flushed_to_drivers==true);
+
+ memset(console_buffer, 0, sizeof(console_buffer));
+
+ // Below log level
+ prlog(PR_TRACE, "Hello World");
+ assert(console_buffer[0] == 0);
+
+ // Should not be flushed to console
+ prlog(PR_DEBUG, "Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,7] Hello World") == 0);
+ assert(flushed_to_drivers==false);
+
+ printf("Hello World");
+ assert(strcmp(console_buffer, "[ 0.000000042,5] Hello World") == 0);
+ assert(flushed_to_drivers==true);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-cpufeatures.c b/roms/skiboot/core/test/run-cpufeatures.c
new file mode 100644
index 000000000..bb89b2573
--- /dev/null
+++ b/roms/skiboot/core/test/run-cpufeatures.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2019 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/* Override this for testing. */
+#define is_rodata(p) fake_is_rodata(p)
+
+char __rodata_start[16];
+#define __rodata_end (__rodata_start + sizeof(__rodata_start))
+
+static inline bool fake_is_rodata(const void *p)
+{
+ return ((char *)p >= __rodata_start && (char *)p < __rodata_end);
+}
+
+#define zalloc(bytes) calloc((bytes), 1)
+
+#include "../device.c"
+#include <assert.h>
+#include "../../test/dt_common.c"
+
+#define __TEST__
+
+static inline unsigned long mfspr(unsigned int spr);
+
+#include <ccan/str/str.c>
+
+#include "../cpufeatures.c"
+
+static unsigned long fake_pvr = PVR_TYPE_P8;
+
+static inline unsigned long mfspr(unsigned int spr)
+{
+ assert(spr == SPR_PVR);
+ return fake_pvr;
+}
+
+int main(void)
+{
+ struct dt_node *dt_root;
+
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, true);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P8E << 16) | 0x100; // P8E DD1.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P8E << 16) | 0x200; // P8E DD2.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P8 << 16) | 0x100; // P8 DD1.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P8 << 16) | 0x200; // P8 DD2.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P8NVL << 16) | 0x100; // P8NVL DD1.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P9 << 16) | 0x200; // P9 DD2.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix"));
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P9 << 16) | 0x201; // P9 DD2.1
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix"));
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") == 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P9 << 16) | 0x202; // P9 DD2.2
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix"));
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") != 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") != 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P9 << 16) | 0x203; // P9 DD2.3
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix"));
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") != 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ fake_pvr = (PVR_TYPE_P9P << 16) | 0x100; // P9P DD1.0
+ dt_root = dt_new_root("");
+ dt_add_cpufeatures(dt_root);
+ dump_dt(dt_root, 0, false);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/mmu-radix"));
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-hypervisor-assist") != 0);
+ assert(dt_find_by_path(dt_root, "cpus/ibm,powerpc-cpu-features/tm-suspend-xer-so-bug") == 0);
+ dt_free(dt_root);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/roms/skiboot/core/test/run-device.c b/roms/skiboot/core/test/run-device.c
new file mode 100644
index 000000000..4a12382bb
--- /dev/null
+++ b/roms/skiboot/core/test/run-device.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2012-2018 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <stdlib.h>
+
+/* Override this for testing. */
+#define is_rodata(p) fake_is_rodata(p)
+
+char __rodata_start[16];
+#define __rodata_end (__rodata_start + sizeof(__rodata_start))
+
+static inline bool fake_is_rodata(const void *p)
+{
+ return ((char *)p >= __rodata_start && (char *)p < __rodata_end);
+}
+
+#define zalloc(bytes) calloc((bytes), 1)
+
+#include "../device.c"
+#include <assert.h>
+#include "../../test/dt_common.c"
+const char *prop_to_fix[] = {"something", NULL};
+const char **props_to_fix(struct dt_node *node);
+
+static void check_path(const struct dt_node *node, const char * expected_path)
+{
+ char * path;
+ path = dt_get_path(node);
+ if (strcmp(path, expected_path) != 0) {
+ printf("check_path: expected %s, got %s\n", expected_path, path);
+ }
+ assert(strcmp(path, expected_path) == 0);
+ free(path);
+}
+
+/* constructs a random nodes only device tree */
+static void build_tree(int max_depth, int min_depth, struct dt_node *parent)
+{
+ char name[64];
+ int i;
+
+ for (i = 0; i < max_depth; i++) {
+ struct dt_node *new;
+
+ snprintf(name, sizeof name, "prefix@%.8x", rand());
+
+ new = dt_new(parent, name);
+
+ if(max_depth > min_depth)
+ build_tree(max_depth - 1, min_depth, new);
+ }
+}
+
+static bool is_sorted(const struct dt_node *root)
+{
+ struct dt_node *end = list_tail(&root->children, struct dt_node, list);
+ struct dt_node *node;
+
+ dt_for_each_child(root, node) {
+ struct dt_node *next =
+ list_entry(node->list.next, struct dt_node, list);
+
+ /* current node must be "less than" the next node */
+ if (node != end && dt_cmp_subnodes(node, next) != -1) {
+ printf("nodes '%s' and '%s' out of order\n",
+ node->name, next->name);
+
+ return false;
+ }
+
+ if (!is_sorted(node))
+ return false;
+ }
+
+ return true;
+}
+
+/*handler for phandle fixup test */
+const char **props_to_fix(struct dt_node *node)
+{
+ const struct dt_property *prop;
+
+ prop = dt_find_property(node, "something");
+ if (prop)
+ return prop_to_fix;
+
+ return NULL;
+}
+
+int main(void)
+{
+ struct dt_node *root, *other_root, *c1, *c2, *c2_c, *gc1, *gc2, *gc3, *ggc1, *ggc2;
+ struct dt_node *addrs, *addr1, *addr2;
+ struct dt_node *i, *subtree, *ev1, *ut1, *ut2;
+ const struct dt_property *p;
+ struct dt_property *p2;
+ unsigned int n;
+ char *s;
+ size_t sz;
+ u32 phandle, ev1_ph, new_prop_ph;
+
+ root = dt_new_root("");
+ assert(!list_top(&root->properties, struct dt_property, list));
+ check_path(root, "/");
+
+ c1 = dt_new_check(root, "c1");
+ assert(!list_top(&c1->properties, struct dt_property, list));
+ check_path(c1, "/c1");
+ assert(dt_find_by_name(root, "c1") == c1);
+ assert(dt_find_by_path(root, "/c1") == c1);
+ assert(dt_new(root, "c1") == NULL);
+
+ c2 = dt_new(root, "c2");
+ c2_c = dt_new_check(root, "c2");
+ assert(c2 == c2_c);
+ assert(!list_top(&c2->properties, struct dt_property, list));
+ check_path(c2, "/c2");
+ assert(dt_find_by_name(root, "c2") == c2);
+ assert(dt_find_by_path(root, "/c2") == c2);
+
+ gc1 = dt_new(c1, "gc1");
+ assert(!list_top(&gc1->properties, struct dt_property, list));
+ check_path(gc1, "/c1/gc1");
+ assert(dt_find_by_name(root, "gc1") == gc1);
+ assert(dt_find_by_path(root, "/c1/gc1") == gc1);
+
+ gc2 = dt_new(c1, "gc2");
+ assert(!list_top(&gc2->properties, struct dt_property, list));
+ check_path(gc2, "/c1/gc2");
+ assert(dt_find_by_name(root, "gc2") == gc2);
+ assert(dt_find_by_path(root, "/c1/gc2") == gc2);
+
+ gc3 = dt_new(c1, "gc3");
+ assert(!list_top(&gc3->properties, struct dt_property, list));
+ check_path(gc3, "/c1/gc3");
+ assert(dt_find_by_name(root, "gc3") == gc3);
+ assert(dt_find_by_path(root, "/c1/gc3") == gc3);
+
+ ggc1 = dt_new(gc1, "ggc1");
+ assert(!list_top(&ggc1->properties, struct dt_property, list));
+ check_path(ggc1, "/c1/gc1/ggc1");
+ assert(dt_find_by_name(root, "ggc1") == ggc1);
+ assert(dt_find_by_path(root, "/c1/gc1/ggc1") == ggc1);
+
+ addrs = dt_new(root, "addrs");
+ assert(!list_top(&addrs->properties, struct dt_property, list));
+ check_path(addrs, "/addrs");
+ assert(dt_find_by_name(root, "addrs") == addrs);
+ assert(dt_find_by_path(root, "/addrs") == addrs);
+
+ addr1 = dt_new_addr(addrs, "addr", 0x1337);
+ assert(!list_top(&addr1->properties, struct dt_property, list));
+ check_path(addr1, "/addrs/addr@1337");
+ assert(dt_find_by_name(root, "addr@1337") == addr1);
+ assert(dt_find_by_name_addr(root, "addr", 0x1337) == addr1);
+ assert(dt_find_by_path(root, "/addrs/addr@1337") == addr1);
+ assert(dt_new_addr(addrs, "addr", 0x1337) == NULL);
+
+ addr2 = dt_new_2addr(addrs, "2addr", 0xdead, 0xbeef);
+ assert(!list_top(&addr2->properties, struct dt_property, list));
+ check_path(addr2, "/addrs/2addr@dead,beef");
+ assert(dt_find_by_name(root, "2addr@dead,beef") == addr2);
+ assert(dt_find_by_path(root, "/addrs/2addr@dead,beef") == addr2);
+ assert(dt_new_2addr(addrs, "2addr", 0xdead, 0xbeef) == NULL);
+
+ /* Test walking the tree, checking and setting values */
+ for (n = 0, i = dt_first(root); i; i = dt_next(root, i), n++) {
+ assert(!list_top(&i->properties, struct dt_property, list));
+ dt_add_property_cells(i, "visited", 1);
+ }
+ assert(n == 9);
+
+ for (n = 0, i = dt_first(root); i; i = dt_next(root, i), n++) {
+ p = list_top(&i->properties, struct dt_property, list);
+ assert(strcmp(p->name, "visited") == 0);
+ assert(p->len == sizeof(u32));
+ assert(fdt32_to_cpu(*(u32 *)p->prop) == 1);
+ }
+ assert(n == 9);
+
+ /* Test cells */
+ dt_add_property_cells(c1, "some-property", 1, 2, 3);
+ p = dt_find_property(c1, "some-property");
+ assert(p);
+ assert(strcmp(p->name, "some-property") == 0);
+ assert(p->len == sizeof(u32) * 3);
+ assert(fdt32_to_cpu(*(u32 *)p->prop) == 1);
+ assert(dt_prop_get_cell(c1, "some-property", 0) == 1);
+ assert(fdt32_to_cpu(*((u32 *)p->prop + 1)) == 2);
+ assert(dt_prop_get_cell(c1, "some-property", 1) == 2);
+ assert(fdt32_to_cpu(*((u32 *)p->prop + 2)) == 3);
+ assert(dt_prop_get_cell_def(c1, "some-property", 2, 42) == 3);
+
+ assert(dt_prop_get_cell_def(c1, "not-a-property", 2, 42) == 42);
+
+ /* Test u64s */
+ dt_add_property_u64s(c2, "some-property", (2LL << 33), (3LL << 33), (4LL << 33));
+ p = dt_find_property(c2, "some-property");
+ assert(p);
+ assert(p->len == sizeof(u64) * 3);
+ assert(fdt64_to_cpu(*(u64 *)p->prop) == (2LL << 33));
+ assert(fdt64_to_cpu(*((u64 *)p->prop + 1)) == (3LL << 33));
+ assert(fdt64_to_cpu(*((u64 *)p->prop + 2)) == (4LL << 33));
+
+ /* Test u32/u64 get defaults */
+ assert(dt_prop_get_u32_def(c1, "u32", 42) == 42);
+ dt_add_property_cells(c1, "u32", 1337);
+ assert(dt_prop_get_u32_def(c1, "u32", 42) == 1337);
+ assert(dt_prop_get_u32(c1, "u32") == 1337);
+
+ assert(dt_prop_get_u64_def(c1, "u64", (42LL << 42)) == (42LL << 42));
+ dt_add_property_u64s(c1, "u64", (1337LL << 42));
+ assert(dt_prop_get_u64_def(c1, "u64", (42LL << 42)) == (1337LL << 42));
+ assert(dt_prop_get_u64(c1, "u64") == (1337LL << 42));
+
+ /* Test freeing a single node */
+ assert(!list_empty(&gc1->children));
+ dt_free(ggc1);
+ assert(list_empty(&gc1->children));
+
+ /* Test rodata logic. */
+ assert(!is_rodata("hello"));
+ assert(is_rodata(__rodata_start));
+ strcpy(__rodata_start, "name");
+ ggc1 = dt_new(root, __rodata_start);
+ assert(ggc1->name == __rodata_start);
+
+ /* Test string node. */
+ dt_add_property_string(ggc1, "somestring", "someval");
+ assert(dt_has_node_property(ggc1, "somestring", "someval"));
+ assert(!dt_has_node_property(ggc1, "somestrin", "someval"));
+ assert(!dt_has_node_property(ggc1, "somestring", "someva"));
+ assert(!dt_has_node_property(ggc1, "somestring", "somevale"));
+
+ /* Test nstr, which allows for non-null-terminated inputs */
+ dt_add_property_nstr(ggc1, "nstring", "somevalue_long", 7);
+ assert(dt_has_node_property(ggc1, "nstring", "someval"));
+ assert(!dt_has_node_property(ggc1, "nstring", "someva"));
+ assert(!dt_has_node_property(ggc1, "nstring", "somevalue_long"));
+
+ /* Test multiple strings */
+ dt_add_property_strings(ggc1, "somestrings",
+ "These", "are", "strings!");
+ p = dt_find_property(ggc1, "somestrings");
+ assert(p);
+ assert(p->len == sizeof(char) * (6 + 4 + 9));
+ s = (char *)p->prop;
+ assert(strcmp(s, "These") == 0);
+ assert(strlen(s) == 5);
+ s += 6;
+ assert(strcmp(s, "are") == 0);
+ assert(strlen(s) == 3);
+ s += 4;
+ assert(strcmp(s, "strings!") == 0);
+ assert(strlen(s) == 8);
+ s += 9;
+ assert(s == (char *)p->prop + p->len);
+ assert(dt_prop_find_string(p, "These"));
+ /* dt_prop_find_string is case insensitve */
+ assert(dt_prop_find_string(p, "ARE"));
+ assert(!dt_prop_find_string(p, "integers!"));
+ /* And always returns false for NULL properties */
+ assert(!dt_prop_find_string(NULL, "anything!"));
+
+ /* Test more get/get_def varieties */
+ assert(dt_prop_get_def(c1, "does-not-exist", NULL) == NULL);
+ sz = 0xbad;
+ assert(dt_prop_get_def_size(c1, "does-not-exist", NULL, &sz) == NULL);
+ assert(sz == 0);
+ dt_add_property_string(c1, "another-property", "xyzzy");
+ assert(dt_prop_get_def(c1, "another-property", NULL) != NULL);
+ assert(strcmp(dt_prop_get(c1, "another-property"), "xyzzy") == 0);
+ n = 0xbad;
+ assert(dt_prop_get_def_size(c1, "another-property", NULL, &sz) != NULL);
+ assert(sz == strlen("xyzzy") + 1);
+
+ /* Test resizing property. */
+ p = p2 = __dt_find_property(c1, "some-property");
+ assert(p);
+ n = p2->len;
+ while (p2 == p) {
+ n *= 2;
+ dt_resize_property(&p2, n);
+ }
+
+ assert(dt_find_property(c1, "some-property") == p2);
+ list_check(&c1->properties, "properties after resizing");
+
+ dt_del_property(c1, p2);
+ list_check(&c1->properties, "properties after delete");
+
+ /* No leaks for valgrind! */
+ dt_free(root);
+
+ /* Test compatible and chip id. */
+ root = dt_new_root("");
+
+ c1 = dt_new(root, "chip1");
+ dt_add_property_cells(c1, "ibm,chip-id", 0xcafe);
+ assert(dt_get_chip_id(c1) == 0xcafe);
+ dt_add_property_strings(c1, "compatible",
+ "specific-fake-chip",
+ "generic-fake-chip");
+ assert(dt_node_is_compatible(c1, "specific-fake-chip"));
+ assert(dt_node_is_compatible(c1, "generic-fake-chip"));
+
+ c2 = dt_new(root, "chip2");
+ dt_add_property_cells(c2, "ibm,chip-id", 0xbeef);
+ assert(dt_get_chip_id(c2) == 0xbeef);
+ dt_add_property_strings(c2, "compatible",
+ "specific-fake-bus",
+ "generic-fake-bus");
+
+ gc1 = dt_new(c1, "coprocessor1");
+ dt_add_property_strings(gc1, "compatible",
+ "specific-fake-coprocessor");
+ gc2 = dt_new(gc1, "coprocessor2");
+ dt_add_property_strings(gc2, "compatible",
+ "specific-fake-coprocessor");
+ gc3 = dt_new(c1, "coprocessor3");
+ dt_add_property_strings(gc3, "compatible",
+ "specific-fake-coprocessor");
+
+
+ assert(dt_find_compatible_node(root, NULL, "generic-fake-bus") == c2);
+ assert(dt_find_compatible_node(root, c2, "generic-fake-bus") == NULL);
+
+ /* we can find all compatible nodes */
+ assert(dt_find_compatible_node(c1, NULL, "specific-fake-coprocessor") == gc1);
+ assert(dt_find_compatible_node(c1, gc1, "specific-fake-coprocessor") == gc2);
+ assert(dt_find_compatible_node(c1, gc2, "specific-fake-coprocessor") == gc3);
+ assert(dt_find_compatible_node(c1, gc3, "specific-fake-coprocessor") == NULL);
+ assert(dt_find_compatible_node(root, NULL, "specific-fake-coprocessor") == gc1);
+ assert(dt_find_compatible_node(root, gc1, "specific-fake-coprocessor") == gc2);
+ assert(dt_find_compatible_node(root, gc2, "specific-fake-coprocessor") == gc3);
+ assert(dt_find_compatible_node(root, gc3, "specific-fake-coprocessor") == NULL);
+
+ /* we can find the coprocessor once on the cpu */
+ assert(dt_find_compatible_node_on_chip(root,
+ NULL,
+ "specific-fake-coprocessor",
+ 0xcafe) == gc1);
+ assert(dt_find_compatible_node_on_chip(root,
+ gc1,
+ "specific-fake-coprocessor",
+ 0xcafe) == gc2);
+ assert(dt_find_compatible_node_on_chip(root,
+ gc2,
+ "specific-fake-coprocessor",
+ 0xcafe) == gc3);
+ assert(dt_find_compatible_node_on_chip(root,
+ gc3,
+ "specific-fake-coprocessor",
+ 0xcafe) == NULL);
+
+ /* we can't find the coprocessor on the bus */
+ assert(dt_find_compatible_node_on_chip(root,
+ NULL,
+ "specific-fake-coprocessor",
+ 0xbeef) == NULL);
+
+ /* Test phandles. We override the automatically generated one. */
+ phandle = 0xf00;
+ dt_add_property(gc3, "phandle", (const void *)&phandle, 4);
+ assert(last_phandle == 0xf00);
+ assert(dt_find_by_phandle(root, 0xf00) == gc3);
+ assert(dt_find_by_phandle(root, 0xf0f) == NULL);
+
+ dt_free(root);
+
+ /* basic sorting */
+ root = dt_new_root("rewt");
+ dt_new(root, "a@1");
+ dt_new(root, "a@2");
+ dt_new(root, "a@3");
+ dt_new(root, "a@4");
+ dt_new(root, "b@4");
+ dt_new(root, "c@4");
+
+ assert(is_sorted(root));
+
+ /* Now test dt_attach_root */
+ other_root = dt_new_root("other_root");
+ dt_new(other_root, "d@1");
+
+ assert(dt_attach_root(root, other_root));
+ other_root = dt_new_root("other_root");
+ assert(!dt_attach_root(root, other_root));
+ dt_free(root);
+
+ /* Test child node sorting */
+ root = dt_new_root("test root");
+ build_tree(5, 3, root);
+
+ if (!is_sorted(root)) {
+ dump_dt(root, 1, false);
+ }
+ assert(is_sorted(root));
+
+ dt_free(root);
+
+ /* check dt_translate_address */
+
+ /* NB: the root bus has two address cells */
+ root = dt_new_root("");
+
+ c1 = dt_new_addr(root, "some-32bit-bus", 0x80000000);
+ dt_add_property_cells(c1, "#address-cells", 1);
+ dt_add_property_cells(c1, "#size-cells", 1);
+ dt_add_property_cells(c1, "ranges", 0x0, 0x8, 0x0, 0x1000);
+
+ gc1 = dt_new_addr(c1, "test", 0x0500);
+ dt_add_property_cells(gc1, "reg", 0x0500, 0x10);
+
+ assert(dt_translate_address(gc1, 0, NULL) == 0x800000500ul);
+
+ /* try three level translation */
+
+ gc2 = dt_new_addr(c1, "another-32bit-bus", 0x40000000);
+ dt_add_property_cells(gc2, "#address-cells", 1);
+ dt_add_property_cells(gc2, "#size-cells", 1);
+ dt_add_property_cells(gc2, "ranges", 0x0, 0x600, 0x100,
+ 0x100, 0x800, 0x100);
+
+ ggc1 = dt_new_addr(gc2, "test", 0x50);
+ dt_add_property_cells(ggc1, "reg", 0x50, 0x10);
+ assert(dt_translate_address(ggc1, 0, NULL) == 0x800000650ul);
+
+ /* test multiple ranges work */
+ ggc2 = dt_new_addr(gc2, "test", 0x150);
+ dt_add_property_cells(ggc2, "reg", 0x150, 0x10);
+ assert(dt_translate_address(ggc2, 0, NULL) == 0x800000850ul);
+
+ /* try 64bit -> 64bit */
+
+ c2 = dt_new_addr(root, "some-64bit-bus", 0xe00000000);
+ dt_add_property_cells(c2, "#address-cells", 2);
+ dt_add_property_cells(c2, "#size-cells", 2);
+ dt_add_property_cells(c2, "ranges", 0x0, 0x0, 0xe, 0x0, 0x2, 0x0);
+
+ gc2 = dt_new_addr(c2, "test", 0x100000000ul);
+ dt_add_property_u64s(gc2, "reg", 0x100000000ul, 0x10ul);
+ assert(dt_translate_address(gc2, 0, NULL) == 0xf00000000ul);
+
+ dt_free(root);
+
+ /* phandle fixup test */
+ subtree = dt_new_root("subtree");
+ ev1 = dt_new(subtree, "ev@1");
+ ev1_ph = ev1->phandle;
+ dt_new(ev1,"a@1");
+ dt_new(ev1,"a@2");
+ dt_new(ev1,"a@3");
+ ut1 = dt_new(subtree, "ut@1");
+ dt_add_property(ut1, "something", (const void *)&ev1->phandle, 4);
+ ut2 = dt_new(subtree, "ut@2");
+ dt_add_property(ut2, "something", (const void *)&ev1->phandle, 4);
+
+ dt_adjust_subtree_phandle(subtree, props_to_fix);
+ assert(!(ev1->phandle == ev1_ph));
+ new_prop_ph = dt_prop_get_u32(ut1, "something");
+ assert(!(new_prop_ph == ev1_ph));
+ new_prop_ph = dt_prop_get_u32(ut2, "something");
+ assert(!(new_prop_ph == ev1_ph));
+ dt_free(subtree);
+ return 0;
+}
+
diff --git a/roms/skiboot/core/test/run-flash-firmware-versions.c b/roms/skiboot/core/test/run-flash-firmware-versions.c
new file mode 100644
index 000000000..9f96f5c19
--- /dev/null
+++ b/roms/skiboot/core/test/run-flash-firmware-versions.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2018-2019 IBM Corp.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdint.h>
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+
+
+#include <interrupts.h>
+#include <bitutils.h>
+
+#include <compiler.h>
+
+/*
+ * Skiboot malloc stubs
+ *
+ * The actual prototypes for these are defined in mem_region-malloc.h,
+ * but that file also #defines malloc, and friends so we don't pull that in
+ * directly.
+ */
+
+#define DEFAULT_ALIGN __alignof__(long)
+
+void *__memalign(size_t blocksize, size_t bytes, const char *location __unused);
+void *__memalign(size_t blocksize, size_t bytes, const char *location __unused)
+{
+ return memalign(blocksize, bytes);
+}
+
+void *__malloc(size_t bytes, const char *location);
+void *__malloc(size_t bytes, const char *location)
+{
+ return __memalign(DEFAULT_ALIGN, bytes, location);
+}
+
+void __free(void *p, const char *location __unused);
+void __free(void *p, const char *location __unused)
+{
+ free(p);
+}
+
+void *__realloc(void *ptr, size_t size, const char *location __unused);
+void *__realloc(void *ptr, size_t size, const char *location __unused)
+{
+ return realloc(ptr, size);
+}
+
+void *__zalloc(size_t bytes, const char *location);
+void *__zalloc(size_t bytes, const char *location)
+{
+ void *p = __malloc(bytes, location);
+
+ if (p)
+ memset(p, 0, bytes);
+ return p;
+}
+
+#include <mem_region-malloc.h>
+
+#include <opal-api.h>
+
+#include "../../libfdt/fdt.c"
+#include "../../libfdt/fdt_ro.c"
+#include "../../libfdt/fdt_sw.c"
+#include "../../libfdt/fdt_strerror.c"
+
+#include "../../core/device.c"
+
+#include "../../libstb/container-utils.h"
+#include "../../libstb/container.h"
+#include "../../libstb/container.c"
+
+#include "../flash-firmware-versions.c"
+#include <assert.h>
+
+char __rodata_start[1], __rodata_end[1];
+
+const char version[]="Hello world!";
+
+enum proc_gen proc_gen = proc_gen_p8;
+
+static char *loaded_version_buf;
+static size_t loaded_version_buf_size;
+
+#define min(x,y) ((x) < (y) ? x : y)
+
+int start_preload_resource(enum resource_id id, uint32_t subid,
+ void *buf, size_t *len)
+{
+ (void)id;
+ (void)subid;
+ (void)buf;
+ if (loaded_version_buf) {
+ *len = min(*len, loaded_version_buf_size);
+ memcpy(buf, loaded_version_buf, *len);
+ } else {
+ *len = 0;
+ }
+
+ return 0;
+}
+
+int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
+{
+ (void)id;
+ (void)idx;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct stat ver_st;
+ int r;
+
+ dt_root = dt_new_root("");
+
+ if (argc > 1) {
+ fd = open(argv[1], O_RDONLY);
+
+ assert(fd > 0);
+ r = fstat(fd, &ver_st);
+ assert(r == 0);
+
+ loaded_version_buf = mmap(NULL, ver_st.st_size,
+ PROT_READ, MAP_PRIVATE, fd, 0);
+ assert(loaded_version_buf != (char*)-1);
+ loaded_version_buf_size = ver_st.st_size;
+ }
+
+ flash_fw_version_preload();
+
+ proc_gen = proc_gen_p9;
+ flash_fw_version_preload();
+ flash_dt_add_fw_version();
+
+ return 0;
+}
+
diff --git a/roms/skiboot/core/test/run-flash-subpartition.c b/roms/skiboot/core/test/run-flash-subpartition.c
new file mode 100644
index 000000000..5b6df87f2
--- /dev/null
+++ b/roms/skiboot/core/test/run-flash-subpartition.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2016 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <opal-api.h>
+#include <stdlib.h>
+
+#include "../flash-subpartition.c"
+#include <assert.h>
+
+/* This is a straight dump of the CAPP ucode partition header */
+char capp[4096] = {0x43, 0x41, 0x50, 0x50, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0xea, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x8e, 0x50, 0x00, 0x02, 0x00, 0xea,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x8e, 0x50,
+ 0x00, 0x02, 0x00, 0xef, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x8e, 0x50, 0x00, 0x02, 0x01, 0xef,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x8e, 0x50,
+ 0x00, 0x01, 0x00, 0xd3, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x8e, 0x50, 0x00, 0x00, 0x00, 0x00 };
+
+int main(void)
+{
+ int rc;
+ uint32_t part_actual;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t subids[] = { 0x100ea, 0x200ea, 0x200ef, 0x201ef, 0x100d3 };
+
+ for (int i = 0; i < sizeof(subids)/sizeof(uint32_t); i++) {
+ offset = 0;
+ rc = flash_subpart_info(capp, sizeof(capp), 0x24000,
+ &part_actual, subids[i],
+ &offset, &size);
+ printf("\nsubid %x\n", subids[i]);
+ printf("part_actual %u\n", part_actual);
+ printf("offset %u\n", offset);
+ printf("size %u\n", size);
+ assert (rc == 0);
+ assert (size == 36432);
+ assert (offset == 4096);
+ assert (part_actual == 40960);
+ }
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-malloc-speed.c b/roms/skiboot/core/test/run-malloc-speed.c
new file mode 100644
index 000000000..39a24f9cb
--- /dev/null
+++ b/roms/skiboot/core/test/run-malloc-speed.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+/* Use these before we undefine them below. */
+static inline void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void real_free(void *p)
+{
+ return free(p);
+}
+
+#include <skiboot.h>
+
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../malloc.c"
+#include "../mem_region.c"
+#include "../device.c"
+
+#undef malloc
+#undef free
+#undef realloc
+
+#include <assert.h>
+#include <stdio.h>
+
+char __rodata_start[1], __rodata_end[1];
+struct dt_node *dt_root;
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val = 1;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val = 0;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 27
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+#define NUM_ALLOCS 4096
+
+int main(void)
+{
+ uint64_t i, len;
+ void **p = real_malloc(sizeof(void*)*NUM_ALLOCS);
+
+ assert(p);
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (unsigned long)real_malloc(skiboot_heap.len);
+
+ len = skiboot_heap.len / NUM_ALLOCS - sizeof(struct alloc_hdr);
+ for (i = 0; i < NUM_ALLOCS; i++) {
+ p[i] = __malloc(len, __location__);
+ assert(p[i] > region_start(&skiboot_heap));
+ assert(p[i] + len <= region_start(&skiboot_heap)
+ + skiboot_heap.len);
+ }
+ assert(mem_check(&skiboot_heap));
+ assert(skiboot_heap.free_list_lock.lock_val == 0);
+ free(region_start(&skiboot_heap));
+ real_free(p);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-malloc.c b/roms/skiboot/core/test/run-malloc.c
new file mode 100644
index 000000000..10cc64e86
--- /dev/null
+++ b/roms/skiboot/core/test/run-malloc.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+/* Use these before we undefine them below. */
+static inline void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void real_free(void *p)
+{
+ return free(p);
+}
+
+#undef malloc
+#undef free
+#undef realloc
+
+#include <skiboot.h>
+
+#define is_rodata(p) true
+
+#include "../mem_region.c"
+#include "../malloc.c"
+#include "../device.c"
+
+#include "mem_region-malloc.h"
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+struct dt_node *dt_root;
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val = 1;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val = 0;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+static bool heap_empty(void)
+{
+ const struct alloc_hdr *h = region_start(&skiboot_heap);
+ return h->num_longs == skiboot_heap.len / sizeof(long);
+}
+
+int main(void)
+{
+ char *test_heap = real_malloc(TEST_HEAP_SIZE);
+ char *p, *p2, *p3, *p4;
+ char *pr;
+ size_t i;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (unsigned long)test_heap;
+ skiboot_heap.len = TEST_HEAP_SIZE;
+
+ /* Allocations of various sizes. */
+ for (i = 0; i < TEST_HEAP_ORDER; i++) {
+ p = malloc(1ULL << i);
+ assert(p);
+ assert(p > (char *)test_heap);
+ assert(p + (1ULL << i) <= (char *)test_heap + TEST_HEAP_SIZE);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ free(p);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(heap_empty());
+ }
+
+ /* Realloc as malloc. */
+ skiboot_heap.free_list_lock.lock_val = 0;
+ p = realloc(NULL, 100);
+ assert(p);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+
+ /* Realloc as free. */
+ p = realloc(p, 0);
+ assert(!p);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(heap_empty());
+
+ /* Realloc longer. */
+ p = realloc(NULL, 100);
+ assert(p);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ p2 = realloc(p, 200);
+ assert(p2 == p);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ free(p2);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(heap_empty());
+
+ /* Realloc shorter. */
+ skiboot_heap.free_list_lock.lock_val = 0;
+ p = realloc(NULL, 100);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(p);
+ p2 = realloc(p, 1);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(p2 == p);
+ free(p2);
+ assert(!skiboot_heap.free_list_lock.lock_val);
+ assert(heap_empty());
+
+ /* zalloc failure */
+ p2 = zalloc(TEST_HEAP_SIZE * 2);
+ assert(p2 == NULL);
+
+ /* Realloc with move. */
+ p2 = malloc(TEST_HEAP_SIZE - 64 - sizeof(struct alloc_hdr)*2);
+ memset(p2, 'a', TEST_HEAP_SIZE - 64 - sizeof(struct alloc_hdr)*2);
+ assert(p2);
+ p = malloc(64);
+ memset(p, 'b', 64);
+ p[63] = 'c';
+ assert(p);
+ free(p2);
+
+ p2 = realloc(p, 128);
+ assert(p2 != p);
+ assert(p2[63] == 'c');
+ free(p2);
+ assert(heap_empty());
+ assert(!skiboot_heap.free_list_lock.lock_val);
+
+ /* Realloc with failure to allocate new size */
+ p2 = malloc(TEST_HEAP_SIZE - sizeof(struct alloc_hdr)*2);
+ assert(p2);
+ memset(p2, 'a', TEST_HEAP_SIZE - sizeof(struct alloc_hdr)*2);
+ p = p2;
+ p2 = realloc(p, TEST_HEAP_SIZE*2);
+ assert(p2==NULL);
+ memset(p, 'b', TEST_HEAP_SIZE - sizeof(struct alloc_hdr)*2);
+ free(p);
+
+ /* Reproduce bug BZ109128/SW257364 */
+ p = malloc(100);
+ p2 = malloc(100);
+ p3 = malloc(100);
+ p4 = malloc(100);
+ free(p2);
+ pr = realloc(p,216);
+ assert(pr);
+ free(p3);
+ free(pr);
+ free(p4);
+ assert(heap_empty());
+ assert(!skiboot_heap.free_list_lock.lock_val);
+
+ real_free(test_heap);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_range_is_reserved.c b/roms/skiboot/core/test/run-mem_range_is_reserved.c
new file mode 100644
index 000000000..9891dbd9a
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_range_is_reserved.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2019 IBM Corp.
+ */
+
+#include <config.h>
+
+/* The lock backtrace structures consume too much room on the skiboot heap */
+#undef DEBUG_LOCKS_BACKTRACE
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+static void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static void real_free(void *p)
+{
+ return free(p);
+}
+
+#undef malloc
+#undef free
+#undef realloc
+
+#include <skiboot.h>
+#include <mem_region-malloc.h>
+
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../mem_region.c"
+#include "../malloc.c"
+
+/* But we need device tree to make copies of names. */
+#undef is_rodata
+#define is_rodata(p) false
+#include "../../libc/string/strdup.c"
+
+#include "../device.c"
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static void add_mem_node(uint64_t start, uint64_t len)
+{
+ struct dt_node *mem;
+ u64 reg[2];
+ char *name;
+
+ name = (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0]));
+ assert(name);
+
+ /* reg contains start and length */
+ reg[0] = cpu_to_be64(start);
+ reg[1] = cpu_to_be64(len);
+
+ sprintf(name, "memory@%llx", (long long)start);
+
+ mem = dt_new(dt_root, name);
+ dt_add_property_string(mem, "device_type", "memory");
+ dt_add_property(mem, "reg", reg, sizeof(reg));
+ free(name);
+}
+
+void add_chip_dev_associativity(struct dt_node *dev __attribute__((unused)))
+{
+}
+
+struct test_region {
+ uint64_t start;
+ uint64_t end;
+};
+
+static struct test {
+ struct test_region regions[3];
+ bool reserved;
+} tests[] = {
+ /* empty region set */
+ { { { 0 } }, false },
+
+ /* single exact match */
+ { { { 0x1000, 0x2000 }, }, true },
+
+ /* overlap downwards */
+ { { { 0x0fff, 0x2000 }, }, true },
+
+ /* overlap upwards */
+ { { { 0x1000, 0x2001 }, }, true },
+
+ /* missing first byte */
+ { { { 0x1001, 0x2000 }, }, false },
+
+ /* missing last byte */
+ { { { 0x1000, 0x1fff }, }, false },
+
+ /* two regions, full coverage, split before start of range */
+ { { { 0x0500, 0x1000 }, { 0x1000, 0x2500 } }, true },
+
+ /* two regions, full coverage, split after start of range */
+ { { { 0x0500, 0x1001 }, { 0x1001, 0x2500 } }, true },
+
+ /* two regions, full coverage, split at middle of range */
+ { { { 0x0500, 0x1500 }, { 0x1500, 0x2500 } }, true },
+
+ /* two regions, full coverage, split before end of range */
+ { { { 0x0500, 0x1fff }, { 0x1fff, 0x2500 } }, true },
+
+ /* two regions, full coverage, split after end of range */
+ { { { 0x0500, 0x2000 }, { 0x2000, 0x2500 } }, true },
+
+ /* two regions, missing byte in middle of range */
+ { { { 0x0500, 0x14ff }, { 0x1500, 0x2500 } }, false },
+
+ /* two regions, missing byte after start of range */
+ { { { 0x0500, 0x1000 }, { 0x1001, 0x2500 } }, false },
+
+ /* two regions, missing byte before end of range */
+ { { { 0x0500, 0x1fff }, { 0x2000, 0x2500 } }, false },
+};
+
+static void run_test(struct test *test)
+{
+ struct test_region *r;
+ bool reserved;
+
+ list_head_init(&regions);
+
+ mem_region_init();
+
+ /* create our reservations */
+ for (r = test->regions; r->start; r++)
+ mem_reserve_fw("r", r->start, r->end - r->start);
+
+ reserved = mem_range_is_reserved(0x1000, 0x1000);
+
+ if (reserved != test->reserved) {
+ struct mem_region *r;
+ fprintf(stderr, "test failed; got %s, expected %s\n",
+ reserved ? "reserved" : "unreserved",
+ test->reserved ? "reserved" : "unreserved");
+
+ fprintf(stderr, "reserved regions:\n");
+
+ list_for_each(&regions, r, list) {
+ fprintf(stderr, "\t: %08"PRIx64"[%08"PRIx64"] %s\n",
+ r->start, r->len, r->name);
+ }
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+int main(void)
+{
+ unsigned int i;
+ void *buf;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (long)real_malloc(TEST_HEAP_SIZE);
+ skiboot_heap.len = TEST_HEAP_SIZE;
+
+ /* shift the OS reserve area out of the way of our playground */
+ skiboot_os_reserve.start = 0x100000;
+ skiboot_os_reserve.len = 0x1000;
+
+ dt_root = dt_new_root("");
+ dt_add_property_cells(dt_root, "#address-cells", 2);
+ dt_add_property_cells(dt_root, "#size-cells", 2);
+
+ buf = real_malloc(1024*1024);
+ add_mem_node((unsigned long)buf, 1024*1024);
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++)
+ run_test(&tests[i]);
+
+ dt_free(dt_root);
+ real_free(buf);
+ real_free((void *)(long)skiboot_heap.start);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region.c b/roms/skiboot/core/test/run-mem_region.c
new file mode 100644
index 000000000..50da8033c
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/* The lock backtrace structures consume too much room on the skiboot heap */
+#undef DEBUG_LOCKS_BACKTRACE
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Use these before we override definitions below. */
+static void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void real_free(void *p)
+{
+ return free(p);
+}
+
+#undef malloc
+#undef free
+#undef realloc
+
+#include <skiboot.h>
+
+#define is_rodata(p) true
+
+#include "../mem_region.c"
+#include "../malloc.c"
+#include "../device.c"
+
+#include <assert.h>
+#include <stdio.h>
+
+struct dt_node *dt_root;
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static bool heap_empty(void)
+{
+ const struct alloc_hdr *h = region_start(&skiboot_heap);
+ return h->num_longs == skiboot_heap.len / sizeof(long);
+}
+
+int main(void)
+{
+ char *test_heap;
+ void *p, *ptrs[100];
+ size_t i;
+ struct mem_region *r;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ test_heap = real_malloc(TEST_HEAP_SIZE);
+ skiboot_heap.start = (unsigned long)test_heap;
+ skiboot_heap.len = TEST_HEAP_SIZE;
+
+ lock(&skiboot_heap.free_list_lock);
+
+ /* Allocations of various sizes. */
+ for (i = 0; i < TEST_HEAP_ORDER; i++) {
+ p = mem_alloc(&skiboot_heap, 1ULL << i, 1, "here");
+ assert(p);
+ assert(mem_check(&skiboot_heap));
+ assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "here"));
+ assert(p > (void *)test_heap);
+ assert(p + (1ULL << i) <= (void *)test_heap + TEST_HEAP_SIZE);
+ assert(mem_allocated_size(p) >= 1ULL << i);
+ mem_free(&skiboot_heap, p, "freed");
+ assert(heap_empty());
+ assert(mem_check(&skiboot_heap));
+ assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "freed"));
+ }
+ p = mem_alloc(&skiboot_heap, 1ULL << i, 1, "here");
+ assert(!p);
+ mem_free(&skiboot_heap, p, "freed");
+ assert(heap_empty());
+ assert(mem_check(&skiboot_heap));
+
+ /* Allocations of various alignments: use small alloc first. */
+ ptrs[0] = mem_alloc(&skiboot_heap, 1, 1, "small");
+ for (i = 0; ; i++) {
+ p = mem_alloc(&skiboot_heap, 1, 1ULL << i, "here");
+ assert(mem_check(&skiboot_heap));
+ /* We will eventually fail... */
+ if (!p) {
+ assert(i >= TEST_HEAP_ORDER);
+ break;
+ }
+ assert(p);
+ assert((long)p % (1ULL << i) == 0);
+ assert(p > (void *)test_heap);
+ assert(p + 1 <= (void *)test_heap + TEST_HEAP_SIZE);
+ mem_free(&skiboot_heap, p, "freed");
+ assert(mem_check(&skiboot_heap));
+ }
+ mem_free(&skiboot_heap, ptrs[0], "small freed");
+ assert(heap_empty());
+ assert(mem_check(&skiboot_heap));
+
+ /* Many little allocations, freed in reverse order. */
+ for (i = 0; i < 100; i++) {
+ ptrs[i] = mem_alloc(&skiboot_heap, sizeof(long), 1, "here");
+ assert(ptrs[i]);
+ assert(ptrs[i] > (void *)test_heap);
+ assert(ptrs[i] + sizeof(long)
+ <= (void *)test_heap + TEST_HEAP_SIZE);
+ assert(mem_check(&skiboot_heap));
+ }
+ mem_dump_free();
+ for (i = 0; i < 100; i++)
+ mem_free(&skiboot_heap, ptrs[100 - 1 - i], "freed");
+
+ assert(heap_empty());
+ assert(mem_check(&skiboot_heap));
+
+ /* Check the prev_free gets updated properly. */
+ ptrs[0] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[0]");
+ ptrs[1] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[1]");
+ assert(ptrs[1] > ptrs[0]);
+ mem_free(&skiboot_heap, ptrs[0], "ptrs[0] free");
+ assert(mem_check(&skiboot_heap));
+ ptrs[0] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[0] again");
+ assert(mem_check(&skiboot_heap));
+ mem_free(&skiboot_heap, ptrs[1], "ptrs[1] free");
+ mem_free(&skiboot_heap, ptrs[0], "ptrs[0] free");
+ assert(mem_check(&skiboot_heap));
+ assert(heap_empty());
+
+#if 0
+ printf("Heap map:\n");
+ for (i = 0; i < TEST_HEAP_SIZE / sizeof(long); i++) {
+ printf("%u", test_bit(skiboot_heap.bitmap, i));
+ if (i % 64 == 63)
+ printf("\n");
+ else if (i % 8 == 7)
+ printf(" ");
+ }
+#endif
+
+ /* Simple enlargement, then free */
+ p = mem_alloc(&skiboot_heap, 1, 1, "one byte");
+ assert(p);
+ assert(mem_resize(&skiboot_heap, p, 100, "hundred bytes"));
+ assert(mem_allocated_size(p) >= 100);
+ assert(mem_check(&skiboot_heap));
+ assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "hundred bytes"));
+ mem_free(&skiboot_heap, p, "freed");
+
+ /* Simple shrink, then free */
+ p = mem_alloc(&skiboot_heap, 100, 1, "100 bytes");
+ assert(p);
+ assert(mem_resize(&skiboot_heap, p, 1, "1 byte"));
+ assert(mem_allocated_size(p) < 100);
+ assert(mem_check(&skiboot_heap));
+ assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "1 byte"));
+ mem_free(&skiboot_heap, p, "freed");
+
+ /* Lots of resizing (enlarge). */
+ p = mem_alloc(&skiboot_heap, 1, 1, "one byte");
+ assert(p);
+ for (i = 1; i <= TEST_HEAP_SIZE - sizeof(struct alloc_hdr); i++) {
+ assert(mem_resize(&skiboot_heap, p, i, "enlarge"));
+ assert(mem_allocated_size(p) >= i);
+ assert(mem_check(&skiboot_heap));
+ }
+
+ /* Can't make it larger though. */
+ assert(!mem_resize(&skiboot_heap, p, i, "enlarge"));
+
+ for (i = TEST_HEAP_SIZE - sizeof(struct alloc_hdr); i > 0; i--) {
+ assert(mem_resize(&skiboot_heap, p, i, "shrink"));
+ assert(mem_check(&skiboot_heap));
+ }
+
+ mem_free(&skiboot_heap, p, "freed");
+ assert(mem_check(&skiboot_heap));
+
+ unlock(&skiboot_heap.free_list_lock);
+
+ /* lock the regions list */
+ lock(&mem_region_lock);
+ /* Test splitting of a region. */
+ r = new_region("base", (unsigned long)test_heap,
+ TEST_HEAP_SIZE, NULL, REGION_SKIBOOT_HEAP);
+ assert(add_region(r));
+ r = new_region("splitter", (unsigned long)test_heap + TEST_HEAP_SIZE/4,
+ TEST_HEAP_SIZE/2, NULL, REGION_RESERVED);
+ assert(add_region(r));
+ /* Now we should have *three* regions. */
+ i = 0;
+ list_for_each(&regions, r, list) {
+ if (region_start(r) == test_heap) {
+ assert(r->len == TEST_HEAP_SIZE/4);
+ assert(strcmp(r->name, "base") == 0);
+ assert(r->type == REGION_SKIBOOT_HEAP);
+ } else if (region_start(r) == test_heap + TEST_HEAP_SIZE / 4) {
+ assert(r->len == TEST_HEAP_SIZE/2);
+ assert(strcmp(r->name, "splitter") == 0);
+ assert(r->type == REGION_RESERVED);
+ assert(!r->free_list.n.next);
+ } else if (region_start(r) == test_heap + TEST_HEAP_SIZE/4*3) {
+ assert(r->len == TEST_HEAP_SIZE/4);
+ assert(strcmp(r->name, "base") == 0);
+ assert(r->type == REGION_SKIBOOT_HEAP);
+ } else
+ abort();
+ assert(mem_check(r));
+ i++;
+ }
+ mem_dump_free();
+ assert(i == 3);
+ while ((r = list_pop(&regions, struct mem_region, list)) != NULL) {
+ lock(&skiboot_heap.free_list_lock);
+ mem_free(&skiboot_heap, r, __location__);
+ unlock(&skiboot_heap.free_list_lock);
+ }
+ unlock(&mem_region_lock);
+ assert(skiboot_heap.free_list_lock.lock_val == 0);
+ real_free(test_heap);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region_init.c b/roms/skiboot/core/test/run-mem_region_init.c
new file mode 100644
index 000000000..e96282de8
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region_init.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+/* Use these before we undefine them below. */
+static inline void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static inline void real_free(void *p)
+{
+ return free(p);
+}
+
+#include "../malloc.c"
+
+#include <skiboot.h>
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../mem_region.c"
+
+/* But we need device tree to make copies of names. */
+#undef is_rodata
+#define is_rodata(p) false
+
+static inline char *skiboot_strdup(const char *str)
+{
+ char *ret = __malloc(strlen(str) + 1, "");
+ return memcpy(ret, str, strlen(str) + 1);
+}
+#undef strdup
+#define strdup skiboot_strdup
+
+#include "../device.c"
+
+#include <skiboot.h>
+
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val = 1;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val = 0;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+/* We actually need a lot of room for the bitmaps! */
+#define TEST_HEAP_ORDER 27
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static void add_mem_node(uint64_t start, uint64_t len)
+{
+ struct dt_node *mem;
+ u64 reg[2];
+ char *name= (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0]));
+
+ assert(name);
+
+ /* reg contains start and length */
+ reg[0] = cpu_to_be64(start);
+ reg[1] = cpu_to_be64(len);
+
+ sprintf(name, "memory@%llx", (unsigned long long)start);
+
+ mem = dt_new(dt_root, name);
+ assert(mem);
+ dt_add_property_string(mem, "device_type", "memory");
+ dt_add_property(mem, "reg", reg, sizeof(reg));
+ free(name);
+}
+
+void add_chip_dev_associativity(struct dt_node *dev __attribute__((unused)))
+{
+}
+
+int main(void)
+{
+ uint64_t end;
+ int builtins;
+ struct mem_region *r;
+ char *heap = real_malloc(TEST_HEAP_SIZE);
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (unsigned long)heap;
+ skiboot_heap.len = TEST_HEAP_SIZE;
+ skiboot_os_reserve.len = 16384;
+
+ dt_root = dt_new_root("");
+ dt_add_property_cells(dt_root, "#address-cells", 2);
+ dt_add_property_cells(dt_root, "#size-cells", 2);
+
+ /* Make sure we overlap the heap, at least. */
+ add_mem_node(0, (uint64_t)(heap + 0x100000000ULL));
+ add_mem_node((uint64_t)heap+0x100000000ULL , 0x100000000ULL);
+ end = (uint64_t)(heap+ 0x100000000ULL + 0x100000000ULL);
+
+ /* Now convert. */
+ mem_region_init();
+ mem_dump_allocs();
+ assert(mem_check(&skiboot_heap));
+
+ builtins = 0;
+ list_for_each(&regions, r, list) {
+ /* Regions must not overlap. */
+ struct mem_region *r2, *pre = NULL, *post = NULL;
+ list_for_each(&regions, r2, list) {
+ if (r == r2)
+ continue;
+ assert(!overlaps(r, r2));
+ }
+
+ /* But should have exact neighbours. */
+ list_for_each(&regions, r2, list) {
+ if (r == r2)
+ continue;
+ if (r2->start == r->start + r->len)
+ post = r2;
+ if (r2->start + r2->len == r->start)
+ pre = r2;
+ }
+ assert(r->start == 0 || pre);
+ assert(r->start + r->len == end || post);
+
+ if (r == &skiboot_code_and_text ||
+ r == &skiboot_heap ||
+ r == &skiboot_after_heap ||
+ r == &skiboot_cpu_stacks ||
+ r == &skiboot_os_reserve)
+ builtins++;
+ else
+ assert(r->type == REGION_MEMORY);
+ assert(mem_check(r));
+ }
+ assert(builtins == 5);
+
+ dt_free(dt_root);
+
+ while ((r = list_pop(&regions, struct mem_region, list)) != NULL) {
+ if (r != &skiboot_code_and_text &&
+ r != &skiboot_heap &&
+ r != &skiboot_after_heap &&
+ r != &skiboot_os_reserve &&
+ r != &skiboot_cpu_stacks) {
+ free(r);
+ }
+ assert(mem_check(&skiboot_heap));
+ }
+ assert(skiboot_heap.free_list_lock.lock_val == 0);
+ real_free(heap);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region_next.c b/roms/skiboot/core/test/run-mem_region_next.c
new file mode 100644
index 000000000..4f2f73c55
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region_next.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Use these before we override definitions below. */
+static void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static void real_free(void *p)
+{
+ return free(p);
+}
+
+#undef malloc
+#undef free
+
+#include <skiboot.h>
+
+#define is_rodata(p) true
+
+#include "../mem_region.c"
+#include "../malloc.c"
+#include "../device.c"
+
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+int main(void)
+{
+ struct mem_region *r;
+ char *test_heap;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ test_heap = real_malloc(TEST_HEAP_SIZE);
+ skiboot_heap.start = (unsigned long)test_heap;
+ skiboot_heap.len = TEST_HEAP_SIZE;
+
+ lock(&mem_region_lock);
+
+ /* empty regions */
+ r = mem_region_next(NULL);
+ assert(!r);
+
+ r = new_region("test.1", 0x1000, 0x1000, NULL, REGION_RESERVED);
+ assert(add_region(r));
+ r = new_region("test.2", 0x2000, 0x1000, NULL, REGION_RESERVED);
+ assert(add_region(r));
+ mem_regions_finalised = true;
+
+ r = mem_region_next(NULL);
+ assert(r);
+ assert(r->start == 0x1000);
+ assert(r->len == 0x1000);
+ assert(r->type == REGION_RESERVED);
+
+ r = mem_region_next(r);
+ assert(r);
+ assert(r->start == 0x2000);
+ assert(r->len == 0x1000);
+ assert(r->type == REGION_RESERVED);
+
+ r = mem_region_next(r);
+ assert(!r);
+
+ unlock(&mem_region_lock);
+ real_free(test_heap);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region_release_unused.c b/roms/skiboot/core/test/run-mem_region_release_unused.c
new file mode 100644
index 000000000..463f54283
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region_release_unused.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+static void *__malloc(size_t size, const char *location __attribute__((unused)))
+{
+ return malloc(size);
+}
+
+static void *__realloc(void *ptr, size_t size, const char *location __attribute__((unused)))
+{
+ return realloc(ptr, size);
+}
+
+static void *__zalloc(size_t size, const char *location __attribute__((unused)))
+{
+ return calloc(size, 1);
+}
+
+static inline void __free(void *p, const char *location __attribute__((unused)))
+{
+ return free(p);
+}
+
+#include <skiboot.h>
+
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../mem_region.c"
+
+/* But we need device tree to make copies of names. */
+#undef is_rodata
+#define is_rodata(p) false
+
+#include "../device.c"
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static void add_mem_node(uint64_t start, uint64_t len)
+{
+ struct dt_node *mem;
+ u64 reg[2];
+ char *name;
+
+ name = (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0]));
+ assert(name);
+
+ /* reg contains start and length */
+ reg[0] = cpu_to_be64(start);
+ reg[1] = cpu_to_be64(len);
+
+ sprintf(name, "memory@%llx", (long long)start);
+
+ mem = dt_new(dt_root, name);
+ dt_add_property_string(mem, "device_type", "memory");
+ dt_add_property(mem, "reg", reg, sizeof(reg));
+ free(name);
+}
+
+void add_chip_dev_associativity(struct dt_node *dev __attribute__((unused)))
+{
+}
+
+int main(void)
+{
+ uint64_t i;
+ struct mem_region *r, *other = NULL;
+ void *other_mem;
+ const char *last;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (unsigned long)malloc(TEST_HEAP_SIZE);
+ skiboot_heap.len = TEST_HEAP_SIZE;
+ skiboot_os_reserve.len = 0;
+
+ dt_root = dt_new_root("");
+ dt_add_property_cells(dt_root, "#address-cells", 2);
+ dt_add_property_cells(dt_root, "#size-cells", 2);
+
+ other_mem = malloc(1024*1024);
+ add_mem_node((unsigned long)other_mem, 1024*1024);
+
+ /* Now convert. */
+ mem_region_init();
+
+ /* Find our node to allocate from */
+ list_for_each(&regions, r, list) {
+ if (region_start(r) == other_mem)
+ other = r;
+ }
+ /* This could happen if skiboot addresses clashed with our alloc. */
+ assert(other);
+ assert(mem_check(other));
+
+ /* Allocate 1k from other region. */
+ lock(&other->free_list_lock);
+ mem_alloc(other, 1024, 1, "1k");
+ unlock(&other->free_list_lock);
+
+ mem_region_release_unused();
+
+ assert(mem_check(&skiboot_heap));
+
+ /* Now we expect it to be split. */
+ i = 0;
+ list_for_each(&regions, r, list) {
+ assert(mem_check(r));
+ i++;
+ if (r == &skiboot_os_reserve)
+ continue;
+ if (r == &skiboot_code_and_text)
+ continue;
+ if (r == &skiboot_heap)
+ continue;
+ if (r == &skiboot_after_heap)
+ continue;
+ if (r == &skiboot_cpu_stacks)
+ continue;
+ if (r == other) {
+ assert(r->type == REGION_MEMORY);
+ assert(r->len < 1024 * 1024);
+ } else {
+ assert(r->type == REGION_OS);
+ assert(r->start == other->start + other->len);
+ assert(r->start + r->len == other->start + 1024*1024);
+ }
+ }
+ assert(i == 7);
+
+ last = NULL;
+ list_for_each(&regions, r, list) {
+ if (last != r->name &&
+ strncmp(r->name, NODE_REGION_PREFIX,
+ strlen(NODE_REGION_PREFIX)) == 0) {
+ /* It's safe to cast away const as this is
+ * only going to happen in test code */
+ free((void*)r->name);
+ break;
+ }
+ last = r->name;
+ }
+
+ dt_free(dt_root);
+ free((void *)(long)skiboot_heap.start);
+ free(other_mem);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region_release_unused_noalloc.c b/roms/skiboot/core/test/run-mem_region_release_unused_noalloc.c
new file mode 100644
index 000000000..d7adc5a9a
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region_release_unused_noalloc.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+static void *__malloc(size_t size, const char *location __attribute__((unused)))
+{
+ return malloc(size);
+}
+
+static void *__realloc(void *ptr, size_t size, const char *location __attribute__((unused)))
+{
+ return realloc(ptr, size);
+}
+
+static void *__zalloc(size_t size, const char *location __attribute__((unused)))
+{
+ return calloc(size, 1);
+}
+
+static inline void __free(void *p, const char *location __attribute__((unused)))
+{
+ return free(p);
+}
+
+#include <skiboot.h>
+
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../mem_region.c"
+
+/* But we need device tree to make copies of names. */
+#undef is_rodata
+#define is_rodata(p) false
+
+#include "../device.c"
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static void add_mem_node(uint64_t start, uint64_t len)
+{
+ struct dt_node *mem;
+ u64 reg[2];
+ char *name;
+
+ name = (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0]));
+ assert(name);
+
+ /* reg contains start and length */
+ reg[0] = cpu_to_be64(start);
+ reg[1] = cpu_to_be64(len);
+
+ sprintf(name, "memory@%llx", (long long)start);
+
+ mem = dt_new(dt_root, name);
+ dt_add_property_string(mem, "device_type", "memory");
+ dt_add_property(mem, "reg", reg, sizeof(reg));
+ free(name);
+}
+
+void add_chip_dev_associativity(struct dt_node *dev __attribute__((unused)))
+{
+}
+
+int main(void)
+{
+ uint64_t i;
+ struct mem_region *r;
+ const char *last;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = 0;
+ skiboot_heap.len = TEST_HEAP_SIZE;
+ skiboot_os_reserve.start = 0;
+ skiboot_os_reserve.len = 0;
+
+ dt_root = dt_new_root("");
+ dt_add_property_cells(dt_root, "#address-cells", 2);
+ dt_add_property_cells(dt_root, "#size-cells", 2);
+
+ add_mem_node(0, 0x100000000ULL);
+ add_mem_node(0x100000000ULL, 0x100000000ULL);
+
+ mem_region_init();
+
+ mem_region_release_unused();
+
+ assert(mem_check(&skiboot_heap));
+
+ /* Now we expect it to be split. */
+ i = 0;
+ list_for_each(&regions, r, list) {
+ assert(mem_check(r));
+ i++;
+ if (r == &skiboot_os_reserve)
+ continue;
+ if (r == &skiboot_code_and_text)
+ continue;
+ if (r == &skiboot_heap)
+ continue;
+ if (r == &skiboot_after_heap)
+ continue;
+ if (r == &skiboot_cpu_stacks)
+ continue;
+
+ /* the memory nodes should all be available to the OS now */
+ assert(r->type == REGION_OS);
+ }
+ assert(i == 9);
+
+ last = NULL;
+ list_for_each(&regions, r, list) {
+ if (last != r->name &&
+ strncmp(r->name, NODE_REGION_PREFIX,
+ strlen(NODE_REGION_PREFIX)) == 0) {
+ /* It's safe to cast away the const as
+ * this never happens at runtime,
+ * only in test and only for valgrind
+ */
+ free((void*)r->name);
+ last = r->name;
+ }
+ }
+
+ dt_free(dt_root);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-mem_region_reservations.c b/roms/skiboot/core/test/run-mem_region_reservations.c
new file mode 100644
index 000000000..c24652f41
--- /dev/null
+++ b/roms/skiboot/core/test/run-mem_region_reservations.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <config.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+#include "dummy-cpu.h"
+
+#include <stdlib.h>
+
+static void *real_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static void real_free(void *p)
+{
+ return free(p);
+}
+
+#undef malloc
+#undef free
+#undef realloc
+
+#include <skiboot.h>
+#include <mem_region-malloc.h>
+
+/* We need mem_region to accept __location__ */
+#define is_rodata(p) true
+#include "../mem_region.c"
+#include "../malloc.c"
+
+/* But we need device tree to make copies of names. */
+#undef is_rodata
+#define is_rodata(p) false
+#include "../../libc/string/strdup.c"
+
+#include "../device.c"
+#include <assert.h>
+#include <stdio.h>
+
+enum proc_chip_quirks proc_chip_quirks;
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val++;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val--;
+}
+
+bool lock_held_by_me(struct lock *l)
+{
+ return l->lock_val;
+}
+
+#define TEST_HEAP_ORDER 16
+#define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
+
+static void add_mem_node(uint64_t start, uint64_t len)
+{
+ struct dt_node *mem;
+ u64 reg[2];
+ char *name;
+
+ name = (char*)malloc(sizeof("memory@") + STR_MAX_CHARS(reg[0]));
+ assert(name);
+
+ /* reg contains start and length */
+ reg[0] = cpu_to_be64(start);
+ reg[1] = cpu_to_be64(len);
+
+ sprintf(name, "memory@%llx", (long long)start);
+
+ mem = dt_new(dt_root, name);
+ dt_add_property_string(mem, "device_type", "memory");
+ dt_add_property(mem, "reg", reg, sizeof(reg));
+ free(name);
+}
+
+void add_chip_dev_associativity(struct dt_node *dev __attribute__((unused)))
+{
+}
+
+static struct {
+ const char *name;
+ uint64_t addr;
+ bool found;
+} test_regions[] = {
+ { "test.1", 0x1000, false },
+ { "test.2", 0x2000, false },
+ { "test.3", 0x4000, false },
+};
+
+static void check_property_reservations(void)
+{
+ const struct dt_property *names, *ranges;
+ unsigned int i, l;
+ const char *name;
+ uint64_t *rangep;
+ const char *at;
+
+ /* check dt properties */
+ names = dt_find_property(dt_root, "reserved-names");
+ ranges = dt_find_property(dt_root, "reserved-ranges");
+
+ assert(names && ranges);
+
+ /* walk through names & ranges properies, ensuring that the test
+ * regions are all present */
+ for (name = names->prop, rangep = (uint64_t *)ranges->prop;
+ name < names->prop + names->len;
+ name += l, rangep += 2) {
+ uint64_t addr;
+
+ addr = dt_get_number(rangep, 2);
+ l = strlen(name) + 1;
+
+ for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+ at = strchr(name, '@');
+ if (strncmp(test_regions[i].name, name,
+ at ? at-name: strlen(name)))
+ continue;
+ assert(test_regions[i].addr == addr);
+ assert(!test_regions[i].found);
+ test_regions[i].found = true;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+ assert(test_regions[i].found);
+ test_regions[i].found = false;
+ }
+}
+
+static void check_node_reservations(void)
+{
+ struct dt_node *parent, *node;
+ unsigned int i;
+
+ parent = dt_find_by_name(dt_root, "reserved-memory");
+ assert(parent);
+
+ assert(dt_prop_get_cell(parent, "#address-cells", 0) == 2);
+ assert(dt_prop_get_cell(parent, "#size-cells", 0) == 2);
+ dt_require_property(parent, "ranges", 0);
+
+ dt_for_each_child(parent, node) {
+ uint64_t addr, size;
+
+ addr = dt_get_address(node, 0, &size);
+
+ for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+ if (strncmp(test_regions[i].name, node->name,
+ strlen(test_regions[i].name)))
+ continue;
+
+ assert(!test_regions[i].found);
+ assert(test_regions[i].addr == addr);
+ assert(size == 0x1000);
+ test_regions[i].found = true;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+ assert(test_regions[i].found);
+ test_regions[i].found = false;
+ }
+}
+
+int main(void)
+{
+ struct mem_region *r;
+ unsigned int i;
+ void *buf;
+
+ /* Use malloc for the heap, so valgrind can find issues. */
+ skiboot_heap.start = (long)real_malloc(TEST_HEAP_SIZE);
+ skiboot_heap.len = TEST_HEAP_SIZE;
+ skiboot_os_reserve.len = skiboot_heap.start;
+
+ dt_root = dt_new_root("");
+ dt_add_property_cells(dt_root, "#address-cells", 2);
+ dt_add_property_cells(dt_root, "#size-cells", 2);
+
+ buf = real_malloc(1024*1024);
+ add_mem_node((unsigned long)buf, 1024*1024);
+
+ /* add pre-init reservations */
+ for (i = 0; i < ARRAY_SIZE(test_regions); i++)
+ mem_reserve_fw(test_regions[i].name,
+ test_regions[i].addr, 0x1000);
+
+ /* Now convert. */
+ mem_region_init();
+
+ /* add a post-init reservation */
+ mem_reserve_fw("test.4", 0x5000, 0x1000);
+
+ /* release unused */
+ mem_region_release_unused();
+
+ /* and create reservations */
+ mem_region_add_dt_reserved();
+
+ /* ensure we can't create further reservations */
+ r = new_region("test.5", 0x5000, 0x1000, NULL, REGION_RESERVED);
+ assert(!add_region(r));
+
+ /* check old property-style reservations */
+ check_property_reservations();
+
+ /* and new node-style reservations */
+ check_node_reservations();
+
+ dt_free(dt_root);
+ real_free(buf);
+ real_free((void *)(long)skiboot_heap.start);
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-msg.c b/roms/skiboot/core/test/run-msg.c
new file mode 100644
index 000000000..3659a12d7
--- /dev/null
+++ b/roms/skiboot/core/test/run-msg.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static bool zalloc_should_fail = false;
+static int zalloc_should_fail_after = 0;
+
+/* Fake top_of_ram -- needed for API's */
+unsigned long top_of_ram = 0xffffffffffffffffULL;
+
+static void *zalloc(size_t size)
+{
+ if (zalloc_should_fail && zalloc_should_fail_after == 0) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if (zalloc_should_fail_after > 0)
+ zalloc_should_fail_after--;
+
+ return calloc(size, 1);
+}
+
+#include "../opal-msg.c"
+#include <skiboot.h>
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val = 1;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val = 0;
+}
+
+void opal_update_pending_evt(uint64_t evt_mask, uint64_t evt_values)
+{
+ (void)evt_mask;
+ (void)evt_values;
+}
+
+static long magic = 8097883813087437089UL;
+static void callback(void *data, int status)
+{
+ assert((status == OPAL_SUCCESS || status == OPAL_PARTIAL));
+ assert(*(uint64_t *)data == magic);
+}
+
+static size_t list_count(struct list_head *list)
+{
+ size_t count = 0;
+ struct opal_msg_entry *dummy;
+
+ list_for_each(list, dummy, link)
+ count++;
+ return count;
+}
+
+int main(void)
+{
+ struct opal_msg_entry* entry;
+ int free_size = OPAL_MAX_MSGS;
+ int nfree = free_size;
+ int npending = 0;
+ int r;
+ static struct opal_msg m;
+ uint64_t *m_ptr = (uint64_t *)&m;
+
+ zalloc_should_fail = true;
+ zalloc_should_fail_after = 3;
+ opal_init_msg();
+
+ zalloc_should_fail = false;
+ opal_init_msg();
+
+ assert(list_count(&msg_pending_list) == npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ /* Callback. */
+ r = opal_queue_msg(0, &magic, callback, (u64)0, (u64)1, (u64)2);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == --nfree);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == 0);
+
+ assert(m.params[0] == 0);
+ assert(m.params[1] == 1);
+ assert(m.params[2] == 2);
+
+ assert(list_count(&msg_pending_list) == --npending);
+ assert(list_count(&msg_free_list) == ++nfree);
+
+ /* No params. */
+ r = opal_queue_msg(0, NULL, NULL);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == --nfree);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == --npending);
+ assert(list_count(&msg_free_list) == ++nfree);
+
+ /* > 8 params (ARRAY_SIZE(entry->msg.params) */
+ r = opal_queue_msg(0, NULL, NULL, 0, 1, 2, 3, 4, 5, 6, 7, 0xBADDA7A);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == OPAL_PARTIAL);
+
+ assert(list_count(&msg_pending_list) == --npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ /* Return OPAL_PARTIAL to callback */
+ r = opal_queue_msg(0, &magic, callback, 0, 1, 2, 3, 4, 5, 6, 7, 0xBADDA7A);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == OPAL_PARTIAL);
+
+ assert(list_count(&msg_pending_list) == --npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ /* return OPAL_PARAMETER */
+ r = _opal_queue_msg(0, NULL, NULL, OPAL_MSG_SIZE, m_ptr);
+ assert(r == OPAL_PARAMETER);
+
+ assert(m.params[0] == 0);
+ assert(m.params[1] == 1);
+ assert(m.params[2] == 2);
+ assert(m.params[3] == 3);
+ assert(m.params[4] == 4);
+ assert(m.params[5] == 5);
+ assert(m.params[6] == 6);
+ assert(m.params[7] == 7);
+
+ /* 8 params (ARRAY_SIZE(entry->msg.params) */
+ r = opal_queue_msg(0, NULL, NULL, 0, 10, 20, 30, 40, 50, 60, 70);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == --nfree);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == --npending);
+ assert(list_count(&msg_free_list) == ++nfree);
+
+ assert(m.params[0] == 0);
+ assert(m.params[1] == 10);
+ assert(m.params[2] == 20);
+ assert(m.params[3] == 30);
+ assert(m.params[4] == 40);
+ assert(m.params[5] == 50);
+ assert(m.params[6] == 60);
+ assert(m.params[7] == 70);
+
+ /* Full list (no free nodes in pending). */
+ while (nfree > 0) {
+ r = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL);
+ assert(r == 0);
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == --nfree);
+ }
+ assert(list_count(&msg_free_list) == 0);
+ assert(nfree == 0);
+ assert(npending == OPAL_MAX_MSGS);
+
+ r = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == OPAL_MAX_MSGS+1);
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ /* Make zalloc fail to test error handling. */
+ zalloc_should_fail = true;
+ r = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL);
+ assert(r == OPAL_RESOURCE);
+
+ assert(list_count(&msg_pending_list) == OPAL_MAX_MSGS+1);
+ assert(list_count(&msg_pending_list) == npending);
+ assert(list_count(&msg_free_list) == nfree);
+
+ /* Empty list (no nodes). */
+ while(!list_empty(&msg_pending_list)) {
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == 0);
+ npending--;
+ nfree++;
+ }
+ assert(list_count(&msg_pending_list) == npending);
+ assert(list_count(&msg_free_list) == nfree);
+ assert(npending == 0);
+ assert(nfree == OPAL_MAX_MSGS+1);
+
+ r = opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL);
+ assert(r == 0);
+
+ assert(list_count(&msg_pending_list) == ++npending);
+ assert(list_count(&msg_free_list) == --nfree);
+
+ /* Request invalid size. */
+ r = opal_get_msg(m_ptr, sizeof(m) - 1);
+ assert(r == OPAL_PARAMETER);
+
+ /* Pass null buffer. */
+ r = opal_get_msg(NULL, sizeof(m));
+ assert(r == OPAL_PARAMETER);
+
+ /* Get msg when none are pending. */
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == 0);
+
+ r = opal_get_msg(m_ptr, sizeof(m));
+ assert(r == OPAL_RESOURCE);
+
+#define test_queue_num(type, val) \
+ r = opal_queue_msg(0, NULL, NULL, \
+ (type)val, (type)val, (type)val, (type)val, \
+ (type)val, (type)val, (type)val, (type)val); \
+ assert(r == 0); \
+ opal_get_msg(m_ptr, sizeof(m)); \
+ assert(r == OPAL_SUCCESS); \
+ assert(m.params[0] == (type)val); \
+ assert(m.params[1] == (type)val); \
+ assert(m.params[2] == (type)val); \
+ assert(m.params[3] == (type)val); \
+ assert(m.params[4] == (type)val); \
+ assert(m.params[5] == (type)val); \
+ assert(m.params[6] == (type)val); \
+ assert(m.params[7] == (type)val)
+
+ /* Test types of various widths */
+ test_queue_num(u64, -1);
+ test_queue_num(s64, -1);
+ test_queue_num(u32, -1);
+ test_queue_num(s32, -1);
+ test_queue_num(u16, -1);
+ test_queue_num(s16, -1);
+ test_queue_num(u8, -1);
+ test_queue_num(s8, -1);
+
+ /* Clean up the list to keep valgrind happy. */
+ while(!list_empty(&msg_free_list)) {
+ entry = list_pop(&msg_free_list, struct opal_msg_entry, link);
+ assert(entry);
+ free(entry);
+ }
+
+ while(!list_empty(&msg_pending_list)) {
+ entry = list_pop(&msg_pending_list, struct opal_msg_entry, link);
+ assert(entry);
+ free(entry);
+ }
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-nvram-format.c b/roms/skiboot/core/test/run-nvram-format.c
new file mode 100644
index 000000000..ba286bea3
--- /dev/null
+++ b/roms/skiboot/core/test/run-nvram-format.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <stdlib.h>
+
+#include "../nvram-format.c"
+
+bool nvram_wait_for_load(void)
+{
+ return true;
+}
+
+bool nvram_validate(void)
+{
+ return true;
+}
+
+bool nvram_has_loaded(void)
+{
+ return true;
+}
+
+static char *nvram_reset(void *nvram_image, int size)
+{
+ struct chrp_nvram_hdr *h = nvram_image;
+
+ /* entire partition used by one key */
+ assert(nvram_format(nvram_image, size) == 0);
+ memset((char *) h + sizeof(*h), 0, NVRAM_SIZE_FW_PRIV - sizeof(*h));
+ assert(nvram_check(nvram_image, size) == 0);
+
+ return (char *) h + sizeof(*h);
+}
+
+int main(void)
+{
+ char *nvram_image;
+ size_t sz;
+ struct chrp_nvram_hdr *h;
+ char *data;
+ const char *result;
+
+ /* 1024 bytes is too small for our NVRAM */
+ nvram_image = malloc(1024);
+ assert(nvram_format(nvram_image, 1024)!=0);
+ free(nvram_image);
+
+ /* 4096 bytes is too small for our NVRAM */
+ nvram_image = malloc(4096);
+ assert(nvram_format(nvram_image, 4096)!=0);
+ free(nvram_image);
+
+ /* 64k is too small for our NVRAM */
+ nvram_image = malloc(0x10000);
+ assert(nvram_format(nvram_image, 0x10000)!=0);
+ free(nvram_image);
+
+ /* 68k is too small for our NVRAM */
+ nvram_image = malloc(68*1024);
+ assert(nvram_format(nvram_image, 68*1024)!=0);
+ free(nvram_image);
+
+ /* 68k+16 bytes (nvram header) should generate empty free space */
+ sz = NVRAM_SIZE_COMMON + NVRAM_SIZE_FW_PRIV
+ + sizeof(struct chrp_nvram_hdr);
+ nvram_image = malloc(sz);
+ assert(nvram_format(nvram_image, sz)==0);
+ assert(nvram_check(nvram_image, sz)==0);
+ assert(nvram_image[sz-14]==0);
+ assert(nvram_image[sz-13]==1);
+ h = (struct chrp_nvram_hdr*)(&nvram_image[NVRAM_SIZE_COMMON + NVRAM_SIZE_FW_PRIV]);
+ assert(memcmp(h->name, "wwwwwwwwwwww", 12)==0);
+ free(nvram_image);
+
+ /* 128k NVRAM check */
+ nvram_image = malloc(128*1024);
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ assert(nvram_check(nvram_image,128*1024)==0);
+
+ /* Now, we corrupt it */
+ nvram_image[0] = 0;
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ /* Does our NUL checking work? */
+ assert(nvram_format(nvram_image, 128 * 1024) == 0);
+ h = (struct chrp_nvram_hdr *) nvram_image;
+ memset((char *) h + sizeof(*h), 0xFF, be16_to_cpu(h->len) * 16 - sizeof(*h));
+ assert(nvram_check(nvram_image, 128 * 1024) != 0);
+
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ /* corrupt the length of the partition */
+ nvram_image[2] = 0;
+ nvram_image[3] = 0;
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ /* corrupt the length of the partition */
+ nvram_image[2] = 0;
+ nvram_image[3] = 0;
+ /* but reset checksum! */
+ h = (struct chrp_nvram_hdr*)nvram_image;
+ h->cksum = chrp_nv_cksum(h);
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ /* make the length insanely beyond end of nvram */
+ nvram_image[2] = 42;
+ nvram_image[3] = 32;
+ /* but reset checksum! */
+ h = (struct chrp_nvram_hdr*)nvram_image;
+ h->cksum = chrp_nv_cksum(h);
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ /* remove skiboot partition */
+ nvram_image[12] = '\0';
+ /* but reset checksum! */
+ h = (struct chrp_nvram_hdr*)nvram_image;
+ h->cksum = chrp_nv_cksum(h);
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ assert(nvram_format(nvram_image, 128*1024)==0);
+ /* remove common partition */
+ nvram_image[NVRAM_SIZE_FW_PRIV+5] = '\0';
+ /* but reset checksum! */
+ h = (struct chrp_nvram_hdr*)(&nvram_image[NVRAM_SIZE_FW_PRIV]);
+ h->cksum = chrp_nv_cksum(h);
+ assert(nvram_check(nvram_image,128*1024) != 0);
+
+ /* test nvram_query() */
+
+ /* does an empty partition break us? */
+ data = nvram_reset(nvram_image, 128*1024);
+ assert(nvram_query_safe("test") == NULL);
+
+ /* does a zero length key break us? */
+ data = nvram_reset(nvram_image, 128*1024);
+ data[0] = '=';
+ assert(nvram_query_safe("test") == NULL);
+
+ /* does a missing = break us? */
+ data = nvram_reset(nvram_image, 128*1024);
+ data[0] = 'a';
+ assert(nvram_query_safe("test") == NULL);
+
+ /* does an empty value break us? */
+ data = nvram_reset(nvram_image, 128*1024);
+ data[0] = 'a';
+ data[1] = '=';
+ result = nvram_query_safe("a");
+ assert(result);
+ assert(strlen(result) == 0);
+
+ /* do we trip over malformed keys? */
+ data = nvram_reset(nvram_image, 128*1024);
+#define TEST_1 "a\0a=\0test=test\0"
+ memcpy(data, TEST_1, sizeof(TEST_1));
+ result = nvram_query_safe("test");
+ assert(result);
+ assert(strcmp(result, "test") == 0);
+
+ free(nvram_image);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-pci-quirk.c b/roms/skiboot/core/test/run-pci-quirk.c
new file mode 100644
index 000000000..fd4d95c10
--- /dev/null
+++ b/roms/skiboot/core/test/run-pci-quirk.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2018 IBM Corp
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <compiler.h>
+#include <stdbool.h>
+
+/* Stubs for quirk_astbmc_vga() */
+
+struct dt_property;
+struct dt_node;
+
+static struct bmc_platform fake_bmc;
+const struct bmc_platform *bmc_platform = &fake_bmc;
+
+static int ast_sio_is_enabled(void)
+{
+ return 0;
+}
+
+static uint32_t ast_ahb_readl(uint32_t reg)
+{
+ return reg;
+}
+
+static struct dt_property *__dt_add_property_cells(
+ struct dt_node *node __unused, const char *name __unused,
+ int count __unused, ...)
+{
+ return (void *)0;
+}
+
+struct pci_device;
+struct pci_cfg_reg_filter;
+typedef int64_t (*pci_cfg_reg_func)(void *dev,
+ struct pci_cfg_reg_filter *pcrf,
+ uint32_t offset, uint32_t len,
+ uint32_t *data, bool write);
+
+
+static struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(
+ struct pci_device *pd __unused,
+ uint32_t start __unused,
+ uint32_t len __unused,
+ uint32_t flags __unused,
+ pci_cfg_reg_func func __unused)
+{
+ return NULL;
+}
+
+#include "../pci-quirk.c"
+
+struct pci_device test_pd;
+int test_fixup_ran;
+
+static void test_fixup(struct phb *phb __unused, struct pci_device *pd __unused)
+{
+ assert(PCI_VENDOR_ID(pd->vdid) == 0x1a03);
+ assert(PCI_DEVICE_ID(pd->vdid) == 0x2000);
+ test_fixup_ran = 1;
+}
+
+/* Quirks are: {fixup function, vendor ID, (device ID or PCI_ANY_ID)} */
+static const struct pci_quirk test_quirk_table[] = {
+ /* ASPEED 2400 VGA device */
+ { 0x1a03, 0x2000, &test_fixup },
+ { 0, 0, NULL }
+};
+
+#define PCI_COMPOSE_VDID(vendor, device) (((device) << 16) | (vendor))
+
+int main(void)
+{
+ /* Unrecognised vendor and device ID */
+ test_pd.vdid = PCI_COMPOSE_VDID(0xabcd, 0xef01);
+ __pci_handle_quirk(NULL, &test_pd, test_quirk_table);
+ assert(test_fixup_ran == 0);
+
+ /* Unrecognised vendor ID, matching device ID */
+ test_pd.vdid = PCI_COMPOSE_VDID(0xabcd, 0x2000);
+ __pci_handle_quirk(NULL, &test_pd, test_quirk_table);
+ assert(test_fixup_ran == 0);
+
+ /* Matching vendor ID, unrecognised device ID */
+ test_pd.vdid = PCI_COMPOSE_VDID(0x1a03, 0xef01);
+ __pci_handle_quirk(NULL, &test_pd, test_quirk_table);
+ assert(test_fixup_ran == 0);
+
+ /* Matching vendor and device ID */
+ test_pd.vdid = PCI_COMPOSE_VDID(0x1a03, 0x2000);
+ __pci_handle_quirk(NULL, &test_pd, test_quirk_table);
+ assert(test_fixup_ran == 1);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-pel.c b/roms/skiboot/core/test/run-pel.c
new file mode 100644
index 000000000..812c8996c
--- /dev/null
+++ b/roms/skiboot/core/test/run-pel.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Test for our PEL record generation. Currently this doesn't actually
+ * test that the records we generate are correct, but it at least lets
+ * us run valgrind over the generation routines to check for buffer
+ * overflows, etc.
+ *
+ * Copyright 2013-2016 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <pel.h>
+#include <errorlog.h>
+#include <device.h>
+
+#define TEST_ERROR 0x1234
+#define TEST_SUBSYS 0x5678
+
+DEFINE_LOG_ENTRY(TEST_ERROR, OPAL_PLATFORM_ERR_EVT, TEST_SUBSYS,
+ OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
+ OPAL_NA);
+
+/* Override this for testing. */
+#define is_rodata(p) fake_is_rodata(p)
+
+char __rodata_start[16];
+#define __rodata_end (__rodata_start + sizeof(__rodata_start))
+
+static inline bool fake_is_rodata(const void *p)
+{
+ return ((char *)p >= __rodata_start && (char *)p < __rodata_end);
+}
+
+#define zalloc(bytes) calloc((bytes), 1)
+
+#include "../device.c"
+#include "../pel.c"
+
+struct dt_node *dt_root = NULL;
+char dt_prop[] = "DUMMY DT PROP";
+
+int rtc_cache_get_datetime(uint32_t *year_month_day,
+ uint64_t *hour_minute_second_millisecond)
+{
+ *year_month_day = 0;
+ *hour_minute_second_millisecond = 0;
+
+ return 0;
+}
+
+int main(void)
+{
+ char *pel_buf;
+ size_t size;
+ struct errorlog *elog;
+ struct opal_err_info *opal_err_info = &err_TEST_ERROR;
+ char *buffer;
+ struct elog_user_data_section *tmp;
+
+ dt_root = dt_new_root("");
+ dt_add_property_string(dt_root, "model", "run-pel-unittest");
+
+ elog = malloc(sizeof(struct errorlog));
+ pel_buf = malloc(PEL_MIN_SIZE + 4);
+ assert(elog);
+ assert(pel_buf);
+
+ memset(elog, 0, sizeof(struct errorlog));
+
+ elog->error_event_type = opal_err_info->err_type;
+ elog->component_id = opal_err_info->cmp_id;
+ elog->subsystem_id = opal_err_info->subsystem;
+ elog->event_severity = opal_err_info->sev;
+ elog->event_subtype = opal_err_info->event_subtype;
+ elog->reason_code = opal_err_info->reason_code;
+ elog->elog_origin = ORG_SAPPHIRE;
+
+ size = pel_size(elog);
+
+ printf("Test buffer too small: ");
+ assert(0 == create_pel_log(elog, NULL, size - 1));
+
+ assert(size <= PEL_MIN_SIZE + 4);
+ assert(size == create_pel_log(elog, pel_buf, size));
+
+ memset(elog, 0, sizeof(struct errorlog));
+
+ elog->error_event_type = opal_err_info->err_type;
+ elog->component_id = opal_err_info->cmp_id;
+ elog->subsystem_id = opal_err_info->subsystem;
+ elog->event_severity = opal_err_info->sev;
+ elog->event_subtype = opal_err_info->event_subtype;
+ elog->reason_code = opal_err_info->reason_code;
+ elog->elog_origin = ORG_SAPPHIRE;
+
+ size = pel_size(elog);
+ pel_buf = realloc(pel_buf, size);
+ assert(pel_buf);
+
+ buffer = elog->user_data_dump + elog->user_section_size;
+ tmp = (struct elog_user_data_section *)buffer;
+ tmp->tag = OPAL_ELOG_SEC_DESC; /* ASCII of DESC */
+ tmp->size = size + sizeof(struct elog_user_data_section) - 1;
+ strcpy(tmp->data_dump, "Hello World!");
+ elog->user_section_size += tmp->size;
+ elog->user_section_count++;
+
+ size = pel_size(elog);
+ pel_buf = realloc(pel_buf, size);
+ assert(pel_buf);
+
+ assert(size == create_pel_log(elog, pel_buf, size));
+
+ free(pel_buf);
+ free(elog);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-pool.c b/roms/skiboot/core/test/run-pool.c
new file mode 100644
index 000000000..e1c3843ff
--- /dev/null
+++ b/roms/skiboot/core/test/run-pool.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2014 IBM Corp
+ */
+
+#include <pool.h>
+
+#include "../pool.c"
+
+#define POOL_OBJ_COUNT 10
+#define POOL_RESERVED_COUNT 2
+#define POOL_NORMAL_COUNT (POOL_OBJ_COUNT - POOL_RESERVED_COUNT)
+
+struct test_object
+{
+ int a;
+ int b;
+ int c;
+};
+
+int main(void)
+{
+ int i, count = 0;
+ struct pool pool;
+ struct test_object *a[POOL_OBJ_COUNT];
+
+ assert(!pool_init(&pool, sizeof(struct test_object), POOL_OBJ_COUNT,
+ POOL_RESERVED_COUNT));
+
+ a[0] = pool_get(&pool, POOL_NORMAL);
+ assert(a[0]);
+ pool_free_object(&pool, a[0]);
+
+ for(i = 0; i < POOL_NORMAL_COUNT; i++)
+ {
+ a[i] = pool_get(&pool, POOL_NORMAL);
+ if (a[i])
+ count++;
+ }
+ assert(count == POOL_NORMAL_COUNT);
+
+ /* Normal pool should be exhausted */
+ assert(!pool_get(&pool, POOL_NORMAL));
+
+ /* Reserved pool should still be available */
+ a[POOL_NORMAL_COUNT] = pool_get(&pool, POOL_HIGH);
+ assert(a[POOL_NORMAL_COUNT]);
+ a[POOL_NORMAL_COUNT + 1] = pool_get(&pool, POOL_HIGH);
+ assert(a[POOL_NORMAL_COUNT + 1]);
+
+ pool_free_object(&pool, a[3]);
+
+ /* Should be a free object to get now */
+ a[3] = pool_get(&pool, POOL_HIGH);
+ assert(a[3]);
+
+ /* This exits depending on whether all tests passed */
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-time-utils.c b/roms/skiboot/core/test/run-time-utils.c
new file mode 100644
index 000000000..04723dd61
--- /dev/null
+++ b/roms/skiboot/core/test/run-time-utils.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2017 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define __TEST__
+
+#include "../time-utils.c"
+
+int main(void)
+{
+ struct tm *t = malloc(sizeof(struct tm));
+ uint32_t *ymd = malloc(sizeof(uint32_t));
+ uint64_t *hms = malloc(sizeof(uint64_t));
+
+ t->tm_year = 1982;
+ t->tm_mon = 0;
+ t->tm_mday = 29;
+ t->tm_hour = 7;
+ t->tm_min = 42;
+ t->tm_sec = 24;
+
+ tm_to_datetime(t, ymd, hms);
+
+ assert(*ymd == 0x19820129);
+ assert(*hms == 0x742240000000000ULL);
+
+ memset(t, 0, sizeof(struct tm));
+
+ *ymd = 0x19760412;
+
+ datetime_to_tm(*ymd, *hms, t);
+ assert(t->tm_year == 1976);
+ assert(t->tm_mon == 03);
+ assert(t->tm_mday == 12);
+ assert(t->tm_hour == 7);
+ assert(t->tm_min == 42);
+ assert(t->tm_sec == 24);
+
+ free(t);
+ free(ymd);
+ free(hms);
+ return 0;
+}
+
diff --git a/roms/skiboot/core/test/run-timebase.c b/roms/skiboot/core/test/run-timebase.c
new file mode 100644
index 000000000..a613609a0
--- /dev/null
+++ b/roms/skiboot/core/test/run-timebase.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 IBM Corp.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define __TEST__
+#include <timebase.h>
+
+unsigned long tb_hz = 512000000;
+
+int main(void)
+{
+ /* This is a fairly solid assumption that the math we're doing
+ * is based on tb_hz of exactly 512mhz.
+ * If we do start doing the math on different tb_hz, you probably
+ * want to go and audit every bit of code that touches tb to
+ * count/delay things.
+ */
+ assert(tb_hz == 512000000);
+ assert(secs_to_tb(1) == tb_hz);
+ assert(secs_to_tb(2) == 1024000000);
+ assert(secs_to_tb(10) == 5120000000);
+ assert(tb_to_secs(512000000) == 1);
+ assert(tb_to_secs(5120000000) == 10);
+ assert(tb_to_secs(1024000000) == 2);
+
+ assert(msecs_to_tb(1) == 512000);
+ assert(msecs_to_tb(100) == 51200000);
+ assert(msecs_to_tb(5) == 2560000);
+ assert(tb_to_msecs(512000) == 1);
+
+ assert(usecs_to_tb(5) == 2560);
+ assert(tb_to_usecs(2560) == 5);
+ assert(usecs_to_tb(5)*1000 == msecs_to_tb(5));
+ assert(tb_to_usecs(512000) == 1000);
+
+ assert(tb_compare(msecs_to_tb(5), usecs_to_tb(5)) == TB_AAFTERB);
+ assert(tb_compare(msecs_to_tb(5), usecs_to_tb(50000)) == TB_ABEFOREB);
+ assert(tb_compare(msecs_to_tb(5), usecs_to_tb(5)*1000) == TB_AEQUALB);
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-timer.c b/roms/skiboot/core/test/run-timer.c
new file mode 100644
index 000000000..8f8b20ed3
--- /dev/null
+++ b/roms/skiboot/core/test/run-timer.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2014-2018 IBM Corp
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define __TEST__
+#include <timer.h>
+#include <skiboot.h>
+
+#define mftb() (stamp)
+#define sync()
+#define smt_lowest()
+#define smt_medium()
+
+enum proc_gen proc_gen = proc_gen_unknown;
+
+static uint64_t stamp, last;
+struct lock;
+static inline void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ (void)l;
+}
+static inline void unlock(struct lock *l) { (void)l; }
+
+unsigned long tb_hz = 512000000;
+
+#include "../timer.c"
+
+#define NUM_TIMERS 100
+
+static struct timer timers[NUM_TIMERS];
+static unsigned int rand_shift, count;
+
+static void init_rand(void)
+{
+ unsigned long max = RAND_MAX;
+
+ /* Get something reasonably small */
+ while(max > 0x10000) {
+ rand_shift++;
+ max >>= 1;
+ }
+}
+
+static void expiry(struct timer *t, void *data, uint64_t now)
+{
+ (void)data;
+ (void)now;
+ assert(t->target >= last);
+ count--;
+}
+
+void p8_sbe_update_timer_expiry(uint64_t new_target)
+{
+ (void)new_target;
+ /* FIXME: do intersting SLW timer sim */
+}
+
+void p9_sbe_update_timer_expiry(uint64_t new_target)
+{
+ (void)new_target;
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ init_rand();
+ for (i = 0; i < NUM_TIMERS; i++) {
+ init_timer(&timers[i], expiry, NULL);
+ schedule_timer(&timers[i], random() >> rand_shift);
+ }
+ count = NUM_TIMERS;
+ while(count) {
+ check_timers(false);
+ stamp++;
+ }
+ return 0;
+}
diff --git a/roms/skiboot/core/test/run-trace.c b/roms/skiboot/core/test/run-trace.c
new file mode 100644
index 000000000..88b090358
--- /dev/null
+++ b/roms/skiboot/core/test/run-trace.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <skiboot-valgrind.h>
+
+/* Don't include these: PPC-specific */
+#define __CPU_H
+#define __TIME_H
+#define __PROCESSOR_H
+
+#if defined(__i386__) || defined(__x86_64__)
+/* This is more than a lwsync, but it'll work */
+static void full_barrier(void)
+{
+ asm volatile("mfence" : : : "memory");
+}
+#define lwsync full_barrier
+#elif defined(__powerpc__) || defined(__powerpc64__)
+static inline void lwsync(void)
+{
+ asm volatile("lwsync" : : : "memory");
+}
+#else
+#error "Define lwsync for this arch"
+#endif
+
+#define zalloc(size) calloc((size), 1)
+
+struct cpu_thread {
+ uint32_t pir;
+ uint32_t chip_id;
+ struct trace_info *trace;
+ uint32_t server_no;
+ bool is_secondary;
+ struct cpu_thread *primary;
+};
+static struct cpu_thread *this_cpu(void);
+
+#define CPUS 4
+
+static struct cpu_thread fake_cpus[CPUS];
+
+static inline struct cpu_thread *next_cpu(struct cpu_thread *cpu)
+{
+ if (cpu == NULL)
+ return &fake_cpus[0];
+ cpu++;
+ if (cpu == &fake_cpus[CPUS])
+ return NULL;
+ return cpu;
+}
+
+#define first_cpu() next_cpu(NULL)
+
+#define for_each_cpu(cpu) \
+ for (cpu = first_cpu(); cpu; cpu = next_cpu(cpu))
+
+static unsigned long timestamp;
+static unsigned long mftb(void)
+{
+ return timestamp;
+}
+
+static void *local_alloc(unsigned int chip_id,
+ size_t size, size_t align)
+{
+ void *p;
+
+ (void)chip_id;
+ if (posix_memalign(&p, align, size))
+ p = NULL;
+ return p;
+}
+
+struct dt_node;
+extern struct dt_node *opal_node;
+
+#include "../trace.c"
+
+#include "../external/trace/trace.c"
+static struct trace_reader trace_readers[CPUS];
+struct trace_reader *my_trace_reader;
+#include "../device.c"
+
+char __rodata_start[1], __rodata_end[1];
+struct dt_node *opal_node;
+struct debug_descriptor debug_descriptor = {
+ .trace_mask = -1
+};
+
+const char *nvram_query_safe(const char *key __unused)
+{
+ return NULL;
+}
+
+void lock_caller(struct lock *l, const char *caller)
+{
+ (void)caller;
+ assert(!l->lock_val);
+ l->lock_val = 1;
+}
+
+void unlock(struct lock *l)
+{
+ assert(l->lock_val);
+ l->lock_val = 0;
+}
+
+struct cpu_thread *my_fake_cpu;
+static struct cpu_thread *this_cpu(void)
+{
+ return my_fake_cpu;
+}
+
+#include <sys/mman.h>
+#define PER_CHILD_TRACES ((RUNNING_ON_VALGRIND) ? (1024*16) : (1024*1024))
+
+static void write_trace_entries(int id)
+{
+ void exit(int);
+ unsigned int i;
+ union trace trace;
+
+ timestamp = id;
+ for (i = 0; i < PER_CHILD_TRACES; i++) {
+ timestamp = i * CPUS + id;
+ assert(sizeof(trace.hdr) % 8 == 0);
+ /* First child never repeats, second repeats once, etc. */
+ trace_add(&trace, 3 + ((i / (id + 1)) % 0x40),
+ sizeof(trace.hdr));
+ }
+
+ /* Final entry has special type, so parent knows it's over. */
+ trace_add(&trace, 0x70, sizeof(trace.hdr));
+ exit(0);
+}
+
+static bool all_done(const bool done[])
+{
+ unsigned int i;
+
+ for (i = 0; i < CPUS; i++)
+ if (!done[i])
+ return false;
+ return true;
+}
+
+static void test_parallel(void)
+{
+ void *p;
+ unsigned int cpu;
+ unsigned int i, counts[CPUS] = { 0 }, overflows[CPUS] = { 0 };
+ unsigned int repeats[CPUS] = { 0 }, num_overflows[CPUS] = { 0 };
+ bool done[CPUS] = { false };
+ size_t len = sizeof(struct trace_info) + TBUF_SZ + sizeof(union trace);
+ int last = 0;
+
+ /* Use a shared mmap to test actual parallel buffers. */
+ i = (CPUS*len + getpagesize()-1)&~(getpagesize()-1);
+ p = mmap(NULL, i, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_SHARED, -1, 0);
+
+ for (i = 0; i < CPUS; i++) {
+ fake_cpus[i].trace = p + i * len;
+ fake_cpus[i].trace->tb.buf_size = cpu_to_be64(TBUF_SZ);
+ fake_cpus[i].trace->tb.max_size = cpu_to_be32(sizeof(union trace));
+ fake_cpus[i].is_secondary = false;
+ memset(&trace_readers[i], 0, sizeof(struct trace_reader));
+ trace_readers[i].tb = &fake_cpus[i].trace->tb;
+ }
+
+ for (i = 0; i < CPUS; i++) {
+ if (!fork()) {
+ /* Child. */
+ my_fake_cpu = &fake_cpus[i];
+ write_trace_entries(i);
+ }
+ }
+
+ while (!all_done(done)) {
+ union trace t;
+
+ for (i = 0; i < CPUS; i++) {
+ if (trace_get(&t, &trace_readers[(i+last) % CPUS]))
+ break;
+ }
+
+ if (i == CPUS) {
+ sched_yield();
+ continue;
+ }
+ i = (i + last) % CPUS;
+ last = i;
+
+ if (t.hdr.type == TRACE_OVERFLOW) {
+ /* Conveniently, each record is 16 bytes here. */
+ assert(be64_to_cpu(t.overflow.bytes_missed) % 16 == 0);
+ overflows[i] += be64_to_cpu(t.overflow.bytes_missed) / 16;
+ num_overflows[i]++;
+ continue;
+ }
+
+ assert(be16_to_cpu(t.hdr.cpu) < CPUS);
+ assert(!done[be16_to_cpu(t.hdr.cpu)]);
+ assert(be64_to_cpu(t.hdr.timestamp) % CPUS == be16_to_cpu(t.hdr.cpu));
+ if (t.hdr.type == TRACE_REPEAT) {
+ assert(t.hdr.len_div_8 * 8 == sizeof(t.repeat));
+ assert(be16_to_cpu(t.repeat.num) != 0);
+ assert(be16_to_cpu(t.repeat.num) <= be16_to_cpu(t.hdr.cpu));
+ repeats[be16_to_cpu(t.hdr.cpu)] += be16_to_cpu(t.repeat.num);
+ } else if (t.hdr.type == 0x70) {
+ cpu = be16_to_cpu(t.hdr.cpu);
+ assert(cpu < CPUS);
+ done[cpu] = true;
+ } else {
+ cpu = be16_to_cpu(t.hdr.cpu);
+ assert(cpu < CPUS);
+ counts[cpu]++;
+ }
+ }
+
+ /* Gather children. */
+ for (i = 0; i < CPUS; i++) {
+ int status;
+ wait(&status);
+ }
+
+ for (i = 0; i < CPUS; i++) {
+ printf("Child %i: %u produced, %u overflows, %llu total\n", i,
+ counts[i], overflows[i],
+ (long long)be64_to_cpu(fake_cpus[i].trace->tb.end));
+ assert(counts[i] + repeats[i] <= PER_CHILD_TRACES);
+ }
+ /* Child 0 never repeats. */
+ assert(repeats[0] == 0);
+ assert(counts[0] + overflows[0] == PER_CHILD_TRACES);
+
+ /*
+ * FIXME: Other children have some fuzz, since overflows may
+ * include repeat record we already read. And odd-numbered
+ * overflows may include more repeat records than normal
+ * records (they alternate).
+ */
+}
+
+int main(void)
+{
+ union trace minimal;
+ union trace large;
+ union trace trace;
+ unsigned int i, j;
+
+ opal_node = dt_new_root("opal");
+ dt_new(dt_new(opal_node, "firmware"), "exports");
+ for (i = 0; i < CPUS; i++) {
+ fake_cpus[i].server_no = i;
+ fake_cpus[i].pir = i;
+ fake_cpus[i].is_secondary = (i & 0x1);
+ fake_cpus[i].primary = &fake_cpus[i & ~0x1];
+ }
+ my_fake_cpu = &fake_cpus[0];
+ my_trace_reader = &trace_readers[0];
+ init_trace_buffers();
+
+ for (i = 0; i < CPUS; i++) {
+ trace_readers[i].tb = &fake_cpus[i].trace->tb;
+ assert(trace_empty(&trace_readers[i]));
+ assert(!trace_get(&trace, &trace_readers[i]));
+ }
+
+ assert(sizeof(trace.hdr) % 8 == 0);
+ timestamp = 1;
+ trace_add(&minimal, 100, sizeof(trace.hdr));
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(be64_to_cpu(trace.hdr.timestamp) == timestamp);
+
+ /* Make it wrap once. */
+ for (i = 0; i < TBUF_SZ / (minimal.hdr.len_div_8 * 8) + 1; i++) {
+ timestamp = i;
+ trace_add(&minimal, 99 + (i%2), sizeof(trace.hdr));
+ }
+
+ assert(trace_get(&trace, my_trace_reader));
+ /* First one must be overflow marker. */
+ assert(trace.hdr.type == TRACE_OVERFLOW);
+ assert(trace.hdr.len_div_8 * 8 == sizeof(trace.overflow));
+ assert(be64_to_cpu(trace.overflow.bytes_missed) == minimal.hdr.len_div_8 * 8);
+
+ for (i = 0; i < TBUF_SZ / (minimal.hdr.len_div_8 * 8); i++) {
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(be64_to_cpu(trace.hdr.timestamp) == i+1);
+ assert(trace.hdr.type == 99 + ((i+1)%2));
+ }
+ assert(!trace_get(&trace, my_trace_reader));
+
+ /* Now put in some weird-length ones, to test overlap.
+ * Last power of 2, minus 8. */
+ for (j = 0; (1 << j) < sizeof(large); j++);
+ for (i = 0; i < TBUF_SZ; i++) {
+ timestamp = i;
+ trace_add(&large, 100 + (i%2), (1 << (j-1)));
+ }
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.type == TRACE_OVERFLOW);
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.len_div_8 == large.hdr.len_div_8);
+ i = be64_to_cpu(trace.hdr.timestamp);
+ while (trace_get(&trace, my_trace_reader))
+ assert(be64_to_cpu(trace.hdr.timestamp) == ++i);
+
+ /* Test repeats. */
+ for (i = 0; i < 65538; i++) {
+ timestamp = i;
+ trace_add(&minimal, 100, sizeof(trace.hdr));
+ }
+ timestamp = i;
+ trace_add(&minimal, 101, sizeof(trace.hdr));
+ timestamp = i+1;
+ trace_add(&minimal, 101, sizeof(trace.hdr));
+
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.timestamp == 0);
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(trace.hdr.type == 100);
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.type == TRACE_REPEAT);
+ assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
+ assert(be16_to_cpu(trace.repeat.num) == 65535);
+ assert(be64_to_cpu(trace.repeat.timestamp) == 65535);
+ assert(trace_get(&trace, my_trace_reader));
+ assert(be64_to_cpu(trace.hdr.timestamp) == 65536);
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(trace.hdr.type == 100);
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.type == TRACE_REPEAT);
+ assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
+ assert(be16_to_cpu(trace.repeat.num) == 1);
+ assert(be64_to_cpu(trace.repeat.timestamp) == 65537);
+
+ assert(trace_get(&trace, my_trace_reader));
+ assert(be64_to_cpu(trace.hdr.timestamp) == 65538);
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(trace.hdr.type == 101);
+ assert(trace_get(&trace, my_trace_reader));
+ assert(trace.hdr.type == TRACE_REPEAT);
+ assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
+ assert(be16_to_cpu(trace.repeat.num) == 1);
+ assert(be64_to_cpu(trace.repeat.timestamp) == 65539);
+
+ /* Now, test adding repeat while we're reading... */
+ timestamp = 0;
+ trace_add(&minimal, 100, sizeof(trace.hdr));
+ assert(trace_get(&trace, my_trace_reader));
+ assert(be64_to_cpu(trace.hdr.timestamp) == 0);
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ assert(trace.hdr.type == 100);
+
+ for (i = 1; i < TBUF_SZ; i++) {
+ timestamp = i;
+ trace_add(&minimal, 100, sizeof(trace.hdr));
+ assert(trace_get(&trace, my_trace_reader));
+ if (i % 65536 == 0) {
+ assert(trace.hdr.type == 100);
+ assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
+ } else {
+ assert(trace.hdr.type == TRACE_REPEAT);
+ assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
+ assert(be16_to_cpu(trace.repeat.num) == 1);
+ }
+ assert(be64_to_cpu(trace.repeat.timestamp) == i);
+ assert(!trace_get(&trace, my_trace_reader));
+ }
+
+ for (i = 0; i < CPUS; i++)
+ if (!fake_cpus[i].is_secondary)
+ free(fake_cpus[i].trace);
+
+ test_parallel();
+
+ return 0;
+}
diff --git a/roms/skiboot/core/test/stubs.c b/roms/skiboot/core/test/stubs.c
new file mode 100644
index 000000000..0e97af249
--- /dev/null
+++ b/roms/skiboot/core/test/stubs.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2013-2019 IBM Corp
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <compiler.h>
+#include "../../ccan/list/list.c"
+
+void _prlog(int log_level __attribute__((unused)), const char* fmt, ...) __attribute__((format (printf, 2, 3)));
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+#define prlog(l, f, ...) do { _prlog(l, pr_fmt(f), ##__VA_ARGS__); } while(0)
+
+void _prlog(int log_level __attribute__((unused)), const char* fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+/* Add any stub functions required for linking here. */
+static void stub_function(void)
+{
+ abort();
+}
+
+struct cpu_thread;
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+ const char *name,
+ void (*func)(void *data), void *data,
+ bool no_return);
+
+void cpu_wait_job(struct cpu_job *job, bool free_it);
+void cpu_process_local_jobs(void);
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+ const char *name,
+ void (*func)(void *data), void *data);
+
+struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
+ const char *name,
+ void (*func)(void *data), void *data)
+{
+ (void)chip_id;
+ return __cpu_queue_job(NULL, name, func, data, false);
+}
+
+struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
+ const char *name,
+ void (*func)(void *data), void *data,
+ bool no_return)
+{
+ (void)cpu;
+ (void)name;
+ (func)(data);
+ (void)no_return;
+ return NULL;
+}
+
+void cpu_wait_job(struct cpu_job *job, bool free_it)
+{
+ (void)job;
+ (void)free_it;
+ return;
+}
+
+void cpu_process_local_jobs(void)
+{
+}
+
+#define STUB(fnname) \
+ void fnname(void) __attribute__((weak, alias ("stub_function")))
+
+STUB(fdt_begin_node);
+STUB(fdt_property);
+STUB(fdt_end_node);
+STUB(fdt_create_with_flags);
+STUB(fdt_add_reservemap_entry);
+STUB(fdt_finish_reservemap);
+STUB(fdt_strerror);
+STUB(fdt_check_header);
+STUB(fdt_check_node_offset_);
+STUB(fdt_next_tag);
+STUB(fdt_string);
+STUB(fdt_get_name);
+STUB(dt_first);
+STUB(dt_next);
+STUB(dt_has_node_property);
+STUB(dt_get_address);
+STUB(add_chip_dev_associativity);
+STUB(pci_check_clear_freeze);