xref: /kvm-unit-tests/lib/x86/io.c (revision 0f54b9b2875b155b02e60904cd21d394fd86e94f)
1 #include "libcflat.h"
2 #include "smp.h"
3 #include "io.h"
4 #ifndef USE_SERIAL
5 #define USE_SERIAL
6 #endif
7 
8 static struct spinlock lock;
9 static int serial_iobase = 0x3f8;
10 static int serial_inited = 0;
11 
12 static void serial_outb(char ch)
13 {
14         u8 lsr;
15 
16         do {
17                 lsr = inb(serial_iobase + 0x05);
18         } while (!(lsr & 0x20));
19 
20         outb(ch, serial_iobase + 0x00);
21 }
22 
23 static void serial_init(void)
24 {
25         u8 lcr;
26 
27         /* set DLAB */
28         lcr = inb(serial_iobase + 0x03);
29         lcr |= 0x80;
30         outb(lcr, serial_iobase + 0x03);
31 
32         /* set baud rate to 115200 */
33         outb(0x01, serial_iobase + 0x00);
34         outb(0x00, serial_iobase + 0x01);
35 
36         /* clear DLAB */
37         lcr = inb(serial_iobase + 0x03);
38         lcr &= ~0x80;
39         outb(lcr, serial_iobase + 0x03);
40 }
41 
42 static void print_serial(const char *buf)
43 {
44 	unsigned long len = strlen(buf);
45 #ifdef USE_SERIAL
46         unsigned long i;
47         if (!serial_inited) {
48             serial_init();
49             serial_inited = 1;
50         }
51 
52         for (i = 0; i < len; i++) {
53             serial_outb(buf[i]);
54         }
55 #else
56         asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
57 #endif
58 }
59 
60 void puts(const char *s)
61 {
62 	spin_lock(&lock);
63 	print_serial(s);
64 	spin_unlock(&lock);
65 }
66 
67 void exit(int code)
68 {
69 #ifdef USE_SERIAL
70         static const char shutdown_str[8] = "Shutdown";
71         int i;
72 
73         /* test device exit (with status) */
74         outl(code, 0xf4);
75 
76         /* if that failed, try the Bochs poweroff port */
77         for (i = 0; i < 8; i++) {
78                 outb(shutdown_str[i], 0x8900);
79         }
80 #else
81         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
82 #endif
83 }
84