diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/external/mambo | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/external/mambo')
-rw-r--r-- | roms/skiboot/external/mambo/Makefile | 10 | ||||
-rw-r--r-- | roms/skiboot/external/mambo/README.md | 73 | ||||
-rw-r--r-- | roms/skiboot/external/mambo/cvc.bin | bin | 0 -> 9984 bytes | |||
-rw-r--r-- | roms/skiboot/external/mambo/mambo-socket-proxy.c | 347 | ||||
-rw-r--r-- | roms/skiboot/external/mambo/mambo_utils.tcl | 794 | ||||
-rw-r--r-- | roms/skiboot/external/mambo/qtrace_utils.tcl | 16 | ||||
-rw-r--r-- | roms/skiboot/external/mambo/skiboot.tcl | 732 |
7 files changed, 1972 insertions, 0 deletions
diff --git a/roms/skiboot/external/mambo/Makefile b/roms/skiboot/external/mambo/Makefile new file mode 100644 index 000000000..942ebf20e --- /dev/null +++ b/roms/skiboot/external/mambo/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +CFLAGS=-O2 -m64 -pthread -Werror -Wall + +CC=$(CROSS)gcc + +all: mambo-socket-proxy + +clean: + rm -rf mambo-socket-proxy diff --git a/roms/skiboot/external/mambo/README.md b/roms/skiboot/external/mambo/README.md new file mode 100644 index 000000000..06a0f3185 --- /dev/null +++ b/roms/skiboot/external/mambo/README.md @@ -0,0 +1,73 @@ +# Running skiboot and Linux in Mambo + +The POWER8 Functional Simulator (aka Mambo) is free to use but not +open source and is only supported on limited platforms. This is a +guide to getting started guide with it with skiboot and linux. + +## Getting Started + +From a bare x86_64 Ubuntu 16.04 install, to running skiboot and linux +in the simulator, you can do do the following: + +### Steps to get Running on Ubuntu +xterm is needed by the simulator. +``` +apt-get install xterm +``` + +### Download mambo from IBM +Download systemsim-p8..deb from: +http://www-304.ibm.com/support/customercare/sas/f/pwrfs/home.html +``` +dpkg -i systemsim-p8*deb +``` + +### Grab your skiboot, linux and initramfs images +How to build a skiboot.lid is in the top level README file. + +Use a 64 bit powerpc kernel here. If compiling yourself, we suggest +using powernv_defconfig. + +If you use op-build to build a full set of OpenPower images, you’ll +likely be able to extract skiboot, zImage.epapr (or vmlinux and +rootfs.cpio.xz) from output/images. We suggest using the +opal_defconfig. + +### Setup environment variables +Setup environment variables to point to your images +``` +export SKIBOOT_ZIMAGE=$HOME/src/op-build/output/images/zImage.epapr +export SKIBOOT=$HOME/src/op-build/output/images/skiboot.lid +export SKIBOOT_AUTORUN=1 +``` +If you want Mambo to autmatically run *AND* exit when the system is +shutdown (or has a HW crash) use this: +``` +export SKIBOOT_AUTORUN=2 +``` +If you want a vmlinux and separate initramfs you can also do this: +``` +export SKIBOOT_ZIMAGE=$HOME/src/op-build/output/images/vmlinux +export SKIBOOT_INITRD=$HOME/src/op-build/output/images/rootfs.cpio.xz +export SKIBOOT=$HOME/src/skiboot/skiboot.lid +export SKIBOOT_AUTORUN=1 +``` + +### Using Real Container Verification Code for Secure Boot + +The CVC code dump is from a real machine, and the code is from the Hostboot +project (see src/securerom). We just include the dump here for testing +purposes. + +``` +export SKIBOOT_CVC_CODE=$HOME/src/skiboot/external/mambo/cvc.bin +export SKIBOOT_ENABLE_MAMBO_STB=1 +``` + +### Run the simulator +``` +/opt/ibm/systemsim-p8/run/pegasus/power8 -f $HOME/src/skiboot/external/mambo/skiboot.tcl +``` + +This should open an xterm and start booting. It should take around +20sec to get to a petitboot console. diff --git a/roms/skiboot/external/mambo/cvc.bin b/roms/skiboot/external/mambo/cvc.bin Binary files differnew file mode 100644 index 000000000..8d4c7e704 --- /dev/null +++ b/roms/skiboot/external/mambo/cvc.bin diff --git a/roms/skiboot/external/mambo/mambo-socket-proxy.c b/roms/skiboot/external/mambo/mambo-socket-proxy.c new file mode 100644 index 000000000..64b677045 --- /dev/null +++ b/roms/skiboot/external/mambo/mambo-socket-proxy.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Compile with: + * gcc -static -O2 mambo-socket-proxy.c -o mambo-socket-proxy -pthread + * Run inside the simulator: + * - to forward host ssh connections to sim ssh server + * ./mambo-socket-proxy -h 10022 -s 22 + * Then connect to port 10022 on your host + * ssh -p 10022 localhost + * - to allow http proxy access from inside the sim to local http proxy + * ./mambo-socket-proxy -b proxy.mynetwork -h 3128 -s 3128 + * + * Copyright (C) 2017 Michael Neuling <mikey@neuling.org>, IBM + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> +#include <getopt.h> + +#define CALL_TCL 86 +#define BOGUS_SOCKET_CONN_PROBE_CODE 224 +#define BOGUS_SOCKET_CONN_SEND_CODE 225 +#define BOGUS_SOCKET_CONN_RECV_CODE 226 + +static inline int callthru2(int command, unsigned long arg1, unsigned long arg2) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2)); + return (c); +} + +static inline int callthru3(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3)); + return (c); +} + +static inline int callthru4(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4)); + return (c); +} + +static inline int callthru5(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + register unsigned long a5 asm("r8") = arg5; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4), "r"(a5)); + return (c); +} + +unsigned long callthru_tcl(const char *str, int strlen) +{ + return callthru2(CALL_TCL, (unsigned long)str, + (unsigned long)strlen); +} + +unsigned long bogus_socket_conn_probe(int dev, void *addr, int conn) +{ + return callthru3(BOGUS_SOCKET_CONN_PROBE_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_recv(int dev, void *addr, int maxlen, int conn) +{ + return callthru4(BOGUS_SOCKET_CONN_RECV_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_send(int dev, void *addr, int maxlen, int conn) +{ + return callthru5(BOGUS_SOCKET_CONN_SEND_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + 0, + (unsigned long)conn); +} + +#define BUF_MAX 1024 + +struct sock_info { + char *host; + int sock; + int dev; + int open; + int conn; +}; + +void *recv_thread(void *ptr) +{ + struct timeval timeout; + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + fd_set set; + + /* 1 sec */ + + + while(1) { + FD_ZERO(&set); + FD_SET(si->sock, &set); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + /* Set timeout to 1 second */ + len = select(si->sock+1, &set, NULL, NULL, &timeout); + if (len <= 0) /* timeout */ + len = -1; + else /* Receive from mambo tcp server */ + len = recv(si->sock, &buf, BUF_MAX, 0); + if (len == 0) { + si->open = 0; + return NULL; /* closed */ + } + if (len != -1) { + bogus_socket_conn_send(si->dev, &buf, len, si->conn); + } + if (!si->open) + return NULL; + } +} + +#define POLL_MAX_NS 10000000 + +void *send_thread(void *ptr) +{ + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + struct timespec t; + int fault_retry = 16; + + t.tv_sec = 0; + t.tv_nsec = POLL_MAX_NS; + + while(1) { + /* Send to mambo tcp server */ + len = bogus_socket_conn_recv(si->dev, &buf, BUF_MAX, si->conn); + if (len == -3 && fault_retry--) { + /* Page fault. Touch the buf and try again */ + memset(buf, 0, BUF_MAX); + continue; + } + fault_retry = 16; + + if (len == -1) /* EAGAIN */ + nanosleep(&t , NULL); + else if (len > 0) + send(si->sock, &buf, len, 0); + else { + si->open = 0; + return NULL; /* closed */ + } + if (!si->open) + return NULL; + } + +} + +void *connect_sockets(void *ptr) +{ + struct sock_info *si = ptr; + pthread_t recv, send; + unsigned long rc = 0; + + if (pthread_create(&recv, NULL, recv_thread, si) || + pthread_create(&send, NULL, send_thread, si)) { + rc = -1; + goto out; + } + + if (pthread_join(recv, NULL) || pthread_join(send, NULL)) { + rc = -1; + goto out; + } + +out: + /* FIXME: Do shutdown better */ + shutdown(si->sock, SHUT_WR); + si->open = 0; + free(si); + return (void *)rc; +} + +void print_usage() { + printf("Usage:\n"); + printf(" mambo-socket-proxy [-b <host>] -h <host port> -s <sim port>\n"); + printf("\n"); + printf(" -h <host port> : Port on the host to forward\n"); + printf(" -s <host port> : Port in the sim to forward\n"); + printf(" -b <host machine> : Connect sim port to host network\n"); + printf("\n"); +} + +int main (int argc, char *argv[]) +{ + char cmd[128]; + struct sockaddr_in ser, client; + pthread_t sockets_thread; + struct sock_info *si; + int sock, conn, rc = 0, option = 0, one_shot = 0, c, sock_desc = 0; + char *host = NULL; + int host_port = -1, sim_port = -1; + int dev = 1; /* backwards starts at 1 so forwards can use 0 */ + + while ((option = getopt(argc, argv,"rb:h:s:")) != -1) { + switch (option) { + case 'b' : + host = optarg; + break; + case 'h' : + host_port = atoi(optarg); + break; + case 's' : + sim_port = atoi(optarg); + break; + default: + print_usage(); + exit(1); + } + } + + if (host_port == -1 || sim_port ==-1) { + print_usage(); + exit(EXIT_FAILURE); + } + + /* + * A host/backwards connection will use dev=0 and conn >= 0. + * The forwards connection will use dev >= 1 and conn=0 + */ + if (host) { + sock_desc = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_addr.s_addr = INADDR_ANY; + ser.sin_port = htons(sim_port); + + if (bind(sock_desc, (struct sockaddr *) &ser, sizeof(ser)) < 0) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + + listen(sock_desc, 3); + } else { + /* + * Cleaning up old bogus socket. + */ + sprintf(cmd, "mysim bogus socket cleanup"); + callthru_tcl(cmd, strlen(cmd)); + sleep(1); /* Cleanup takes a while */ + sprintf(cmd, "mysim bogus socket init 0 server " + "127.0.0.1 %i poll 0 nonblock", host_port); + callthru_tcl(cmd, strlen(cmd)); + } + + while (1) { + + if (host) { + sock = accept(sock_desc, (struct sockaddr *)&client, (socklen_t*)&c); + if (sock < 0) { + perror("accept failed"); + rc = -1; + goto out; + } + + sprintf(cmd, "mysim bogus socket init %i client %s %i poll 0", + dev, host, host_port); + callthru_tcl(cmd, strlen(cmd)); + while (bogus_socket_conn_probe(dev, NULL, 0) == -1) + sleep(1); + } else { + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + do { + conn = bogus_socket_conn_probe(0, NULL, -1); + nanosleep(&t , NULL); + } while (conn == -1); + + sock = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_port = htons(sim_port); + ser.sin_addr.s_addr = inet_addr("127.0.0.1"); + memset(ser.sin_zero, '\0', sizeof ser.sin_zero); + + if (connect(sock, (struct sockaddr *) &ser, sizeof(ser))) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + } + + si = malloc(sizeof(struct sock_info)); + si->host = host; + si->sock = sock; + si->dev = host?dev:0; + si->open = 1; + si->conn = host?0:conn; + + if (pthread_create(&sockets_thread, NULL, connect_sockets, si)) { + rc = -1; + goto out; + } + + if (one_shot) + break; + ++dev; // FIXME: do a real allocator + } +out: + exit(rc); +} diff --git a/roms/skiboot/external/mambo/mambo_utils.tcl b/roms/skiboot/external/mambo/mambo_utils.tcl new file mode 100644 index 000000000..96f8971ab --- /dev/null +++ b/roms/skiboot/external/mambo/mambo_utils.tcl @@ -0,0 +1,794 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# +# Make Mambo behave a bit more like gdb +# +set target_t 0 +set target_c 0 +set target_p 0 + +proc target { { t 0 } { c 0 } { p 0 } } { + global target_t + global target_c + global target_p + + set target_t $t + set target_c $c + set target_p $p + + return "targeting cpu $p:$c:$t" +} + +proc p { reg { t -1 } { c -1 } { p -1 } } { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + switch -regexp $reg { + ^r$ { + set val [mysim cpu $p:$c:$t display gprs] + } + ^r[0-9]+$ { + regexp "r(\[0-9\]*)" $reg dummy num + set val [mysim cpu $p:$c:$t display gpr $num] + } + ^f[0-9]+$ { + regexp "f(\[0-9\]*)" $reg dummy num + set val [mysim cpu $p:$c:$t display fpr $num] + } + ^v[0-9]+$ { + regexp "v(\[0-9\]*)" $reg dummy num + set val [mysim cpu $p:$c:$t display vmxr $num] + } + default { + set val [mysim cpu $p:$c:$t display spr $reg] + } + } + + return "$val" +} + +# +# behave like gdb +# +proc sr { reg val { t -1} { c -1 } { p -1 } } { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + switch -regexp $reg { + ^r[0-9]+$ { + regexp "r(\[0-9\]*)" $reg dummy num + mysim cpu $p:$c:$t set gpr $num $val + } + ^f[0-9]+$ { + regexp "f(\[0-9\]*)" $reg dummy num + mysim cpu $p:$c:$t set fpr $num $val + } + ^v[0-9]+$ { + regexp "v(\[0-9\]*)" $reg dummy num + mysim cpu $p:$c:$t set vmxr $num $val + } + default { + mysim cpu $p:$c:$t set spr $reg $val + } + } + p $reg $t +} + +proc b { addr } { + mysim trigger set pc $addr "just_stop" + set at [i $addr] + puts "breakpoint set at $at" +} + +# Run until $console_string appears on the Linux console +# +# eg. +# break_on_console "Freeing unused kernel memory:" +# break_on_console "buildroot login:" + +proc break_on_console { console_string } { + mysim trigger set console "$console_string" "just_stop" +} + +proc clear_console_break { console_string } { + mysim trigger clear console "$console_string" +} + +proc wr { start stop } { + mysim trigger set memory system w $start $stop 0 "just_stop" +} + +proc c { } { + mysim go +} + +proc i { pc { t -1 } { c -1 } { p -1 } } { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + set pc_laddr [mysim cpu $p:$c:$t util itranslate $pc] + set inst [mysim cpu $p:$c:$t memory display $pc_laddr 4] + set disasm [mysim cpu $p:$c:$t util ppc_disasm $inst $pc] + return "\[$p:$c:$t\]: $pc ($pc_laddr) Enc:$inst : $disasm" +} + +proc ipc { { t -1 } { c -1 } { p -1 } } { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + set pc [mysim cpu $p:$c:$t display spr pc] + i $pc $t $c $p +} + +proc ipca { } { + set cpus [myconf query cpus] + set threads [myconf query processor/number_of_threads] + + for { set i 0 } { $i < $cpus } { incr i 1 } { + for { set j 0 } { $j < $threads } { incr j 1 } { + puts [ipc $j $i] + } + } +} + +proc pa { spr } { + set cpus [myconf query cpus] + set threads [myconf query processor/number_of_threads] + + for { set i 0 } { $i < $cpus } { incr i 1 } { + for { set j 0 } { $j < $threads } { incr j 1 } { + set val [mysim cpu $i thread $j display spr $spr] + puts "CPU: $i THREAD: $j SPR $spr = $val" + } + } +} + +proc s { {nr 1} } { + for { set i 0 } { $i < $nr } { incr i 1 } { + mysim step 1 + ipca + } +} + +proc S { {nr 1} } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + for { set i 0 } { $i < $nr } { incr i 1 } { + mysim cpu $p:$c:$t step 1 + puts [ipc] + } +} + +proc z { count } { + while { $count > 0 } { + s + incr count -1 + } +} + +proc sample_pc { sample count } { + while { $count > 0 } { + mysim cycle $sample + ipc + incr count -1 + } +} + +proc e2p { ea } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set pa [ mysim cpu $p:$c:$t util dtranslate $ea ] + puts "$pa" +} + +proc x { pa { size 8 } } { + set val [ mysim memory display $pa $size ] + puts "$pa : $val" +} + +proc it { ea } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + mysim cpu $p:$c:$t util itranslate $ea +} +proc dt { ea } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + mysim cpu $p:$c:$t util dtranslate $ea +} + +proc ex { ea { size 8 } } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set pa [ mysim cpu $p:$c:$t util dtranslate $ea ] + set val [ mysim memory display $pa $size ] + puts "$pa : $val" +} + +proc di { location { count 16 } } { + set addr [expr $location & 0xfffffffffffffff0] + disasm_mem mysim $addr $count +} + +proc hexdump { location count } { + set addr [expr $location & 0xfffffffffffffff0] + set top [expr $addr + ($count * 15)] + for { set i $addr } { $i < $top } { incr i 16 } { + set val [expr $i + (4 * 0)] + set val0 [format "%08x" [mysim memory display $val 4]] + set val [expr $i + (4 * 1)] + set val1 [format "%08x" [mysim memory display $val 4]] + set val [expr $i + (4 * 2)] + set val2 [format "%08x" [mysim memory display $val 4]] + set val [expr $i + (4 * 3)] + set val3 [format "%08x" [mysim memory display $val 4]] + + set ascii "" + for { set j 0 } { $j < 16 } { incr j } { + set byte [get_char [expr $i + $j]] + if { $byte < 0x20 || $byte >= 127} { + set c "." + } else { + set c [format %c $byte] + } + set ascii [string cat "$ascii" "$c"] + } + + set loc [format "0x%016x" $i] + puts "$loc: $val0 $val1 $val2 $val3 $ascii" + } +} + +proc get_char { addr } { + return [expr [mysim memory display "$addr" 1]] +} + +proc p_str { addr { limit 0 } } { + set addr_limit 0xfffffffffffffffff + if { $limit > 0 } { set addr_limit [expr $limit + $addr] } + set s "" + + for {} { [get_char "$addr"] != 0} { incr addr 1 } { + # memory display returns hex values with a leading 0x + set c [format %c [get_char "$addr"]] + set s [string cat "$s" "$c"] + if { $addr == $addr_limit } { break } + } + + puts "$s" +} + +proc slbv {} { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + puts [mysim cpu $p:$c:$t display slb valid] +} + +proc regs { { t -1 } { c -1 } { p -1 }} { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + puts "GPRS:" + puts [mysim cpu $p:$c:$t display gprs] +} + +proc tlbv {} { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + puts "$p:$c:$t:TLB: ----------------------" + puts [mysim cpu $p:$c:$t display tlb valid] +} + +proc exc { { i SystemReset } } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + puts "$p:$c:$t:EXCEPTION:$i" + puts [mysim cpu $p:$c:$t interrupt $i] +} + +proc just_stop { args } { + simstop + ipca +} + +proc st { count } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set sp [mysim cpu $p:$c:$t display gpr 1] + puts "SP: $sp" + ipc + set lr [mysim cpu $p:$c:$t display spr lr] + i $lr + while { $count > 0 } { + set sp [mysim cpu $p:$c:$t util itranslate $sp] + set lr [mysim memory display [expr $sp++16] 8] + i $lr + set sp [mysim memory display $sp 8] + + incr count -1 + } +} + +proc mywatch { } { + while { [mysim memory display 0x700 8] != 0 } { + mysim cycle 1 + } + puts "condition occurred " + ipc +} + +# +# force gdb to attach +# +proc gdb { { timeout 0 } } { + mysim set fast off + mysim debugger wait $timeout +} + +proc egdb { { timeout 0 }} { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set srr0 [mysim cpu $p:$c:$t display spr srr0] + set srr1 [mysim cpu $p:$c:$t display spr srr1] + mysim cpu $p:$c:$t set spr pc $srr0 + mysim cpu $p:$c:$t set spr msr $srr1 + gdb $timeout +} + +proc mem_display_64_le { addr } { + set data 0 + for {set i 0} {$i < 8} {incr i} { + set data [ expr $data << 8 ] + set l [ mysim memory display [ expr $addr+7-$i ] 1 ] + set data [ expr $data | $l ] + } + return [format 0x%X $data] +} + +proc mem_display_64 { addr le } { + if { $le } { + return [ mem_display_64_le $addr ] + } + # mysim memory display is big endian + return [ mysim memory display $addr 8 ] +} + +proc bt { {sp 0} } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set lr [mysim cpu $p:$c:$t display spr pc] + set sym [addr2func $lr] + puts "pc:\t\t\t\t$lr\t$sym" + if { $sp == 0 } { + set sp [mysim cpu $p:$c:$t display gpr 1] + } + set lr [mysim cpu $p:$c:$t display spr lr] + set sym [addr2func $lr] + puts "lr:\t\t\t\t$lr\t$sym" + + set msr [mysim cpu $p:$c:$t display spr msr] + set le [ expr $msr & 1 ] + + # Limit to 200 in case of an infinite loop + for {set i 0} {$i < 200} {incr i} { + set pa [ mysim cpu $p:$c:$t util dtranslate $sp ] + set bc [ mem_display_64 $pa $le ] + set lr [ mem_display_64 [ expr $pa + 16 ] $le ] + set sym [addr2func $lr] + puts "stack:$pa \t$lr\t$sym" + if { $bc == 0 } { break } + set sp $bc + } + puts "" +} + +proc ton { } {mysim mode turbo } +proc toff { } {mysim mode simple } + +proc don { opt } { + simdebug set $opt 1 +} + +proc doff { opt } { + simdebug set $opt 0 +} + +# skisym and linsym return the address of a symbol, looked up from +# the relevant System.map or skiboot.map file. +proc linsym { name } { + global linux_symbol_map + + # create a regexp that matches the symbol name + set base {([[:xdigit:]]*) (.)} + set exp [concat $base " $name\$"] + set ret "" + + foreach {line addr type} [regexp -line -inline $exp $linux_symbol_map] { + set ret "0x$addr" + } + + return $ret +} + +# skisym factors in skiboot's load address +proc skisym { name } { + global skiboot_symbol_map + global mconf + + set base {([[:xdigit:]]*) (.)} + set exp [concat $base " $name\$"] + set ret "" + + foreach {line addr type} [regexp -line -inline $exp $skiboot_symbol_map] { + set actual_addr [expr "0x$addr" + $mconf(boot_load)] + set ret [format "0x%.16x" $actual_addr] + } + + return $ret +} + +proc addr2func { addr } { + global skiboot_symbol_list + global linux_symbol_list + global user_symbol_list + global mconf + + set prevname "" + set preva "0" + + if { [ info exists linux_symbol_list ] && "$addr" >= 0xc000000000000000} { + foreach line $linux_symbol_list { + lassign $line a type name + if { "0x$a" > $addr } { + set o [format "0x%x" [expr $addr - "0x$preva"]] + return "$prevname+$o" + } + set prevname $name + set preva $a + } + } + # Assume skiboot is less that 4MB big + if { [ info exists skiboot_symbol_list ] && + "$addr" > $mconf(boot_load) && "$addr" < [expr $mconf(boot_load) + 4194304] } { + set mapaddr [expr $addr - $mconf(boot_load)] + + foreach line $skiboot_symbol_list { + lassign $line a type name + if { "0x$a" > $mapaddr } { + set o [format "0x%x" [expr $mapaddr - "0x$preva"]] + return "$prevname+$o" + } + set prevname $name + set preva $a + } + } + if { [ info exists user_symbol_list ] } { + foreach line $user_symbol_list { + lassign $line a type name + if { "0x$a" > $addr } { + set o [format "0x%x" [expr $addr - "0x$preva"]] + return "$prevname+$o" + } + set prevname $name + set preva $a + } + } + return "+$addr" +} + +proc current_insn { { t -1 } { c -1 } { p -1 }} { + global target_t + global target_c + global target_p + + if { $t == -1 } { set t $target_t } + if { $c == -1 } { set c $target_c } + if { $p == -1 } { set p $target_p } + + set pc [mysim cpu $p:$c:$t display spr pc] + set pc_laddr [mysim cpu $p:$c:$t util itranslate $pc] + set inst [mysim cpu $p:$c:$t memory display $pc_laddr 4] + set disasm [mysim cpu $p:$c:$t util ppc_disasm $inst $pc] + return $disasm +} + +set SRR1 0 +set DSISR 0 +set DAR 0 + +proc sreset_trigger { args } { + global SRR1 + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + mysim trigger clear pc 0x100 + mysim trigger clear pc 0x104 + set s [expr [mysim cpu $p:$c:$t display spr srr1] & ~0x00000000003c0002] + set SRR1 [expr $SRR1 | $s] + mysim cpu $p:$c:$t set spr srr1 $SRR1 +} + +proc exc_sreset { } { + global SRR1 + global DSISR + global DAR + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + # In case of recoverable MCE, idle wakeup always sets RI, others get + # RI from current environment. For unrecoverable, RI would always be + # clear by hardware. + if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } { + set msr_ri 0x2 + set SRR1_powersave [expr (0x2 << (63-47))] + } else { + set msr_ri [expr [mysim cpu $p:$c:$t display spr msr] & 0x2] + set SRR1_powersave 0 + } + + # reason system reset + set SRR1_reason 0x4 + + set SRR1 [expr 0x0 | $msr_ri | $SRR1_powersave] + set SRR1 [expr $SRR1 | ((($SRR1_reason >> 3) & 0x1) << (63-42))] + set SRR1 [expr $SRR1 | ((($SRR1_reason >> 2) & 0x1) << (63-43))] + set SRR1 [expr $SRR1 | ((($SRR1_reason >> 1) & 0x1) << (63-44))] + set SRR1 [expr $SRR1 | ((($SRR1_reason >> 0) & 0x1) << (63-45))] + + if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } { + # mambo has a quirk that interrupts from idle wake immediately + # and go over current instruction. + mysim trigger set pc 0x100 "sreset_trigger" + mysim trigger set pc 0x104 "sreset_trigger" + mysim cpu $p:$c:$t interrupt SystemReset + } else { + mysim trigger set pc 0x100 "sreset_trigger" + mysim trigger set pc 0x104 "sreset_trigger" + mysim cpu $p:$c:$t interrupt SystemReset + } + + # sleep and sometimes other types of interrupts do not trigger 0x100 + if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x100 ] } { + sreset_trigger + } + if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x104 ] } { + sreset_trigger + } +} + +proc mce_trigger { args } { + global SRR1 + global DSISR + global DAR + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + mysim trigger clear pc 0x200 + mysim trigger clear pc 0x204 + + set s [expr [mysim cpu 0 display spr srr1] & ~0x00000000801f0002] + set SRR1 [expr $SRR1 | $s] + mysim cpu $p:$c:$t set spr srr1 $SRR1 + mysim cpu $p:$c:$t set spr dsisr $DSISR + mysim cpu $p:$c:$t set spr dar $DAR ; list +} + +# +# Inject a machine check. Recoverable MCE types can be forced to unrecoverable +# by clearing MSR_RI bit from SRR1 (which hardware may do). +# If d_side is 0, then cause goes into SRR1. Otherwise it gets put into DSISR. +# DAR is hardcoded to always 0xdeadbeefdeadbeef +# +# Default with no arguments is a recoverable i-side TLB multi-hit +# Other options: +# d_side=1 dsisr=0x80 - recoverable d-side SLB multi-hit +# d_side=1 dsisr=0x8000 - ue error on instruction fetch +# d_side=0 cause=0xd - unrecoverable i-side async store timeout (POWER9 only) +# d_side=0 cause=0x1 - unrecoverable i-side ifetch +# +proc exc_mce { { d_side 0 } { cause 0x5 } { recoverable 1 } } { + global SRR1 + global DSISR + global DAR + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + +# puts "INJECTING MCE" + + # In case of recoverable MCE, idle wakeup always sets RI, others get + # RI from current environment. For unrecoverable, RI would always be + # clear by hardware. + if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } { + set msr_ri 0x2 + set SRR1_powersave [expr (0x2 << (63-47))] + } else { + set msr_ri [expr [mysim cpu $p:$c:$t display spr msr] & 0x2] + set SRR1_powersave 0 + } + + if { !$recoverable } { + set msr_ri 0x0 + } + + if { $d_side } { + set is_dside 1 + set SRR1_mc_cause 0x0 + set DSISR $cause + set DAR 0xdeadbeefdeadbeef + } else { + set is_dside 0 + set SRR1_mc_cause $cause + set DSISR 0x0 + set DAR 0x0 + } + + set SRR1 [expr 0x0 | $msr_ri | $SRR1_powersave] + + set SRR1 [expr $SRR1 | ($is_dside << (63-42))] + set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 3) & 0x1) << (63-36))] + set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 2) & 0x1) << (63-43))] + set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 1) & 0x1) << (63-44))] + set SRR1 [expr $SRR1 | ((($SRR1_mc_cause >> 0) & 0x1) << (63-45))] + + if { [current_insn] in { "stop" "nap" "sleep" "winkle" } } { + # mambo has a quirk that interrupts from idle wake immediately + # and go over current instruction. + mysim trigger set pc 0x200 "mce_trigger" + mysim trigger set pc 0x204 "mce_trigger" + mysim cpu $p:$c:$t interrupt MachineCheck + } else { + mysim trigger set pc 0x200 "mce_trigger" + mysim trigger set pc 0x204 "mce_trigger" + mysim cpu $p:$c:$t interrupt MachineCheck + } + + # sleep and sometimes other types of interrupts do not trigger 0x200 + if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x200 ] } { + mce_trigger + } + if { [expr [mysim cpu $p:$c:$t display spr pc] == 0x204 ] } { + mce_trigger + } +} + +set R1 0 + +# Avoid stopping if we re-enter the same code. Wait until r1 matches. +# This helps stepping over exceptions or function calls etc. +proc stop_stack_match { args } { + global R1 + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set r1 [mysim cpu $p:$c:$t display gpr 1] + if { $R1 == $r1 } { + simstop + ipca + } +} + +# inject default recoverable MCE and step over it. Useful for testing whether +# code copes with taking an interleaving MCE. +proc inject_mce { } { + global R1 + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set R1 [mysim cpu $p:$c:$t display gpr 1] + set pc [mysim cpu $p:$c:$t display spr pc] + mysim trigger set pc $pc "stop_stack_match" + exc_mce + c + mysim trigger clear pc $pc ; list +} + +# +# We've stopped at addr and we need to inject the mce and continue +# +proc trigger_mce_ue_addr {args} { + set addr [lindex [lindex $args 0] 1] + mysim trigger clear memory system rw $addr $addr + exc_mce 0x1 0x8000 0x1 +} + +proc inject_mce_ue_on_addr {addr} { + mysim trigger set memory system rw $addr $addr 1 "trigger_mce_ue_addr" +} + +# inject and step over one instruction, and repeat. +proc inject_mce_step { {nr 1} } { + for { set i 0 } { $i < $nr } { incr i 1 } { + inject_mce + s + } +} + +# inject if RI is set and step over one instruction, and repeat. +proc inject_mce_step_ri { {nr 1} } { + upvar #0 target_t t + upvar #0 target_c c + upvar #0 target_p p + + set reserve_inject 1 + set reserve_inject_skip 0 + set reserve_counter 0 + + for { set i 0 } { $i < $nr } { incr i 1 } { + if { [expr [mysim cpu $p:$c:$t display spr msr] & 0x2] } { + # inject_mce + if { [mysim cpu $p:$c:$t display reservation] in { "none" } } { + inject_mce + mysim cpu $p:$c:$t set reservation none + if { $reserve_inject_skip } { + set reserve_inject 1 + set reserve_inject_skip 0 + } + } else { + if { $reserve_inject } { + inject_mce + mysim cpu $p:$c:$t set reservation none + set reserve_inject 0 + } else { + set reserve_inject_skip 1 + set reserve_counter [ expr $reserve_counter + 1 ] + if { $reserve_counter > 30 } { + mysim cpu $p:$c:$t set reservation none + } + } + } + } + s + } +} diff --git a/roms/skiboot/external/mambo/qtrace_utils.tcl b/roms/skiboot/external/mambo/qtrace_utils.tcl new file mode 100644 index 000000000..bb20b31d3 --- /dev/null +++ b/roms/skiboot/external/mambo/qtrace_utils.tcl @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +if { [file exists $env(LIB_DIR)/perf/qtrace.tcl] == 1} { + if { [catch {source $env(LIB_DIR)/perf/qtrace.tcl} issue ] } { + puts "QTrace not available: $issue" + } + + proc start_qtrace { { qtfile qtrace.qt } } { + QTrace::Initialize p9 mysim + QTrace::Start $qtfile mysim + } + + proc stop_qtrace { } { + QTrace::Stop mysim + } +} diff --git a/roms/skiboot/external/mambo/skiboot.tcl b/roms/skiboot/external/mambo/skiboot.tcl new file mode 100644 index 000000000..0ecb55a77 --- /dev/null +++ b/roms/skiboot/external/mambo/skiboot.tcl @@ -0,0 +1,732 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# +# scripts to run skiboot (and a payload) with Mambo (otherwise known as the +# POWER[89] Functional Simulator) +# +# Copyright 2014-2019 IBM Corp. + +# need to get images path defined early +source $env(LIB_DIR)/ppc/util.tcl +if { [file exists qtrace_utils.tcl] } then { + source qtrace_utils.tcl +} + +# +# Call tclreadline's Loop to move to friendlier +# commandline if one exists +# +proc readline { } { + set readline [catch { package require tclreadline }] + if { $readline == 0 } { + ::tclreadline::Loop + } +} + +proc mconfig { name env_name def } { + global mconf + global env + + if { [info exists env($env_name)] } { set mconf($name) $env($env_name) } + if { ![info exists mconf($name)] } { set mconf($name) $def } +} + +mconfig cpus CPUS 1 +mconfig threads THREADS 1 +mconfig memory MEM_SIZE 4G + +# Create multiple memory nodes? This will create a MEM_SIZE region +# on each chip (CPUS above). +mconfig numa MAMBO_NUMA 0 + +# Should we stop on an illeagal instruction +mconfig stop_on_ill MAMBO_STOP_ON_ILL false + +# Location of application binary to load +mconfig boot_image SKIBOOT ../../skiboot.lid + +# Boot: Memory location to load boot_image, for binary or vmlinux +mconfig boot_load MAMBO_BOOT_LOAD 0x30000000 + +# Boot: Value of PC after loading, for binary or vmlinux +mconfig boot_pc MAMBO_BOOT_PC 0x30000010 + +# Payload: Allow for a Linux style ramdisk/initrd +if { ![info exists env(SKIBOOT_ZIMAGE)] } { + error "Please set SKIBOOT_ZIMAGE to the path of your zImage.epapr" +} +mconfig payload PAYLOAD $env(SKIBOOT_ZIMAGE) + +mconfig linux_cmdline LINUX_CMDLINE "" + +# Paylod: Memory location for a Linux style ramdisk/initrd +mconfig payload_addr PAYLOAD_ADDR 0x20000000; + +# FW: Where should ePAPR Flat Devtree Binary be loaded +mconfig epapr_dt_addr EPAPR_DT_ADDR 0x1f00000;# place at 31M + +# Disk: Location of file to use a bogus disk 0 +mconfig rootdisk ROOTDISK none + +# Disk: File to use for re COW file: none or <file> +mconfig rootdisk_cow MAMBO_ROOTDISK_COW none + +# Disk: COW method to use +mconfig rootdisk_cow_method MAMBO_ROOTDISK_COW_METHOD newcow + +# Disk: COW hash size +mconfig rootdisk_cow_hash MAMBO_ROOTDISK_COW_HASH 1024 + +# Net: What type of networking: none, phea, bogus +mconfig net MAMBO_NET none + +# Net: What MAC address to use +mconfig net_mac MAMBO_NET_MAC 00:11:22:33:44:55 + +# Net: What is the name of the tap device +mconfig net_tapdev MAMBO_NET_TAPDEV "tap0" + +# Enable (default) or disable the "speculation-policy-favor-security" setting, +# set to 0 to disable. When enabled it causes Linux's RFI flush to be enabled. +mconfig speculation_policy_favor_security MAMBO_SPECULATION_POLICY_FAVOR_SECURITY 1 + +# These values ~= P9N DD2.3, except for fw_count_cache_flush_assist=0 because it +# exercises more kernel code. +# See https://github.com/open-power/hostboot/blob/7ce2a9daac0ccf759376929b2ec40bbbc7ca3398/src/usr/hdat/hdatiplparms.H#L520 +mconfig needs_l1d_flush_msr_hv MAMBO_NEEDS_L1D_FLUSH_MSR_HV 1 +mconfig needs_l1d_flush_msr_pr MAMBO_NEEDS_L1D_FLUSH_MSR_PR 1 +mconfig fw_l1d_thread_split MAMBO_FW_L1D_THREAD_SPLIT 1 +mconfig needs_spec_barrier MAMBO_NEEDS_SPEC_BARRIER 1 +mconfig fw_bcctrl_serialized MAMBO_FW_BCCTRL_SERIALIZED 0 +mconfig fw_count_cache_disabled MAMBO_FW_COUNT_CACHE_DISABLED 0 +mconfig needs_count_cache_flush MAMBO_NEEDS_COUNT_CACHE_FLUSH 1 +mconfig fw_count_cache_flush_assist MAMBO_COUNT_CACHE_FLUSH_ASSIST 0 +mconfig inst_spec_barrier_ori31 MAMBO_INST_SPEC_BARRIER_ORI31 1 +mconfig inst_l1d_flush_trig2 MAMBO_INST_L1D_FLUSH_TRIG2 1 +mconfig inst_l1d_flush_ori30 MAMBO_INST_L1D_FLUSH_ORI30 0 + +# +# Create machine config +# +set default_config [display default_configure] +define dup $default_config myconf +myconf config cpus $mconf(cpus) +myconf config processor/number_of_threads $mconf(threads) +myconf config memory_size $mconf(memory) +myconf config processor_option/ATTN_STOP true +myconf config processor_option/stop_on_illegal_instruction $mconf(stop_on_ill) +myconf config UART/0/enabled false +myconf config SimpleUART/enabled false +myconf config enable_rtas_support false +myconf config processor/cpu_frequency 512M +myconf config processor/timebase_frequency 1/1 +myconf config enable_pseries_nvram false +myconf config machine_option/NO_RAM TRUE +myconf config machine_option/NO_ROM TRUE +myconf config machine_option/MEMORY_OVERFLOW FALSE + +if { $default_config == "PEGASUS" } { + # We need to be DD2 or greater on p8 for the HILE HID bit. + myconf config processor/initial/PVR 0x4b0201 + + if { $mconf(numa) } { + myconf config memory_region_id_shift 35 + } +} + +if { $default_config == "P9" } { + # PVR configured for POWER9 DD2.3 Scale out 24 Core (ie SMT4) + myconf config processor/initial/PVR 0x4e1203 + myconf config processor/initial/SIM_CTRL1 0x4228301710000000 + + if { $mconf(numa) } { + myconf config memory_region_id_shift 45 + } +} + +if { $default_config == "P10" } { + # PVR configured for POWER10 DD1.0 + myconf config processor/initial/PVR 0x800100 + myconf config processor/initial/SIM_CTRL1 0xc228100400000000 + + if { $mconf(numa) } { + myconf config memory_region_id_shift 44 + } +} + + +if { $mconf(numa) } { + myconf config memory_regions $mconf(cpus) +} + +if { [info exists env(SKIBOOT_SIMCONF)] } { + source $env(SKIBOOT_SIMCONF) +} + +define machine myconf mysim + +# +# Include various utilities +# + +source $env(LIB_DIR)/common/epapr.tcl +if {![info exists of::encode_compat]} { + source $env(LIB_DIR)/common/openfirmware_utils.tcl +} + +# Only source mambo_utils.tcl if it exists in the current directory. That +# allows running mambo in another directory to the one skiboot.tcl is in. +if { [file exists mambo_utils.tcl] } then { + source mambo_utils.tcl + + if { [info exists env(USER_MAP)] } { + global user_symbol_map user_symbol_list + + set fp [open $env(USER_MAP) r] + set user_symbol_map [read $fp] + set user_symbol_list [split $user_symbol_map "\n"] + close $fp + } + + if { [info exists env(VMLINUX_MAP)] } { + global linux_symbol_map linux_symbol_list + + set fp [open $env(VMLINUX_MAP) r] + set linux_symbol_map [read $fp] + set linux_symbol_list [split $linux_symbol_map "\n"] + close $fp + } + + if { [info exists env(SKIBOOT_MAP)] } { + global skiboot_symbol_map skiboot_symbol_list + + set fp [open $env(SKIBOOT_MAP) r] + set skiboot_symbol_map [read $fp] + set skiboot_symbol_list [split $skiboot_symbol_map "\n"] + close $fp + } +} + +# +# Instanciate xscom +# + +set xscom_base 0x1A0000000000 +mysim xscom create $xscom_base + +# Setup bogus IO + +if { $mconf(rootdisk) != "none" } { + # Now load the bogus disk image + switch $mconf(rootdisk_cow) { + none { + mysim bogus disk init 0 $mconf(rootdisk) rw + puts "bogusdisk initialized for $mconf(rootdisk)" + } + default { + mysim bogus disk init 0 $mconf(rootdisk) \ + $mconf(rootdisk_cow_method) \ + $mconf(rootdisk_cow) $mconf(rootdisk_cow_hash) + } + } +} +switch $mconf(net) { + none { + puts "No network support selected" + } + bogus - bogusnet { + mysim bogus net init 0 $mconf(net_mac) $mconf(net_tapdev) + } + default { + error "Bad net \[none | bogus]: $mconf(net)" + } +} + +# Device tree fixups + +set root_node [mysim of find_device "/"] + +mysim of addprop $root_node string "epapr-version" "ePAPR-1.0" +mysim of setprop $root_node "compatible" "ibm,powernv" + +set cpus_node [mysim of find_device "/cpus"] +mysim of addprop $cpus_node int "#address-cells" 1 +mysim of addprop $cpus_node int "#size-cells" 0 + +set mem0_node [mysim of find_device "/memory@0"] +mysim of addprop $mem0_node int "ibm,chip-id" 0 + +set xscom_node [ mysim of addchild $root_node xscom [format %x $xscom_base]] +set reg [list $xscom_base 0x10000000] +mysim of addprop $xscom_node array64 "reg" reg +mysim of addprop $xscom_node empty "scom-controller" "" +mysim of addprop $xscom_node int "ibm,chip-id" 0 +mysim of addprop $xscom_node int "#address-cells" 1 +mysim of addprop $xscom_node int "#size-cells" 1 +set compat [list] +lappend compat "ibm,xscom" +lappend compat "ibm,power8-xscom" +set compat [of::encode_compat $compat] +mysim of addprop $xscom_node byte_array "compatible" $compat + +set chosen_node [mysim of find_device /chosen] +set base_addr [list $mconf(payload_addr)] +mysim of addprop $chosen_node array64 "kernel-base-address" base_addr + +# Load any initramfs +set cpio_start 0x80000000 +set cpio_end $cpio_start +set cpio_size 0 +if { [info exists env(SKIBOOT_INITRD)] } { + + set cpios [split $env(SKIBOOT_INITRD) ","] + + foreach cpio_file $cpios { + set cpio_file [string trim $cpio_file] + set cpio_size [file size $cpio_file] + mysim mcm 0 memory fread $cpio_end $cpio_size $cpio_file + set cpio_end [expr $cpio_end + $cpio_size] + # Linux requires cpios are 4 byte aligned + set cpio_end [expr $cpio_end + 3 & 0xfffffffffffffffc] + } + + mysim of addprop $chosen_node int "linux,initrd-start" $cpio_start + mysim of addprop $chosen_node int "linux,initrd-end" $cpio_end +} + +# Map persistent memory disks +proc pmem_node_add { root start size } { + set start_hex [format %x $start] + set node [mysim of addchild $root "pmem@$start_hex" ""] + set reg [list [expr $start >> 32] [expr $start & 0xffffffff] [expr $size >> 32] [expr $size & 0xffffffff] ] + mysim of addprop $node array "reg" reg + mysim of addprop $node string "compatible" "pmem-region" + mysim of addprop $node empty "volatile" "1" + mysim of addprop $node int "ibm,chip-id" 0 + return [expr $start + $size] +} + +set pmem_files "" +if { [info exists env(PMEM_DISK)] } { + set pmem_files [split $env(PMEM_DISK) ","] +} +set pmem_sizes "" +if { [info exists env(PMEM_VOLATILE)] } { + set pmem_sizes [split $env(PMEM_VOLATILE) ","] +} +set pmem_modes "" +if { [info exists env(PMEM_MODE)] } { + set pmem_modes [split $env(PMEM_MODE) ","] +} +set pmem_root [mysim of addchild $root_node "pmem" ""] +mysim of addprop $pmem_root int "#address-cells" 2 +mysim of addprop $pmem_root int "#size-cells" 2 +mysim of addprop $pmem_root empty "ranges" "" +# Start above where XICS normally is at 0x1A0000000000 +set pmem_start [expr 0x20000000000] +set pmem_file_ix 0 +foreach pmem_file $pmem_files { # PMEM_DISK + set pmem_file [string trim $pmem_file] + set pmem_size [file size $pmem_file] + if { [expr [llength $pmem_modes] > $pmem_file_ix] } { + set pmem_mode [lindex $pmem_modes $pmem_file_ix] + } else { + set pmem_mode "rw" + } + if {[catch {mysim memory mmap $pmem_start $pmem_size $pmem_file $pmem_mode}]} { + puts "ERROR: pmem: 'mysim mmap' command needs newer mambo" + exit + } + set pmem_start [pmem_node_add $pmem_root $pmem_start $pmem_size] + set pmem_file_ix [expr $pmem_file_ix + 1] +} +foreach pmem_size $pmem_sizes { # PMEM_VOLATILE + set pmem_start [pmem_node_add $pmem_root $pmem_start $pmem_size] +} + + +# Default NVRAM is blank and will be formatted by Skiboot if no file is provided +set fake_nvram_start $cpio_end +set fake_nvram_size 0x40000 +# Load any fake NVRAM file if provided +if { [info exists env(SKIBOOT_NVRAM)] } { + # Set up and write NVRAM file + set fake_nvram_file $env(SKIBOOT_NVRAM) + set fake_nvram_size [file size $fake_nvram_file] + mysim mcm 0 memory fread $fake_nvram_start $fake_nvram_size $fake_nvram_file +} + +# Add device tree entry for NVRAM +set reserved_memory [mysim of addchild $root_node "reserved-memory" ""] +mysim of addprop $reserved_memory int "#size-cells" 2 +mysim of addprop $reserved_memory int "#address-cells" 2 +mysim of addprop $reserved_memory empty "ranges" "" + +set cvc_code_start [expr $fake_nvram_start + $fake_nvram_size] +set cvc_code_end $cvc_code_start +set cvc_code_size 0 + +if { [info exists env(SKIBOOT_CVC_CODE)] } { + set cvc_file $env(SKIBOOT_CVC_CODE) + + set cvc_code_size [file size $cvc_file] + mysim mcm 0 memory fread $cvc_code_start $cvc_code_size $cvc_file + set cvc_code_end [expr $cvc_code_start + $cvc_code_size] + + # Set up Device Tree for Container Verification Code + set hb [mysim of addchild $root_node "ibm,hostboot" ""] + set hb_reserved_memory [mysim of addchild $hb "reserved-memory" ""] + mysim of addprop $hb_reserved_memory int "#address-cells" 2 + mysim of addprop $hb_reserved_memory int "#size-cells" 2 + + set hb_cvc_code_node [mysim of addchild $hb_reserved_memory "ibm,secure-crypt-algo-code" [format %x $cvc_code_start]] + set reg [list $cvc_code_start $cvc_code_size] + mysim of addprop $hb_cvc_code_node array64 "reg" reg + mysim of addprop $hb_cvc_code_node empty "name" "ibm,secure-crypt-algo-code" + + set cvc_code_node [mysim of addchild $reserved_memory "ibm,secure-crypt-algo-code" [format %x $cvc_code_start]] + set reg [list $cvc_code_start $cvc_code_size] + mysim of addprop $cvc_code_node array64 "reg" reg + mysim of addprop $cvc_code_node empty "name" "ibm,secure-crypt-algo-code" +} + +set initramfs_res [mysim of addchild $reserved_memory "initramfs" ""] +set reg [list $cpio_start $cpio_size ] +mysim of addprop $initramfs_res array64 "reg" reg +mysim of addprop $initramfs_res empty "name" "initramfs" + +set fake_nvram_node [mysim of addchild $reserved_memory "ibm,fake-nvram" ""] +set reg [list $fake_nvram_start $fake_nvram_size ] +mysim of addprop $fake_nvram_node array64 "reg" reg +mysim of addprop $fake_nvram_node empty "name" "ibm,fake-nvram" + +set opal_node [mysim of addchild $root_node "ibm,opal" ""] + +# Allow P9/P10 to use all idle states +if { $default_config == "P9" || $default_config == "P10" } { + set power_mgt_node [mysim of addchild $opal_node "power-mgt" ""] + mysim of addprop $power_mgt_node int "ibm,enabled-stop-levels" 0xffffffff +} + +proc add_feature_node { parent name { value 1 } } { + if { $value != 1 } { + set value "disabled" + } else { + set value "enabled" + } + set np [mysim of addchild $parent $name ""] + mysim of addprop $np empty $value "" +} + +set np [mysim of addchild $opal_node "fw-features" ""] +add_feature_node $np "speculation-policy-favor-security" $mconf(speculation_policy_favor_security) +add_feature_node $np "needs-l1d-flush-msr-hv-1-to-0" $mconf(needs_l1d_flush_msr_hv) +add_feature_node $np "needs-l1d-flush-msr-pr-0-to-1" $mconf(needs_l1d_flush_msr_pr) +add_feature_node $np "fw-l1d-thread-split" $mconf(fw_l1d_thread_split) +add_feature_node $np "needs-spec-barrier-for-bound-checks" $mconf(needs_spec_barrier) +add_feature_node $np "fw-bcctrl-serialized" $mconf(fw_bcctrl_serialized) +add_feature_node $np "fw-count-cache-disabled" $mconf(fw_count_cache_disabled) +add_feature_node $np "needs-count-cache-flush-on-context-switch" $mconf(needs_count_cache_flush) +add_feature_node $np "fw-count-cache-flush-bcctr2,0,0" $mconf(fw_count_cache_flush_assist) +add_feature_node $np "inst-spec-barrier-ori31,31,0" $mconf(inst_spec_barrier_ori31) +add_feature_node $np "inst-l1d-flush-trig2" $mconf(inst_l1d_flush_trig2) +add_feature_node $np "inst-l1d-flush-ori30,30,0" $mconf(inst_l1d_flush_ori30) + + +# Init CPUs +set pir 0 +for { set c 0 } { $c < $mconf(cpus) } { incr c } { + set cpu_node [mysim of find_device "/cpus/PowerPC@$pir"] + mysim of addprop $cpu_node int "ibm,pir" $pir + set reg [list 0x0000001c00000028 0xffffffffffffffff] + mysim of addprop $cpu_node array64 "ibm,processor-segment-sizes" reg + + mysim of addprop $cpu_node int "ibm,chip-id" $c + + # Create a chip node to tell skiboot to create another chip for this CPU. + # This bubbles up to Linux which will then see a new chip (aka nid). + # For chip 0 the xscom node above has already definied chip 0, so skip it. + if { $c > 0 } { + set node [mysim of addchild $root_node "mambo-chip" [format %x $c]] + mysim of addprop $node int "ibm,chip-id" $c + mysim of addprop $node string "compatible" "ibm,mambo-chip" + + if { $mconf(numa) } { + set shift [myconf query memory_region_id_shift] + set addr [format %lx [expr (1 << $shift) * $c]] + set node [mysim of find_device "/memory@$addr"] + mysim of addprop $node int "ibm,chip-id" $c + } + } + + set reg {} + lappend reg 0x0000000c 0x00000010 0x00000018 0x00000022 + mysim of addprop $cpu_node array "ibm,processor-page-sizes" reg + + set reg {} + lappend reg 0x0c 0x000 3 0x0c 0x0000 ;# 4K seg 4k pages + lappend reg 0x10 0x0007 ;# 4K seg 64k pages + lappend reg 0x18 0x0038 ;# 4K seg 16M pages + lappend reg 0x10 0x110 2 0x10 0x0001 ;# 64K seg 64k pages + lappend reg 0x18 0x0008 ;# 64K seg 16M pages + lappend reg 0x18 0x100 1 0x18 0x0000 ;# 16M seg 16M pages + lappend reg 0x22 0x120 1 0x22 0x0003 ;# 16G seg 16G pages + mysim of addprop $cpu_node array "ibm,segment-page-sizes" reg + + if { $default_config == "P9" || $default_config == "P10" } { + # Set actual page size encodings + set reg {} + # 4K pages + lappend reg 0x0000000c + # 64K pages + lappend reg 0xa0000010 + # 2M pages + lappend reg 0x20000015 + # 1G pages + lappend reg 0x4000001e + mysim of addprop $cpu_node array "ibm,processor-radix-AP-encodings" reg + + set reg {} + # POWER9 PAPR defines upto bytes 62-63 + # POWER10 PAPR defines upto byte 64-65 + # header + bytes 0-5 + if { $default_config == "P9" } { + lappend reg 0x4000f63fc70080c0 + } else { + lappend reg 0x4200f63fc70080c0 + } + # bytes 6-13 + lappend reg 0x8000000000000000 + # bytes 14-21 + lappend reg 0x0000800080008000 + # bytes 22-29 22/23=TM + lappend reg 0x0000800080008000 + # bytes 30-37 + lappend reg 0x80008000C0008000 + # bytes 38-45 40/41=radix + lappend reg 0x8000800080008000 + # bytes 46-55 + lappend reg 0x8000800080008000 + # bytes 54-61 58/59=seg tbl + lappend reg 0x8000800080008000 + # bytes 62-69 64/65=DAWR1(P10 only) + if { $default_config == "P9" } { + lappend reg 0x8000000000000000 + } else { + lappend reg 0x8000800000000000 + } + mysim of addprop $cpu_node array64 "ibm,pa-features" reg + } else { + set reg {} + lappend reg 0x6000f63fc70080c0 + mysim of addprop $cpu_node array64 "ibm,pa-features" reg + } + + set irqreg [list] + for { set t 0 } { $t < $mconf(threads) } { incr t } { + mysim mcm 0 cpu $c thread $t set spr pc $mconf(boot_pc) + mysim mcm 0 cpu $c thread $t set gpr 3 $mconf(epapr_dt_addr) + mysim mcm 0 cpu $c thread $t config_on + mysim mcm 0 cpu $c thread $t set spr pir $pir + lappend irqreg $pir + incr pir + } + mysim of addprop $cpu_node array "ibm,ppc-interrupt-server#s" irqreg +} + +#Add In-Memory Collection Counter nodes +if { $default_config == "P9" || $default_config == "P10" } { + #Add the base node "imc-counters" + set imc_c [mysim of addchild $root_node "imc-counters" ""] + mysim of addprop $imc_c string "compatible" "ibm,opal-in-memory-counters" + mysim of addprop $imc_c int "#address-cells" 1 + mysim of addprop $imc_c int "#size-cells" 1 + mysim of addprop $imc_c int "version-id" 1 + + #Add a common mcs event node + set mcs_et [mysim of addchild $imc_c "nest-mcs-events" ""] + mysim of addprop $mcs_et int "#address-cells" 1 + mysim of addprop $mcs_et int "#size-cells" 1 + + #Add a event + set et [mysim of addchild $mcs_et event [format %x 0]] + mysim of addprop $et string "event-name" "64B_RD_OR_WR_DISP_PORT01" + mysim of addprop $et string "unit" "MiB/s" + mysim of addprop $et string "scale" "4" + mysim of addprop $et int "reg" 0 + + #Add a event + set et [mysim of addchild $mcs_et event [format %x 1]] + mysim of addprop $et string "event-name" "64B_WR_DISP_PORT01" + mysim of addprop $et string "unit" "MiB/s" + mysim of addprop $et int "reg" 40 + + #Add a event + set et [mysim of addchild $mcs_et event [format %x 2]] + mysim of addprop $et string "event-name" "64B_RD_DISP_PORT01" + mysim of addprop $et string "scale" "100" + mysim of addprop $et int "reg" 64 + + #Add a event + set et [mysim of addchild $mcs_et event [format %x 3]] + mysim of addprop $et string "event-name" "64B_XX_DISP_PORT01" + mysim of addprop $et int "reg" 32 + + #Add a mcs device node + set mcs_01 [mysim of addchild $imc_c "mcs01" ""] + mysim of addprop $mcs_01 string "compatible" "ibm,imc-counters" + mysim of addprop $mcs_01 string "events-prefix" "PM_MCS01_" + mysim of addprop $mcs_01 int "reg" 65536 + mysim of addprop $mcs_01 int "size" 262144 + mysim of addprop $mcs_01 int "offset" 1572864 + mysim of addprop $mcs_01 int "events" $mcs_et + mysim of addprop $mcs_01 int "type" 16 + mysim of addprop $mcs_01 string "unit" "KiB/s" + mysim of addprop $mcs_01 string "scale" "8" + + #Add a common core event node + set ct_et [mysim of addchild $imc_c "core-thread-events" ""] + mysim of addprop $ct_et int "#address-cells" 1 + mysim of addprop $ct_et int "#size-cells" 1 + + #Add a event + set cet [mysim of addchild $ct_et event [format %x 200]] + mysim of addprop $cet string "event-name" "0THRD_NON_IDLE_PCYC" + mysim of addprop $cet string "desc" "The number of processor cycles when all threads are idle" + mysim of addprop $cet int "reg" 200 + + #Add a core device node + set core [mysim of addchild $imc_c "core" ""] + mysim of addprop $core string "compatible" "ibm,imc-counters" + mysim of addprop $core string "events-prefix" "CPM_" + mysim of addprop $core int "reg" 24 + mysim of addprop $core int "size" 8192 + mysim of addprop $core string "scale" "512" + mysim of addprop $core int "events" $ct_et + mysim of addprop $core int "type" 4 + + #Add a thread device node + set thread [mysim of addchild $imc_c "thread" ""] + mysim of addprop $thread string "compatible" "ibm,imc-counters" + mysim of addprop $thread string "events-prefix" "CPM_" + mysim of addprop $thread int "reg" 24 + mysim of addprop $thread int "size" 8192 + mysim of addprop $thread string "scale" "512" + mysim of addprop $thread int "events" $ct_et + mysim of addprop $thread int "type" 1 + + #Add a common trace event node + set tr_et [mysim of addchild $imc_c "trace-events" ""] + mysim of addprop $tr_et int "#address-cells" 1 + mysim of addprop $tr_et int "#size-cells" 1 + + #Add an event + set tr [mysim of addchild $tr_et event [format 10200000]] + mysim of addprop $tr string "event-name" "cycles" + mysim of addprop $tr string "desc" "Reference cycles" + mysim of addprop $tr int "reg" 0x10200000 + + #Add a trace device node + set trace [mysim of addchild $imc_c "trace" ""] + mysim of addprop $trace string "compatible" "ibm,imc-counters" + mysim of addprop $trace string "events-prefix" "trace_" + mysim of addprop $trace int "reg" 0 + mysim of addprop $trace int "size" 262144 + mysim of addprop $trace int "events" $tr_et + mysim of addprop $trace int "type" 2 + +} + +mconfig enable_stb SKIBOOT_ENABLE_MAMBO_STB 0 + +if { [info exists env(SKIBOOT_ENABLE_MAMBO_STB)] } { + set stb_node [ mysim of addchild $root_node "ibm,secureboot" "" ] + + # For P8 we still use the softrom emulation + if { $default_config == "PEGASUS" || ! [info exists env(SKIBOOT_CVC_CODE)] } { + mysim of addprop $stb_node string "compatible" "ibm,secureboot-v1-softrom" + } else { + # on P9 we can use the real CVC + mysim of addprop $stb_node string "compatible" "ibm,secureboot-v2" + } +# mysim of addprop $stb_node string "secure-enabled" "" + mysim of addprop $stb_node string "trusted-enabled" "" + mysim of addprop $stb_node string "hash-algo" "sha512" + mysim of addprop $stb_node int "hw-key-hash-size" 64 + set hw_key_hash {} + lappend hw_key_hash 0x40d487ff + lappend hw_key_hash 0x7380ed6a + lappend hw_key_hash 0xd54775d5 + lappend hw_key_hash 0x795fea0d + lappend hw_key_hash 0xe2f541fe + lappend hw_key_hash 0xa9db06b8 + lappend hw_key_hash 0x466a42a3 + lappend hw_key_hash 0x20e65f75 + lappend hw_key_hash 0xb4866546 + lappend hw_key_hash 0x0017d907 + lappend hw_key_hash 0x515dc2a5 + lappend hw_key_hash 0xf9fc5095 + lappend hw_key_hash 0x4d6ee0c9 + lappend hw_key_hash 0xb67d219d + lappend hw_key_hash 0xfb708535 + lappend hw_key_hash 0x1d01d6d1 + mysim of addprop $stb_node array "hw-key-hash" hw_key_hash + + if { $default_config != "PEGASUS" && [info exists env(SKIBOOT_CVC_CODE)] } { + set cvc_node [ mysim of addchild $stb_node "ibm,cvc" "" ] + mysim of addprop $cvc_node string "compatible" "ibm,container-verification-code" + mysim of addprop $cvc_node int "memory-region" $hb_cvc_code_node + + # I'm sure hardcoding these addresses will *never* cause us a problem... + set sha_node [ mysim of addchild $cvc_node "ibm,cvc-service" [format %x 0x40]] + mysim of addprop $sha_node string "name" "ibm,cvc-service" + mysim of addprop $sha_node string "compatible" "ibm,cvc-sha512" + mysim of addprop $sha_node int "reg" 0x40 + mysim of addprop $sha_node int "version" 1 + + set verify_node [ mysim of addchild $cvc_node "ibm,cvc-service" [format %x 0x50]] + mysim of addprop $verify_node string "name" "ibm,cvc-service" + mysim of addprop $verify_node string "compatible" "ibm,cvc-verify" + mysim of addprop $verify_node int "reg" 0x50 + mysim of addprop $verify_node int "version" 1 + } +} + +# Kernel command line args, appended to any from the device tree +# e.g.: of::set_bootargs "xmon" +# +# Can be set from the environment by setting LINUX_CMDLINE. +of::set_bootargs $mconf(linux_cmdline) + +# Load images + +set boot_size [file size $mconf(boot_image)] +mysim memory fread $mconf(boot_load) $boot_size $mconf(boot_image) + +set payload_size [file size $mconf(payload)] +mysim memory fread $mconf(payload_addr) $payload_size $mconf(payload) + +if { $payload_size > [expr $mconf(boot_load) - $mconf(payload_addr)] } { + error "vmlinux is too large, consider adjusting PAYLOAD_ADDR" +} + +# Flatten it +epapr::of2dtb mysim $mconf(epapr_dt_addr) + +# Set run speed +mysim mode fastest + +if { [info exists env(GDB_SERVER)] } { + mysim debugger wait $env(GDB_SERVER) +} + +if { [info exists env(SKIBOOT_AUTORUN)] } { + if [catch { mysim go }] { + readline + } +} else { + readline +} + +if { [info exists env(SKIBOOT_AUTORUN)] && $env(SKIBOOT_AUTORUN) == 2 } { + quit +} |