Copy required SerialICE files (not patched yet), add receive byte function to romcc_console, add SerialICE to bootblock_simple
SerialICE revision: 107
Signed-off-by: Tadas Slotkus devtadas@gmail.com --- src/arch/x86/SerialICE/io.h | 195 ++++++++++++++++++++++++++ src/arch/x86/SerialICE/serial.c | 187 ++++++++++++++++++++++++ src/arch/x86/SerialICE/serialice.c | 257 ++++++++++++++++++++++++++++++++++ src/arch/x86/init/bootblock_simple.c | 2 + src/arch/x86/lib/romcc_console.c | 7 + 5 files changed, 648 insertions(+), 0 deletions(-) create mode 100644 src/arch/x86/SerialICE/io.h create mode 100644 src/arch/x86/SerialICE/serial.c create mode 100644 src/arch/x86/SerialICE/serialice.c
diff --git a/src/arch/x86/SerialICE/io.h b/src/arch/x86/SerialICE/io.h new file mode 100644 index 0000000..a47feef --- /dev/null +++ b/src/arch/x86/SerialICE/io.h @@ -0,0 +1,195 @@ +/* + * SerialICE + * + * Copyright (C) 2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IO_H +#define IO_H + +/* Memory functions */ + +static inline u8 read8(unsigned long addr) +{ + return *((volatile u8 *)(addr)); +} + +static inline u16 read16(unsigned long addr) +{ + return *((volatile u16 *)(addr)); +} + +static inline u32 read32(unsigned long addr) +{ + return *((volatile u32 *)(addr)); +} + +static inline void write8(unsigned long addr, u8 value) +{ + *((volatile u8 *)(addr)) = value; +} + +static inline void write16(unsigned long addr, u16 value) +{ + *((volatile u16 *)(addr)) = value; +} + +static inline void write32(unsigned long addr, u32 value) +{ + *((volatile u32 *)(addr)) = value; +} + +/* IO functions */ + +#if defined( __ROMCC__ ) && !defined (__GNUC__) +static inline void outb(u8 value, u16 port) +{ + __builtin_outb(value, port); +} + +static inline void outw(u16 value, u16 port) +{ + __builtin_outw(value, port); +} + +static inline void outl(u32 value, u16 port) +{ + __builtin_outl(value, port); +} + +static inline u8 inb(u16 port) +{ + return __builtin_inb(port); +} + +static inline u16 inw(u16 port) +{ + return __builtin_inw(port); +} + +static inline u32 inl(u16 port) +{ + return __builtin_inl(port); +} +#else +static inline void outb(u8 value, u16 port) +{ + __asm__ __volatile__("outb %b0, %w1"::"a"(value), "Nd"(port)); +} + +static inline void outw(u16 value, u16 port) +{ + __asm__ __volatile__("outw %w0, %w1"::"a"(value), "Nd"(port)); +} + +static inline void outl(u32 value, u16 port) +{ + __asm__ __volatile__("outl %0, %w1"::"a"(value), "Nd"(port)); +} + +static inline u8 inb(u16 port) +{ + u8 value; + __asm__ __volatile__("inb %w1, %b0":"=a"(value): "Nd"(port)); + return value; +} + +static inline u16 inw(u16 port) +{ + u16 value; + __asm__ __volatile__("inw %w1, %w0":"=a"(value): "Nd"(port)); + return value; +} + +static inline u32 inl(u16 port) +{ + u32 value; + __asm__ __volatile__("inl %w1, %0":"=a"(value): "Nd"(port)); + return value; +} +#endif /* __ROMCC__ && !__GNUC__ */ + +/* MSR functions */ + +typedef struct { u32 lo, hi; } msr_t; + +static inline msr_t rdmsr(u32 index, u32 key) +{ + msr_t result; + __asm__ __volatile__ ( + "rdmsr" + : "=a" (result.lo), "=d" (result.hi) + : "c" (index), "D" (key) + ); + return result; +} + +static inline void wrmsr(u32 index, msr_t msr, u32 key) +{ + __asm__ __volatile__ ( + "wrmsr" + : /* No outputs */ + : "c" (index), "a" (msr.lo), "d" (msr.hi), "D" (key) + ); +} + +/* CPUID functions */ + +static inline u32 cpuid_eax(u32 op, u32 op2) +{ + u32 eax; + + __asm__("cpuid" + : "=a" (eax) + : "a" (op), "c" (op2) + : "ebx", "edx" ); + return eax; +} + +static inline u32 cpuid_ebx(u32 op, u32 op2) +{ + u32 eax, ebx; + + __asm__("cpuid" + : "=b" (ebx) + : "a" (op), "c" (op2) + : "edx"); + return ebx; +} + +static inline u32 cpuid_ecx(u32 op, u32 op2) +{ + u32 eax, ecx; + + __asm__("cpuid" + : "=c" (ecx) + : "a" (op), "c" (op2) + : "ebx", "edx" ); + return ecx; +} + +static inline u32 cpuid_edx(u32 op, u32 op2) +{ + u32 eax, edx; + + __asm__("cpuid" + : "=d" (edx) + : "a" (op), "c" (op2) + : "ebx"); + return edx; +} + +#endif diff --git a/src/arch/x86/SerialICE/serial.c b/src/arch/x86/SerialICE/serial.c new file mode 100644 index 0000000..9aaecb6 --- /dev/null +++ b/src/arch/x86/SerialICE/serial.c @@ -0,0 +1,187 @@ +/* + * SerialICE + * + * Copyright (C) 2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Data */ +#define UART_RBR 0x00 +#define UART_TBR 0x00 + +/* Control */ +#define UART_IER 0x01 +#define UART_IIR 0x02 +#define UART_FCR 0x02 +#define UART_LCR 0x03 +#define UART_MCR 0x04 +#define UART_DLL 0x00 +#define UART_DLM 0x01 + +/* Status */ +#define UART_LSR 0x05 +#define UART_MSR 0x06 +#define UART_SCR 0x07 + +/* SIO functions */ + +static void sio_init(void) +{ + int divisor = 115200 / SIO_SPEED; + int lcs = 3; + outb(0x00, SIO_PORT + UART_IER); + outb(0x01, SIO_PORT + UART_FCR); + outb(0x03, SIO_PORT + UART_MCR); + outb(0x80 | lcs, SIO_PORT + UART_LCR); + outb(divisor & 0xff, SIO_PORT + UART_DLL); + outb((divisor >> 8) & 0xff, SIO_PORT + UART_DLM); + outb(lcs, SIO_PORT + UART_LCR); +} + +static void sio_putc(u8 data) +{ + while (!(inb(SIO_PORT + UART_LSR) & 0x20)) ; + outb(data, SIO_PORT + UART_TBR); + while (!(inb(SIO_PORT + UART_LSR) & 0x40)) ; +} + +static u8 sio_getc(void) +{ + u8 val; + while (!(inb(SIO_PORT + UART_LSR) & 0x01)) ; + + val = inb(SIO_PORT + UART_RBR); + +#if ECHO_MODE + sio_putc(val); +#endif + return val; +} + +/* SIO helpers */ + +static void sio_putstring(char *string) +{ + /* Very simple, no %d, %x etc. */ + while (*string) { + if (*string == '\n') + sio_putc('\r'); + sio_putc(*string); + string++; + } +} + +#define sio_put_nibble(nibble) \ + if (nibble > 9) \ + nibble += ('a' - 10); \ + else \ + nibble += '0'; \ + sio_putc(nibble) + +static void sio_put8(u8 data) +{ + int i; + u8 c; + + c = (data >> 4) & 0xf; + sio_put_nibble(c); + + c = data & 0xf; + sio_put_nibble(c); +} + +static void sio_put16(u16 data) +{ + int i; + for (i=12; i >= 0; i -= 4) { + u8 c = (data >> i) & 0xf; + sio_put_nibble(c); + } +} + +static void sio_put32(u32 data) +{ + int i; + for (i=28; i >= 0; i -= 4) { + u8 c = (data >> i) & 0xf; + sio_put_nibble(c); + } +} + +static u8 sio_get_nibble(void) +{ + u8 ret = 0; + u8 nibble = sio_getc(); + + if (nibble >= '0' && nibble <= '9') { + ret = (nibble - '0'); + } else if (nibble >= 'a' && nibble <= 'f') { + ret = (nibble - 'a') + 0xa; + } else if (nibble >= 'A' && nibble <= 'F') { + ret = (nibble - 'A') + 0xa; + } else { + sio_putstring("ERROR: parsing number\n"); + } + return ret; +} + +static u8 sio_get8(void) +{ + u8 data; + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + return data; +} + +static u16 sio_get16(void) +{ + u16 data; + + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + + return data; +} + +static u32 sio_get32(void) +{ + u32 data; + + data = sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + data = data << 4; + data |= sio_get_nibble(); + + return data; +} + + diff --git a/src/arch/x86/SerialICE/serialice.c b/src/arch/x86/SerialICE/serialice.c new file mode 100644 index 0000000..35531dc --- /dev/null +++ b/src/arch/x86/SerialICE/serialice.c @@ -0,0 +1,257 @@ +/* + * SerialICE + * + * Copyright (C) 2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <types.h> +#include <serialice.h> +#include <io.h> + +/* SIO functions */ +#include "serial.c" + +/* Hardware specific functions */ + +#include "chipset.c" + +/* Accessor functions */ + +static void serialice_read_memory(void) +{ + u8 width; + u32 addr; + + // Format: + // *rm00000000.w + addr = sio_get32(); + sio_getc(); // skip . + width = sio_getc(); + + sio_putc('\r'); sio_putc('\n'); + + switch (width) { + case 'b': sio_put8(read8(addr)); break; + case 'w': sio_put16(read16(addr)); break; + case 'l': sio_put32(read32(addr)); break; + } +} + +static void serialice_write_memory(void) +{ + u8 width; + u32 addr; + u32 data; + + // Format: + // *wm00000000.w=0000 + addr = sio_get32(); + sio_getc(); // skip . + width = sio_getc(); + sio_getc(); // skip = + + switch (width) { + case 'b': data = sio_get8(); write8(addr, (u8)data); break; + case 'w': data = sio_get16(); write16(addr, (u16)data); break; + case 'l': data = sio_get32(); write32(addr, (u32)data); break; + } +} + +static void serialice_read_io(void) +{ + u8 width; + u16 port; + + // Format: + // *ri0000.w + port = sio_get16(); + sio_getc(); // skip . + width = sio_getc(); + + sio_putc('\r'); sio_putc('\n'); + + switch (width) { + case 'b': sio_put8(inb(port)); break; + case 'w': sio_put16(inw(port)); break; + case 'l': sio_put32(inl(port)); break; + } +} + +static void serialice_write_io(void) +{ + u8 width; + u16 port; + u32 data; + + // Format: + // *wi0000.w=0000 + port = sio_get16(); + sio_getc(); // skip . + width = sio_getc(); + sio_getc(); // skip = + + switch (width) { + case 'b': data = sio_get8(); outb((u8)data, port); break; + case 'w': data = sio_get16(); outw((u16)data, port); break; + case 'l': data = sio_get32(); outl((u32)data, port); break; + } +} + +static void serialice_read_msr(void) +{ + u32 addr, key; + msr_t msr; + + // Format: + // *rc00000000.9c5a203a + addr = sio_get32(); + sio_getc(); // skip . + key = sio_get32(); // key in %edi + + sio_putc('\r'); sio_putc('\n'); + + msr = rdmsr(addr, key); + sio_put32(msr.hi); + sio_putc('.'); + sio_put32(msr.lo); +} + +static void serialice_write_msr(void) +{ + u32 addr, key; + msr_t msr; + + // Format: + // *wc00000000.9c5a203a=00000000.00000000 + addr = sio_get32(); + sio_getc(); // skip . + key = sio_get32(); // read key in %edi + sio_getc(); // skip = + msr.hi = sio_get32(); + sio_getc(); // skip . + msr.lo = sio_get32(); + +#ifdef __ROMCC__ + /* Cheat to avoid register outage */ + wrmsr(addr, msr, 0x9c5a203a); +#else + wrmsr(addr, msr, key); +#endif +} + +static void serialice_cpuinfo(void) +{ + u32 eax, ecx; + u32 reg32; + + // Format: + // --EAX--- --ECX--- + // *ci00000000.00000000 + eax = sio_get32(); + sio_getc(); // skip . + ecx = sio_get32(); + + sio_putc('\r'); sio_putc('\n'); + + /* This code looks quite crappy but this way we don't + * have to worry about running out of registers if we + * occupy eax, ebx, ecx, edx at the same time + */ + reg32 = cpuid_eax(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_ebx(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_ecx(eax, ecx); + sio_put32(reg32); + sio_putc('.'); + + reg32 = cpuid_edx(eax, ecx); + sio_put32(reg32); +} + +static void serialice_mainboard(void) +{ + sio_putc('\r'); sio_putc('\n'); + + /* must be defined in mainboard/<boardname>.c */ + sio_putstring(boardname); +} + +static void serialice_version(void) +{ + sio_putstring("\nSerialICE v" VERSION " (" __DATE__ ")\n"); +} + +int main(void) +{ + chipset_init(); + + sio_init(); + + serialice_version(); + + while(1) { + u16 c; + sio_putstring("\n> "); + + c = sio_getc(); + if (c != '*') + continue; + + c = sio_getc() << 8; + c |= sio_getc(); + + switch(c) { + case (('r' << 8)|'m'): // Read Memory *rm + serialice_read_memory(); + break; + case (('w' << 8)|'m'): // Write Memory *wm + serialice_write_memory(); + break; + case (('r' << 8)|'i'): // Read IO *ri + serialice_read_io(); + break; + case (('w' << 8)|'i'): // Write IO *wi + serialice_write_io(); + break; + case (('r' << 8)|'c'): // Read CPU MSR *rc + serialice_read_msr(); + break; + case (('w' << 8)|'c'): // Write CPU MSR *wc + serialice_write_msr(); + break; + case (('c' << 8)|'i'): // Read CPUID *ci + serialice_cpuinfo(); + break; + case (('m' << 8)|'b'): // Read mainboard type *mb + serialice_mainboard(); + break; + case (('v' << 8)|'i'): // Read version info *vi + serialice_version(); + break; + default: + sio_putstring("ERROR\n"); + break; + } + } + + // Never get here: + return 0; +} diff --git a/src/arch/x86/init/bootblock_simple.c b/src/arch/x86/init/bootblock_simple.c index 5d7c611..8386868 100644 --- a/src/arch/x86/init/bootblock_simple.c +++ b/src/arch/x86/init/bootblock_simple.c @@ -1,4 +1,5 @@ #include <bootblock_common.h> +#include "../SerialICE/serialice.c"
static void main(unsigned long bist) { @@ -12,6 +13,7 @@ static void main(unsigned long bist) sanitize_cmos(); #endif
+ serialice_main(); const char* target1 = "fallback/romstage"; unsigned long entry; entry = findstage(target1); diff --git a/src/arch/x86/lib/romcc_console.c b/src/arch/x86/lib/romcc_console.c index 13ee1f0..3747136 100644 --- a/src/arch/x86/lib/romcc_console.c +++ b/src/arch/x86/lib/romcc_console.c @@ -48,6 +48,13 @@ static void __console_tx_byte(unsigned char byte) #endif }
+static unsigned char __console_rx_byte(void) +{ +#if CONFIG_CONSOLE_SERIAL8250 + return uart8250_rx_byte(CONFIG_TTYS0_BASE); +#endif +} + static void __console_tx_nibble(unsigned nibble) { unsigned char digit;