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