xref: /kvm-unit-tests/lib/x86/io.c (revision f1abb07b7692593d59990805010d8fdc990cb70e)
1 #include "libcflat.h"
2 #include "vm.h"
3 #include "smp.h"
4 #include "asm/io.h"
5 #include "asm/page.h"
6 #ifndef USE_SERIAL
7 #define USE_SERIAL
8 #endif
9 
10 static struct spinlock lock;
11 static int serial_iobase = 0x3f8;
12 static int serial_inited = 0;
13 
14 static void serial_outb(char ch)
15 {
16         u8 lsr;
17 
18         do {
19                 lsr = inb(serial_iobase + 0x05);
20         } while (!(lsr & 0x20));
21 
22         outb(ch, serial_iobase + 0x00);
23 }
24 
25 static void serial_init(void)
26 {
27         u8 lcr;
28 
29         /* set DLAB */
30         lcr = inb(serial_iobase + 0x03);
31         lcr |= 0x80;
32         outb(lcr, serial_iobase + 0x03);
33 
34         /* set baud rate to 115200 */
35         outb(0x01, serial_iobase + 0x00);
36         outb(0x00, serial_iobase + 0x01);
37 
38         /* clear DLAB */
39         lcr = inb(serial_iobase + 0x03);
40         lcr &= ~0x80;
41         outb(lcr, serial_iobase + 0x03);
42 }
43 
44 static void print_serial(const char *buf)
45 {
46 	unsigned long len = strlen(buf);
47 #ifdef USE_SERIAL
48         unsigned long i;
49         if (!serial_inited) {
50             serial_init();
51             serial_inited = 1;
52         }
53 
54         for (i = 0; i < len; i++) {
55             serial_outb(buf[i]);
56         }
57 #else
58         asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
59 #endif
60 }
61 
62 void puts(const char *s)
63 {
64 	spin_lock(&lock);
65 	print_serial(s);
66 	spin_unlock(&lock);
67 }
68 
69 void exit(int code)
70 {
71 #ifdef USE_SERIAL
72         static const char shutdown_str[8] = "Shutdown";
73         int i;
74 
75         /* test device exit (with status) */
76         outl(code, 0xf4);
77 
78         /* if that failed, try the Bochs poweroff port */
79         for (i = 0; i < 8; i++) {
80                 outb(shutdown_str[i], 0x8900);
81         }
82 #else
83         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
84 #endif
85 }
86 
87 void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
88 {
89 	phys_addr_t base = phys_addr & PAGE_MASK;
90 	phys_addr_t offset = phys_addr - base;
91 
92 	/*
93 	 * The kernel sets PTEs for an ioremap() with page cache disabled,
94 	 * but we do not do that right now. It would make sense that I/O
95 	 * mappings would be uncached - and may help us find bugs when we
96 	 * properly map that way.
97 	 */
98 	return vmap(phys_addr, size) + offset;
99 }
100