1 /*
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 #include <arch/x86.h>
10 #include <platform/pc.h>
11 #include <platform/console.h>
12 #include <string.h>
13 #include <lib/io.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 
18 /* memory mapped framebuffer */
19 #define FB (0xB8000U + KERNEL_ASPACE_BASE)
20 
21 /* CGA values */
22 #define CURSOR_START        0x0A
23 #define CURSOR_END          0x0B
24 #define VIDEO_ADDRESS_MSB   0x0C
25 #define VIDEO_ADDRESS_LSB   0x0D
26 #define CURSOR_POS_MSB      0x0E
27 #define CURSOR_POS_LSB      0x0F
28 
29 /* curr settings */
30 static unsigned char curr_x;
31 static unsigned char curr_y;
32 static unsigned char curr_start;
33 static unsigned char curr_end;
34 static unsigned char curr_attr = 0x7;
35 
36 /* video page buffer */
37 #define VPAGE_SIZE      2048
38 #define PAGE_MAX        8
39 
40 static int active_page = 0;
41 static int visual_page = 0;
42 
43 static int curs_x[PAGE_MAX];
44 static int curs_y[PAGE_MAX];
45 
46 static struct {
47     int x1, y1, x2, y2;
48 } view_window = {
49     0, 0, 79, 24
50 };
51 
platform_init_console(void)52 void platform_init_console(void) {
53     curr_save();
54     window(0, 0, 79, 24);
55     clear();
56     place(0, 0);
57 }
58 
set_visual_page(int page)59 void set_visual_page(int page) {
60     unsigned short page_offset = page*VPAGE_SIZE;
61     visual_page = page;
62 
63     outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB);
64     outp(CGA_DATA_REG, page_offset & 0xFF);
65     outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB);
66     outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF);
67 }
68 
set_active_page(int page)69 void set_active_page(int page) {
70     curs_x[active_page] = curr_x;
71     curs_y[active_page] = curr_y;
72     curr_x = curs_x[page];
73     curr_y = curs_y[page];
74     active_page = page;
75 }
76 
get_visual_page(void)77 int get_visual_page(void) {
78     return visual_page;
79 }
80 
get_active_page(void)81 int get_active_page(void) {
82     return active_page;
83 }
84 
place(int x,int y)85 void place(int x,int y) {
86     unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE;
87 
88     /*
89      * program CGA using index reg, then data reg
90      */
91     outp(CGA_INDEX_REG, CURSOR_POS_LSB);
92     outp(CGA_DATA_REG, cursor_word & 0xFF);
93     outp(CGA_INDEX_REG, CURSOR_POS_MSB);
94     outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF);
95 
96     curr_x = x;
97     curr_y = y;
98 }
99 
cursor(int start,int end)100 void cursor(int start,int end) {
101     outp(CGA_INDEX_REG, CURSOR_START);
102     outp(CGA_DATA_REG, start);
103     outp(CGA_INDEX_REG, CURSOR_END);
104     outp(CGA_DATA_REG, end);
105 }
106 
curr_save(void)107 void curr_save(void) {
108 #if 0
109     /* grab some info from the bios data area (these should be defined in memmap.h */
110     curr_attr = *((unsigned char *)FB + 159);
111     curr_x = *((unsigned char *)0x00450);
112     curr_y = *((unsigned char *)0x00451);
113     curr_end = *((unsigned char *)0x00460);
114     curr_start = *((unsigned char *)0x00461);
115 #endif
116     active_page = visual_page = 0;
117 }
118 
curr_restore(void)119 void curr_restore(void) {
120 #if 0
121     *((unsigned char *)0x00450) = curr_x;
122     *((unsigned char *)0x00451) = curr_y;
123 #endif
124 
125     place(curr_x, curr_y);
126     cursor(curr_start, curr_end);
127 }
128 
window(int x1,int y1,int x2,int y2)129 void window(int x1, int y1, int x2, int y2) {
130     view_window.x1 = x1;
131     view_window.y1 = y1;
132     view_window.x2 = x2;
133     view_window.y2 = y2;
134 
135     //place(x1, y1);
136 }
137 
_clear(char c,char attr,int x1,int y1,int x2,int y2)138 void _clear(char c,char attr,int x1,int y1,int x2,int y2) {
139     register int i,j;
140     unsigned short w = attr;
141 
142     w <<= 8;
143     w |= c;
144     for (i = x1; i <= x2; i++) {
145         for (j = y1; j <= y2; j++) {
146             *((unsigned short *)(uintptr_t)(FB + 2*i+160*j + 2 * active_page * VPAGE_SIZE)) = w;
147         }
148     }
149 
150     place(x1,y1);
151     curr_y = y1;
152     curr_x = x1;
153 }
154 
clear()155 void clear() {
156     _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2,
157            view_window.y2);
158 }
159 
_scroll(char attr,int x1,int y1,int x2,int y2)160 void _scroll(char attr, int x1, int y1, int x2, int y2) {
161     register int x,y;
162     unsigned short xattr = attr << 8,w;
163     unsigned char *v = (unsigned char *)(uintptr_t)(FB + active_page*(2*VPAGE_SIZE));
164 
165     for (y = y1+1; y <= y2; y++) {
166         for (x = x1; x <= x2; x++) {
167             w = *((unsigned short *) (v + 2*(y*80+x)));
168             *((unsigned short *)(v + 2*((y-1)*80+x))) = w;
169         }
170     }
171 
172     for (x = x1; x <= x2; x++) {
173         *((unsigned short *)(v + 2*((y-1)*80+x))) = xattr;
174     }
175 }
176 
scroll(void)177 void scroll(void) {
178     _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2,
179             view_window.y2);
180 }
181 
cputc(char c)182 void cputc(char c) {
183     static unsigned short scan_x, x, y;
184     unsigned char *v = (unsigned char *)(uintptr_t)(FB + active_page*(2*VPAGE_SIZE));
185     x = curr_x;
186     y = curr_y;
187 
188     switch (c) {
189         case '\t':
190             x += 8;
191             if (x >= view_window.x2+1) {
192                 x = view_window.x1;
193                 if (y == view_window.y2) {
194                     scroll();
195                 } else {
196                     y++;
197                 }
198             } else {
199                 scan_x = 0;
200 
201                 while ((scan_x+8) < x) {
202                     scan_x += 8;
203                 }
204 
205                 x = scan_x;
206             }
207             break;
208 
209         case '\r':
210             x = view_window.x1;
211             break;
212 
213         case '\n':
214             if (y == view_window.y2) {
215                 scroll();
216             } else {
217                 y++;
218             }
219             break;
220 
221         case '\b':
222             x--;
223             *(v + 2*(x + y*80)) = ' ';
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 = vsprintf(cbuf, fmt, parms);
276     va_end(parms);
277 
278     puts_xy(x, y, attr, cbuf);
279 
280     return result;
281 }
282