aboutsummaryrefslogtreecommitdiff
path: root/kernel/l0/dbglog.c
blob: e0426258da67f959a31630c7a7f897f16605fd72 (plain) (blame)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <stdarg.h>
#include <string.h>
#include <printf.h>
#include <mutex.h>

#include <dbglog.h>
#include <config.h>
#include <sys.h>

// ==================================================================

#ifdef DBGLOG_TO_SCREEN

static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;

static uint8_t vga_color = 7;
static uint16_t* vga_buffer = 0;
static uint16_t vga_row = 0, vga_column = 0;

static uint16_t make_vgaentry(char c, uint8_t color) {
	uint16_t c16 = c;
	uint16_t color16 = color;
	return c16 | color16 << 8;
}

static void vga_putentryat(char c, uint8_t color, size_t x, size_t y) {
	const size_t index = y * VGA_WIDTH + x;
	vga_buffer[index] = make_vgaentry(c, color);
}

static void vga_update_cursor() {
	uint16_t cursor_location = vga_row * 80 + vga_column;
	outb(0x3D4, 14);	//Sending high cursor byte
	outb(0x3D5, cursor_location >> 8);
	outb(0x3D4, 15);	//Sending high cursor byte
	outb(0x3D5, cursor_location);
}
 
static void vga_init() {
	vga_row = 0;
	vga_column = 0;
	vga_buffer = (uint16_t*) (K_HIGHHALF_ADDR + 0xB8000);

	for (size_t y = 0; y < VGA_HEIGHT; y++) {
		for (size_t x = 0; x < VGA_WIDTH; x++) {
			vga_putentryat(' ', vga_color, x, y);
		}
	}

	vga_update_cursor();
}

static void vga_scroll() {
	for (size_t i = 0; i < VGA_WIDTH * (VGA_HEIGHT - 1); i++) {
		vga_buffer[i] = vga_buffer[i + VGA_WIDTH];
	}
	for (size_t x = 0; x < VGA_WIDTH; x++) {
		vga_putentryat(' ', vga_color, x, VGA_HEIGHT - 1);
	}
	vga_row--;
}

static void vga_newline() {
	vga_column = 0;
	if (++vga_row == VGA_HEIGHT) {
		vga_scroll();
	}
}
 
static void vga_putc(char c) {
	if (c == '\n') {
		vga_newline();
	} else if (c == '\t') {
		vga_putc(' ');
		while (vga_column % 4 != 0) vga_putc(' ');
	} else {
		vga_putentryat(c, vga_color, vga_column, vga_row);
		if (++vga_column == VGA_WIDTH) {
			vga_newline();
		}
	}
}
 
static void vga_puts(const char* data) {
	size_t datalen = strlen(data);
	for (size_t i = 0; i < datalen; i++)
		vga_putc(data[i]);

	vga_update_cursor();
}

#endif	// DBGLOG_TO_SCREEN

// ==================================================================

#ifdef DBGLOG_TO_SERIAL

#define SER_PORT 0x3F8		// COM1

static void serial_init() {
	outb(SER_PORT + 1, 0x00);		// disable interrupts
	outb(SER_PORT + 3, 0x80);		// set baud rate
	outb(SER_PORT + 0, 0x03);		// set divisor to 3 (38400 baud)
	outb(SER_PORT + 1, 0x00);
	outb(SER_PORT + 3, 0x03);		// 8 bits, no parity, one stop bit
	outb(SER_PORT + 2, 0xC7);		// enable FIFO, clear them, with 14-byte threshold
}

static void serial_putc(const char c) {
	while (!(inb(SER_PORT + 5) & 0x20));
	outb(SER_PORT, c);
}

static void serial_puts(const char *c) {
	while (*c) {
		serial_putc(*c);
		c++;
	}
}

#endif	// DBGLOG_TO_SERIAL

// ==================================================================

STATIC_MUTEX(dbglog_mutex);

void dbglog_setup() {
	mutex_lock(&dbglog_mutex);
#ifdef DBGLOG_TO_SCREEN
	vga_init();
#endif
#ifdef DBGLOG_TO_SERIAL
	serial_init();
#endif
	mutex_unlock(&dbglog_mutex);
}

void dbg_print(const char* str) {
#ifdef DBGLOG_TO_SCREEN
	vga_puts(str);
#endif
#ifdef DBGLOG_TO_SERIAL
	serial_puts(str);
#endif
}

void dbg_printf(const char* fmt, ...) {
	va_list ap;
	char buffer[256];

	va_start(ap, fmt);
	vsnprintf(buffer, 256, fmt, ap);
	va_end(ap);

	dbg_print(buffer);
}

/* vim: set ts=4 sw=4 tw=0 noet :*/