1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

add UART support

if CONFIG_VGA isn't defined, HermitCore use the UART device to dump
kernel messges.
This commit is contained in:
Stefan Lankes 2016-08-01 00:20:54 +02:00
parent c10ab74d67
commit 6aa60f882b
15 changed files with 791 additions and 4 deletions

View file

@ -140,6 +140,7 @@ include/hermit/config.inc: include/hermit/config.h
@awk '/^#define MAX_CORES/{ print "%define MAX_CORES", $$3 }' include/hermit/config.h >> include/hermit/config.inc
@awk '/^#define KERNEL_STACK_SIZE/{ print "%define KERNEL_STACK_SIZE", $$3 }' include/hermit/config.h >> include/hermit/config.inc
@awk '/^#define VIDEO_MEM_ADDR/{ print "%define VIDEO_MEM_ADDR", $$3 }' include/hermit/config.h >> include/hermit/config.inc
@awk '/^#define CONFIG_VGA/{ print "%define CONFIG_VGA", $$3 }' include/hermit/config.h >> include/hermit/config.inc
@awk '/^#define DYNAMIC_TICKS/{ print "%define DYNAMIC_TICKS", $$3 }' include/hermit/config.h >> include/hermit/config.inc
@awk '/^#define SAVE_FPU/{ print "%define SAVE_FPU", $$3 }' include/hermit/config.h >> include/hermit/config.inc

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014-2016, Stefan Lankes, Daniel Krebs, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_UART_H__
#define __ARCH_UART_H__
#include <hermit/stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Initialize UART output
*
* @return Returns 0 on success
*/
int uart_init(void);
/** @brief Initialize UART output without a device check
*
* @return Returns 0 on success
*/
int uart_early_init(char*);
/** @brief Simple string output on a serial device.
*
* If you want a new line you will have to "\\n".
*
* @return Length of output in bytes
*/
int uart_puts(const char *text);
/** @brief Simple character output on a serial device.
*
* @return The original input character casted to int
*/
int uart_putchar(unsigned char c);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,4 +1,4 @@
C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c pci.c vga.c
C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c pci.c vga.c uart.c
ASM_source := entry.asm string.asm
MODULE := arch_x86_kernel

View file

@ -163,6 +163,7 @@ start64:
add rax, [base]
mov QWORD [rdi+511*8], rax
%ifdef CONFIG_VGA
; map vga 1:1
mov rax, VIDEO_MEM_ADDR ; map vga
and rax, ~0xFFF ; page align lower half
@ -171,6 +172,7 @@ start64:
add rdi, boot_pgt
or rax, 0x113 ; set present, global, writable and cache disable bits
mov QWORD [rdi], rax
%endif
; remap kernel
mov rdi, kernel_start

View file

@ -0,0 +1,328 @@
/*
* Copyright (c) 2014-2016, Stefan Lankes, Daniel Krebs, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hermit/stdlib.h>
#include <hermit/stdio.h>
#include <hermit/errno.h>
#include <hermit/string.h>
#include <hermit/ctype.h>
#include <hermit/vma.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/uart.h>
#include <asm/irq.h>
#ifdef CONFIG_PCI
#include <asm/pci.h>
#endif
#ifndef CONFIG_VGA
/*
* This implementation based on following tutorial:
* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming
*/
#define UART_RX 0 /* In: Receive buffer */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_TX 0 /* Out: Transmit buffer */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_LSR 5 /* Line Status Register */
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
#define UART_FCR_TRIGGER_1 0x00 /* Trigger RDI at FIFO level 1 byte */
#define UART_FCR_TRIGGER_4 0x40 /* Trigger RDI at FIFO level 4 byte */
#define UART_FCR_TRIGGER_8 0x80 /* Trigger RDI at FIFO level 8 byte */
#define UART_FCR_TRIGGER_14 0xc0 /* Trigger RDI at FIFO level 14 byte*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
#define UART_MCR_CLKSEL 0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) */
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */
#define UART_MCR_XONANY 0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */
#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C550C/TI16C750) */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
static uint8_t mmio = 0;
static size_t iobase = 0;
static inline unsigned char read_from_uart(uint32_t off)
{
uint8_t c;
if (mmio)
c = *((const volatile unsigned char*) (iobase + off));
else
c = inportb(iobase + off);
return c;
}
static void write_to_uart(uint32_t off, unsigned char c)
{
if (mmio)
*((volatile unsigned char*) (iobase + off)) = c;
else
outportb(iobase + off, c);
}
/* Get a single character on a serial device */
static unsigned char uart_getchar(void)
{
return read_from_uart(UART_RX);
}
/* Puts a single character on a serial device */
int uart_putchar(unsigned char c)
{
if (!iobase)
return 0;
write_to_uart(UART_TX, c);
return (int) c;
}
/* Uses the routine above to output a string... */
int uart_puts(const char *text)
{
size_t i, len = strlen(text);
if (!iobase)
return 0;
for (i = 0; i < len; i++)
uart_putchar(text[i]);
return len;
}
/* Handles all UART's interrupt */
static void uart_handler(struct state *s)
{
unsigned char c = read_from_uart(UART_IIR);
while (!(c & UART_IIR_NO_INT)) {
if (c & UART_IIR_RDI) {
c = uart_getchar();
//TODO: handle input messages
goto out;
}
if(c & UART_IIR_THRI) {
// acknowledge interrupt
c = read_from_uart(UART_IIR);
goto out;
}
if(c & UART_IIR_RLSI) {
// acknowledge interrupt
c = read_from_uart(UART_LSR);
goto out;
}
out:
c = read_from_uart(UART_IIR);
}
}
static int uart_config(void)
{
/*
* enable FIFOs
* clear RX and TX FIFO
* set irq trigger to 8 bytes
*/
write_to_uart(UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_1);
/* disable interrupts */
write_to_uart(UART_IER, 0);
/* DTR + RTS */
write_to_uart(UART_MCR, UART_MCR_DTR|UART_MCR_RTS);
/*
* 8bit word length
* 1 stop bit
* no partity
* set DLAB=1
*/
char lcr = UART_LCR_WLEN8;
write_to_uart(UART_LCR, lcr);
lcr = read_from_uart(UART_LCR) | UART_LCR_DLAB;
write_to_uart(UART_LCR, lcr);
/*
* set baudrate to 115200
*/
uint32_t divisor = 1843200 / 115200;
write_to_uart(UART_DLL, divisor & 0xff);
write_to_uart(UART_DLM, (divisor >> 8) & 0xff);
/* set DLAB=0 */
write_to_uart(UART_LCR, lcr & (~UART_LCR_DLAB));
return 0;
}
extern const void kernel_start;
int uart_early_init(char* cmdline)
{
#if 1
// default value of our QEMU configuration
iobase = 0xc110;
#else
if (BUILTIN_EXPECT(!cmdline, 0))
return -EINVAL;
char* str = strstr(cmdline, "uart=");
if (!str)
return -EINVAL;
if (strncmp(str, "uart=io:", 8) == 0) {
iobase = strtol(str+8, (char **)NULL, 16);
if (!iobase)
return -EINVAL;
mmio = 0;
} else if (strncmp(str, "uart=mmio:", 10) == 0) {
iobase = strtol(str+10, (char **)NULL, 16);
if (!iobase)
return -EINVAL;
if (iobase >= PAGE_MAP_ENTRIES*PAGE_SIZE) {
/* at this point we use the boot page table
* => IO address is not mapped
* => dirty hack, map device before the kernel
*/
int err;
size_t newaddr = ((size_t) &kernel_start - PAGE_SIZE);
err = page_map_bootmap(newaddr & PAGE_MASK, iobase & PAGE_MASK, PG_GLOBAL | PG_ACCESSED | PG_DIRTY | PG_RW | PG_PCD);
if (BUILTIN_EXPECT(err, 0)) {
iobase = 0;
return err;
}
iobase = newaddr;
}
mmio = 1;
}
#endif
// configure uart
return uart_config();
}
int uart_init(void)
{
#ifdef CONFIG_PCI
pci_info_t pci_info;
uint32_t bar = 0;
// Searching for Intel's UART device
if (pci_get_device_info(0x8086, 0x0936, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's UART device
if (pci_get_device_info(0x1b36, 0x0002, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 2x UART device (pci-serial-2x)
if (pci_get_device_info(0x1b36, 0x0003, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 4x UART device (pci-serial-4x)
if (pci_get_device_info(0x1b36, 0x0004, iobase, &pci_info) == 0)
goto Lsuccess;
return -1;
Lsuccess:
iobase = pci_info.base[bar];
irq_install_handler(32+pci_info.irq, uart_handler);
if (pci_info.type[0]) {
mmio = 0;
kprintf("UART uses io address 0x%x\n", iobase);
} else {
mmio = 1;
page_map(iobase & PAGE_MASK, iobase & PAGE_MASK, 1, PG_GLOBAL | PG_ACCESSED | PG_DIRTY | PG_RW | PG_PCD);
kprintf("UART uses mmio address 0x%x\n", iobase);
vma_add(iobase, iobase + PAGE_SIZE, VMA_READ|VMA_WRITE);
}
// configure uart
return uart_config();
#else
// per default we use COM1...
if (!iobase)
iobase = 0x3F8;
mmio = 0;
if ((iobase == 0x3F8) || (iobase == 0x3E8))
irq_install_handler(32+4, uart_handler);
else if ((iobase == 0x2F8) || (iobase == 0x2E8))
irq_install_handler(32+3, uart_handler);
else
return -EINVAL;
// configure uart
return uart_config();
#endif
}
#endif

View file

@ -29,6 +29,8 @@
#include <asm/io.h>
#include <asm/vga.h>
#ifdef CONFIG_VGA
/*
* These define our textpointer, our background and foreground
* colors (attributes), and x and y cursor coordinates
@ -234,3 +236,5 @@ void vga_init(void)
// our bootloader already cleared the screen
vga_clear();
}
#endif

View file

@ -12,8 +12,9 @@ STRIP_DEBUG = --strip-debug
KEEP_DEBUG = --only-keep-debug
OUTPUT_FORMAT = -O elf32-i386
NAME = ldhermit
TTY := $(shell tty)
C_source := main.c printf.c string.c stdio.c vga.c page.c
C_source := main.c printf.c string.c stdio.c vga.c uart.c page.c
ASM_source := entry.asm
OBJS := $(C_source:.c=.o)
@ -48,10 +49,12 @@ $(NAME).elf: $(OBJS)
$Q$(OBJCOPY) $(STRIP_DEBUG) $(OUTPUT_FORMAT) $(NAME).elf
qemu:
@echo "Do you already start netcat (nc -l 4555)?"
$(QEMU) -smp 10 -m 4G -kernel $(NAME).elf -initrd ../../../usr/tests/hello \
-net nic,model=rtl8139 -net user -net dump \
-curses -monitor telnet:127.0.0.1:1235,server,nowait \
-s
-chardev socket,host=127.0.0.1,port=4555,id=gnc0 \
-device pci-serial,chardev=gnc0 \
-monitor telnet:127.0.0.1:1235,server,nowait -nographic
clean:
@echo Cleaning loader

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014-2016, Stefan Lankes, Daniel Krebs, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_UART_H__
#define __ARCH_UART_H__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Initialize UART output
*
* @return Returns 0 on success
*/
int uart_init(void);
/** @brief Initialize UART output without a device check
*
* @return Returns 0 on success
*/
int uart_early_init(char*);
/** @brief Simple string output on a serial device.
*
* If you want a new line you will have to "\\n".
*
* @return Length of output in bytes
*/
int uart_puts(const char *text);
/** @brief Simple character output on a serial device.
*
* @return The original input character casted to int
*/
int uart_putchar(unsigned char c);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -28,23 +28,33 @@
#include <string.h>
#include <multiboot.h>
#include <vga.h>
#include <uart.h>
int koutput_init(void)
{
#ifdef CONFIG_VGA
vga_init();
#else
uart_early_init((char*) mb_info->cmdline);
#endif
return 0;
}
int kputchar(int c)
{
#ifdef CONFIG_VGA
vga_putchar(c);
#else
uart_putchar(c);
#endif
return 1;
}
int kputs(const char *str)
{
#ifdef CONFIG_UART
#if 0
int i, len = strlen(str);
@ -55,4 +65,7 @@ int kputs(const char *str)
#else
return vga_puts(str);
#endif
#else // CONFIG_UART
return uart_puts(str);
#endif
}

View file

@ -0,0 +1,274 @@
/*
* Copyright (c) 2014-2016, Stefan Lankes, Daniel Krebs, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <page.h>
#include <io.h>
#include <uart.h>
#ifndef CONFIG_VGA
/*
* This implementation based on following tutorial:
* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming
*/
#define UART_RX 0 /* In: Receive buffer */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_TX 0 /* Out: Transmit buffer */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_LSR 5 /* Line Status Register */
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
#define UART_FCR_TRIGGER_1 0x00 /* Trigger RDI at FIFO level 1 byte */
#define UART_FCR_TRIGGER_4 0x40 /* Trigger RDI at FIFO level 4 byte */
#define UART_FCR_TRIGGER_8 0x80 /* Trigger RDI at FIFO level 8 byte */
#define UART_FCR_TRIGGER_14 0xc0 /* Trigger RDI at FIFO level 14 byte*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
#define UART_MCR_CLKSEL 0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) */
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */
#define UART_MCR_XONANY 0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */
#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C550C/TI16C750) */
#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
#define UART_MCR_OUT2 0x08 /* Out2 complement */
#define UART_MCR_OUT1 0x04 /* Out1 complement */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_MCR_DTR 0x01 /* DTR complement */
static uint8_t mmio = 0;
static size_t iobase = 0;
static inline unsigned char read_from_uart(uint32_t off)
{
uint8_t c;
if (mmio)
c = *((const volatile unsigned char*) (iobase + off));
else
c = inportb(iobase + off);
return c;
}
static void write_to_uart(uint32_t off, unsigned char c)
{
if (mmio)
*((volatile unsigned char*) (iobase + off)) = c;
else
outportb(iobase + off, c);
}
/* Puts a single character on a serial device */
int uart_putchar(unsigned char c)
{
if (!iobase)
return 0;
write_to_uart(UART_TX, c);
return (int) c;
}
/* Uses the routine above to output a string... */
int uart_puts(const char *text)
{
size_t i, len = strlen(text);
if (!iobase)
return 0;
for (i = 0; i < len; i++)
uart_putchar(text[i]);
return len;
}
static int uart_config(void)
{
/*
* enable FIFOs
* clear RX and TX FIFO
* set irq trigger to 8 bytes
*/
write_to_uart(UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_1);
/* disable interrupts */
write_to_uart(UART_IER, 0);
/* DTR + RTS */
write_to_uart(UART_MCR, UART_MCR_DTR|UART_MCR_RTS);
/*
* 8bit word length
* 1 stop bit
* no partity
* set DLAB=1
*/
char lcr = UART_LCR_WLEN8;
write_to_uart(UART_LCR, lcr);
lcr = read_from_uart(UART_LCR) | UART_LCR_DLAB;
write_to_uart(UART_LCR, lcr);
/*
* set baudrate to 115200
*/
uint32_t divisor = 1843200 / 115200;
write_to_uart(UART_DLL, divisor & 0xff);
write_to_uart(UART_DLM, (divisor >> 8) & 0xff);
/* set DLAB=0 */
write_to_uart(UART_LCR, lcr & (~UART_LCR_DLAB));
return 0;
}
extern const void kernel_start;
int uart_early_init(char* cmdline)
{
#if 1
// default value of our QEMU configuration
iobase = 0xc110;
#else
if (BUILTIN_EXPECT(!cmdline, 0))
return -EINVAL;
char* str = strstr(cmdline, "uart=");
if (!str)
return -EINVAL;
if (strncmp(str, "uart=io:", 8) == 0) {
iobase = strtol(str+8, (char **)NULL, 16);
if (!iobase)
return -EINVAL;
mmio = 0;
} else if (strncmp(str, "uart=mmio:", 10) == 0) {
iobase = strtol(str+10, (char **)NULL, 16);
if (!iobase)
return -EINVAL;
if (iobase >= PAGE_MAP_ENTRIES*PAGE_SIZE) {
/* at this point we use the boot page table
* => IO address is not mapped
* => dirty hack, map device before the kernel
*/
int err;
size_t newaddr = ((size_t) &kernel_start - PAGE_SIZE);
err = page_map_bootmap(newaddr & PAGE_MASK, iobase & PAGE_MASK, PG_GLOBAL | PG_ACCESSED | PG_DIRTY | PG_RW | PG_PCD);
if (BUILTIN_EXPECT(err, 0)) {
iobase = 0;
return err;
}
iobase = newaddr;
}
mmio = 1;
}
#endif
// configure uart
return uart_config();
}
int uart_init(void)
{
#ifdef CONFIG_PCI
pci_info_t pci_info;
uint32_t bar = 0;
// Searching for Intel's UART device
if (pci_get_device_info(0x8086, 0x0936, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's UART device
if (pci_get_device_info(0x1b36, 0x0002, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 2x UART device (pci-serial-2x)
if (pci_get_device_info(0x1b36, 0x0003, iobase, &pci_info) == 0)
goto Lsuccess;
// Searching for Qemu's 4x UART device (pci-serial-4x)
if (pci_get_device_info(0x1b36, 0x0004, iobase, &pci_info) == 0)
goto Lsuccess;
return -1;
Lsuccess:
iobase = pci_info.base[bar];
//irq_install_handler(32+pci_info.irq, uart_handler);
if (pci_info.type[0]) {
mmio = 0;
kprintf("UART uses io address 0x%x\n", iobase);
} else {
mmio = 1;
page_map(iobase & PAGE_MASK, iobase & PAGE_MASK, 1, PG_GLOBAL | PG_ACCESSED | PG_DIRTY | PG_RW | PG_PCD);
kprintf("UART uses mmio address 0x%x\n", iobase);
vma_add(iobase, iobase + PAGE_SIZE, VMA_READ|VMA_WRITE);
}
// configure uart
return uart_config();
#else
// per default we use COM1...
if (!iobase)
iobase = 0x3F8;
mmio = 0;
// configure uart
return uart_config();
#endif
}
#endif

View file

@ -29,6 +29,8 @@
#include <io.h>
#include <vga.h>
#ifdef CONFIG_UART
#define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */
/*
@ -235,3 +237,5 @@ void vga_init(void)
textmemptr = (unsigned short *)VIDEO_MEM_ADDR;
vga_clear();
}
#endif

View file

@ -47,6 +47,7 @@ extern "C" {
#define MAILBOX_SIZE 128
//#define WITH_PCI_IDS
//#define SAVE_FPU
//#define CONFIG_VGA
#define BYTE_ORDER LITTLE_ENDIAN

View file

@ -38,6 +38,7 @@
#include <hermit/rcce.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/uart.h>
#include <lwip/init.h>
#include <lwip/sys.h>
@ -126,6 +127,9 @@ static int hermit_init(void)
timer_init();
multitasking_init();
memory_init();
#ifndef CONFIG_VGA
uart_init();
#endif
return 0;
}

View file

@ -33,9 +33,12 @@
#include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/vga.h>
#include <asm/uart.h>
static atomic_int32_t kmsg_counter = ATOMIC_INIT(-1);
#ifdef CONFIG_VGA
static spinlock_irqsave_t vga_lock = SPINLOCK_IRQSAVE_INIT;
#endif
/* Workaround for a compiler bug. gcc 5.1 seems to ignore this array, if we
defined it as as static array. At least it is as static array not part of
@ -45,7 +48,13 @@ static spinlock_irqsave_t vga_lock = SPINLOCK_IRQSAVE_INIT;
int koutput_init(void)
{
if (is_single_kernel())
{
#ifdef CONFIG_VGA
vga_init();
#else
uart_early_init(NULL);
#endif
}
return 0;
}
@ -62,9 +71,13 @@ int kputchar(int c)
kmessages[pos % KMSG_SIZE] = (unsigned char) c;
if (is_single_kernel()) {
#ifdef CONFIG_VGA
spinlock_irqsave_lock(&vga_lock);
vga_putchar(c);
spinlock_irqsave_unlock(&vga_lock);
#else
uart_putchar(c);
#endif
}
return 1;
@ -80,9 +93,13 @@ int kputs(const char *str)
}
if (is_single_kernel()) {
#ifdef CONFIG_VGA
spinlock_irqsave_lock(&vga_lock);
vga_puts(str);
spinlock_irqsave_unlock(&vga_lock);
#else
uart_puts(str);
#endif
}
return len;

View file

@ -69,10 +69,12 @@ int vma_init(void)
if (BUILTIN_EXPECT(ret, 0))
goto out;
#ifdef CONFIG_VGA
// add VGA video memory
ret = vma_add(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR + PAGE_SIZE, VMA_READ|VMA_WRITE);
if (BUILTIN_EXPECT(ret, 0))
goto out;
#endif
out:
return ret;