1 // Copyright 2016 The Fuchsia Authors
2 // Copyright (c) 2009 Corey Tabaka
3 // Copyright (c) 2016 Travis Geiselbrecht
4 //
5 // Use of this source code is governed by a MIT-style
6 // license that can be found in the LICENSE file or at
7 // https://opensource.org/licenses/MIT
8
9 #if WITH_LEGACY_PC_CONSOLE
10
11 #include <arch/x86.h>
12 #include <lib/io.h>
13 #include <platform/console.h>
14 #include <platform/pc.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 /* memory mapped framebuffer */
21 #define FB (0xB8000U + KERNEL_ASPACE_BASE)
22
23 /* CGA values */
24 #define CURSOR_START 0x0A
25 #define CURSOR_END 0x0B
26 #define VIDEO_ADDRESS_MSB 0x0C
27 #define VIDEO_ADDRESS_LSB 0x0D
28 #define CURSOR_POS_MSB 0x0E
29 #define CURSOR_POS_LSB 0x0F
30
31 /* curr settings */
32 static unsigned char curr_x;
33 static unsigned char curr_y;
34 static unsigned char curr_start;
35 static unsigned char curr_end;
36 static unsigned char curr_attr = 0x7;
37
38 /* video page buffer */
39 #define VPAGE_SIZE 2048
40 #define PAGE_MAX 8
41
42 static int active_page = 0;
43 static int visual_page = 0;
44
45 static int curs_x[PAGE_MAX];
46 static int curs_y[PAGE_MAX];
47
48 static struct {
49 int x1, y1, x2, y2;
50 } view_window = {
51 0, 0, 79, 24};
52
platform_init_console(void)53 void platform_init_console(void) {
54 curr_save();
55 window(0, 0, 79, 24);
56 clear();
57 place(0, 0);
58 }
59
set_visual_page(int page)60 void set_visual_page(int page) {
61 unsigned short page_offset = page * VPAGE_SIZE;
62 visual_page = page;
63
64 outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB);
65 outp(CGA_DATA_REG, page_offset & 0xFF);
66 outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB);
67 outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF);
68 }
69
set_active_page(int page)70 void set_active_page(int page) {
71 curs_x[active_page] = curr_x;
72 curs_y[active_page] = curr_y;
73 curr_x = curs_x[page];
74 curr_y = curs_y[page];
75 active_page = page;
76 }
77
get_visual_page(void)78 int get_visual_page(void) {
79 return visual_page;
80 }
81
get_active_page(void)82 int get_active_page(void) {
83 return active_page;
84 }
85
place(int x,int y)86 void place(int x, int y) {
87 unsigned short cursor_word = x + y * 80 + active_page * VPAGE_SIZE;
88
89 /*
90 * program CGA using index reg, then data reg
91 */
92 outp(CGA_INDEX_REG, CURSOR_POS_LSB);
93 outp(CGA_DATA_REG, cursor_word & 0xFF);
94 outp(CGA_INDEX_REG, CURSOR_POS_MSB);
95 outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF);
96
97 curr_x = x;
98 curr_y = y;
99 }
100
cursor(int start,int end)101 void cursor(int start, int end) {
102 outp(CGA_INDEX_REG, CURSOR_START);
103 outp(CGA_DATA_REG, start);
104 outp(CGA_INDEX_REG, CURSOR_END);
105 outp(CGA_DATA_REG, end);
106 }
107
curr_save(void)108 void curr_save(void) {
109 #if 0
110 /* grab some info from the bios data area (these should be defined in memmap.h */
111 curr_attr = *((unsigned char *)FB + 159);
112 curr_x = *((unsigned char *)0x00450);
113 curr_y = *((unsigned char *)0x00451);
114 curr_end = *((unsigned char *)0x00460);
115 curr_start = *((unsigned char *)0x00461);
116 #endif
117 active_page = visual_page = 0;
118 }
119
curr_restore(void)120 void curr_restore(void) {
121 #if 0
122 *((unsigned char *)0x00450) = curr_x;
123 *((unsigned char *)0x00451) = curr_y;
124 #endif
125
126 place(curr_x, curr_y);
127 cursor(curr_start, curr_end);
128 }
129
window(int x1,int y1,int x2,int y2)130 void window(int x1, int y1, int x2, int y2) {
131 view_window.x1 = x1;
132 view_window.y1 = y1;
133 view_window.x2 = x2;
134 view_window.y2 = y2;
135
136 //place(x1, y1);
137 }
138
_clear(char c,char attr,int x1,int y1,int x2,int y2)139 void _clear(char c, char attr, int x1, int y1, int x2, int y2) {
140 register int i, j;
141 unsigned short w = attr;
142
143 w <<= 8;
144 w |= c;
145 for (i = x1; i <= x2; i++) {
146 for (j = y1; j <= y2; j++) {
147 *((unsigned short*)(uintptr_t)(FB + 2 * i + 160 * j + 2 * active_page * VPAGE_SIZE)) = w;
148 }
149 }
150
151 place(x1, y1);
152 curr_y = y1;
153 curr_x = x1;
154 }
155
clear()156 void clear() {
157 _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2,
158 view_window.y2);
159 }
160
_scroll(char attr,int x1,int y1,int x2,int y2)161 void _scroll(char attr, int x1, int y1, int x2, int y2) {
162 register int x, y;
163 unsigned short xattr = attr << 8, w;
164 unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE));
165
166 for (y = y1 + 1; y <= y2; y++) {
167 for (x = x1; x <= x2; x++) {
168 w = *((unsigned short*)(v + 2 * (y * 80 + x)));
169 *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = w;
170 }
171 }
172
173 for (x = x1; x <= x2; x++) {
174 *((unsigned short*)(v + 2 * ((y - 1) * 80 + x))) = xattr;
175 }
176 }
177
scroll(void)178 void scroll(void) {
179 _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2,
180 view_window.y2);
181 }
182
cputc(char c)183 void cputc(char c) {
184 static unsigned short scan_x, x, y;
185 unsigned char* v = (unsigned char*)(uintptr_t)(FB + active_page * (2 * VPAGE_SIZE));
186 x = curr_x;
187 y = curr_y;
188
189 switch (c) {
190 case '\t':
191 x += 8;
192 if (x >= view_window.x2 + 1) {
193 x = view_window.x1;
194 if (y == view_window.y2) {
195 scroll();
196 } else {
197 y++;
198 }
199 } else {
200 scan_x = 0;
201
202 while ((scan_x + 8) < x) {
203 scan_x += 8;
204 }
205
206 x = scan_x;
207 }
208 break;
209
210 case '\r':
211 x = view_window.x1;
212 break;
213
214 case '\n':
215 if (y == view_window.y2) {
216 scroll();
217 } else {
218 y++;
219 }
220 break;
221
222 case '\b':
223 x--;
224 break;
225
226 default:
227 *(v + 2 * (x + y * 80)) = c;
228 x++;
229
230 if (x >= view_window.x2 + 1) {
231 x = view_window.x1;
232 if (y == view_window.y2) {
233 scroll();
234 } else {
235 y++;
236 }
237 }
238 }
239
240 place(x, y);
241 }
242
cputs(char * s)243 void cputs(char* s) {
244 char c;
245 while (*s != '\0') {
246 c = *s++;
247 cputc(c);
248 }
249 }
250
puts_xy(int x,int y,char attr,char * s)251 void puts_xy(int x, int y, char attr, char* s) {
252 unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE));
253 while (*s != 0) {
254 *v = *s;
255 s++;
256 v++;
257 *v = attr;
258 v++;
259 }
260 }
261
putc_xy(int x,int y,char attr,char c)262 void putc_xy(int x, int y, char attr, char c) {
263 unsigned char* v = (unsigned char*)(uintptr_t)(FB + (80 * y + x) * 2 + active_page * (2 * VPAGE_SIZE));
264 *v = c;
265 v++;
266 *v = attr;
267 }
268
printf_xy(int x,int y,char attr,char * fmt,...)269 int printf_xy(int x, int y, char attr, char* fmt, ...) {
270 char cbuf[200];
271 va_list parms;
272 int result;
273
274 va_start(parms, fmt);
275 result = vsnprintf(cbuf, sizeof(cbuf), fmt, parms);
276 va_end(parms);
277
278 puts_xy(x, y, attr, cbuf);
279
280 return result;
281 }
282
283 #endif
284