Rudolf Marek (r.marek@assembler.cz) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1096
-gerrit
commit 2eea3421b95a5b1127805ac623ea5a16cfae2e83 Author: Rudolf Marek r.marek@assembler.cz Date: Tue Jun 5 00:29:45 2012 +0200
Hack in the target part of serialICE this needs to be done in more sane way.
Just some quick and dirty way of using real serialICE.
Change-Id: I4b39eba9526bdd21e99044bc5f67106176d26e2b Signed-off-by: Rudolf Marek r.marek@assembler.cz --- src/arch/x86/lib/cbfs_and_run.c | 5 +- src/lib/Makefile.inc | 1 + src/lib/serialice/serial.c | 196 ++++++++++++++++++++++++++++++ src/lib/serialice/serialice.c | 256 +++++++++++++++++++++++++++++++++++++++ src/lib/serialice/serialice.h | 31 +++++ 5 files changed, 487 insertions(+), 2 deletions(-)
diff --git a/src/arch/x86/lib/cbfs_and_run.c b/src/arch/x86/lib/cbfs_and_run.c index 62b2789..a63e50d 100644 --- a/src/arch/x86/lib/cbfs_and_run.c +++ b/src/arch/x86/lib/cbfs_and_run.c @@ -25,7 +25,6 @@ static void cbfs_and_run_core(const char *filename, unsigned ebp) { u8 *dst; - timestamp_add_now(TS_START_COPYRAM); print_debug("Loading image.\n"); dst = cbfs_load_stage(filename); @@ -40,13 +39,15 @@ static void cbfs_and_run_core(const char *filename, unsigned ebp) :: "a"(ebp), "D"(dst) ); } - +void serialice_main(void); void __attribute__((regparm(0))) copy_and_run(unsigned cpu_reset) { // FIXME fix input parameters instead normalizing them here. if (cpu_reset == 1) cpu_reset = -1; else cpu_reset = 0;
+ serialice_main(); + cbfs_and_run_core(CONFIG_CBFS_PREFIX "/coreboot_ram", cpu_reset); }
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 3bd7f99..e6ae8b6 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -21,6 +21,7 @@ romstage-$(CONFIG_USBDEBUG) += usbdebug.c romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c romstage-y += compute_ip_checksum.c romstage-y += memmove.c +romstage-y += serialice/serialice.c
ifneq ($(CONFIG_HAVE_ARCH_MEMSET),y) ramstage-y += memset.c diff --git a/src/lib/serialice/serial.c b/src/lib/serialice/serial.c new file mode 100644 index 0000000..529009c --- /dev/null +++ b/src/lib/serialice/serial.c @@ -0,0 +1,196 @@ +/* + * 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) +{ +#if SIO_SPEED > 115200 + /* "high speed" serial requires special chip setup + * (to be done in superio_init), and special divisor + * values (implement superio_serial_divisor() for that). + * Maybe it requires even more, but so far that seems + * to be enough. + */ + int divisor = superio_serial_divisor(SIO_SPEED); +#else + int divisor = 115200 / SIO_SPEED; +#endif + 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(const 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) +{ + 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/lib/serialice/serialice.c b/src/lib/serialice/serialice.c new file mode 100644 index 0000000..0a5a8e0 --- /dev/null +++ b/src/lib/serialice/serialice.c @@ -0,0 +1,256 @@ +/* + * 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 "serialice.h" +#include <arch/io.h> +#include <cpu/x86/msr.h> +#include <arch/cpu.h> + +const char boardname[33]="infinite improbability board "; + + +/* Hardware specific functions */ + +/* SIO functions */ +#include "serial.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); + 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); +#endif +} + +static void serialice_cpuinfo(void) +{ + u32 eax, ecx; + u32 reg32 = 0xdeadbeef; + + // 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"); +} +void serialice_main(void); + +void serialice_main(void) +{ + 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: +} diff --git a/src/lib/serialice/serialice.h b/src/lib/serialice/serialice.h new file mode 100644 index 0000000..1d01849 --- /dev/null +++ b/src/lib/serialice/serialice.h @@ -0,0 +1,31 @@ +/* + * 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 SERIALICE_H +#define SERIALICE_H + +#include "config.h" + +#define ECHO_MODE 1 + +#define VERSION "42" +#define SIO_SPEED 115200 +#define SIO_PORT 0x3f8 + +#endif