xref: /kvm-unit-tests/lib/x86/io.c (revision ac1690b24369315f978581ea8368f34deaccd9f1)
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         }
50 
51         for (i = 0; i < len; i++) {
52             serial_outb(buf[i]);
53         }
54 #else
55         asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
56 #endif
57 }
58 
59 void puts(const char *s)
60 {
61 	spin_lock(&lock);
62 	print_serial(s);
63 	spin_unlock(&lock);
64 }
65 
66 void exit(int code)
67 {
68 #ifdef USE_SERIAL
69         static const char shutdown_str[8] = "Shutdown";
70         int i;
71 
72         /* test device exit (with status) */
73         outl(code, 0xf4);
74 
75         /* if that failed, try the Bochs poweroff port */
76         for (i = 0; i < 8; i++) {
77                 outb(shutdown_str[i], 0x8900);
78         }
79 #else
80         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
81 #endif
82 }
83