From 4d12464cee896e517dcdf9a206fc33f1cb2b5abf Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 19 Nov 2012 10:23:37 +0100 Subject: [PATCH] Read BIOS data area (BDA) to get serial I/O ports If the I/O ports are non default (3f8), we had to specify manually the correct I/O ports. With this commit the BDA is read and the I/O port of the first serial interface (COM) is taken. If no serial interface is available no device configuration will be undertaken. --- base-nova/src/base/console/core_console.h | 70 +++++++++++++++-------- base-nova/src/core/include/nova_util.h | 6 +- base-nova/src/core/include/platform.h | 2 +- base-nova/src/core/platform.cc | 8 ++- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/base-nova/src/base/console/core_console.h b/base-nova/src/base/console/core_console.h index dfbf8b7f6..529e61d33 100644 --- a/base-nova/src/base/console/core_console.h +++ b/base-nova/src/base/console/core_console.h @@ -1,6 +1,7 @@ /* * \brief Console backend for NOVA * \author Norman Feske + * \author Alexander Boettcher * \date 2009-12-28 */ @@ -18,15 +19,13 @@ /* NOVA includes */ #include -typedef unsigned char uint8_t; - /** * Read byte from I/O port */ -inline uint8_t inb(unsigned short port) +inline Genode::uint8_t inb(Genode::uint16_t port) { - uint8_t res; + Genode::uint8_t res; asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port)); return res; } @@ -35,7 +34,7 @@ inline uint8_t inb(unsigned short port) /** * Write byte to I/O port */ -inline void outb(unsigned short port, uint8_t val) +inline void outb(Genode::uint16_t port, Genode::uint8_t val) { asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port)); } @@ -44,14 +43,14 @@ inline void outb(unsigned short port, uint8_t val) /** * Definitions of PC serial ports */ -enum Comport { COMPORT_0, COMPORT_1, COMPORT_2, COMPORT_3 }; - enum { -// COMPORT_0_BASE = 0x1010, /* comport of serial PCI card */ - COMPORT_0_BASE = 0x3f8, /* default comport 0, used wiht Qemu */ - COMPORT_1_BASE = 0x2f8, - COMPORT_2_BASE = 0x3e8, - COMPORT_3_BASE = 0x2e8, + MAP_ADDR_BDA = 0x1000, + + BDA_SERIAL_BASE_COM1 = 0x400, + BDA_EQUIPMENT_WORD = 0x410, + BDA_EQUIPMENT_SERIAL_COUNT_MASK = 0x7, + BDA_EQUIPMENT_SERIAL_COUNT_SHIFT = 9, + COMPORT_DATA_OFFSET = 0, COMPORT_STATUS_OFFSET = 5, @@ -65,8 +64,11 @@ enum { * * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' */ -static void init_comport(unsigned short port, unsigned baud) +static void init_comport(Genode::uint16_t port, unsigned baud) { + if (!port) + return; + const unsigned IER = port + 1, EIR = port + 2, @@ -98,17 +100,15 @@ static void init_comport(unsigned short port, unsigned baud) /** * Output character to serial port */ -inline void serial_out_char(Comport comport, uint8_t c) +inline void serial_out_char(Genode::uint16_t comport, Genode::uint8_t c) { - static int io_port[] = { COMPORT_0_BASE, COMPORT_1_BASE, - COMPORT_2_BASE, COMPORT_3_BASE }; - /* wait until serial port is ready */ - uint8_t ready = STATUS_THR_EMPTY; - while ((inb(io_port[comport] + COMPORT_STATUS_OFFSET) & ready) != ready); + Genode::uint8_t ready = STATUS_THR_EMPTY; + while ((inb(comport + COMPORT_STATUS_OFFSET) & ready) != ready); /* output character */ - outb(io_port[comport] + COMPORT_DATA_OFFSET, c); + outb(comport + COMPORT_DATA_OFFSET, c); + } @@ -116,18 +116,42 @@ namespace Genode { class Core_console : public Console { + private: + + uint16_t _comport; + protected: void _out_char(char c) { + if (!_comport) + return; + if (c == '\n') - serial_out_char(COMPORT_0, '\r'); - serial_out_char(COMPORT_0, c); + serial_out_char(_comport, '\r'); + serial_out_char(_comport, c); } public: - Core_console() { init_comport(COMPORT_0_BASE, 115200); } + Core_console() : _comport(0) + { + /** + * Read BDA (Bios Data Area) to obtain I/O ports of COM + * interfaces. The page must be mapped by the platform code ! + */ + char * map_bda = reinterpret_cast(MAP_ADDR_BDA); + uint16_t serial_count = *reinterpret_cast(map_bda + BDA_EQUIPMENT_WORD); + serial_count >>= BDA_EQUIPMENT_SERIAL_COUNT_SHIFT; + serial_count &= BDA_EQUIPMENT_SERIAL_COUNT_MASK; + + if (serial_count > 0) + _comport = *reinterpret_cast( + map_bda + BDA_SERIAL_BASE_COM1); + + init_comport(_comport, 115200); + + } }; } diff --git a/base-nova/src/core/include/nova_util.h b/base-nova/src/core/include/nova_util.h index cae559e83..815f3105c 100644 --- a/base-nova/src/core/include/nova_util.h +++ b/base-nova/src/core/include/nova_util.h @@ -74,8 +74,12 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, static inline int unmap_local(Nova::Crd crd, bool self = true) { return Nova::revoke(crd, self); } +inline int +map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, Nova::Crd dst) { + return map_local(utcb, src, dst, true); } -inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { +inline int +map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) { return map_local(utcb, crd, crd, true); } diff --git a/base-nova/src/core/include/platform.h b/base-nova/src/core/include/platform.h index 544518740..48c476068 100644 --- a/base-nova/src/core/include/platform.h +++ b/base-nova/src/core/include/platform.h @@ -36,7 +36,7 @@ namespace Genode { /** * Virtual address range usable by non-core processes */ - addr_t _vm_base; + const addr_t _vm_base; size_t _vm_size; void _preserve_page(addr_t phys_page); diff --git a/base-nova/src/core/platform.cc b/base-nova/src/core/platform.cc index f00d35c9d..b2478a3c2 100644 --- a/base-nova/src/core/platform.cc +++ b/base-nova/src/core/platform.cc @@ -194,7 +194,7 @@ static void init_core_page_fault_handler() Platform::Platform() : _io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()), _irq_alloc(core_mem_alloc()), - _vm_base(0), _vm_size(0) + _vm_base(0x2000), _vm_size(0) { Hip *hip = (Hip *)__initial_sp; @@ -211,6 +211,11 @@ Platform::Platform() : /* locally map the whole I/O port range */ enum { ORDER_64K = 16 }; map_local_one_to_one(__main_thread_utcb, Io_crd(0, ORDER_64K)); + /* map BDA region, core_console reads out serial i/o ports at 0x400 */ + map_local_phys_to_virt(__main_thread_utcb, + Mem_crd(0x0, 0, Rights(true, false, false)), + Mem_crd(0x1, 0, Rights(true, false, false))); + /* * Now that we can access the I/O ports for comport 0, printf works... @@ -223,7 +228,6 @@ Platform::Platform() : } /* configure virtual address spaces */ - _vm_base = get_page_size(); #ifdef __x86_64__ _vm_size = 0x800000000000UL - _vm_base; #else