1 #include "libcflat.h"
2 #include "smp.h"
3 #include "fwcfg.h"
4 #include "asm/io.h"
5 #include "asm/page.h"
6 #include "vmalloc.h"
7 #ifndef USE_SERIAL
8 #define USE_SERIAL
9 #endif
10
11 static struct spinlock lock;
12 static int serial_iobase = 0x3f8;
13 static int serial_inited = 0;
14
serial_outb(char ch)15 static void serial_outb(char ch)
16 {
17 u8 lsr;
18
19 do {
20 lsr = inb(serial_iobase + 0x05);
21 } while (!(lsr & 0x20));
22
23 outb(ch, serial_iobase + 0x00);
24 }
25
serial_put(char ch)26 static void serial_put(char ch)
27 {
28 /* Force carriage return to be performed on \n */
29 if (ch == '\n')
30 serial_outb('\r');
31 serial_outb(ch);
32 }
33
serial_init(void)34 static void serial_init(void)
35 {
36 u8 lcr;
37
38 /* set DLAB */
39 lcr = inb(serial_iobase + 0x03);
40 lcr |= 0x80;
41 outb(lcr, serial_iobase + 0x03);
42
43 /* set baud rate to 115200 */
44 outb(0x01, serial_iobase + 0x00);
45 outb(0x00, serial_iobase + 0x01);
46
47 /* clear DLAB */
48 lcr = inb(serial_iobase + 0x03);
49 lcr &= ~0x80;
50 outb(lcr, serial_iobase + 0x03);
51
52 /* IER: disable interrupts */
53 outb(0x00, serial_iobase + 0x01);
54 /* LCR: 8 bits, no parity, one stop bit */
55 outb(0x03, serial_iobase + 0x03);
56 /* FCR: disable FIFO queues */
57 outb(0x00, serial_iobase + 0x02);
58 /* MCR: RTS, DTR on */
59 outb(0x03, serial_iobase + 0x04);
60 }
61
print_serial(const char * buf)62 static void print_serial(const char *buf)
63 {
64 unsigned long len = strlen(buf);
65 #ifdef USE_SERIAL
66 unsigned long i;
67 if (!serial_inited) {
68 serial_init();
69 serial_inited = 1;
70 }
71
72 for (i = 0; i < len; i++) {
73 serial_put(buf[i]);
74 }
75 #else
76 asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
77 #endif
78 }
79
puts(const char * s)80 void puts(const char *s)
81 {
82 spin_lock(&lock);
83 print_serial(s);
84 spin_unlock(&lock);
85 }
86
exit(int code)87 void exit(int code)
88 {
89 #ifdef USE_SERIAL
90 static const char shutdown_str[8] = "Shutdown";
91 int i;
92
93 /* test device exit (with status) */
94 outl(code, 0xf4);
95
96 /* if that failed, try the Bochs poweroff port */
97 for (i = 0; i < 8; i++) {
98 outb(shutdown_str[i], 0x8900);
99 }
100 #else
101 asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
102 #endif
103 if (no_test_device)
104 printf("--- DONE: %d ---\n", code);
105
106 /* Fallback */
107 while (1) {
108 asm volatile("hlt" ::: "memory");
109 }
110 }
111
ioremap(phys_addr_t phys_addr,size_t size)112 void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
113 {
114 phys_addr_t base = phys_addr & PAGE_MASK;
115 phys_addr_t offset = phys_addr - base;
116
117 /*
118 * The kernel sets PTEs for an ioremap() with page cache disabled,
119 * but we do not do that right now. It would make sense that I/O
120 * mappings would be uncached - and may help us find bugs when we
121 * properly map that way.
122 */
123 return vmap(phys_addr, size) + offset;
124 }
125