xref: /kvm-unit-tests/lib/x86/io.c (revision b3a7cfdc37fdd034286ee079b6b8ec3dea5fce9c)
1 #include "libcflat.h"
2 #include "smp.h"
3 #include "asm/io.h"
4 #include "asm/page.h"
5 #include "vmalloc.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         /* IER: disable interrupts */
44         outb(0x00, serial_iobase + 0x01);
45         /* LCR: 8 bits, no parity, one stop bit */
46         outb(0x03, serial_iobase + 0x03);
47         /* FCR: disable FIFO queues */
48         outb(0x00, serial_iobase + 0x02);
49         /* MCR: RTS, DTR on */
50         outb(0x03, serial_iobase + 0x04);
51 }
52 
53 static void print_serial(const char *buf)
54 {
55 	unsigned long len = strlen(buf);
56 #ifdef USE_SERIAL
57         unsigned long i;
58         if (!serial_inited) {
59             serial_init();
60             serial_inited = 1;
61         }
62 
63         for (i = 0; i < len; i++) {
64             serial_outb(buf[i]);
65         }
66 #else
67         asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
68 #endif
69 }
70 
71 void puts(const char *s)
72 {
73 	spin_lock(&lock);
74 	print_serial(s);
75 	spin_unlock(&lock);
76 }
77 
78 void exit(int code)
79 {
80 #ifdef USE_SERIAL
81         static const char shutdown_str[8] = "Shutdown";
82         int i;
83 
84         /* test device exit (with status) */
85         outl(code, 0xf4);
86 
87         /* if that failed, try the Bochs poweroff port */
88         for (i = 0; i < 8; i++) {
89                 outb(shutdown_str[i], 0x8900);
90         }
91 #else
92         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
93 #endif
94 }
95 
96 void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
97 {
98 	phys_addr_t base = phys_addr & PAGE_MASK;
99 	phys_addr_t offset = phys_addr - base;
100 
101 	/*
102 	 * The kernel sets PTEs for an ioremap() with page cache disabled,
103 	 * but we do not do that right now. It would make sense that I/O
104 	 * mappings would be uncached - and may help us find bugs when we
105 	 * properly map that way.
106 	 */
107 	return vmap(phys_addr, size) + offset;
108 }
109