3 * \brief Support for the x86 platform
6 * \author Adam Lackorznynski <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.
22 class Uart_x86 : public Uart
27 inline unsigned long rd(unsigned long reg) const;
28 inline void wr(unsigned long reg, unsigned long val) const;
31 Uart_x86(int rx_irq, int tx_irq)
32 : Uart(rx_irq, tx_irq), _base(~0UL) {}
33 bool startup(unsigned long base);
35 bool enable_rx_irq(bool enable = true);
36 bool enable_tx_irq(bool enable = true);
37 bool change_mode(Transfer_mode m, Baud_rate r);
38 int get_char(bool blocking = true) const;
39 int char_avail() const;
40 inline void out_char(char c) const;
41 int write(char const *s, unsigned long count) const;
47 #include "base_critical.h"
48 #include "ARCH-x86/serial.h"
49 #include <l4/util/cpu.h>
50 #include <l4/util/port_io.h>
53 /** VGA console output */
58 /* Reset any scrolling */
59 l4util_out32(0xc, 0x3d4);
60 l4util_out32(0, 0x3d5);
61 l4util_out32(0xd, 0x3d4);
62 l4util_out32(0, 0x3d5);
66 vga_putchar(unsigned char c)
68 static int ofs = -1, esc, esc_val, attr = 0x07;
69 unsigned char *vidbase = (unsigned char*)0xb8000;
71 base_critical_enter();
75 /* Called for the first time - initialize. */
92 if (c >= '0' && c <= '9')
94 esc_val = 10*esc_val + c - '0';
99 attr = esc_val ? 0x0f : 0x07;
109 memmove(vidbase, vidbase+80*2, 80*2*24);
110 memset(vidbase+80*2*24, 0, 80*2);
111 /* fall through... */
117 ofs = (ofs + 8) & ~7;
126 /* Wrap if we reach the end of a line. */
130 /* Stuff the character into the video buffer. */
132 volatile unsigned char *p = vidbase + 80*2*24 + ofs*2;
141 base_critical_leave();
144 /** Poor man's getchar, only returns raw scan code. We don't need to know
145 * _which_ key was pressed, we only want to know _if_ a key was pressed. */
147 raw_keyboard_getscancode(void)
149 unsigned status, scan_code;
151 base_critical_enter();
155 /* Wait until a scan code is ready and read it. */
156 status = l4util_in8(0x64);
157 if ((status & 0x01) == 0)
159 base_critical_leave();
162 scan_code = l4util_in8(0x60);
164 /* Drop mouse events */
165 if ((status & 0x20) != 0)
167 base_critical_leave();
171 base_critical_leave();
177 bool Uart_x86::startup(unsigned long /*base*/)
178 // real uart init will be made by startup.cc if told by cmdline
179 { vga_init(); return true; }
181 void Uart_x86::shutdown() {}
182 bool Uart_x86::enable_rx_irq(bool) { return true; }
183 bool Uart_x86::enable_tx_irq(bool) { return false; }
184 bool Uart_x86::change_mode(Transfer_mode, Baud_rate) { return false; }
186 int Uart_x86::get_char(bool blocking) const
190 c = com_cons_try_getchar();
192 c = raw_keyboard_getscancode();
194 } while (c == -1 && blocking);
199 int Uart_x86::char_avail() const
201 return com_cons_char_avail();
204 void Uart_x86::out_char(char c) const
206 vga_putchar(c); // vga out
207 com_cons_putchar(c); // serial out
210 int Uart_x86::write(char const *s, unsigned long count) const
212 unsigned long c = count;
225 static inline l4_uint32_t
226 pci_conf_addr(l4_uint32_t bus, l4_uint32_t dev, l4_uint32_t fn, l4_uint32_t reg)
227 { return 0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
229 static l4_uint32_t pci_read(unsigned char bus, l4_uint32_t dev,
230 l4_uint32_t fn, l4_uint32_t reg,
233 l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
237 case 8: return l4util_in8(0xcfc + (reg & 3));
238 case 16: return l4util_in16((0xcfc + (reg & 3)) & ~1UL);
239 case 32: return l4util_in32(0xcfc);
244 static void pci_write(unsigned char bus, l4_uint32_t dev,
245 l4_uint32_t fn, l4_uint32_t reg,
246 l4_uint32_t val, unsigned char width)
248 l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
252 case 8: l4util_out8(val, 0xcfc + (reg & 3)); break;
253 case 16: l4util_out16(val, (0xcfc + (reg & 3)) & ~1UL); break;
254 case 32: l4util_out32(val, 0xcfc); break;
258 static void pci_enable_io(unsigned char bus, l4_uint32_t dev,
261 unsigned cmd = pci_read(bus, dev, fn, 4, 16);
262 pci_write(bus, dev, fn, 4, cmd | 1, 16);
267 static bool pci_handle_serial_dev(unsigned char bus, l4_uint32_t dev,
268 l4_uint32_t subdev, bool scan_only)
270 bool dev_enabled = false;
273 for (int bar = 0; bar < 6; ++bar)
275 int a = 0x10 + bar * 4;
277 unsigned v = pci_read(bus, dev, subdev, a, 32);
278 pci_write(bus, dev, subdev, a, ~0U, 32);
279 unsigned x = pci_read(bus, dev, subdev, a, 32);
285 for (s = 2; s < 32; ++s)
289 // for now we only take IO-BARs of size 8
293 if (!scan_only && !dev_enabled)
295 pci_enable_io(bus, dev, subdev);
300 printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
305 printf(" Potential serial port\n");
312 printf("BAR%d: %08x (sz=%d)\n", bar, v & ~0xf, 1 << s);
317 unsigned long search_pci_serial_devs(bool scan_only)
319 l4_umword_t bus, buses, dev;
321 for (bus=0, buses=1; bus<buses; bus++)
323 for (dev = 0; dev < 32; dev++)
325 unsigned char hdr_type = pci_read(bus, dev, 0, 0xe, 8);
326 l4_umword_t subdevs = (hdr_type & 0x80) ? 8 : 1;
328 for (l4_umword_t subdev = 0; subdev < subdevs; subdev++)
330 unsigned vendor = pci_read(bus, dev, subdev, 0, 16);
331 unsigned device = pci_read(bus, dev, subdev, 2, 16);
333 if ((vendor == 0xffff && device == 0xffff) ||
334 (device == 0x0000 && device == 0x0000))
337 unsigned classcode = pci_read(bus, dev, subdev, 0x0b, 8);
338 unsigned subclass = pci_read(bus, dev, subdev, 0x0a, 8);
340 if (classcode == 0x06 && subclass == 0x04)
343 unsigned prog = pci_read(bus, dev, subdev, 9, 8);
346 printf("%02lx:%02lx.%1lx Class %02x.%02x Prog %02x: %04x:%04x\n",
347 bus, dev, subdev, classcode, subclass, prog, vendor, device);
349 if (classcode == 7 && subclass == 0)
350 if (unsigned long port = pci_handle_serial_dev(bus, dev,
361 class Platform_x86 : public Platform_base
364 bool probe() { return true; }
367 // this is just a wrapper around serial.c
368 // if you think this could be done better you're right...
369 static L4::Uart_x86 _uart(1,1);
371 set_stdio_uart(&_uart);
374 void setup_memory_map(l4util_mb_info_t *mbi,
375 Region_list *ram, Region_list *regions)
377 if (!(mbi->flags & L4UTIL_MB_MEM_MAP))
379 assert(mbi->flags & L4UTIL_MB_MEMORY);
380 ram->add(Region::n(0, (mbi->mem_upper + 1024) << 10, ".ram",
385 l4util_mb_addr_range_t *mmap;
386 l4util_mb_for_each_mmap_entry(mmap, mbi)
388 unsigned long long start = (unsigned long long)mmap->addr;
389 unsigned long long end = (unsigned long long)mmap->addr + mmap->size;
394 ram->add(Region::n(start, end, ".ram", Region::Ram));
399 regions->add(Region::n(start, end, ".BIOS", Region::Arch, mmap->type));
402 regions->add(Region::n(start, end, ".BIOS", Region::No_mem));
410 regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
415 REGISTER_PLATFORM(Platform_x86);