From 0b019d0508df6d6910fec7a11f35e0f0f7a70526 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 9 Jul 2015 11:03:11 +0200 Subject: [PATCH] base: move x86 uart driver from nova to base So it can be reused by base-hw-x86 instead of re-writing it. Fixes #1403 --- .../src/core/include/spec/x86/serial.h | 136 ++------------ .../base-nova/src/base/console/core_console.h | 172 +++++------------- .../base/include/drivers/uart/x86_uart_base.h | 111 +++++++++++ 3 files changed, 166 insertions(+), 253 deletions(-) create mode 100644 repos/base/include/drivers/uart/x86_uart_base.h diff --git a/repos/base-hw/src/core/include/spec/x86/serial.h b/repos/base-hw/src/core/include/spec/x86/serial.h index b797b3740..f33e81e6c 100644 --- a/repos/base-hw/src/core/include/spec/x86/serial.h +++ b/repos/base-hw/src/core/include/spec/x86/serial.h @@ -5,142 +5,30 @@ */ /* - * Copyright (C) 2012-2013 Genode Labs GmbH + * Copyright (C) 2012-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -#ifndef _SERIAL_H_ -#define _SERIAL_H_ +#pragma once /* Genode includes */ -#include +#include + +namespace Genode { class Serial; } /** - * Read byte from I/O port + * Serial output driver for core */ -inline Genode::uint8_t inb(Genode::uint16_t port) +class Genode::Serial : public X86_uart_base { - Genode::uint8_t res; - asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port)); - return res; -} + private: + enum { IO_PORT = 0x3f8, CLOCK_UNUSED = 0 }; -/** - * Write byte to I/O port - */ -inline void outb(Genode::uint16_t port, Genode::uint8_t val) -{ - asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port)); -} + public: - -/** - * Definitions of PC serial ports - */ -enum { - COMPORT_DATA_OFFSET = 0, - COMPORT_STATUS_OFFSET = 5, - - STATUS_THR_EMPTY = 0x20, /* transmitter hold register empty */ - STATUS_DHR_EMPTY = 0x40, /* data hold register empty - - data completely sent */ + Serial(unsigned baud_rate) + : X86_uart_base(IO_PORT, CLOCK_UNUSED, baud_rate) { } }; - - -/** - * Initialize serial port - * - * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' - */ -static void init_comport(Genode::uint16_t port, unsigned baud) -{ - if (!port) - return; - - unsigned const ier = port + 1; - unsigned const eir = port + 2; - unsigned const lcr = port + 3; - unsigned const mcr = port + 4; - unsigned const lsr = port + 5; - unsigned const msr = port + 6; - unsigned const dllo = port + 0; - unsigned const dlhi = port + 1; - - outb(lcr, 0x80); /* select bank 1 */ - outb(dllo, (115200/baud) >> 0); - outb(dlhi, (115200/baud) >> 8); - outb(lcr, 0x03); /* set 8,n,1 */ - outb(ier, 0x00); /* disable interrupts */ - outb(eir, 0x07); /* enable FIFOs */ - outb(mcr, 0x0b); /* force data terminal ready */ - outb(ier, 0x01); /* enable rx interrupts */ - inb(ier); - inb(eir); - inb(lcr); - inb(mcr); - inb(lsr); - inb(msr); -} - - -/** - * Output character to serial port - */ -inline void serial_out_char(Genode::uint16_t comport, Genode::uint8_t c) -{ - /* wait until serial port is ready */ - Genode::uint8_t ready = STATUS_THR_EMPTY; - while ((inb(comport + COMPORT_STATUS_OFFSET) & ready) != ready); - - /* output character */ - outb(comport + COMPORT_DATA_OFFSET, c); -} - - -namespace Genode { - - /** - * Serial output driver for core - */ - class Serial - { - private: - - uint16_t _comport; - - public: - - void put_char(char c) - { - if (!_comport) - return; - - if (c == '\n') - serial_out_char(_comport, '\r'); - serial_out_char(_comport, c); - } - - /** - * Constructor - * - * XXX: The 'baud_rate' argument is ignored for now. - */ - Serial(unsigned) : _comport(0x3f8) - { - init_comport(_comport, 115200); - } - - Serial(const char *s) : _comport(0x3f8) - { - init_comport(_comport, 115200); - - while (*s) - put_char(*s++); - } - }; -} - -#endif /* _SERIAL_H_ */ diff --git a/repos/base-nova/src/base/console/core_console.h b/repos/base-nova/src/base/console/core_console.h index 93acbb1e5..2b0fcf7b2 100644 --- a/repos/base-nova/src/base/console/core_console.h +++ b/repos/base-nova/src/base/console/core_console.h @@ -6,149 +6,63 @@ */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2009-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include +#pragma once + #include +/* Genode includes */ +#include -/** - * Read byte from I/O port - */ -inline Genode::uint8_t inb(Genode::uint16_t port) +namespace Genode { class Core_console; } + +class Genode::Core_console : public X86_uart_base, public Console { - Genode::uint8_t res; - asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port)); - return res; -} + private: + addr_t _port() + { + /** + * Read BDA (Bios Data Area) to obtain I/O ports of COM + * interfaces. The page must be mapped by the platform code ! + */ -/** - * Write byte to I/O port - */ -inline void outb(Genode::uint16_t port, Genode::uint8_t val) -{ - asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port)); -} + enum { + 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, + }; -/** - * Definitions of PC serial ports - */ -enum { - MAP_ADDR_BDA = 0x1000, + 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) + return *reinterpret_cast(map_bda + BDA_SERIAL_BASE_COM1); - BDA_SERIAL_BASE_COM1 = 0x400, - BDA_EQUIPMENT_WORD = 0x410, - BDA_EQUIPMENT_SERIAL_COUNT_MASK = 0x7, - BDA_EQUIPMENT_SERIAL_COUNT_SHIFT = 9, + return 0; + } - COMPORT_DATA_OFFSET = 0, - COMPORT_STATUS_OFFSET = 5, + enum { CLOCK = 0, BAUDRATE = 115200 }; - STATUS_THR_EMPTY = 0x20, /* transmitter hold register empty */ - STATUS_DHR_EMPTY = 0x40, /* data hold register empty - data completely sent */ + void _out_char(char c) + { + if (c == '\n') + put_char('\r'); + + put_char(c); + } + + public: + + Core_console() : X86_uart_base(_port(), CLOCK, BAUDRATE) {} }; - - -/** - * Initialize serial port - * - * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' - */ -static void init_comport(Genode::uint16_t port, unsigned baud) -{ - if (!port) - return; - - const unsigned - IER = port + 1, - EIR = port + 2, - LCR = port + 3, - MCR = port + 4, - LSR = port + 5, - MSR = port + 6, - DLLO = port + 0, - DLHI = port + 1; - - outb(LCR, 0x80); /* select bank 1 */ - for (volatile int i = 10000000; i--; ); - outb(DLLO, (115200/baud) >> 0); - outb(DLHI, (115200/baud) >> 8); - outb(LCR, 0x03); /* set 8,N,1 */ - outb(IER, 0x00); /* disable interrupts */ - outb(EIR, 0x07); /* enable FIFOs */ - outb(MCR, 0x0b); /* force data terminal ready */ - outb(IER, 0x01); /* enable RX interrupts */ - inb(IER); - inb(EIR); - inb(LCR); - inb(MCR); - inb(LSR); - inb(MSR); -} - - -/** - * Output character to serial port - */ -inline void serial_out_char(Genode::uint16_t comport, Genode::uint8_t c) -{ - /* wait until serial port is ready */ - Genode::uint8_t ready = STATUS_THR_EMPTY; - while ((inb(comport + COMPORT_STATUS_OFFSET) & ready) != ready); - - /* output character */ - outb(comport + COMPORT_DATA_OFFSET, c); - -} - - -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, '\r'); - serial_out_char(_comport, c); - } - - public: - - 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/repos/base/include/drivers/uart/x86_uart_base.h b/repos/base/include/drivers/uart/x86_uart_base.h new file mode 100644 index 000000000..5d9b74fd3 --- /dev/null +++ b/repos/base/include/drivers/uart/x86_uart_base.h @@ -0,0 +1,111 @@ +/* + * \brief Console backend for NOVA + * \author Norman Feske + * \author Alexander Boettcher + * \date 2009-12-28 + */ + +/* + * Copyright (C) 2009-2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#pragma once + +/* Genode includes */ +#include + +namespace Genode { class X86_uart_base; } + +class Genode::X86_uart_base +{ + private: + + uint16_t _port; + + enum { + COMPORT_DATA_OFFSET = 0, + COMPORT_STATUS_OFFSET = 5, + + STATUS_THR_EMPTY = 0x20, /* transmitter hold register empty */ + STATUS_DHR_EMPTY = 0x40, /* data hold register empty - data completely sent */ + }; + + + /** + * Read byte from I/O port + */ + uint8_t _inb(uint16_t port) + { + uint8_t res; + asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port)); + return res; + } + + + /** + * Write byte to I/O port + */ + void _outb(uint16_t port, uint8_t val) + { + asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port)); + } + + public: + + X86_uart_base(addr_t const port, unsigned const clock, + unsigned const baud_rate) + : _port(port) + { + + /** + * Initialize serial port + * + * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' + */ + + if (!port) + return; + + const unsigned + IER = port + 1, + EIR = port + 2, + LCR = port + 3, + MCR = port + 4, + LSR = port + 5, + MSR = port + 6, + DLLO = port + 0, + DLHI = port + 1; + + _outb(LCR, 0x80); /* select bank 1 */ + for (volatile int i = 10000000; i--; ); + _outb(DLLO, (115200/baud_rate) >> 0); + _outb(DLHI, (115200/baud_rate) >> 8); + _outb(LCR, 0x03); /* set 8,N,1 */ + _outb(IER, 0x00); /* disable interrupts */ + _outb(EIR, 0x07); /* enable FIFOs */ + _outb(MCR, 0x0b); /* force data terminal ready */ + _outb(IER, 0x01); /* enable RX interrupts */ + _inb(IER); + _inb(EIR); + _inb(LCR); + _inb(MCR); + _inb(LSR); + _inb(MSR); + } + + void put_char(char const c) + { + if (!_port) + return; + + /* wait until serial port is ready */ + Genode::uint8_t ready = STATUS_THR_EMPTY; + while ((_inb(_port + COMPORT_STATUS_OFFSET) & ready) != ready); + + /* output character */ + _outb(_port + COMPORT_DATA_OFFSET, c); + } +};