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