diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2017-12-31 18:47:16 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2017-12-31 18:47:25 +0100 |
commit | 3a96085b999220c4da0c5ef7d1f7ba26b9ddfb98 (patch) | |
tree | 77f1445aae2e6be5135594e95986b3278bbc061c /package/aboot/src/cons.c | |
parent | cc28479164b8dc8afd4310716da32f16022f5974 (diff) |
dec-multia: make netboot possible, add aboot bootloader
Diffstat (limited to 'package/aboot/src/cons.c')
-rw-r--r-- | package/aboot/src/cons.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/package/aboot/src/cons.c b/package/aboot/src/cons.c new file mode 100644 index 000000000..3de796b3a --- /dev/null +++ b/package/aboot/src/cons.c @@ -0,0 +1,190 @@ +#include <alloca.h> + +#include <linux/kernel.h> + +#include <asm/console.h> +#include "hwrpb.h" +#include "system.h" + +#include "aboot.h" +#include "cons.h" +#include "utils.h" +#include "string.h" + +#ifndef CCB_OPEN_CONSOLE /* new callback w/ ARM v4 */ +# define CCB_OPEN_CONSOLE 0x07 +#endif + +#ifndef CCB_CLOSE_CONSOLE /* new callback w/ ARM v4 */ +# define CCB_CLOSE_CONSOLE 0x08 +#endif + +long cons_dev; /* console device */ + +long +cons_puts(const char *str, long len) +{ + long remaining, written; + union ccb_stsdef { + long int l_sts; + struct { + int written; + unsigned discard : 29; + unsigned v_sts0 : 1; + unsigned v_sts1 : 1; + unsigned v_err : 1; + } s; + } ccb_sts; + + for (remaining = len; remaining; remaining -= written) { + ccb_sts.l_sts = dispatch(CCB_PUTS, cons_dev, str, remaining); + if (!ccb_sts.s.v_err) { + written = ccb_sts.s.written; + str += written; + } else { + if (ccb_sts.s.v_sts1) + halt(); /* This is a hard error */ + written = 0; + } + } + return len; +} + +void +cons_putchar(char c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = 0; + cons_puts(buf,1); +} + +int +cons_getchar(void) +{ + long c; + + while ((c = dispatch(CCB_GETC, cons_dev)) < 0) + ; + return c; +} + + +long +cons_getenv(long index, char *envval, long maxlen) +{ + /* + * This may seem silly, but some SRM implementations have + * problems returning values to buffers that are not 8 byte + * aligned. We work around this by always using a buffer + * allocated on the stack (which guaranteed to by 8 byte + * aligned). + */ + char * tmp = alloca(maxlen); + long len; + + len = dispatch(CCB_GET_ENV, index, tmp, maxlen - 1); + if (len >= 0) { + memcpy(envval, tmp, len); + envval[len] = '\0'; + } + return len; +} + + +long +cons_open(const char *devname) +{ + return dispatch(CCB_OPEN, devname, strlen(devname)); +} + + +long +cons_close(long dev) +{ + return dispatch(CCB_CLOSE, dev); +} + + +long +cons_read(long dev, void *buf, long count, long offset) +{ + static char readbuf[SECT_SIZE]; /* minimize frame size */ + + if ((count & (SECT_SIZE-1)) == 0 && (offset & (SECT_SIZE-1)) == 0) { + /* I/O is aligned... this is easy! */ + return dispatch(CCB_READ, dev, count, buf, + offset / SECT_SIZE); + } else { + long bytesleft, iocount, blockoffset, iosize, lbn, retval; + + bytesleft = count; + iocount = 0; + blockoffset = offset % SECT_SIZE; + lbn = offset / SECT_SIZE; + + while (bytesleft > 0) { + if ((blockoffset == 0) && (bytesleft >= SECT_SIZE)) { + /* + * This portion of the I/O is aligned, + * so read it straight in: + */ + iosize = SECT_SIZE; + retval = dispatch(CCB_READ, dev, iosize, buf, + lbn); + if (retval != iosize) { + printf("read error 0x%lx\n",retval); + return -1; + } + } else { + /* + * Not aligned; must read it into a + * temporary buffer and go from there. + */ + retval = dispatch(CCB_READ, dev, SECT_SIZE, + readbuf, lbn); + if (retval != SECT_SIZE) { + printf("read error, lbn %ld: 0x%lx\n", + lbn, retval); + return -1; + } + iosize = bytesleft; + if (blockoffset + iosize >= SECT_SIZE) { + iosize = SECT_SIZE - blockoffset; + } + memcpy(buf, readbuf + blockoffset, iosize); + } + buf += iosize; + iocount += iosize; + bytesleft -= iosize; + blockoffset = 0; + ++lbn; + } + return iocount; + } +} + + +void cons_open_console(void) +{ + dispatch(CCB_OPEN_CONSOLE); +} + +void cons_close_console(void) +{ + dispatch(CCB_CLOSE_CONSOLE); +} + +void +cons_init(void) +{ + char envval[256]; + + if (cons_getenv(ENV_TTY_DEV, envval, sizeof(envval)) < 0) { + halt(); /* better than random crash */ + } + cons_dev = simple_strtoul(envval, 0, 10); + + cons_open_console(); +} |