xref: /kvm-unit-tests/lib/powerpc/io.c (revision 386ed5c2f9e98a2605817748c44c0cefa60dc88e)
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 "io.h"
15 
16 static struct spinlock print_lock;
17 
18 void putchar(int c)
19 {
20 	if (machine_is_powernv())
21 		opal_putchar(c);
22 	else
23 		papr_putchar(c);
24 }
25 
26 int __getchar(void)
27 {
28 	if (machine_is_powernv())
29 		return __opal_getchar();
30 	else
31 		return __papr_getchar();
32 }
33 
34 void io_init(void)
35 {
36 	if (machine_is_powernv())
37 		assert(!opal_init());
38 	else
39 		rtas_init();
40 }
41 
42 void puts(const char *s)
43 {
44 	spin_lock(&print_lock);
45 	while (*s)
46 		putchar(*s++);
47 	spin_unlock(&print_lock);
48 }
49 
50 /*
51  * Defining halt to take 'code' as an argument guarantees that it will
52  * be in r3 when we halt. That gives us a final chance to see the exit
53  * status while inspecting the halted unit test state.
54  */
55 extern void halt(int code);
56 
57 void exit(int code)
58 {
59 	static int exited = 0;
60 
61 // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
62 //        maybe by plugging chr-testdev into a spapr-vty.
63 	if (atomic_fetch_inc(&exited) == 0) {
64 		printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
65 		if (machine_is_powernv())
66 			opal_power_off();
67 		else
68 			rtas_power_off();
69 	}
70 	halt(code);
71 	__builtin_unreachable();
72 }
73