summaryrefslogtreecommitdiffstats
path: root/contrib/baremetal/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/baremetal/misc.c')
-rw-r--r--contrib/baremetal/misc.c351
1 files changed, 351 insertions, 0 deletions
diff --git a/contrib/baremetal/misc.c b/contrib/baremetal/misc.c
new file mode 100644
index 00000000..924ccd6d
--- /dev/null
+++ b/contrib/baremetal/misc.c
@@ -0,0 +1,351 @@
+/**************************************************************************
+MISC Support Routines
+**************************************************************************/
+
+#include "etherboot.h"
+
+/**************************************************************************
+SLEEP
+**************************************************************************/
+void sleep(int secs)
+{
+ unsigned long tmo;
+
+ for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; )
+ /* Nothing */;
+}
+
+/**************************************************************************
+TWIDDLE
+**************************************************************************/
+void twiddle()
+{
+ static unsigned long lastticks = 0;
+ static int count=0;
+ static const char tiddles[]="-\\|/";
+ unsigned long ticks;
+ if ((ticks = currticks()) == lastticks)
+ return;
+ lastticks = ticks;
+ putchar(tiddles[(count++)&3]);
+ putchar('\b');
+}
+
+/**************************************************************************
+STRCASECMP (not entirely correct, but this will do for our purposes)
+**************************************************************************/
+int strcasecmp(a,b)
+ char *a, *b;
+{
+ while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
+ return((*a & ~0x20) - (*b & ~0x20));
+}
+
+/**************************************************************************
+PRINTF and friends
+
+ Formats:
+ %[#]X - 4 bytes long (8 hex digits)
+ %[#]x - 2 bytes int (4 hex digits)
+ - optional # prefixes 0x
+ %b - 1 byte int (2 hex digits)
+ %d - decimal int
+ %c - char
+ %s - string
+ %I - Internet address in x.x.x.x notation
+ Note: width specification not supported
+**************************************************************************/
+static char *do_printf(char *buf, const char *fmt, const int *dp)
+{
+ register char *p;
+ int alt;
+ char tmp[16];
+ static const char hex[]="0123456789ABCDEF";
+
+ while (*fmt) {
+ if (*fmt == '%') { /* switch() uses more space */
+ alt = 0;
+ fmt++;
+ if (*fmt == '#') {
+ alt = 1;
+ fmt++;
+ }
+ if (*fmt == 'X') {
+ const long *lp = (const long *)dp;
+ register long h = *lp++;
+ dp = (const int *)lp;
+ if (alt) {
+ *buf++ = '0';
+ *buf++ = 'x';
+ }
+ *(buf++) = hex[(h>>28)& 0x0F];
+ *(buf++) = hex[(h>>24)& 0x0F];
+ *(buf++) = hex[(h>>20)& 0x0F];
+ *(buf++) = hex[(h>>16)& 0x0F];
+ *(buf++) = hex[(h>>12)& 0x0F];
+ *(buf++) = hex[(h>>8)& 0x0F];
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'x') {
+ register int h = *(dp++);
+ if (alt) {
+ *buf++ = '0';
+ *buf++ = 'x';
+ }
+ *(buf++) = hex[(h>>12)& 0x0F];
+ *(buf++) = hex[(h>>8)& 0x0F];
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'b') {
+ register int h = *(dp++);
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'd') {
+ register int dec = *(dp++);
+ p = tmp;
+ if (dec < 0) {
+ *(buf++) = '-';
+ dec = -dec;
+ }
+ do {
+ *(p++) = '0' + (dec%10);
+ dec = dec/10;
+ } while(dec);
+ while ((--p) >= tmp) *(buf++) = *p;
+ }
+ if (*fmt == 'I') {
+ union {
+ long l;
+ unsigned char c[4];
+ } u;
+ const long *lp = (const long *)dp;
+ u.l = *lp++;
+ dp = (const int *)lp;
+ buf = sprintf(buf,"%d.%d.%d.%d",
+ u.c[0], u.c[1], u.c[2], u.c[3]);
+ }
+ if (*fmt == 'c')
+ *(buf++) = *(dp++);
+ if (*fmt == 's') {
+ p = (char *)*dp++;
+ while (*p) *(buf++) = *p++;
+ }
+ } else *(buf++) = *fmt;
+ fmt++;
+ }
+ *buf = '\0';
+ return(buf);
+}
+
+char *sprintf(char *buf, const char *fmt, ...)
+{
+ return do_printf(buf, fmt, ((const int *)&fmt)+1);
+}
+
+void printf(const char *fmt, ...)
+{
+ char buf[120], *p;
+
+ p = buf;
+ do_printf(buf, fmt, ((const int *)&fmt)+1);
+ while (*p) putchar(*p++);
+}
+
+#ifdef IMAGE_MENU
+/**************************************************************************
+INET_ATON - Convert an ascii x.x.x.x to binary form
+**************************************************************************/
+int inet_aton(char *p, in_addr *i)
+{
+ unsigned long ip = 0;
+ int val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = (ip << 8) | val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = (ip << 8) | val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ i->s_addr = htonl((ip << 8) | val);
+ return(1);
+}
+
+#endif /* IMAGE_MENU */
+
+int getdec(char **ptr)
+{
+ char *p = *ptr;
+ int ret=0;
+ if ((*p < '0') || (*p > '9')) return(-1);
+ while ((*p >= '0') && (*p <= '9')) {
+ ret = ret*10 + (*p - '0');
+ p++;
+ }
+ *ptr = p;
+ return(ret);
+}
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_SET_A20 0xdf /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+#define KB_UNSET_A20 0xdd /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+#ifndef IBM_L40
+static void empty_8042(void)
+{
+ unsigned long time;
+ char st;
+
+ time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
+ while ((((st = inb(K_CMD)) & K_OBUF_FUL) ||
+ (st & K_IBUF_FUL)) &&
+ currticks() < time)
+ inb(K_RDWR);
+}
+#endif IBM_L40
+
+/*
+ * Gate A20 for high memory
+ */
+void gateA20_set(void)
+{
+#ifdef IBM_L40
+ outb(0x2, 0x92);
+#else /* IBM_L40 */
+ empty_8042();
+ outb(KC_CMD_WOUT, K_CMD);
+ empty_8042();
+ outb(KB_SET_A20, K_RDWR);
+ empty_8042();
+#endif /* IBM_L40 */
+}
+
+#ifdef TAGGED_IMAGE
+/*
+ * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit
+ * ones) don't expect it to be set by the boot loader.
+ */
+void gateA20_unset(void)
+{
+#ifdef IBM_L40
+ outb(0x0, 0x92);
+#else /* IBM_L40 */
+ empty_8042();
+ outb(KC_CMD_WOUT, K_CMD);
+ empty_8042();
+ outb(KB_UNSET_A20, K_RDWR);
+ empty_8042();
+#endif /* IBM_L40 */
+}
+#endif
+
+#ifdef ETHERBOOT32
+/* Serial console is only implemented in ETHERBOOT32 for now */
+void
+putchar(int c)
+{
+#ifndef ANSIESC
+ if (c == '\n')
+ putchar('\r');
+#endif
+
+#ifdef CONSOLE_CRT
+#ifdef ANSIESC
+ handleansi(c);
+#else
+ putc(c);
+#endif
+#endif
+#ifdef CONSOLE_SERIAL
+#ifdef ANSIESC
+ if (c == '\n')
+ serial_putc('\r');
+#endif
+ serial_putc(c);
+#endif
+}
+
+/**************************************************************************
+GETCHAR - Read the next character from the console WITHOUT ECHO
+**************************************************************************/
+int
+getchar(void)
+{
+ int c = 256;
+
+#if defined CONSOLE_CRT || defined CONSOLE_SERIAL
+ do {
+#ifdef CONSOLE_CRT
+ if (ischar())
+ c = getc();
+#endif
+#ifdef CONSOLE_SERIAL
+ if (serial_ischar())
+ c = serial_getc();
+#endif
+ } while (c==256);
+ if (c == '\r')
+ c = '\n';
+#endif
+ return c;
+}
+
+int
+iskey(void)
+{
+#ifdef CONSOLE_CRT
+ if (ischar())
+ return 1;
+#endif
+#ifdef CONSOLE_SERIAL
+ if (serial_ischar())
+ return 1;
+#endif
+ return 0;
+}
+#endif /* ETHERBOOT32 */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
+#include <asm/msr.h>
+
+#define CPUCLOCK 166
+
+unsigned long currticks(void)
+{
+ register unsigned long l, h;
+ long long unsigned p;
+ long long unsigned hh,ll;
+
+ rdtsc(l, h);
+ ll = l, hh = h;
+
+ p = (ll + hh * 0x100000000LL) * 182 / (CPUCLOCK * 100000LL);
+ return (unsigned)p;
+}
+