| #include "libcflat.h" |
| #include "smp.h" |
| #include "asm/io.h" |
| #include "asm/page.h" |
| #include "vmalloc.h" |
| #ifndef USE_SERIAL |
| #define USE_SERIAL |
| #endif |
| |
| static struct spinlock lock; |
| static int serial_iobase = 0x3f8; |
| static int serial_inited = 0; |
| |
| static void serial_outb(char ch) |
| { |
| u8 lsr; |
| |
| do { |
| lsr = inb(serial_iobase + 0x05); |
| } while (!(lsr & 0x20)); |
| |
| outb(ch, serial_iobase + 0x00); |
| } |
| |
| static void serial_put(char ch) |
| { |
| /* Force carriage return to be performed on \n */ |
| if (ch == '\n') |
| serial_outb('\r'); |
| serial_outb(ch); |
| } |
| |
| static void serial_init(void) |
| { |
| u8 lcr; |
| |
| /* set DLAB */ |
| lcr = inb(serial_iobase + 0x03); |
| lcr |= 0x80; |
| outb(lcr, serial_iobase + 0x03); |
| |
| /* set baud rate to 115200 */ |
| outb(0x01, serial_iobase + 0x00); |
| outb(0x00, serial_iobase + 0x01); |
| |
| /* clear DLAB */ |
| lcr = inb(serial_iobase + 0x03); |
| lcr &= ~0x80; |
| outb(lcr, serial_iobase + 0x03); |
| |
| /* IER: disable interrupts */ |
| outb(0x00, serial_iobase + 0x01); |
| /* LCR: 8 bits, no parity, one stop bit */ |
| outb(0x03, serial_iobase + 0x03); |
| /* FCR: disable FIFO queues */ |
| outb(0x00, serial_iobase + 0x02); |
| /* MCR: RTS, DTR on */ |
| outb(0x03, serial_iobase + 0x04); |
| } |
| |
| static void print_serial(const char *buf) |
| { |
| unsigned long len = strlen(buf); |
| #ifdef USE_SERIAL |
| unsigned long i; |
| if (!serial_inited) { |
| serial_init(); |
| serial_inited = 1; |
| } |
| |
| for (i = 0; i < len; i++) { |
| serial_put(buf[i]); |
| } |
| #else |
| asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); |
| #endif |
| } |
| |
| void puts(const char *s) |
| { |
| spin_lock(&lock); |
| print_serial(s); |
| spin_unlock(&lock); |
| } |
| |
| void exit(int code) |
| { |
| #ifdef USE_SERIAL |
| static const char shutdown_str[8] = "Shutdown"; |
| int i; |
| |
| /* test device exit (with status) */ |
| outl(code, 0xf4); |
| |
| /* if that failed, try the Bochs poweroff port */ |
| for (i = 0; i < 8; i++) { |
| outb(shutdown_str[i], 0x8900); |
| } |
| #else |
| asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); |
| #endif |
| |
| /* Fallback */ |
| while (1) { |
| asm volatile("hlt" ::: "memory"); |
| } |
| } |
| |
| void __iomem *ioremap(phys_addr_t phys_addr, size_t size) |
| { |
| phys_addr_t base = phys_addr & PAGE_MASK; |
| phys_addr_t offset = phys_addr - base; |
| |
| /* |
| * The kernel sets PTEs for an ioremap() with page cache disabled, |
| * but we do not do that right now. It would make sense that I/O |
| * mappings would be uncached - and may help us find bugs when we |
| * properly map that way. |
| */ |
| return vmap(phys_addr, size) + offset; |
| } |