forked from ReKernel/ReKernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvga.c
More file actions
executable file
·114 lines (99 loc) · 3.53 KB
/
vga.c
File metadata and controls
executable file
·114 lines (99 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "vga.h"
#define VGA_BUF ((volatile uint16_t *)0xB8000)
#define COLS 80
#define ROWS 25
static int row, col;
static uint8_t cur_colour;
static uint8_t make_colour(vga_colour_t fg, vga_colour_t bg) {
return (uint8_t)((bg << 4) | fg);
}
static uint16_t make_entry(char c, uint8_t colour) {
return (uint16_t)((uint16_t)colour << 8 | (uint8_t)c);
}
/* Move hardware cursor via VGA CRTC registers */
static void update_cursor(void) {
uint16_t pos = (uint16_t)(row * COLS + col);
__asm__ volatile (
"outb %0, %1" :: "a"((uint8_t)0x0F), "Nd"((uint16_t)0x3D4));
__asm__ volatile (
"outb %0, %1" :: "a"((uint8_t)(pos & 0xFF)), "Nd"((uint16_t)0x3D5));
__asm__ volatile (
"outb %0, %1" :: "a"((uint8_t)0x0E), "Nd"((uint16_t)0x3D4));
__asm__ volatile (
"outb %0, %1" :: "a"((uint8_t)((pos >> 8) & 0xFF)), "Nd"((uint16_t)0x3D5));
}
static void scroll(void) {
if (row < ROWS) return;
for (int r = 1; r < ROWS; r++)
for (int c = 0; c < COLS; c++)
VGA_BUF[(r-1)*COLS+c] = VGA_BUF[r*COLS+c];
for (int c = 0; c < COLS; c++)
VGA_BUF[(ROWS-1)*COLS+c] = make_entry(' ', cur_colour);
row = ROWS - 1;
}
void vga_init(void) {
cur_colour = make_colour(VGA_LIGHT_GREY, VGA_BLACK);
vga_clear();
}
void vga_set_colour(vga_colour_t fg, vga_colour_t bg) {
cur_colour = make_colour(fg, bg);
}
void vga_clear(void) {
for (int i = 0; i < ROWS * COLS; i++)
VGA_BUF[i] = make_entry(' ', cur_colour);
row = col = 0;
update_cursor();
}
void vga_putchar(char c) {
if (c == '\n') { col = 0; row++; }
else if (c == '\r') { col = 0; }
else if (c == '\b') {
if (col > 0) { col--; VGA_BUF[row*COLS+col] = make_entry(' ', cur_colour); }
} else if (c == '\t') {
col = (col + 8) & ~7;
if (col >= COLS) { col = 0; row++; }
} else {
VGA_BUF[row*COLS+col] = make_entry(c, cur_colour);
if (++col >= COLS) { col = 0; row++; }
}
scroll();
update_cursor();
}
void vga_puts(const char *s) {
while (*s) vga_putchar(*s++);
}
/* ── Minimal printf (%c %s %d %u %x) ─────────────────────────────────────── */
/* va_list implementation for -ffreestanding */
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_arg(v,l) __builtin_va_arg(v,l)
#define va_end(v) __builtin_va_end(v)
static void print_uint(uint32_t n, uint32_t base) {
const char *digits = "0123456789abcdef";
char buf[32];
int i = 0;
if (n == 0) { vga_putchar('0'); return; }
while (n) { buf[i++] = digits[n % base]; n /= base; }
while (i--) vga_putchar(buf[i]);
}
static void print_int(int32_t n) {
if (n < 0) { vga_putchar('-'); print_uint((uint32_t)(-n), 10); }
else print_uint((uint32_t)n, 10);
}
void vga_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
for (; *fmt; fmt++) {
if (*fmt != '%') { vga_putchar(*fmt); continue; }
switch (*++fmt) {
case 'c': vga_putchar((char)va_arg(args, int)); break;
case 's': vga_puts(va_arg(args, const char *)); break;
case 'd': print_int(va_arg(args, int32_t)); break;
case 'u': print_uint(va_arg(args, uint32_t), 10); break;
case 'x': print_uint(va_arg(args, uint32_t), 16); break;
case '%': vga_putchar('%'); break;
default: vga_putchar('?'); break;
}
}
va_end(args);
}