| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: eficons.c,v 1.4.2.6 2020/03/09 09:48:00 martin Exp $ */ | | 1 | /* $NetBSD: eficons.c,v 1.4.2.7 2023/09/15 15:44:20 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org> | | 4 | * Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -16,29 +16,32 @@ | | | @@ -16,29 +16,32 @@ |
16 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 16 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
| | | 29 | #include <sys/param.h> |
29 | #include <sys/bitops.h> | | 30 | #include <sys/bitops.h> |
30 | #include <sys/stdint.h> | | 31 | #include <sys/stdint.h> |
31 | | | 32 | |
| | | 33 | #include <comio_direct.h> |
| | | 34 | |
32 | #include "efiboot.h" | | 35 | #include "efiboot.h" |
33 | | | 36 | |
34 | #include "bootinfo.h" | | 37 | #include "bootinfo.h" |
35 | #include "vbe.h" | | 38 | #include "vbe.h" |
36 | | | 39 | |
37 | #ifndef DEFAULT_GOP_MODE | | 40 | #ifndef DEFAULT_GOP_MODE |
38 | #define DEFAULT_GOP_MODE "1024x768" | | 41 | #define DEFAULT_GOP_MODE "1024x768" |
39 | #endif | | 42 | #endif |
40 | #define FALLBACK_GOP_MODE 0 | | 43 | #define FALLBACK_GOP_MODE 0 |
41 | | | 44 | |
42 | extern struct x86_boot_params boot_params; | | 45 | extern struct x86_boot_params boot_params; |
43 | | | 46 | |
44 | struct btinfo_console btinfo_console; | | 47 | struct btinfo_console btinfo_console; |
| @@ -50,42 +53,50 @@ static int keybuf_read = 0; | | | @@ -50,42 +53,50 @@ static int keybuf_read = 0; |
50 | static int keybuf_write = 0; | | 53 | static int keybuf_write = 0; |
51 | | | 54 | |
52 | static SERIAL_IO_INTERFACE *serios[4]; | | 55 | static SERIAL_IO_INTERFACE *serios[4]; |
53 | static int default_comspeed = | | 56 | static int default_comspeed = |
54 | #if defined(CONSPEED) | | 57 | #if defined(CONSPEED) |
55 | CONSPEED; | | 58 | CONSPEED; |
56 | #else | | 59 | #else |
57 | 9600; | | 60 | 9600; |
58 | #endif | | 61 | #endif |
59 | static u_char serbuf[16]; | | 62 | static u_char serbuf[16]; |
60 | static int serbuf_read = 0; | | 63 | static int serbuf_read = 0; |
61 | static int serbuf_write = 0; | | 64 | static int serbuf_write = 0; |
62 | | | 65 | |
| | | 66 | static int raw_com_addr = 0; |
| | | 67 | |
63 | static void eficons_init_video(void); | | 68 | static void eficons_init_video(void); |
64 | static void efi_switch_video_to_text_mode(void); | | 69 | static void efi_switch_video_to_text_mode(void); |
65 | | | 70 | |
66 | static int efi_cons_getc(void); | | 71 | static int efi_cons_getc(void); |
67 | static int efi_cons_putc(int); | | 72 | static int efi_cons_putc(int); |
68 | static int efi_cons_iskey(int); | | 73 | static int efi_cons_iskey(int); |
69 | static int efi_cons_waitforinputevent(uint64_t); | | 74 | static int efi_cons_waitforinputevent(uint64_t); |
70 | | | 75 | |
71 | static void efi_com_probe(void); | | 76 | static void efi_com_probe(void); |
72 | static bool efi_valid_com(int); | | 77 | static bool efi_valid_com(int); |
73 | static int efi_com_init(int, int); | | 78 | static int efi_com_init(int, int); |
74 | static int efi_com_getc(void); | | 79 | static int efi_com_getc(void); |
75 | static int efi_com_putc(int); | | 80 | static int efi_com_putc(int); |
76 | static int efi_com_status(int); | | 81 | static int efi_com_status(int); |
77 | static int efi_com_waitforinputevent(uint64_t); | | 82 | static int efi_com_waitforinputevent(uint64_t); |
78 | | | 83 | |
| | | 84 | static int raw_com_init(int, int); |
| | | 85 | static int raw_com_getc(void); |
| | | 86 | static int raw_com_putc(int); |
| | | 87 | static int raw_com_status(int); |
| | | 88 | static int raw_com_waitforinputevent(uint64_t); |
| | | 89 | |
79 | static int efi_find_gop_mode(char *); | | 90 | static int efi_find_gop_mode(char *); |
80 | | | 91 | |
81 | static int iodev; | | 92 | static int iodev; |
82 | static int (*internal_getchar)(void) = efi_cons_getc; | | 93 | static int (*internal_getchar)(void) = efi_cons_getc; |
83 | static int (*internal_putchar)(int) = efi_cons_putc; | | 94 | static int (*internal_putchar)(int) = efi_cons_putc; |
84 | static int (*internal_iskey)(int) = efi_cons_iskey; | | 95 | static int (*internal_iskey)(int) = efi_cons_iskey; |
85 | static int (*internal_waitforinputevent)(uint64_t) = efi_cons_waitforinputevent; | | 96 | static int (*internal_waitforinputevent)(uint64_t) = efi_cons_waitforinputevent; |
86 | | | 97 | |
87 | static int | | 98 | static int |
88 | getcomaddr(int idx) | | 99 | getcomaddr(int idx) |
89 | { | | 100 | { |
90 | static const short comioport[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; | | 101 | static const short comioport[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
91 | | | 102 | |
| @@ -124,43 +135,38 @@ efi_consinit(int dev, int ioport, int sp | | | @@ -124,43 +135,38 @@ efi_consinit(int dev, int ioport, int sp |
124 | awaitkey(7, 0)) | | 135 | awaitkey(7, 0)) |
125 | goto ok; | | 136 | goto ok; |
126 | } | | 137 | } |
127 | goto nocom; | | 138 | goto nocom; |
128 | ok: | | 139 | ok: |
129 | break; | | 140 | break; |
130 | | | 141 | |
131 | case CONSDEV_COM0: | | 142 | case CONSDEV_COM0: |
132 | case CONSDEV_COM1: | | 143 | case CONSDEV_COM1: |
133 | case CONSDEV_COM2: | | 144 | case CONSDEV_COM2: |
134 | case CONSDEV_COM3: | | 145 | case CONSDEV_COM3: |
135 | iodev = dev; | | 146 | iodev = dev; |
136 | btinfo_console.addr = ioport; | | 147 | btinfo_console.addr = ioport; |
137 | if (btinfo_console.addr == 0) { | | 148 | if (btinfo_console.addr == 0) |
138 | if (!efi_valid_com(iodev)) | | | |
139 | goto nocom; | | | |
140 | btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); | | 149 | btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); |
141 | } | | | |
142 | if (speed != 0) | | 150 | if (speed != 0) |
143 | btinfo_console.speed = speed; | | 151 | btinfo_console.speed = speed; |
144 | efi_com_init(btinfo_console.addr, btinfo_console.speed); | | 152 | efi_com_init(btinfo_console.addr, btinfo_console.speed); |
145 | break; | | 153 | break; |
146 | | | 154 | |
147 | case CONSDEV_COM0KBD: | | 155 | case CONSDEV_COM0KBD: |
148 | case CONSDEV_COM1KBD: | | 156 | case CONSDEV_COM1KBD: |
149 | case CONSDEV_COM2KBD: | | 157 | case CONSDEV_COM2KBD: |
150 | case CONSDEV_COM3KBD: | | 158 | case CONSDEV_COM3KBD: |
151 | iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; | | 159 | iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; |
152 | if (!efi_valid_com(iodev)) | | | |
153 | goto nocom; | | | |
154 | btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); | | 160 | btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); |
155 | | | 161 | |
156 | efi_cons_putc('0' + iodev - CONSDEV_COM0); | | 162 | efi_cons_putc('0' + iodev - CONSDEV_COM0); |
157 | efi_com_init(btinfo_console.addr, btinfo_console.speed); | | 163 | efi_com_init(btinfo_console.addr, btinfo_console.speed); |
158 | /* check for: | | 164 | /* check for: |
159 | * 1. successful output | | 165 | * 1. successful output |
160 | * 2. optionally, keypress within 7s | | 166 | * 2. optionally, keypress within 7s |
161 | */ | | 167 | */ |
162 | if (efi_com_putc(':') && | | 168 | if (efi_com_putc(':') && |
163 | efi_com_putc('-') && | | 169 | efi_com_putc('-') && |
164 | efi_com_putc('(') && | | 170 | efi_com_putc('(') && |
165 | awaitkey(7, 0)) | | 171 | awaitkey(7, 0)) |
166 | goto kbd; | | 172 | goto kbd; |
| @@ -858,42 +864,43 @@ efi_valid_com(int dev) | | | @@ -858,42 +864,43 @@ efi_valid_com(int dev) |
858 | getcomaddr(idx) != 0; | | 864 | getcomaddr(idx) != 0; |
859 | } | | 865 | } |
860 | | | 866 | |
861 | static int | | 867 | static int |
862 | efi_com_init(int addr, int speed) | | 868 | efi_com_init(int addr, int speed) |
863 | { | | 869 | { |
864 | EFI_STATUS status; | | 870 | EFI_STATUS status; |
865 | SERIAL_IO_INTERFACE *serio; | | 871 | SERIAL_IO_INTERFACE *serio; |
866 | | | 872 | |
867 | if (speed <= 0) | | 873 | if (speed <= 0) |
868 | return 0; | | 874 | return 0; |
869 | | | 875 | |
870 | if (!efi_valid_com(iodev)) | | 876 | if (!efi_valid_com(iodev)) |
871 | return 0; | | 877 | return raw_com_init(addr, speed); |
872 | | | 878 | |
873 | serio = serios[iodev - CONSDEV_COM0]; | | 879 | serio = serios[iodev - CONSDEV_COM0]; |
874 | | | 880 | |
875 | if (serio->Mode->BaudRate != btinfo_console.speed) { | | 881 | if (serio->Mode->BaudRate != btinfo_console.speed) { |
876 | status = uefi_call_wrapper(serio->SetAttributes, 7, serio, | | 882 | status = uefi_call_wrapper(serio->SetAttributes, 7, serio, |
877 | speed, serio->Mode->ReceiveFifoDepth, | | 883 | speed, serio->Mode->ReceiveFifoDepth, |
878 | serio->Mode->Timeout, serio->Mode->Parity, | | 884 | serio->Mode->Timeout, serio->Mode->Parity, |
879 | serio->Mode->DataBits, serio->Mode->StopBits); | | 885 | serio->Mode->DataBits, serio->Mode->StopBits); |
880 | if (EFI_ERROR(status)) { | | 886 | if (EFI_ERROR(status)) { |
881 | printf("com%d: SetAttribute() failed with status=%" PRIxMAX | | 887 | printf("com%d: SetAttribute() failed with status=%" PRIxMAX |
882 | "\n", iodev - CONSDEV_COM0, (uintmax_t)status); | | 888 | "\n", iodev - CONSDEV_COM0, (uintmax_t)status); |
883 | return 0; | | 889 | return 0; |
884 | } | | 890 | } |
885 | } | | 891 | } |
886 | | | 892 | |
| | | 893 | raw_com_addr = 0; |
887 | default_comspeed = speed; | | 894 | default_comspeed = speed; |
888 | internal_getchar = efi_com_getc; | | 895 | internal_getchar = efi_com_getc; |
889 | internal_putchar = efi_com_putc; | | 896 | internal_putchar = efi_com_putc; |
890 | internal_iskey = efi_com_status; | | 897 | internal_iskey = efi_com_status; |
891 | internal_waitforinputevent = efi_com_waitforinputevent; | | 898 | internal_waitforinputevent = efi_com_waitforinputevent; |
892 | memset(serbuf, 0, sizeof(serbuf)); | | 899 | memset(serbuf, 0, sizeof(serbuf)); |
893 | serbuf_read = serbuf_write = 0; | | 900 | serbuf_read = serbuf_write = 0; |
894 | | | 901 | |
895 | return speed; | | 902 | return speed; |
896 | } | | 903 | } |
897 | | | 904 | |
898 | static int | | 905 | static int |
899 | efi_com_getc(void) | | 906 | efi_com_getc(void) |
| @@ -1008,13 +1015,75 @@ efi_com_waitforinputevent(uint64_t timeo | | | @@ -1008,13 +1015,75 @@ efi_com_waitforinputevent(uint64_t timeo |
1008 | uefi_call_wrapper(BS->CloseEvent, 1, timer); | | 1015 | uefi_call_wrapper(BS->CloseEvent, 1, timer); |
1009 | return EINVAL; | | 1016 | return EINVAL; |
1010 | } | | 1017 | } |
1011 | status = WaitForSingleEvent(&timer, timeout); | | 1018 | status = WaitForSingleEvent(&timer, timeout); |
1012 | uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerCancel, 0); | | 1019 | uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerCancel, 0); |
1013 | uefi_call_wrapper(BS->CloseEvent, 1, periodic); | | 1020 | uefi_call_wrapper(BS->CloseEvent, 1, periodic); |
1014 | uefi_call_wrapper(BS->CloseEvent, 1, timer); | | 1021 | uefi_call_wrapper(BS->CloseEvent, 1, timer); |
1015 | if (!EFI_ERROR(status)) | | 1022 | if (!EFI_ERROR(status)) |
1016 | return 0; | | 1023 | return 0; |
1017 | if (status == EFI_TIMEOUT) | | 1024 | if (status == EFI_TIMEOUT) |
1018 | return ETIMEDOUT; | | 1025 | return ETIMEDOUT; |
1019 | return EINVAL; | | 1026 | return EINVAL; |
1020 | } | | 1027 | } |
| | | 1028 | |
| | | 1029 | static int |
| | | 1030 | raw_com_init(int addr, int speed) |
| | | 1031 | { |
| | | 1032 | |
| | | 1033 | if (addr == 0 || speed <= 0) |
| | | 1034 | return 0; |
| | | 1035 | |
| | | 1036 | speed = cominit_d(addr, speed); |
| | | 1037 | |
| | | 1038 | raw_com_addr = addr; |
| | | 1039 | default_comspeed = speed; |
| | | 1040 | internal_getchar = raw_com_getc; |
| | | 1041 | internal_putchar = raw_com_putc; |
| | | 1042 | internal_iskey = raw_com_status; |
| | | 1043 | internal_waitforinputevent = raw_com_waitforinputevent; |
| | | 1044 | |
| | | 1045 | return speed; |
| | | 1046 | } |
| | | 1047 | |
| | | 1048 | static int |
| | | 1049 | raw_com_getc(void) |
| | | 1050 | { |
| | | 1051 | |
| | | 1052 | if (raw_com_addr == 0) |
| | | 1053 | panic("%s: Invalid serial port", __func__); |
| | | 1054 | return comgetc_d(raw_com_addr); |
| | | 1055 | } |
| | | 1056 | |
| | | 1057 | static int |
| | | 1058 | raw_com_putc(int c) |
| | | 1059 | { |
| | | 1060 | |
| | | 1061 | if (raw_com_addr == 0) |
| | | 1062 | panic("%s: Invalid serial port", __func__); |
| | | 1063 | return computc_d(c, raw_com_addr); |
| | | 1064 | } |
| | | 1065 | |
| | | 1066 | static int |
| | | 1067 | raw_com_status(int intr) |
| | | 1068 | { |
| | | 1069 | |
| | | 1070 | if (raw_com_addr == 0) |
| | | 1071 | panic("%s: Invalid serial port", __func__); |
| | | 1072 | return comstatus_d(raw_com_addr); |
| | | 1073 | } |
| | | 1074 | |
| | | 1075 | static int |
| | | 1076 | raw_com_waitforinputevent(uint64_t timeout /* in 0.1 usec */) |
| | | 1077 | { |
| | | 1078 | uint64_t ms; |
| | | 1079 | |
| | | 1080 | if (raw_com_addr == 0) |
| | | 1081 | panic("%s: Invalid serial port", __func__); |
| | | 1082 | |
| | | 1083 | for (ms = howmany(timeout, 10 * 1000); ms != 0; ms--) { |
| | | 1084 | if (raw_com_status(0)) |
| | | 1085 | return 0; |
| | | 1086 | uefi_call_wrapper(BS->Stall, 1, 1000); |
| | | 1087 | } |
| | | 1088 | return ETIMEDOUT; |
| | | 1089 | } |