Copy arm's setup code (also DT based) over to powerpc, adapting it a bit. Also bring over arm's setup selftest, giving powerpc its first test.
Signed-off-by: Andrew Jones <drjo...@redhat.com> --- lib/powerpc/asm/setup.h | 27 ++++++++++++++++ lib/powerpc/setup.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/ppc64/asm/setup.h | 1 + powerpc/cstart64.S | 9 ++++++ powerpc/selftest.c | 64 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 lib/powerpc/asm/setup.h create mode 100644 lib/ppc64/asm/setup.h diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h new file mode 100644 index 0000000000000..745226a8cf067 --- /dev/null +++ b/lib/powerpc/asm/setup.h @@ -0,0 +1,27 @@ +#ifndef _ASMPOWERPC_SETUP_H_ +#define _ASMPOWERPC_SETUP_H_ +/* + * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjo...@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include <libcflat.h> + +#define NR_CPUS 8 /* arbitrarily set for now */ +extern u32 cpus[NR_CPUS]; +extern int nr_cpus; + +extern phys_addr_t __physical_start, __physical_end; + +#define PHYSICAL_START (__physical_start) +#define PHYSICAL_END (__physical_end) + +#ifdef __powerpc64__ +#define L1_CACHE_SHIFT 7 +#else +#define L1_CACHE_SHIFT 5 +#endif +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#endif /* _ASMPOWERPC_SETUP_H_ */ diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c index e69de29bb2d1d..1794d1f39066a 100644 --- a/lib/powerpc/setup.c +++ b/lib/powerpc/setup.c @@ -0,0 +1,82 @@ +/* + * Initialize machine setup information and I/O. + * + * After running setup() unit tests may query how many cpus they have + * (nr_cpus), how much memory they have (PHYSICAL_END - PHYSICAL_START), + * may use dynamic memory allocation (malloc, etc.), printf, and exit. + * Finally, argc and argv are also ready to be passed to main(). + * + * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjo...@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include <libcflat.h> +#include <libfdt/libfdt.h> +#include <devicetree.h> +#include <alloc.h> +#include <asm/setup.h> +#include <asm/page.h> + +extern unsigned long stacktop; +extern void io_init(void); +extern void setup_args(const char *args); + +u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) }; +int nr_cpus; + +phys_addr_t __physical_start, __physical_end; + +static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused) +{ + int cpu = nr_cpus++; + assert(cpu < NR_CPUS); + cpus[cpu] = regval; +} + +static void cpu_init(void) +{ + nr_cpus = 0; + assert(dt_for_each_cpu_node(cpu_set, NULL) == 0); +} + +static void mem_init(phys_addr_t freemem_start) +{ + /* we only expect one membank to be defined in the DT */ + struct dt_pbus_reg regs[1]; + phys_addr_t mem_start, mem_end; + + assert(dt_get_memory_params(regs, 1)); + + mem_start = regs[0].addr; + mem_end = mem_start + regs[0].size; + +// assert(!(mem_start & ~PHYS_MASK) && !((mem_end-1) & ~PHYS_MASK)); + assert(freemem_start >= mem_start && freemem_start < mem_end); + + __physical_start = mem_start; /* PHYSICAL_START */ + __physical_end = mem_end; /* PHYSICAL_END */ + + phys_alloc_init(freemem_start, mem_end - freemem_start); + phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); +} + +void setup(const void *fdt) +{ + const char *bootargs; + u32 fdt_size; + + /* + * Move the fdt to just above the stack. The free memory + * then starts just after the fdt. + */ + fdt_size = fdt_totalsize(fdt); + assert(fdt_move(fdt, &stacktop, fdt_size) == 0); + assert(dt_init(&stacktop) == 0); + + mem_init(PAGE_ALIGN((unsigned long)&stacktop + fdt_size)); + io_init(); + cpu_init(); + + assert(dt_get_bootargs(&bootargs) == 0); + setup_args(bootargs); +} diff --git a/lib/ppc64/asm/setup.h b/lib/ppc64/asm/setup.h new file mode 100644 index 0000000000000..20192985928a4 --- /dev/null +++ b/lib/ppc64/asm/setup.h @@ -0,0 +1 @@ +#include "../../powerpc/asm/setup.h" diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S index d7c51cd352ee4..141d4563563d5 100644 --- a/powerpc/cstart64.S +++ b/powerpc/cstart64.S @@ -21,10 +21,19 @@ .section .init +/* + * start is the entry point. r3 points to the DTB + */ .globl start start: LOAD_REG_IMMEDIATE(r1, stackptr) LOAD_REG_IMMEDIATE(r2, tocptr) + bl .setup + + /* run the test */ + LOAD_REG_IMMEDIATE(r5, __argc) + LOAD_REG_IMMEDIATE(r4, __argv) + lwz r3, 0(r5) bl .main bl .exit b halt diff --git a/powerpc/selftest.c b/powerpc/selftest.c index 2f2a5215dd55c..b1d5e73029f46 100644 --- a/powerpc/selftest.c +++ b/powerpc/selftest.c @@ -1,7 +1,65 @@ +/* + * Test the framework itself. These tests confirm that setup works. + * + * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjo...@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ #include <libcflat.h> +#include <util.h> +#include <alloc.h> /* phys_addr_t */ +#include <asm/setup.h> -int main(void) +static void check_setup(int argc, char **argv) { - printf("hello world\n"); - return 0; + int nr_tests = 0, i; + char *var; + long val; + + for (i = 0; i < argc; ++i) { + + var = parse_keyval(argv[i], &val); + if (!var) + continue; + + report_prefix_push(var); + + if (strcmp(var, "mem") == 0) { + + phys_addr_t memsize = PHYSICAL_END - PHYSICAL_START; + phys_addr_t expected = ((phys_addr_t)val)*1024*1024; + + report("size = %d MB", memsize == expected, + memsize/1024/1024); + ++nr_tests; + + } else if (strcmp(var, "smp") == 0) { + + report("nr_cpus = %d", nr_cpus == (int)val, nr_cpus); + ++nr_tests; + } + + report_prefix_pop(); + } + + if (nr_tests < 2) + report_abort("missing input"); +} + +int main(int argc, char **argv) +{ + report_prefix_push("selftest"); + + if (argc < 1) + report_abort("no test specified"); + + report_prefix_push(argv[0]); + + if (strcmp(argv[0], "setup") == 0) { + + check_setup(argc-1, &argv[1]); + + } + + return report_summary(); } -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html