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