xref: /kvm-unit-tests/lib/powerpc/io.c (revision 93c847c1e5cbe266496ee66dc83dcfa24c401c96)
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 Piggin void 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 Piggin int __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 Jones void 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 Jones void 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 Jones void 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