blob: 478a9917612806a98c23d67ea0982fd7caf3d247 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* lib.c - MemTest-86 Version 3.4
2 *
3 * Released under version 2 of the Gnu Public License.
4 * By Chris Brady
5 */
6#include "io.h"
7#include "serial.h"
8#include "test.h"
9#include "config.h"
10#include "screen_buffer.h"
11#include "stdint.h"
12#include "cpuid.h"
13#include "smp.h"
14
15
16int slock = 0, lsr = 0;
17short serial_cons = SERIAL_CONSOLE_DEFAULT;
Martin Roth26b11612016-03-03 19:40:34 -070018#if SERIAL_TTY > 3
19#error Bad SERIAL_TTY. Only ttyS0 thru ttyS3 are supported.
Martin Roth9b1b3352016-02-24 12:27:06 -080020#endif
21short serial_tty = SERIAL_TTY;
Martin Roth26b11612016-03-03 19:40:34 -070022const short serial_base_ports[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
Martin Roth9b1b3352016-02-24 12:27:06 -080023
24#if ((115200%SERIAL_BAUD_RATE) != 0)
25#error Bad default baud rate
26#endif
27int serial_baud_rate = SERIAL_BAUD_RATE;
28unsigned char serial_parity = 0;
29unsigned char serial_bits = 8;
30
31struct ascii_map_str {
32 int ascii;
33 int keycode;
34};
35
36inline void reboot(void)
37{
Martin Roth4dcd13d2016-02-24 13:53:07 -080038
Martin Roth9b1b3352016-02-24 12:27:06 -080039 /* tell the BIOS to do a cold start */
40 *((unsigned short *)0x472) = 0x0;
Martin Roth4dcd13d2016-02-24 13:53:07 -080041
Martin Roth9b1b3352016-02-24 12:27:06 -080042 while(1)
43 {
44 outb(0xFE, 0x64);
45 outb(0x02, 0xcf9); /* reset that doesn't rely on the keyboard controller */
46 outb(0x04, 0xcf9);
47 outb(0x0E, 0xcf9);
48 }
49}
50
Ben Gardner3754fd42016-04-29 09:21:36 -050051int strlen(const char *string)
52{
53 int i = 0;
54
55 while (*string++)
56 i++;
Martin Roth9b1b3352016-02-24 12:27:06 -080057 return i;
58}
59
Ben Gardner3754fd42016-04-29 09:21:36 -050060int strstr(const char *haystack, const char *needle)
Martin Roth9b1b3352016-02-24 12:27:06 -080061{
Ben Gardner3754fd42016-04-29 09:21:36 -050062 int haystack_len = strlen(haystack);
63 int needle_len = strlen(needle);
64 int max_idx = haystack_len - needle_len;
65 int idx;
66
67 for (idx = 0; idx <= max_idx; idx++) {
68 if (memcmp(haystack + idx, needle, needle_len) == 0)
69 return idx;
Martin Roth9b1b3352016-02-24 12:27:06 -080070 }
Ben Gardner3754fd42016-04-29 09:21:36 -050071 return -1;
Martin Roth9b1b3352016-02-24 12:27:06 -080072}
73
74int memcmp(const void *s1, const void *s2, ulong count)
75{
76 const unsigned char *src1 = s1, *src2 = s2;
77 int i;
78 for(i = 0; i < count; i++) {
79 if (src1[i] != src2[i]) {
80 return (int)src1[i] - (int)src2[i];
81 }
82 }
83 return 0;
84}
85
86int strncmp(const char *s1, const char *s2, ulong n) {
87 signed char res = 0;
88 while (n) {
89 res = *s1 - *s2;
90 if (res != 0)
91 return res;
92 if (*s1 == '\0')
93 return 0;
94 ++s1, ++s2;
95 --n;
96 }
97 return res;
98}
99
100void *memmove(void *dest, const void *src, ulong n)
101{
102 long i;
103 char *d = (char *)dest, *s = (char *)src;
104
105 /* If src == dest do nothing */
106 if (dest < src) {
107 for(i = 0; i < n; i++) {
108 d[i] = s[i];
109 }
110 }
111 else if (dest > src) {
112 for(i = n -1; i >= 0; i--) {
113 d[i] = s[i];
114 }
115 }
116 return dest;
117}
118
119char toupper(char c)
120{
121 if (c >= 'a' && c <= 'z')
122 return c + 'A' -'a';
123 else
124 return c;
125}
126
127int isdigit(char c)
128{
129 return c >= '0' && c <= '9';
130}
131
132int isxdigit(char c)
133{
134 return isdigit(c) || (toupper(c) >= 'A' && toupper(c) <= 'F'); }
135
136unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) {
137 unsigned long result = 0, value;
138
139 if (!base) {
140 base = 10;
141 if (*cp == '0') {
142 base = 8;
143 cp++;
144 if (toupper(*cp) == 'X' && isxdigit(cp[1])) {
145 cp++;
146 base = 16;
147 }
148 }
149 } else if (base == 16) {
150 if (cp[0] == '0' && toupper(cp[1]) == 'X')
151 cp += 2;
152 }
153 while (isxdigit(*cp) &&
154 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
155 result = result*base + value;
156 cp++;
157 }
158 if (endp)
159 *endp = (char *)cp;
160 return result;
161}
162
163/*
164 * Scroll the error message area of the screen as needed
165 * Starts at line LINE_SCROLL and ends at line 23
166 */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800167void scroll(void)
Martin Roth9b1b3352016-02-24 12:27:06 -0800168{
169 int i, j;
170 char *s, tmp;
171
172 /* Only scroll if at the bottom of the screen */
173 if (v->msg_line < 23) {
174 v->msg_line++;
175 } else {
176 /* If scroll lock is on, loop till it is cleared */
177 while (slock) {
178 check_input();
179 }
180 for (i=LINE_SCROLL; i<23; i++) {
181 s = (char *)(SCREEN_ADR + ((i+1) * 160));
182 for (j=0; j<160; j+=2, s+=2) {
183 *(s-160) = *s;
184 tmp = get_scrn_buf(i+1, j/2);
185 set_scrn_buf(i, j/2, tmp);
186 }
187 }
188 /* Clear the newly opened line */
189 s = (char *)(SCREEN_ADR + (23 * 160));
190 for (j=0; j<80; j++) {
191 *s = ' ';
192 set_scrn_buf(23, j, ' ');
193 s += 2;
194 }
195 tty_print_region(LINE_SCROLL, 0, 23, 79);
196 }
197}
198
199/*
200 * Clear scroll region
201 */
202void clear_scroll(void)
203{
204 int i;
205 char *s;
206
207 s = (char*)(SCREEN_ADR+LINE_HEADER*160);
208 for(i=0; i<80*(24-LINE_HEADER); i++) {
209 *s++ = ' ';
210 *s++ = 0x17;
211 }
212}
213
214/*
215 * Place a single character on screen
216 */
217void cplace(int y, int x, const char c)
218{
219 char *dptr;
220
221 dptr = (char *)(SCREEN_ADR + (160*y) + (2*x));
222 *dptr = c;
223}
224
225/*
226 * Print characters on screen
227 */
228void cprint(int y, int x, const char *text)
229{
230 register int i;
231 char *dptr;
232
233 dptr = (char *)(SCREEN_ADR + (160*y) + (2*x));
234 for (i=0; text[i]; i++) {
235 *dptr = text[i];
236 dptr += 2;
237 }
238 tty_print_line(y, x, text);
239}
240
Martin Roth4dcd13d2016-02-24 13:53:07 -0800241void itoa(char s[], int n)
Martin Roth9b1b3352016-02-24 12:27:06 -0800242{
243 int i, sign;
244
245 if((sign = n) < 0)
246 n = -n;
247 i=0;
248 do {
249 s[i++] = n % 10 + '0';
250 } while ((n /= 10) > 0);
251 if(sign < 0)
252 s[i++] = '-';
253 s[i] = '\0';
254 reverse(s);
255}
256
257void reverse(char s[])
258{
259 int c, i, j;
260 for(j = 0; s[j] != 0; j++)
261 ;
262
263 for(i=0, j = j - 1; i < j; i++, j--) {
264 c = s[i];
265 s[i] = s[j];
266 s[j] = c;
267 }
268}
269void memcpy (void *dst, void *src, int len)
270{
271 char *s = (char*)src;
272 char *d = (char*)dst;
273 int i;
274
275 if (len <= 0) {
276 return;
277 }
278 for (i = 0 ; i < len; i++) {
279 *d++ = *s++;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800280 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800281}
282
283/*
284 * Print a people friendly address
285 */
286void aprint(int y, int x, ulong page)
287{
288 /* page is in multiples of 4K */
289 if ((page << 2) < 9999) {
290 dprint(y, x, page << 2, 4, 0);
291 cprint(y, x+4, "K");
292 }
293 else if ((page >>8) < 9999) {
294 dprint(y, x, (page + (1 << 7)) >> 8, 4, 0);
295 cprint(y, x+4, "M");
296 }
297 else if ((page >>18) < 9999) {
298 dprint(y, x, (page + (1 << 17)) >> 18, 4, 0);
299 cprint(y, x+4, "G");
300 }
301 else {
302 dprint(y, x, (page + (1 << 27)) >> 28, 4, 0);
303 cprint(y, x+4, "T");
304 }
305}
306
307/*
308 * Print a decimal number on screen
309 */
310void dprint(int y, int x, ulong val, int len, int right)
311{
312 ulong j, k;
313 int i, flag=0;
314 char buf[18];
315
316 if (val > 999999999 || len > 9) {
317 return;
318 }
319 for(i=0, j=1; i<len-1; i++) {
320 j *= 10;
321 }
322 if (!right) {
323 for (i=0; j>0; j/=10) {
324 k = val/j;
325 if (k > 9) {
326 j *= 100;
327 continue;
328 }
329 if (flag || k || j == 1) {
330 buf[i++] = k + '0';
331 flag++;
332 } else {
333 buf[i++] = ' ';
334 }
335 val -= k * j;
336 }
337 } else {
338 for(i=0; i<len; j/=10) {
339 if (j) {
340 k = val/j;
341 if (k > 9) {
342 j *= 100;
343 len++;
344 continue;
345 }
346 if (k == 0 && flag == 0) {
Martin Roth4dcd13d2016-02-24 13:53:07 -0800347 continue;
Martin Roth9b1b3352016-02-24 12:27:06 -0800348 }
349 buf[i++] = k + '0';
350 val -= k * j;
351 } else {
352 if (flag == 0 && i < len-1) {
353 buf[i++] = '0';
354 } else {
355 buf[i++] = ' ';
356 }
357 }
358 flag++;
359 }
360 }
361 buf[i] = 0;
362 cprint(y,x,buf);
363}
364
365/*
366 * Print a hex number on screen at least digits long
367 */
368void hprint2(int y,int x, unsigned long val, int digits)
369{
370 unsigned long j;
371 int i, idx, flag = 0;
372 char buf[18];
373
374 for (i=0, idx=0; i<8; i++) {
375 j = val >> (28 - (4 * i));
376 j &= 0xf;
377 if (j < 10) {
378 if (flag || j || i == 7) {
379 buf[idx++] = j + '0';
380 flag++;
381 } else {
382 buf[idx++] = '0';
383 }
384 } else {
385 buf[idx++] = j + 'a' - 10;
386 flag++;
387 }
388 }
389 if (digits > 8) {
390 digits = 8;
391 }
392 if (flag > digits) {
393 digits = flag;
394 }
395 buf[idx] = 0;
396 cprint(y,x,buf + (idx - digits));
397}
398
399/*
400 * Print a hex number on screen exactly digits long
401 */
402void hprint3(int y,int x, unsigned long val, int digits)
403{
404 unsigned long j;
405 int i, idx, flag = 0;
406 char buf[18];
407
408 for (i=0, idx=0; i<digits; i++) {
409 j = 0xf & val;
410 val /= 16;
411
412 if (j < 10) {
413 if (flag || j || i == 7) {
414 buf[digits - ++idx] = j + '0';
415 flag++;
416 } else {
417 buf[digits - ++idx] = '0';
418 }
419 } else {
420 buf[digits - ++idx] = j + 'a' - 10;
421 flag++;
422 }
423 }
424 buf[idx] = 0;
425 cprint(y,x,buf);
426}
427
428/*
429 * Print a hex number on screen
430 */
431void hprint(int y, int x, unsigned long val)
432{
433 return hprint2(y, x, val, 8);
434}
435
436/*
437 * Print an address in 0000m0000k0000 notation
438 */
439void xprint(int y,int x, ulong val)
440{
441 ulong j;
442
443 j = (val & 0xffc00000) >> 20;
444 dprint(y, x, j, 4, 0);
445 cprint(y, x+4, "m");
446 j = (val & 0xffc00) >> 10;
447 dprint(y, x+5, j, 4, 0);
448 cprint(y, x+9, "k");
449 j = val & 0x3ff;
450 dprint(y, x+10, j, 4, 0);
451}
452
453char *codes[] = {
454 " Divide",
455 " Debug",
456 " NMI",
457 " Brkpnt",
458 "Overflow",
459 " Bound",
460 " Inv_Op",
461 " No_Math",
462 "Double_Fault",
463 "Seg_Over",
464 " Inv_TSS",
465 " Seg_NP",
466 "Stack_Fault",
467 "Gen_Prot",
468 "Page_Fault",
469 " Resvd",
470 " FPE",
471 "Alignment",
472 " Mch_Chk",
473 "SIMD FPE"
474};
475
476struct eregs {
477 ulong ss;
478 ulong ds;
479 ulong esp;
480 ulong ebp;
481 ulong esi;
482 ulong edi;
483 ulong edx;
484 ulong ecx;
485 ulong ebx;
486 ulong eax;
487 ulong vect;
488 ulong code;
489 ulong eip;
490 ulong cs;
491 ulong eflag;
492};
Martin Roth4dcd13d2016-02-24 13:53:07 -0800493
Martin Roth9b1b3352016-02-24 12:27:06 -0800494/* Handle an interrupt */
495void inter(struct eregs *trap_regs)
496{
497 int i, line;
498 unsigned char *pp;
499 ulong address = 0;
500 int my_cpu_num = smp_my_cpu_num();
501
502 /* Get the page fault address */
503 if (trap_regs->vect == 14) {
504 __asm__("movl %%cr2,%0":"=r" (address));
505 }
506#ifdef PARITY_MEM
507
508 /* Check for a parity error */
509 if (trap_regs->vect == 2) {
510 parity_err(trap_regs->edi, trap_regs->esi);
511 return;
512 }
513#endif
514
515 /* clear scrolling region */
516 pp=(unsigned char *)(SCREEN_ADR+(2*80*(LINE_SCROLL-2)));
517 for(i=0; i<2*80*(24-LINE_SCROLL-2); i++, pp+=2) {
518 *pp = ' ';
519 }
520 line = LINE_SCROLL-2;
521
522 cprint(line, 0, "Unexpected Interrupt - Halting CPU");
523 dprint(line, COL_MID + 4, my_cpu_num, 2, 1);
524 cprint(line+2, 0, " Type: ");
525 if (trap_regs->vect <= 19) {
526 cprint(line+2, 7, codes[trap_regs->vect]);
527 } else {
528 hprint(line+2, 7, trap_regs->vect);
529 }
530 cprint(line+3, 0, " PC: ");
531 hprint(line+3, 7, trap_regs->eip);
532 cprint(line+4, 0, " CS: ");
533 hprint(line+4, 7, trap_regs->cs);
534 cprint(line+5, 0, "Eflag: ");
535 hprint(line+5, 7, trap_regs->eflag);
536 cprint(line+6, 0, " Code: ");
537 hprint(line+6, 7, trap_regs->code);
538 cprint(line+7, 0, " DS: ");
539 hprint(line+7, 7, trap_regs->ds);
540 cprint(line+8, 0, " SS: ");
541 hprint(line+8, 7, trap_regs->ss);
542 if (trap_regs->vect == 14) {
543 /* Page fault address */
544 cprint(line+7, 0, " Addr: ");
545 hprint(line+7, 7, address);
546 }
547
548 cprint(line+2, 20, "eax: ");
549 hprint(line+2, 25, trap_regs->eax);
550 cprint(line+3, 20, "ebx: ");
551 hprint(line+3, 25, trap_regs->ebx);
552 cprint(line+4, 20, "ecx: ");
553 hprint(line+4, 25, trap_regs->ecx);
554 cprint(line+5, 20, "edx: ");
555 hprint(line+5, 25, trap_regs->edx);
556 cprint(line+6, 20, "edi: ");
557 hprint(line+6, 25, trap_regs->edi);
558 cprint(line+7, 20, "esi: ");
559 hprint(line+7, 25, trap_regs->esi);
560 cprint(line+8, 20, "ebp: ");
561 hprint(line+8, 25, trap_regs->ebp);
562 cprint(line+9, 20, "esp: ");
563 hprint(line+9, 25, trap_regs->esp);
564
565 cprint(line+1, 38, "Stack:");
566 for (i=0; i<10; i++) {
567 hprint(line+2+i, 38, trap_regs->esp+(4*i));
568 hprint(line+2+i, 47, *(ulong*)(trap_regs->esp+(4*i)));
569 hprint(line+2+i, 57, trap_regs->esp+(4*(i+10)));
570 hprint(line+2+i, 66, *(ulong*)(trap_regs->esp+(4*(i+10))));
571 }
572
573 cprint(line+11, 0, "CS:EIP: ");
574 pp = (unsigned char *)trap_regs->eip;
575 for(i = 0; i < 9; i++) {
576 hprint2(line+11, 8+(3*i), pp[i], 2);
577 }
578
579 while(1) {
580 check_input();
581 }
582}
583
Martin Roth4dcd13d2016-02-24 13:53:07 -0800584void set_cache(int val)
Martin Roth9b1b3352016-02-24 12:27:06 -0800585{
586 switch(val) {
587 case 0:
Martin Roth4dcd13d2016-02-24 13:53:07 -0800588 cache_off();
Martin Roth9b1b3352016-02-24 12:27:06 -0800589 break;
590 case 1:
591 cache_on();
592 break;
593 }
594}
595
Martin Roth69593432016-03-27 19:46:03 -0600596int get_key(void) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800597 int c;
598
599 c = inb(0x64);
Martin Roth17128ac2016-03-03 19:45:49 -0700600 if ((c & 1) && (c != 0xff)) {
601 return inb(0x60);
602 } else if (serial_cons) {
603 int comstat;
604 comstat = serial_echo_inb(UART_LSR);
605 if (comstat & UART_LSR_DR) {
606 c = serial_echo_inb(UART_RX);
607 /* Pressing '.' has same effect as 'c'
608 on a keyboard.
609 Oct 056 Dec 46 Hex 2E Ascii .
610 */
611 return (ascii_to_keycode(c));
Martin Roth9b1b3352016-02-24 12:27:06 -0800612 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800613 }
Martin Roth17128ac2016-03-03 19:45:49 -0700614 return(0);
Martin Roth9b1b3352016-02-24 12:27:06 -0800615}
616
617void check_input(void)
618{
619 unsigned char c;
620
621 if ((c = get_key())) {
622 switch(c & 0x7f) {
Martin Roth4dcd13d2016-02-24 13:53:07 -0800623 case 1:
Martin Roth9b1b3352016-02-24 12:27:06 -0800624 /* "ESC" key was pressed, bail out. */
625 cprint(LINE_RANGE, COL_MID+23, "Halting... ");
626 reboot();
627 break;
628 case 46:
629 /* c - Configure */
630 get_config();
631 break;
632 case 28:
633 /* CR - clear scroll lock */
634 slock = 0;
635 footer();
636 break;
637 case 57:
638 /* SP - set scroll lock */
639 slock = 1;
640 footer();
641 break;
642 case 0x26:
643 /* ^L/L - redraw the display */
Michał Żygowski485c4fd2018-01-04 09:35:14 +0100644 if (serial_cons) {
645 tty_print_screen();
646 } else {
647 clear_screen_buf();
648 tty_print_region(0, 0, 80, 100);
649 }
Martin Roth9b1b3352016-02-24 12:27:06 -0800650 break;
651 }
652 }
653}
654
Martin Roth69593432016-03-27 19:46:03 -0600655void footer(void)
Martin Roth9b1b3352016-02-24 12:27:06 -0800656{
657 cprint(24, 0, "(ESC)exit (c)configuration (SP)scroll_lock (CR)scroll_unlock");
658 if (slock) {
659 cprint(24, 74, "Locked");
660 } else {
661 cprint(24, 74, " ");
662 }
663}
664
665ulong getval(int x, int y, int result_shift)
666{
667 unsigned long val;
668 int done;
669 int c;
670 int i, n;
671 int base;
672 int shift;
673 char buf[16];
674
675 for(i = 0; i < sizeof(buf)/sizeof(buf[0]); i++ ) {
676 buf[i] = ' ';
677 }
678 buf[sizeof(buf)/sizeof(buf[0]) -1] = '\0';
Martin Roth4dcd13d2016-02-24 13:53:07 -0800679
Martin Roth9b1b3352016-02-24 12:27:06 -0800680 wait_keyup();
681 done = 0;
682 n = 0;
683 base = 10;
684 while(!done) {
685 /* Read a new character and process it */
686 c = get_key();
687 switch(c) {
688 case 0x26: /* ^L/L - redraw the display */
689 tty_print_screen();
690 break;
691 case 0x1c: /* CR */
692 /* If something has been entered we are done */
693 if(n) done = 1;
694 break;
695 case 0x19: /* p */ buf[n] = 'p'; break;
696 case 0x22: /* g */ buf[n] = 'g'; break;
697 case 0x32: /* m */ buf[n] = 'm'; break;
698 case 0x25: /* k */ buf[n] = 'k'; break;
699 case 0x2d: /* x */
700 /* Only allow 'x' after an initial 0 */
701 if (n == 1 && (buf[0] == '0')) {
702 buf[n] = 'x';
703 }
704 break;
705 case 0x0e: /* BS */
706 if (n > 0) {
707 n -= 1;
708 buf[n] = ' ';
709 }
710 break;
711 /* Don't allow entering a number not in our current base */
712 case 0x0B: if (base >= 1) buf[n] = '0'; break;
713 case 0x02: if (base >= 2) buf[n] = '1'; break;
714 case 0x03: if (base >= 3) buf[n] = '2'; break;
715 case 0x04: if (base >= 4) buf[n] = '3'; break;
716 case 0x05: if (base >= 5) buf[n] = '4'; break;
717 case 0x06: if (base >= 6) buf[n] = '5'; break;
718 case 0x07: if (base >= 7) buf[n] = '6'; break;
719 case 0x08: if (base >= 8) buf[n] = '7'; break;
720 case 0x09: if (base >= 9) buf[n] = '8'; break;
721 case 0x0A: if (base >= 10) buf[n] = '9'; break;
722 case 0x1e: if (base >= 11) buf[n] = 'a'; break;
723 case 0x30: if (base >= 12) buf[n] = 'b'; break;
724 case 0x2e: if (base >= 13) buf[n] = 'c'; break;
725 case 0x20: if (base >= 14) buf[n] = 'd'; break;
726 case 0x12: if (base >= 15) buf[n] = 'e'; break;
727 case 0x21: if (base >= 16) buf[n] = 'f'; break;
728 default:
729 break;
730 }
731 /* Don't allow anything to be entered after a suffix */
732 if (n > 0 && (
Martin Roth4dcd13d2016-02-24 13:53:07 -0800733 (buf[n-1] == 'p') || (buf[n-1] == 'g') ||
Martin Roth9b1b3352016-02-24 12:27:06 -0800734 (buf[n-1] == 'm') || (buf[n-1] == 'k'))) {
735 buf[n] = ' ';
736 }
737 /* If we have entered a character increment n */
738 if (buf[n] != ' ') {
739 n++;
740 }
741 buf[n] = ' ';
742 /* Print the current number */
743 cprint(x, y, buf);
744
745 /* Find the base we are entering numbers in */
746 base = 10;
747 if ((buf[0] == '0') && (buf[1] == 'x')) {
748 base = 16;
749 }
750 else if (buf[0] == '0') {
751 base = 8;
752 }
753 }
754 /* Compute our current shift */
755 shift = 0;
756 switch(buf[n-1]) {
757 case 'g': /* gig */ shift = 30; break;
758 case 'm': /* meg */ shift = 20; break;
759 case 'p': /* page */ shift = 12; break;
760 case 'k': /* kilo */ shift = 10; break;
761 }
762 shift -= result_shift;
763
764 /* Compute our current value */
765 val = simple_strtoul(buf, 0, base);
766 if (shift > 0) {
767 if (shift >= 32) {
768 val = 0xffffffff;
769 } else {
770 val <<= shift;
771 }
772 } else {
773 if (-shift >= 32) {
774 val = 0;
775 }
776 else {
777 val >>= -shift;
778 }
779 }
780 return val;
781}
782
783void ttyprint(int y, int x, const char *p)
784{
785 static char sx[3];
786 static char sy[3];
Martin Roth4dcd13d2016-02-24 13:53:07 -0800787
Martin Roth9b1b3352016-02-24 12:27:06 -0800788 sx[0]='\0';
789 sy[0]='\0';
790 x++; y++;
791 itoa(sx, x);
792 itoa(sy, y);
Ben Gardnerb72a23a2016-03-04 17:40:38 -0600793 serial_echo_print("\x1b[");
Martin Roth9b1b3352016-02-24 12:27:06 -0800794 serial_echo_print(sy);
795 serial_echo_print(";");
796 serial_echo_print(sx);
797 serial_echo_print("H");
798 serial_echo_print(p);
799}
800
801void serial_echo_init(void)
802{
Martin Roth1286f192016-02-25 10:26:59 -0800803 int comstat, serial_div;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800804 unsigned char lcr;
Martin Roth9b1b3352016-02-24 12:27:06 -0800805
806 /* read the Divisor Latch */
807 comstat = serial_echo_inb(UART_LCR);
808 serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
Martin Roth1286f192016-02-25 10:26:59 -0800809 serial_echo_inb(UART_DLM);
810 serial_echo_inb(UART_DLL);
Martin Roth9b1b3352016-02-24 12:27:06 -0800811 serial_echo_outb(comstat, UART_LCR);
812
813 /* now do hardwired init */
814 lcr = serial_parity | (serial_bits - 5);
815 serial_echo_outb(lcr, UART_LCR); /* No parity, 8 data bits, 1 stop */
816 serial_div = 115200 / serial_baud_rate;
817 serial_echo_outb(0x80|lcr, UART_LCR); /* Access divisor latch */
818 serial_echo_outb(serial_div & 0xff, UART_DLL); /* baud rate divisor */
819 serial_echo_outb((serial_div >> 8) & 0xff, UART_DLM);
820 serial_echo_outb(lcr, UART_LCR); /* Done with divisor */
821
822 /* Prior to disabling interrupts, read the LSR and RBR
823 * registers */
824 comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
825 comstat = serial_echo_inb(UART_RX); /* COM? RBR */
826 serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
827
828 clear_screen_buf();
829
830 return;
831}
832
833/*
834 * Get_number of digits
835 */
836int getnum(ulong val)
837{
838 int len = 0;
839 int i = 1;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800840
Martin Roth9b1b3352016-02-24 12:27:06 -0800841 while(i <= val)
842 {
843 len++;
844 i *= 10;
845 }
846
847 return len;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800848
Martin Roth9b1b3352016-02-24 12:27:06 -0800849}
850
851
852void serial_echo_print(const char *p)
853{
854 if (!serial_cons) {
855 return;
856 }
857 /* Now, do each character */
858 while (*p) {
859 WAIT_FOR_XMITR;
860
861 /* Send the character out. */
862 serial_echo_outb(*p, UART_TX);
863 if(*p==10) {
864 WAIT_FOR_XMITR;
865 serial_echo_outb(13, UART_TX);
866 }
867 p++;
868 }
869}
870
871/* Except for multi-character key sequences this mapping
872 * table is complete. So it should not need to be updated
873 * when new keys are searched for. However the key handling
874 * should really be turned around and only in get_key should
875 * we worry about the exact keycode that was pressed. Everywhere
876 * else we should switch on the character...
877 */
878struct ascii_map_str ser_map[] =
879/*ascii keycode ascii keycode*/
Martin Roth4dcd13d2016-02-24 13:53:07 -0800880{
Martin Roth9b1b3352016-02-24 12:27:06 -0800881 /* Special cases come first so I can leave
882 * their ``normal'' mapping in the table,
883 * without it being activated.
884 */
885 { 27, 0x01}, /* ^[/ESC -> ESC */
886 { 127, 0x0e}, /* DEL -> BS */
887 { 8, 0x0e}, /* ^H/BS -> BS */
888 { 10, 0x1c}, /* ^L/NL -> CR */
889 { 13, 0x1c}, /* ^M/CR -> CR */
890 { 9, 0x0f}, /* ^I/TAB -> TAB */
891 { 19, 0x39}, /* ^S -> SP */
892 { 17, 28}, /* ^Q -> CR */
893
894 { ' ', 0x39}, /* SP -> SP */
895 { 'a', 0x1e},
896 { 'A', 0x1e},
897 { 1, 0x1e}, /* ^A -> A */
898 { 'b', 0x30},
899 { 'B', 0x30},
900 { 2, 0x30}, /* ^B -> B */
901 { 'c', 0x2e},
902 { 'C', 0x2e},
903 { 3, 0x2e}, /* ^C -> C */
904 { 'd', 0x20},
905 { 'D', 0x20},
906 { 4, 0x20}, /* ^D -> D */
907 { 'e', 0x12},
908 { 'E', 0x12},
909 { 5, 0x12}, /* ^E -> E */
910 { 'f', 0x21},
911 { 'F', 0x21},
912 { 6, 0x21}, /* ^F -> F */
913 { 'g', 0x22},
914 { 'G', 0x22},
915 { 7, 0x22}, /* ^G -> G */
916 { 'h', 0x23},
917 { 'H', 0x23},
918 { 8, 0x23}, /* ^H -> H */
919 { 'i', 0x17},
920 { 'I', 0x17},
921 { 9, 0x17}, /* ^I -> I */
922 { 'j', 0x24},
923 { 'J', 0x24},
924 { 10, 0x24}, /* ^J -> J */
925 { 'k', 0x25},
926 { 'K', 0x25},
927 { 11, 0x25}, /* ^K -> K */
928 { 'l', 0x26},
929 { 'L', 0x26},
930 { 12, 0x26}, /* ^L -> L */
931 { 'm', 0x32},
932 { 'M', 0x32},
933 { 13, 0x32}, /* ^M -> M */
934 { 'n', 0x31},
935 { 'N', 0x31},
936 { 14, 0x31}, /* ^N -> N */
937 { 'o', 0x18},
938 { 'O', 0x18},
939 { 15, 0x18}, /* ^O -> O */
940 { 'p', 0x19},
941 { 'P', 0x19},
942 { 16, 0x19}, /* ^P -> P */
943 { 'q', 0x10},
944 { 'Q', 0x10},
945 { 17, 0x10}, /* ^Q -> Q */
946 { 'r', 0x13},
947 { 'R', 0x13},
948 { 18, 0x13}, /* ^R -> R */
949 { 's', 0x1f},
950 { 'S', 0x1f},
951 { 19, 0x1f}, /* ^S -> S */
952 { 't', 0x14},
953 { 'T', 0x14},
954 { 20, 0x14}, /* ^T -> T */
955 { 'u', 0x16},
956 { 'U', 0x16},
957 { 21, 0x16}, /* ^U -> U */
958 { 'v', 0x2f},
959 { 'V', 0x2f},
960 { 22, 0x2f}, /* ^V -> V */
961 { 'w', 0x11},
962 { 'W', 0x11},
963 { 23, 0x11}, /* ^W -> W */
964 { 'x', 0x2d},
965 { 'X', 0x2d},
966 { 24, 0x2d}, /* ^X -> X */
967 { 'y', 0x15},
968 { 'Y', 0x15},
969 { 25, 0x15}, /* ^Y -> Y */
970 { 'z', 0x2c},
971 { 'Z', 0x2c},
972 { 26, 0x2c}, /* ^Z -> Z */
973 { '-', 0x0c},
974 { '_', 0x0c},
975 { 31, 0x0c}, /* ^_ -> _ */
976 { '=', 0x0c},
977 { '+', 0x0c},
978 { '[', 0x1a},
979 { '{', 0x1a},
980 { 27, 0x1a}, /* ^[ -> [ */
981 { ']', 0x1b},
982 { '}', 0x1b},
983 { 29, 0x1b}, /* ^] -> ] */
984 { ';', 0x27},
985 { ':', 0x27},
986 { '\'', 0x28},
987 { '"', 0x28},
988 { '`', 0x29},
989 { '~', 0x29},
990 { '\\', 0x2b},
991 { '|', 0x2b},
992 { 28, 0x2b}, /* ^\ -> \ */
993 { ',', 0x33},
994 { '<', 0x33},
995 { '.', 0x34},
996 { '>', 0x34},
997 { '/', 0x35},
998 { '?', 0x35},
999 { '1', 0x02},
1000 { '!', 0x02},
1001 { '2', 0x03},
1002 { '@', 0x03},
1003 { '3', 0x04},
1004 { '#', 0x04},
1005 { '4', 0x05},
1006 { '$', 0x05},
1007 { '5', 0x06},
1008 { '%', 0x06},
1009 { '6', 0x07},
1010 { '^', 0x07},
1011 { 30, 0x07}, /* ^^ -> 6 */
1012 { '7', 0x08},
1013 { '&', 0x08},
1014 { '8', 0x09},
1015 { '*', 0x09},
1016 { '9', 0x0a},
1017 { '(', 0x0a},
1018 { '0', 0x0b},
1019 { ')', 0x0b},
1020 { 0, 0}
1021};
1022
1023/*
1024 * Given an ascii character, return the keycode
1025 *
1026 * Uses ser_map definition above.
1027 *
1028 * It would be more efficient to use an array of 255 characters
1029 * and directly index into it.
1030 */
1031int ascii_to_keycode (int in)
1032{
1033 struct ascii_map_str *p;
1034 for (p = ser_map; p->ascii; p++) {
1035 if (in ==p->ascii)
1036 return p->keycode;
1037 }
1038 return 0;
1039}
1040
1041/*
1042 * Call this when you want to wait for the user to lift the
1043 * finger off of a key. It is a noop if you are using a
1044 * serial console.
1045 */
1046void wait_keyup( void ) {
1047 /* Check to see if someone lifted the keyboard key */
1048 while (1) {
1049 if ((get_key() & 0x80) != 0) {
1050 return;
1051 }
1052 /* Trying to simulate waiting for a key release with
1053 * the serial port is to nasty to let live.
1054 * In particular some menus don't even display until
1055 * you release the key that caused to to get there.
1056 * With the serial port this results in double pressing
1057 * or something worse for just about every key.
1058 */
1059 if (serial_cons) {
1060 return;
1061 }
1062 }
1063}
1064
1065/*
1066 * Handles "console=<param>" command line option
1067 *
1068 * Examples of accepted params:
1069 * ttyS0
1070 * ttyS1
1071 * ttyS0,115200
1072 * ttyS0,9600e8
1073 */
1074void serial_console_setup(char *param)
1075{
1076 char *option, *end;
1077 unsigned long tty;
1078 unsigned long baud_rate;
1079 unsigned char parity, bits;
1080
1081 if (strncmp(param, "ttyS", 4))
1082 return; /* not a serial port */
1083
1084 param += 4;
1085
1086 tty = simple_strtoul(param, &option, 10);
1087
1088 if (option == param)
1089 return; /* there were no digits */
1090
1091 if (tty > 1)
1092 return; /* only ttyS0 and ttyS1 supported */
1093
1094 if (*option == '\0' || *option == ' ')
1095 goto save_tty; /* no options given, just ttyS? */
1096
1097 if (*option != ',')
1098 return; /* missing the comma separator */
1099
1100 /* baud rate must follow */
1101 option++;
1102 baud_rate = simple_strtoul(option, &end, 10);
1103
1104 if (end == option)
1105 return; /* no baudrate after comma */
1106
1107 if (baud_rate == 0 || (115200 % baud_rate) != 0)
1108 return; /* wrong baud rate */
1109
1110 if (*end == '\0' || *end == ' ')
1111 goto save_baud_rate; /* no more options given */
1112
1113 switch (toupper(*end)) {
1114 case 'N':
1115 parity = 0;
1116 break;
1117 case 'O':
1118 parity = UART_LCR_PARITY;
1119 break;
1120 case 'E':
1121 parity = UART_LCR_PARITY | UART_LCR_EPAR;
1122 break;
1123 default:
1124 /* Unknown parity */
1125 return;
1126 }
1127
1128 end++;
1129 if (*end == '\0' || *end == ' ')
1130 goto save_parity;
1131
1132 /* word length (bits) */
1133 if (*end < '7' || *end > '8')
1134 return; /* invalid number of bits */
1135
1136 bits = *end - '0';
1137
1138 end++;
1139
Ben Gardner85b2d912016-03-30 16:11:19 -05001140 if (*end != '\0' && *end != ' ')
Martin Roth9b1b3352016-02-24 12:27:06 -08001141 return; /* garbage at the end */
1142
1143 serial_bits = bits;
1144 save_parity:
1145 serial_parity = parity;
1146 save_baud_rate:
1147 serial_baud_rate = (int) baud_rate;
1148 save_tty:
1149 serial_tty = (short) tty;
1150 serial_cons = 1;
1151}
1152
1153/* Get a comma seperated list of numbers */
1154void get_list(int x, int y, int len, char *buf)
1155{
1156 int c, n = 0;
1157
1158 len--;
1159 wait_keyup();
1160 while(1) {
1161 /* Read a new character and process it */
1162 c = get_key();
1163 switch(c) {
1164 case 0x1c: /* CR */
1165 /* If something has been entered we are done */
1166 if(n) {
1167 buf[n] = 0;
1168 return;
1169 }
1170 break;
1171 case 0x0e: /* BS */
1172 if (n > 0) {
1173 n -= 1;
1174 buf[n] = ' ';
1175 }
1176 break;
1177 case 0x0B: buf[n++] = '0'; break;
1178 case 0x02: buf[n++] = '1'; break;
1179 case 0x03: buf[n++] = '2'; break;
1180 case 0x04: buf[n++] = '3'; break;
1181 case 0x05: buf[n++] = '4'; break;
1182 case 0x06: buf[n++] = '5'; break;
1183 case 0x07: buf[n++] = '6'; break;
1184 case 0x08: buf[n++] = '7'; break;
1185 case 0x09: buf[n++] = '8'; break;
1186 case 0x0a: buf[n++] = '9'; break;
1187 case 0x33: buf[n++] = ','; break;
1188 }
1189 cprint(x, y, buf);
1190 if (n >= len) {
1191 buf[n] = 0;
1192 return;
1193 }
1194 }
Martin Roth69593432016-03-27 19:46:03 -06001195}