blob: 394d9c8399959ff55feb9a106c70b914273affaa [file] [log] [blame]
swissChilid8137922021-02-17 15:34:07 -08001#include "vga.h"
swissChili9b3584b2021-02-18 13:57:27 -08002#include "io.h"
swissChilidc25b2b2021-02-23 17:07:13 -08003#include "paging.h"
swissChili0b35bf22021-02-18 12:49:40 -08004#include "log.h"
swissChilid8137922021-02-17 15:34:07 -08005
6static uint cursor_x = 0;
7static uint cursor_y = 0;
8
swissChili9bd74de2021-06-15 20:30:48 -07009static uchar color = WHITE;
swissChilid8137922021-02-17 15:34:07 -080010
swissChilidc25b2b2021-02-23 17:07:13 -080011static ushort *fb = (ushort *)PHYS_TO_VIRT(0xB8000);
swissChilid8137922021-02-17 15:34:07 -080012
swissChili9bd74de2021-06-15 20:30:48 -070013#define BUFFER_SIZE 16
14static char buffer[BUFFER_SIZE];
15static uint buffer_index = 0;
16static bool in_escape = false;
17
swissChilid8137922021-02-17 15:34:07 -080018static void move_cursor()
19{
swissChilidc25b2b2021-02-23 17:07:13 -080020 ushort pos = cursor_y * 80 + cursor_x;
swissChilid8137922021-02-17 15:34:07 -080021
swissChilidc25b2b2021-02-23 17:07:13 -080022 outb(0x3d4, 0x0e);
23 outb(0x3d5, pos >> 8);
24 outb(0x3d4, 0x0f);
25 outb(0x3d5, pos & 0xff);
swissChilid8137922021-02-17 15:34:07 -080026}
27
28static void scroll()
29{
30 ushort blank = ' ' | color << 8;
31
32 while (cursor_y >= 25) // end of line
33 {
34 // scroll everything up
35 memcpy(fb, &fb[80], 24 * 80 * 2);
36
37 for (int i = 24 * 80; i < 25 * 80; i++)
38 {
39 fb[i] = blank;
40 }
41
42 cursor_y--;
43 }
44}
45
46void vga_set_color(enum vga_colors fg, enum vga_colors bg)
47{
swissChilidc25b2b2021-02-23 17:07:13 -080048 color = (bg << 4) | (fg & 0xf);
swissChilid8137922021-02-17 15:34:07 -080049}
50
swissChili9bd74de2021-06-15 20:30:48 -070051void got_escape()
52{
53 if (buffer[0] != '[')
54 return;
55
56 int c = parse_int(buffer+1);
57
58 static const char ansi_to_vga_colors[] =
59 {
60 [30] = BLACK,
61 RED,
62 GREEN,
63 LIGHT_BROWN,
64 BLUE,
65 MAGENTA,
66 CYAN,
67 WHITE,
68 [90] = LIGHT_GREY,
69 LIGHT_RED,
70 LIGHT_GREEN,
71 LIGHT_BROWN,
72 LIGHT_BLUE,
73 LIGHT_MAGENTA,
74 LIGHT_CYAN,
75 WHITE,
76 };
77
78 if (c == 0)
79 {
80 color = WHITE;
81 }
82 else if ((c >= 30 && c <= 37) || (c >= 90 && c <= 97))
83 {
84 color &= 0xf0;
85 color |= ansi_to_vga_colors[c];
86 }
87 else if ((c >= 40 && c <= 47) || (c >= 100 && c <= 107))
88 {
89 color &= 0x0f;
90 color |= ansi_to_vga_colors[c - 10] << 4;
91 }
92}
93
swissChilid8137922021-02-17 15:34:07 -080094void vga_put(char c)
95{
swissChili9bd74de2021-06-15 20:30:48 -070096 if (in_escape)
97 {
98 if (buffer_index >= BUFFER_SIZE || c == 'm')
99 {
100 // For now we are only supporting color escape sequences.
101 if (c == 'm')
102 got_escape();
103
104 // Escape sequence is too long, sorry. Failing silently.
105 in_escape = false;
106 buffer_index = 0;
107 memset(buffer, 0, sizeof(buffer));
108 }
109 else
110 {
111 buffer[buffer_index++] = c;
112 }
113
114 return;
115 }
116
swissChilid8137922021-02-17 15:34:07 -0800117 switch (c)
118 {
119 case '\b':
120 if (cursor_x > 0)
121 cursor_x--;
swissChili19ef4182021-02-21 17:45:51 -0800122 fb[cursor_y * 80 + cursor_x] = ' ' | (color << 8);
swissChilid8137922021-02-17 15:34:07 -0800123 break;
124 case '\t':
swissChili825d46b2021-02-21 10:14:16 -0800125 cursor_x = (cursor_x + 8) & ~7;
swissChilid8137922021-02-17 15:34:07 -0800126 break;
127 case '\n':
128 cursor_y++;
129 case '\r':
130 cursor_x = 0;
131 break;
swissChili9bd74de2021-06-15 20:30:48 -0700132 case 033:
133 in_escape = true;
134 break;
swissChilid8137922021-02-17 15:34:07 -0800135 default:
swissChilid8137922021-02-17 15:34:07 -0800136 fb[cursor_y * 80 + cursor_x] = c | (color << 8);
swissChili19ef4182021-02-21 17:45:51 -0800137 cursor_x++;
swissChilid8137922021-02-17 15:34:07 -0800138 }
139
140 if (cursor_x >= 80) // off screen
141 {
142 cursor_x = 0;
143 cursor_y++;
144 }
145
146 scroll();
147 move_cursor();
148}
149
150void vga_clear()
151{
swissChili959aa8a2021-02-23 19:43:00 -0800152 for (int i = 0; i < 25 * 80; i++)
153 {
154 fb[i] = ' ' | (WHITE << 8);
155 }
156
swissChilid8137922021-02-17 15:34:07 -0800157 cursor_x = 0;
158 cursor_y = 0;
159 move_cursor();
160}
161
162void vga_write(char *c)
163{
164 for (int i = 0; c[i]; i++)
165 vga_put(c[i]);
166}
167
168void vga_putd(uint d)
169{
swissChili0b35bf22021-02-18 12:49:40 -0800170 char str[48];
171 memset(str, 0, 48);
172 uint i = 0;
173
swissChilidefeb0d2021-02-18 15:28:36 -0800174 do
swissChili0b35bf22021-02-18 12:49:40 -0800175 {
176 str[i++] = (d % 10) + '0';
177 d /= 10;
swissChili825d46b2021-02-21 10:14:16 -0800178 } while (d > 0 && i < 48); // should never be more than 48 digits anyway
swissChili0b35bf22021-02-18 12:49:40 -0800179
180 for (uint j = i; j; j--)
181 {
182 vga_put(str[j - 1]);
183 }
swissChilid8137922021-02-17 15:34:07 -0800184}
185
swissChili0b35bf22021-02-18 12:49:40 -0800186static bool vga_put_nibble(uchar n, bool first)
swissChilid8137922021-02-17 15:34:07 -0800187{
swissChilidc25b2b2021-02-23 17:07:13 -0800188 // if (first && n == 0)
189 // return true;
swissChili825d46b2021-02-21 10:14:16 -0800190
swissChilid8137922021-02-17 15:34:07 -0800191 if (n <= 9)
192 vga_put('0' + n);
193 else
194 vga_put('A' + n - 10);
swissChili0b35bf22021-02-18 12:49:40 -0800195
196 return false;
swissChilid8137922021-02-17 15:34:07 -0800197}
198
199void vga_putx(uint x)
200{
swissChili825d46b2021-02-21 10:14:16 -0800201 bool first = false;
swissChili0b35bf22021-02-18 12:49:40 -0800202
swissChili825d46b2021-02-21 10:14:16 -0800203 for (int shift = 24; shift >= 0; shift -= 8)
swissChilid8137922021-02-17 15:34:07 -0800204 {
swissChili825d46b2021-02-21 10:14:16 -0800205 uchar byte = x >> shift;
swissChilid8137922021-02-17 15:34:07 -0800206
swissChili825d46b2021-02-21 10:14:16 -0800207 first = vga_put_nibble((byte & 0xf0) >> 4, first);
swissChili0b35bf22021-02-18 12:49:40 -0800208 first = vga_put_nibble(byte & 0x0f, first);
swissChilid8137922021-02-17 15:34:07 -0800209 }
210}
swissChilidc25b2b2021-02-23 17:07:13 -0800211
212void init_vga()
213{
swissChili959aa8a2021-02-23 19:43:00 -0800214 // Enable and set max scan line
215 outb(0x3D4, 0x09);
swissChilidc25b2b2021-02-23 17:07:13 -0800216 outb(0x3D5, 15);
217
swissChili959aa8a2021-02-23 19:43:00 -0800218 // Cursor end line
219 outb(0x3D4, 0x0B);
swissChilidc25b2b2021-02-23 17:07:13 -0800220 outb(0x3D5, 15);
221
swissChili959aa8a2021-02-23 19:43:00 -0800222 // Cursor start line
223 outb(0x3D4, 0x0A);
224 outb(0x3D5, 14);
swissChilidc25b2b2021-02-23 17:07:13 -0800225}