11e95c7ccSAndrew Jones /* 21e95c7ccSAndrew Jones * Each architecture must implement puts() and exit(). 31e95c7ccSAndrew Jones * 41e95c7ccSAndrew Jones * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> 51e95c7ccSAndrew Jones * 61e95c7ccSAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 71e95c7ccSAndrew Jones */ 81e95c7ccSAndrew Jones #include <libcflat.h> 9e65bcc62SAndrew Jones #include <asm/spinlock.h> 102f9ce69eSAndrew Jones #include <asm/rtas.h> 114ff26ec5SThomas Huth #include <asm/setup.h> 12610c5a9cSNicholas Piggin #include <asm/processor.h> 13c76b0d0aSNicholas Piggin #include <asm/atomic.h> 14*93c847c1SNicholas Piggin #include <asm/smp.h> 154ff26ec5SThomas Huth #include "io.h" 16e65bcc62SAndrew Jones 17e65bcc62SAndrew Jones static struct spinlock print_lock; 181e95c7ccSAndrew Jones putchar(int c)19610c5a9cSNicholas Pigginvoid putchar(int c) 20610c5a9cSNicholas Piggin { 21610c5a9cSNicholas Piggin if (machine_is_powernv()) 22610c5a9cSNicholas Piggin opal_putchar(c); 23610c5a9cSNicholas Piggin else 24610c5a9cSNicholas Piggin papr_putchar(c); 25610c5a9cSNicholas Piggin } 26610c5a9cSNicholas Piggin __getchar(void)27610c5a9cSNicholas Pigginint __getchar(void) 28610c5a9cSNicholas Piggin { 29610c5a9cSNicholas Piggin if (machine_is_powernv()) 30610c5a9cSNicholas Piggin return __opal_getchar(); 31610c5a9cSNicholas Piggin else 32610c5a9cSNicholas Piggin return __papr_getchar(); 33610c5a9cSNicholas Piggin } 34610c5a9cSNicholas Piggin io_init(void)351e95c7ccSAndrew Jonesvoid io_init(void) 361e95c7ccSAndrew Jones { 37610c5a9cSNicholas Piggin if (machine_is_powernv()) 38610c5a9cSNicholas Piggin assert(!opal_init()); 39610c5a9cSNicholas Piggin else 402f9ce69eSAndrew Jones rtas_init(); 411e95c7ccSAndrew Jones } 421e95c7ccSAndrew Jones puts(const char * s)43e65bcc62SAndrew Jonesvoid puts(const char *s) 441e95c7ccSAndrew Jones { 45*93c847c1SNicholas Piggin bool user = in_usermode(); 46*93c847c1SNicholas Piggin 47*93c847c1SNicholas Piggin if (user) 48*93c847c1SNicholas Piggin exit_usermode(); 49e65bcc62SAndrew Jones spin_lock(&print_lock); 50e65bcc62SAndrew Jones while (*s) 51e65bcc62SAndrew Jones putchar(*s++); 52e65bcc62SAndrew Jones spin_unlock(&print_lock); 53*93c847c1SNicholas Piggin if (user) 54*93c847c1SNicholas Piggin enter_usermode(); 551e95c7ccSAndrew Jones } 561e95c7ccSAndrew Jones 57764aa0b8SAndrew Jones /* 58764aa0b8SAndrew Jones * Defining halt to take 'code' as an argument guarantees that it will 59764aa0b8SAndrew Jones * be in r3 when we halt. That gives us a final chance to see the exit 60764aa0b8SAndrew Jones * status while inspecting the halted unit test state. 61764aa0b8SAndrew Jones */ 62764aa0b8SAndrew Jones extern void halt(int code); 63764aa0b8SAndrew Jones exit(int code)64e65bcc62SAndrew Jonesvoid exit(int code) 651e95c7ccSAndrew Jones { 66c76b0d0aSNicholas Piggin static int exited = 0; 67c76b0d0aSNicholas Piggin 68f5a87330SAndrew Jones // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(), 69f5a87330SAndrew Jones // maybe by plugging chr-testdev into a spapr-vty. 70c76b0d0aSNicholas Piggin if (atomic_fetch_inc(&exited) == 0) { 71f5a87330SAndrew Jones printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 72610c5a9cSNicholas Piggin if (machine_is_powernv()) 73610c5a9cSNicholas Piggin opal_power_off(); 74610c5a9cSNicholas Piggin else 75f5a87330SAndrew Jones rtas_power_off(); 76c76b0d0aSNicholas Piggin } 77e65bcc62SAndrew Jones halt(code); 7896d79976SAndre Przywara __builtin_unreachable(); 791e95c7ccSAndrew Jones } 80