xref: /kvm-unit-tests/lib/powerpc/io.c (revision 93c847c1e5cbe266496ee66dc83dcfa24c401c96)
1 /*
2  * Each architecture must implement puts() and exit().
3  *
4  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5  *
6  * This work is licensed under the terms of the GNU LGPL, version 2.
7  */
8 #include <libcflat.h>
9 #include <asm/spinlock.h>
10 #include <asm/rtas.h>
11 #include <asm/setup.h>
12 #include <asm/processor.h>
13 #include <asm/atomic.h>
14 #include <asm/smp.h>
15 #include "io.h"
16 
17 static struct spinlock print_lock;
18 
putchar(int c)19 void putchar(int c)
20 {
21 	if (machine_is_powernv())
22 		opal_putchar(c);
23 	else
24 		papr_putchar(c);
25 }
26 
__getchar(void)27 int __getchar(void)
28 {
29 	if (machine_is_powernv())
30 		return __opal_getchar();
31 	else
32 		return __papr_getchar();
33 }
34 
io_init(void)35 void io_init(void)
36 {
37 	if (machine_is_powernv())
38 		assert(!opal_init());
39 	else
40 		rtas_init();
41 }
42 
puts(const char * s)43 void puts(const char *s)
44 {
45 	bool user = in_usermode();
46 
47 	if (user)
48 		exit_usermode();
49 	spin_lock(&print_lock);
50 	while (*s)
51 		putchar(*s++);
52 	spin_unlock(&print_lock);
53 	if (user)
54 		enter_usermode();
55 }
56 
57 /*
58  * Defining halt to take 'code' as an argument guarantees that it will
59  * be in r3 when we halt. That gives us a final chance to see the exit
60  * status while inspecting the halted unit test state.
61  */
62 extern void halt(int code);
63 
exit(int code)64 void exit(int code)
65 {
66 	static int exited = 0;
67 
68 // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
69 //        maybe by plugging chr-testdev into a spapr-vty.
70 	if (atomic_fetch_inc(&exited) == 0) {
71 		printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
72 		if (machine_is_powernv())
73 			opal_power_off();
74 		else
75 			rtas_power_off();
76 	}
77 	halt(code);
78 	__builtin_unreachable();
79 }
80