xref: /kvm-unit-tests/lib/powerpc/io.c (revision c76b0d0a3842ba312a2d8512f7a3728f4598bf94)
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>
13*c76b0d0aSNicholas Piggin #include <asm/atomic.h>
144ff26ec5SThomas Huth #include "io.h"
15e65bcc62SAndrew Jones 
16e65bcc62SAndrew Jones static struct spinlock print_lock;
171e95c7ccSAndrew Jones 
18610c5a9cSNicholas Piggin void putchar(int c)
19610c5a9cSNicholas Piggin {
20610c5a9cSNicholas Piggin 	if (machine_is_powernv())
21610c5a9cSNicholas Piggin 		opal_putchar(c);
22610c5a9cSNicholas Piggin 	else
23610c5a9cSNicholas Piggin 		papr_putchar(c);
24610c5a9cSNicholas Piggin }
25610c5a9cSNicholas Piggin 
26610c5a9cSNicholas Piggin int __getchar(void)
27610c5a9cSNicholas Piggin {
28610c5a9cSNicholas Piggin 	if (machine_is_powernv())
29610c5a9cSNicholas Piggin 		return __opal_getchar();
30610c5a9cSNicholas Piggin 	else
31610c5a9cSNicholas Piggin 		return __papr_getchar();
32610c5a9cSNicholas Piggin }
33610c5a9cSNicholas Piggin 
341e95c7ccSAndrew Jones void io_init(void)
351e95c7ccSAndrew Jones {
36610c5a9cSNicholas Piggin 	if (machine_is_powernv())
37610c5a9cSNicholas Piggin 		assert(!opal_init());
38610c5a9cSNicholas Piggin 	else
392f9ce69eSAndrew Jones 		rtas_init();
401e95c7ccSAndrew Jones }
411e95c7ccSAndrew Jones 
42e65bcc62SAndrew Jones void puts(const char *s)
431e95c7ccSAndrew Jones {
44e65bcc62SAndrew Jones 	spin_lock(&print_lock);
45e65bcc62SAndrew Jones 	while (*s)
46e65bcc62SAndrew Jones 		putchar(*s++);
47e65bcc62SAndrew Jones 	spin_unlock(&print_lock);
481e95c7ccSAndrew Jones }
491e95c7ccSAndrew Jones 
50764aa0b8SAndrew Jones /*
51764aa0b8SAndrew Jones  * Defining halt to take 'code' as an argument guarantees that it will
52764aa0b8SAndrew Jones  * be in r3 when we halt. That gives us a final chance to see the exit
53764aa0b8SAndrew Jones  * status while inspecting the halted unit test state.
54764aa0b8SAndrew Jones  */
55764aa0b8SAndrew Jones extern void halt(int code);
56764aa0b8SAndrew Jones 
57e65bcc62SAndrew Jones void exit(int code)
581e95c7ccSAndrew Jones {
59*c76b0d0aSNicholas Piggin 	static int exited = 0;
60*c76b0d0aSNicholas Piggin 
61f5a87330SAndrew Jones // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
62f5a87330SAndrew Jones //        maybe by plugging chr-testdev into a spapr-vty.
63*c76b0d0aSNicholas Piggin 	if (atomic_fetch_inc(&exited) == 0) {
64f5a87330SAndrew Jones 		printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
65610c5a9cSNicholas Piggin 		if (machine_is_powernv())
66610c5a9cSNicholas Piggin 			opal_power_off();
67610c5a9cSNicholas Piggin 		else
68f5a87330SAndrew Jones 			rtas_power_off();
69*c76b0d0aSNicholas Piggin 	}
70e65bcc62SAndrew Jones 	halt(code);
7196d79976SAndre Przywara 	__builtin_unreachable();
721e95c7ccSAndrew Jones }
73