xref: /kvm-unit-tests/lib/x86/io.c (revision 5747945371b47c51cb16187a26111d06f58f06b2)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "smp.h"
3*57479453SNadav Amit #include "fwcfg.h"
455601383SAlexander Gordeev #include "asm/io.h"
5f1abb07bSAlexander Gordeev #include "asm/page.h"
6dcda215bSPaolo Bonzini #include "vmalloc.h"
728fb1a86SLucas Meneghel Rodrigues #ifndef USE_SERIAL
828fb1a86SLucas Meneghel Rodrigues #define USE_SERIAL
9ac1690b2SAvi Kivity #endif
107d36db35SAvi Kivity 
117d36db35SAvi Kivity static struct spinlock lock;
1228fb1a86SLucas Meneghel Rodrigues static int serial_iobase = 0x3f8;
1328fb1a86SLucas Meneghel Rodrigues static int serial_inited = 0;
1428fb1a86SLucas Meneghel Rodrigues 
serial_outb(char ch)1528fb1a86SLucas Meneghel Rodrigues static void serial_outb(char ch)
1628fb1a86SLucas Meneghel Rodrigues {
1728fb1a86SLucas Meneghel Rodrigues         u8 lsr;
1828fb1a86SLucas Meneghel Rodrigues 
1928fb1a86SLucas Meneghel Rodrigues         do {
2028fb1a86SLucas Meneghel Rodrigues                 lsr = inb(serial_iobase + 0x05);
2128fb1a86SLucas Meneghel Rodrigues         } while (!(lsr & 0x20));
2228fb1a86SLucas Meneghel Rodrigues 
2328fb1a86SLucas Meneghel Rodrigues         outb(ch, serial_iobase + 0x00);
2428fb1a86SLucas Meneghel Rodrigues }
2528fb1a86SLucas Meneghel Rodrigues 
serial_put(char ch)260f4f2acbSEugene Korenevsky static void serial_put(char ch)
270f4f2acbSEugene Korenevsky {
280f4f2acbSEugene Korenevsky         /* Force carriage return to be performed on \n */
290f4f2acbSEugene Korenevsky         if (ch == '\n')
300f4f2acbSEugene Korenevsky                 serial_outb('\r');
310f4f2acbSEugene Korenevsky         serial_outb(ch);
320f4f2acbSEugene Korenevsky }
330f4f2acbSEugene Korenevsky 
serial_init(void)3428fb1a86SLucas Meneghel Rodrigues static void serial_init(void)
3528fb1a86SLucas Meneghel Rodrigues {
3628fb1a86SLucas Meneghel Rodrigues         u8 lcr;
3728fb1a86SLucas Meneghel Rodrigues 
3828fb1a86SLucas Meneghel Rodrigues         /* set DLAB */
3928fb1a86SLucas Meneghel Rodrigues         lcr = inb(serial_iobase + 0x03);
4028fb1a86SLucas Meneghel Rodrigues         lcr |= 0x80;
4128fb1a86SLucas Meneghel Rodrigues         outb(lcr, serial_iobase + 0x03);
4228fb1a86SLucas Meneghel Rodrigues 
4328fb1a86SLucas Meneghel Rodrigues         /* set baud rate to 115200 */
4428fb1a86SLucas Meneghel Rodrigues         outb(0x01, serial_iobase + 0x00);
4528fb1a86SLucas Meneghel Rodrigues         outb(0x00, serial_iobase + 0x01);
4628fb1a86SLucas Meneghel Rodrigues 
4728fb1a86SLucas Meneghel Rodrigues         /* clear DLAB */
4828fb1a86SLucas Meneghel Rodrigues         lcr = inb(serial_iobase + 0x03);
4928fb1a86SLucas Meneghel Rodrigues         lcr &= ~0x80;
5028fb1a86SLucas Meneghel Rodrigues         outb(lcr, serial_iobase + 0x03);
51b3a7cfdcSEugene Korenevsky 
52b3a7cfdcSEugene Korenevsky         /* IER: disable interrupts */
53b3a7cfdcSEugene Korenevsky         outb(0x00, serial_iobase + 0x01);
54b3a7cfdcSEugene Korenevsky         /* LCR: 8 bits, no parity, one stop bit */
55b3a7cfdcSEugene Korenevsky         outb(0x03, serial_iobase + 0x03);
56b3a7cfdcSEugene Korenevsky         /* FCR: disable FIFO queues */
57b3a7cfdcSEugene Korenevsky         outb(0x00, serial_iobase + 0x02);
58b3a7cfdcSEugene Korenevsky         /* MCR: RTS, DTR on */
59b3a7cfdcSEugene Korenevsky         outb(0x03, serial_iobase + 0x04);
6028fb1a86SLucas Meneghel Rodrigues }
617d36db35SAvi Kivity 
print_serial(const char * buf)627d36db35SAvi Kivity static void print_serial(const char *buf)
637d36db35SAvi Kivity {
647d36db35SAvi Kivity 	unsigned long len = strlen(buf);
6528fb1a86SLucas Meneghel Rodrigues #ifdef USE_SERIAL
6628fb1a86SLucas Meneghel Rodrigues         unsigned long i;
6728fb1a86SLucas Meneghel Rodrigues         if (!serial_inited) {
6828fb1a86SLucas Meneghel Rodrigues             serial_init();
690f54b9b2SPaolo Bonzini             serial_inited = 1;
7028fb1a86SLucas Meneghel Rodrigues         }
717d36db35SAvi Kivity 
7228fb1a86SLucas Meneghel Rodrigues         for (i = 0; i < len; i++) {
730f4f2acbSEugene Korenevsky             serial_put(buf[i]);
7428fb1a86SLucas Meneghel Rodrigues         }
7528fb1a86SLucas Meneghel Rodrigues #else
767d36db35SAvi Kivity         asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
7728fb1a86SLucas Meneghel Rodrigues #endif
787d36db35SAvi Kivity }
797d36db35SAvi Kivity 
puts(const char * s)807d36db35SAvi Kivity void puts(const char *s)
817d36db35SAvi Kivity {
827d36db35SAvi Kivity 	spin_lock(&lock);
837d36db35SAvi Kivity 	print_serial(s);
847d36db35SAvi Kivity 	spin_unlock(&lock);
857d36db35SAvi Kivity }
867d36db35SAvi Kivity 
exit(int code)877d36db35SAvi Kivity void exit(int code)
887d36db35SAvi Kivity {
8928fb1a86SLucas Meneghel Rodrigues #ifdef USE_SERIAL
9028fb1a86SLucas Meneghel Rodrigues         static const char shutdown_str[8] = "Shutdown";
9128fb1a86SLucas Meneghel Rodrigues         int i;
9228fb1a86SLucas Meneghel Rodrigues 
9328fb1a86SLucas Meneghel Rodrigues         /* test device exit (with status) */
9428fb1a86SLucas Meneghel Rodrigues         outl(code, 0xf4);
9528fb1a86SLucas Meneghel Rodrigues 
9628fb1a86SLucas Meneghel Rodrigues         /* if that failed, try the Bochs poweroff port */
9728fb1a86SLucas Meneghel Rodrigues         for (i = 0; i < 8; i++) {
9828fb1a86SLucas Meneghel Rodrigues                 outb(shutdown_str[i], 0x8900);
9928fb1a86SLucas Meneghel Rodrigues         }
10028fb1a86SLucas Meneghel Rodrigues #else
1017d36db35SAvi Kivity         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
10228fb1a86SLucas Meneghel Rodrigues #endif
103*57479453SNadav Amit 	if (no_test_device)
104*57479453SNadav Amit 		printf("--- DONE: %d ---\n", code);
105ce5a7e2dSNadav Amit 
106ce5a7e2dSNadav Amit 	/* Fallback */
107ce5a7e2dSNadav Amit 	while (1) {
108ce5a7e2dSNadav Amit 		asm volatile("hlt" ::: "memory");
109ce5a7e2dSNadav Amit 	}
1107d36db35SAvi Kivity }
111f1abb07bSAlexander Gordeev 
ioremap(phys_addr_t phys_addr,size_t size)112f1abb07bSAlexander Gordeev void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
113f1abb07bSAlexander Gordeev {
114f1abb07bSAlexander Gordeev 	phys_addr_t base = phys_addr & PAGE_MASK;
115f1abb07bSAlexander Gordeev 	phys_addr_t offset = phys_addr - base;
116f1abb07bSAlexander Gordeev 
117f1abb07bSAlexander Gordeev 	/*
118f1abb07bSAlexander Gordeev 	 * The kernel sets PTEs for an ioremap() with page cache disabled,
119f1abb07bSAlexander Gordeev 	 * but we do not do that right now. It would make sense that I/O
120f1abb07bSAlexander Gordeev 	 * mappings would be uncached - and may help us find bugs when we
121f1abb07bSAlexander Gordeev 	 * properly map that way.
122f1abb07bSAlexander Gordeev 	 */
123f1abb07bSAlexander Gordeev 	return vmap(phys_addr, size) + offset;
124f1abb07bSAlexander Gordeev }
125