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