3 * \brief Support for the x86 platform
6 * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
10 * (c) 2008-2009 Author(s)
11 * economic rights: Technische Universität Dresden (Germany)
13 * This file is part of TUD:OS and distributed under the terms of the
14 * GNU General Public License 2.
15 * Please see the COPYING-GPL-2 file for details.
19 #include <l4/drivers/uart_pxa.h>
20 #include <l4/drivers/io_regblock_port.h>
23 #include "base_critical.h"
25 #include <l4/util/cpu.h>
26 #include <l4/util/port_io.h>
32 /** VGA console output */
34 static void vga_init()
36 /* Reset any scrolling */
37 l4util_out32(0xc, 0x3d4);
38 l4util_out32(0, 0x3d5);
39 l4util_out32(0xd, 0x3d4);
40 l4util_out32(0, 0x3d5);
43 static void vga_putchar(unsigned char c)
45 static int ofs = -1, esc, esc_val, attr = 0x07;
46 unsigned char *vidbase = (unsigned char*)0xb8000;
48 base_critical_enter();
52 /* Called for the first time - initialize. */
69 if (c >= '0' && c <= '9')
71 esc_val = 10*esc_val + c - '0';
76 attr = esc_val ? 0x0f : 0x07;
86 memmove(vidbase, vidbase+80*2, 80*2*24);
87 memset(vidbase+80*2*24, 0, 80*2);
103 /* Wrap if we reach the end of a line. */
107 /* Stuff the character into the video buffer. */
109 volatile unsigned char *p = vidbase + 80*2*24 + ofs*2;
118 base_critical_leave();
121 /** Poor man's getchar, only returns raw scan code. We don't need to know
122 * _which_ key was pressed, we only want to know _if_ a key was pressed. */
123 static int raw_keyboard_getscancode(void)
125 unsigned status, scan_code;
127 base_critical_enter();
131 /* Wait until a scan code is ready and read it. */
132 status = l4util_in8(0x64);
133 if ((status & 0x01) == 0)
135 base_critical_leave();
138 scan_code = l4util_in8(0x60);
140 /* Drop mouse events */
141 if ((status & 0x20) != 0)
143 base_critical_leave();
147 base_critical_leave();
152 static inline l4_uint32_t
153 pci_conf_addr(l4_uint32_t bus, l4_uint32_t dev, l4_uint32_t fn, l4_uint32_t reg)
154 { return 0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
156 static l4_uint32_t pci_read(unsigned char bus, l4_uint32_t dev,
157 l4_uint32_t fn, l4_uint32_t reg,
160 l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
164 case 8: return l4util_in8(0xcfc + (reg & 3));
165 case 16: return l4util_in16((0xcfc + (reg & 3)) & ~1UL);
166 case 32: return l4util_in32(0xcfc);
171 static void pci_write(unsigned char bus, l4_uint32_t dev,
172 l4_uint32_t fn, l4_uint32_t reg,
173 l4_uint32_t val, unsigned char width)
175 l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
179 case 8: l4util_out8(val, 0xcfc + (reg & 3)); break;
180 case 16: l4util_out16(val, (0xcfc + (reg & 3)) & ~1UL); break;
181 case 32: l4util_out32(val, 0xcfc); break;
185 static void pci_enable_io(unsigned char bus, l4_uint32_t dev,
188 unsigned cmd = pci_read(bus, dev, fn, 4, 16);
189 pci_write(bus, dev, fn, 4, cmd | 1, 16);
196 enum Type { NO_BAR, IO_BAR, MEM_BAR };
200 Resource() : type(NO_BAR) {}
203 enum { NUM_BARS = 6 };
210 Resource bars[NUM_BARS];
212 unsigned long get_port(int idx)
214 if (idx >= num_ports)
218 return bars[first_bar + idx].base;
220 return bars[first_bar].base + 8 * idx;
228 int pci_handle_serial_dev(unsigned char bus, l4_uint32_t dev,
229 l4_uint32_t subdev, bool print,
233 bool dev_enabled = false;
240 for (int bar = 0; bar < NUM_BARS; ++bar)
242 int a = 0x10 + bar * 4;
244 unsigned v = pci_read(bus, dev, subdev, a, 32);
245 pci_write(bus, dev, subdev, a, ~0U, 32);
246 unsigned x = pci_read(bus, dev, subdev, a, 32);
247 pci_write(bus, dev, subdev, a, v, 32);
253 for (s = 2; s < 32; ++s)
257 board->bars[bar].base = v & ~3UL;
258 board->bars[bar].len = 1 << s;
259 board->bars[bar].type = (v & 1) ? Resource::IO_BAR : Resource::MEM_BAR;
262 printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
264 switch (board->bars[bar].type)
266 case Resource::IO_BAR:
268 if (first_port == -1)
271 case Resource::MEM_BAR:
279 printf(" serial IO card: mem bars: %d io bars: %d\n", num_membars, num_iobars);
281 if (num_membars <= 1 && num_iobars == 1)
283 board->first_bar = first_port;
284 board->num_ports = board->bars[first_port].len / 8;
285 board->port_per_bar = false;
286 printf(" use serial IO card: bar=%d ports=%d\n", first_port, board->num_ports);
287 pci_enable_io(bus, dev, subdev);
292 board->num_ports = 0;
293 board->first_bar = -1;
295 for (int bar = 0; bar < NUM_BARS; ++bar)
297 if (board->bars[bar].type == Resource::IO_BAR && board->bars[bar].len == 8
298 && (board->first_bar == -1
299 || (board->first_bar + board->num_ports) == bar))
302 if (board->first_bar == -1)
303 board->first_bar = bar;
307 board->port_per_bar = true;
308 return board->num_ports;
312 // for now we only take IO-BARs of size 8
316 if (!scan_only && !dev_enabled)
318 pci_enable_io(bus, dev, subdev);
323 printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
328 printf(" Potential serial port\n");
335 printf("BAR%d: %08x (sz=%d)\n", bar, v & ~0xf, 1 << s);
342 _search_pci_serial_devs(Serial_board *board, unsigned look_for_subclass,
345 l4_umword_t bus, buses, dev;
347 for (bus=0, buses=20; bus<buses; bus++)
349 for (dev = 0; dev < 32; dev++)
351 unsigned char hdr_type = pci_read(bus, dev, 0, 0xe, 8);
352 l4_umword_t subdevs = (hdr_type & 0x80) ? 8 : 1;
354 for (l4_umword_t subdev = 0; subdev < subdevs; subdev++)
356 unsigned vendor = pci_read(bus, dev, subdev, 0, 16);
357 unsigned device = pci_read(bus, dev, subdev, 2, 16);
359 if (vendor == 0xffff)
367 unsigned classcode = pci_read(bus, dev, subdev, 0x0b, 8);
368 unsigned subclass = pci_read(bus, dev, subdev, 0x0a, 8);
370 if (classcode == 0x06 && subclass == 0x04)
373 unsigned prog = pci_read(bus, dev, subdev, 9, 8);
376 printf("%02lx:%02lx.%1lx Class %02x.%02x Prog %02x: %04x:%04x\n",
377 bus, dev, subdev, classcode, subclass, prog, vendor, device);
379 if (classcode == 7 && subclass == look_for_subclass)
380 if (unsigned long port = pci_handle_serial_dev(bus, dev,
381 subdev, print, board))
390 search_pci_serial_devs(int port_idx)
393 if (!_search_pci_serial_devs(&board, 0, true)) // classes should be 7:0
394 if (!_search_pci_serial_devs(&board, 0x80, true)) // but sometimes it's 7:80
397 return board.get_port(port_idx);
400 class Uart_vga : public L4::Uart
406 bool startup(L4::Io_register_block const *)
414 bool enable_rx_irq(bool) { return false; }
415 bool enable_tx_irq(bool) { return false; }
416 bool change_mode(Transfer_mode, Baud_rate) { return true; }
417 int get_char(bool blocking) const
421 c = raw_keyboard_getscancode();
422 while (blocking && c == -1);
426 int char_avail() const
428 return raw_keyboard_getscancode() != -1;
431 int write(char const *s, unsigned long count) const
433 unsigned long c = count;
445 class Dual_uart : public L4::Uart
451 Dual_uart(L4::Uart *u1)
455 void set_uart2(L4::Uart *u2)
460 bool startup(L4::Io_register_block const *)
474 bool enable_rx_irq(bool e)
476 bool r1 = _u1->enable_rx_irq(e);
477 bool r2 = _u2 ? _u2->enable_rx_irq(e) : false;
481 bool enable_tx_irq(bool e)
483 bool r1 = _u1->enable_tx_irq(e);
484 bool r2 = _u2 ? _u2->enable_tx_irq(e) : false;
489 bool change_mode(Transfer_mode m, Baud_rate r)
491 bool r1 = _u1->change_mode(m, r);
492 bool r2 = _u2 ? _u2->change_mode(m, r) : false;
496 int char_avail() const
498 return _u1->char_avail() || (_u2 && _u2->char_avail());
501 int get_char(bool blocking) const
506 c = _u1->get_char(false);
508 c = _u2->get_char(false);
510 while (blocking && c == -1);
514 int write(char const *s, unsigned long count) const
516 int r = _u1->write(s, count);
518 _u2->write(s, count);
524 l4util_mb_info_t *x86_bootloader_mbi;
528 class Platform_x86 : public Platform_base
531 bool probe() { return true; }
533 int init_uart(int com_port_or_base, int com_irq, Dual_uart *du)
535 base_critical_enter();
537 switch (com_port_or_base)
539 case 1: com_port_or_base = 0x3f8;
543 case 2: com_port_or_base = 0x2f8;
547 case 3: com_port_or_base = 0x3e8; break;
548 case 4: com_port_or_base = 0x2e8; break;
551 unsigned baudrate = 115200;
552 static L4::Io_register_block_port uart_regs(com_port_or_base);
553 static L4::Uart_16550 _uart(L4::Uart_16550::Base_rate_x86);
554 if ( !_uart.startup(&uart_regs)
555 || !_uart.change_mode(L4::Uart_16550::MODE_8N1, baudrate))
557 printf("Could not find or enable UART\n");
558 base_critical_leave();
562 du->set_uart2(&_uart);
564 kuart.access_type = L4_kernel_options::Uart_type_ioport;
565 kuart.irqno = com_irq;
566 kuart.base_address = com_port_or_base;
567 kuart.baud = baudrate;
568 kuart_flags |= L4_kernel_options::F_uart_base
569 | L4_kernel_options::F_uart_baud;
571 kuart_flags |= L4_kernel_options::F_uart_irq;
573 base_critical_leave();
584 static Uart_vga _vga;
585 static Dual_uart du(&_vga);
588 if ((s = check_arg(x86_bootloader_mbi, "-comirq")))
591 comirq = strtoul(s, 0, 0);
594 if ((s = check_arg(x86_bootloader_mbi, "-comport")))
597 if ((pci = !strncmp(s, "pci:", 4)))
600 comport = strtoul(s, 0, 0);
603 if (!check_arg(x86_bootloader_mbi, "-noserial"))
607 if (unsigned long port = search_pci_serial_devs(comport))
612 printf("PCI IO port = %x\n", comport);
618 if (init_uart(comport, comirq, &du))
619 printf("UART init failed\n");
623 void setup_memory_map(l4util_mb_info_t *mbi,
624 Region_list *ram, Region_list *regions)
626 if (!(mbi->flags & L4UTIL_MB_MEM_MAP))
628 assert(mbi->flags & L4UTIL_MB_MEMORY);
629 ram->add(Region::n(0, (mbi->mem_upper + 1024) << 10, ".ram",
634 l4util_mb_addr_range_t *mmap;
635 l4util_mb_for_each_mmap_entry(mmap, mbi)
637 unsigned long long start = (unsigned long long)mmap->addr;
638 unsigned long long end = (unsigned long long)mmap->addr + mmap->size;
643 ram->add(Region::n(start, end, ".ram", Region::Ram));
648 regions->add(Region::n(start, end, ".BIOS", Region::Arch, mmap->type));
651 regions->add(Region::n(start, end, ".BIOS", Region::No_mem));
659 regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
664 // Fix EBDA in conventional memory
665 unsigned long p = *(l4_uint16_t *)0x40e << 4;
669 unsigned long e = p + 1024;
670 Region *r = ram->find(Region(p, e - 1));
673 if (e - 1 < r->end())
674 ram->add(Region::n(e, r->end(), ".ram", Region::Ram));
682 REGISTER_PLATFORM(Platform_x86);