diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/core/test | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/core/test')
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 Binary files differnew file mode 100644 index 000000000..2ab241af5 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-0 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-1 b/roms/skiboot/core/test/firmware-versions-input/version-1 Binary files differnew file mode 100644 index 000000000..746327a8b --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-1 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-10 b/roms/skiboot/core/test/firmware-versions-input/version-10 Binary files differnew file mode 100644 index 000000000..013af6089 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-10 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-11 b/roms/skiboot/core/test/firmware-versions-input/version-11 Binary files differnew file mode 100644 index 000000000..55e835321 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-11 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-16 b/roms/skiboot/core/test/firmware-versions-input/version-16 Binary files differnew file mode 100644 index 000000000..8906af4e9 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-16 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-2 b/roms/skiboot/core/test/firmware-versions-input/version-2 Binary files differnew file mode 100644 index 000000000..f012ffd23 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-2 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-26 b/roms/skiboot/core/test/firmware-versions-input/version-26 Binary files differnew file mode 100644 index 000000000..adfd5bbcf --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-26 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-27 b/roms/skiboot/core/test/firmware-versions-input/version-27 Binary files differnew file mode 100644 index 000000000..d7ade9863 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-27 diff --git a/roms/skiboot/core/test/firmware-versions-input/version-29 b/roms/skiboot/core/test/firmware-versions-input/version-29 Binary files differnew file mode 100644 index 000000000..b1476a3a5 --- /dev/null +++ b/roms/skiboot/core/test/firmware-versions-input/version-29 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(®ions); + + 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(®ions, 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(®ions, 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(®ions, 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(®ions, r, list) { + /* Regions must not overlap. */ + struct mem_region *r2, *pre = NULL, *post = NULL; + list_for_each(®ions, r2, list) { + if (r == r2) + continue; + assert(!overlaps(r, r2)); + } + + /* But should have exact neighbours. */ + list_for_each(®ions, 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(®ions, 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(®ions, 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(®ions, 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(®ions, 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(®ions, 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(®ions, 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); |