-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkernel.c
244 lines (199 loc) · 6.07 KB
/
kernel.c
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
My first attempt at writing some sort of kernel in C. Parts of it work, parts of it don't.
Real mode bootloader loads 64 sectors in memory (512 bytes/sector) using int 13h, switches to protected mode then hands
control to the "first stage" kernel which sets up the segment registers and stack and then hands control to this particular code.
Entry point is void main() (located at physical address 0x8000).
*/
#include <stdint.h>
/* Memory related constants */
#define COMMAND_BUFFER 0x7C00
#define VGA_MEM_START 0xB8000
#define MAIN_ENTRY_POINT 0x8000 // We're being loaded at this particular address
/* Graphics related constants */
/* NOTE: Don't change the location of the main void in this file and don't define any functions above it, the first stage kernel won't be able to jump to it if you do so */
void main()
{
draw_rectangle(0x7f, 70, 20, 5, 2);
write_message(&"TovOS v0.0.1a", 0x1f, 3, 33);
write_message(&">", 0x1f, 5, 6);
update_cursor(6 + strlen(&">\0"), 5);
char *buffer = (char *) COMMAND_BUFFER; // We'll try to store a string at this address
while(1)
{
wait_key(buffer);
}
}
/* Utility functions */
/* NOTE: What I define here as "string" are actually series (strings) of bytes */
/* Compares two strings located at given addresses */
/* Strings must be null terminated. Returns true if strings are equal, false if not. Case sensitive */
int strcmp(char *str1, char *str2)
{
while(*str1 && *str2)
{
if(*str1 != *str2){
return 0;
}
str1++;
str2++;
}
return 1;
}
/* Returns the length of a null-terminated string starting at addr */
int strlen(char *addr)
{
int len = 0;
while(*addr)
{
len++;
addr++;
}
return len;
}
/* I/O functions */
/* Reads data from given I/O port - uses inline assembly */
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ("inb %1, %0"
:"=a"(ret)
:"Nd"(port));
return ret;
}
/* Writes data at give I/O port - uses inline assembly */
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
/* VGA Specific functions */
void disable_cursor()
{
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
}
void update_cursor(int x, int y)
{
uint16_t pos = y * 80 + x;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t) (pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
}
/* Prints a null terminated string located at specified address */
void write_message(char *msg_address, int color, int row, int column)
{
volatile uint16_t * location = (volatile uint16_t *) VGA_MEM_START + (80 * row + column);
while(*msg_address)
{
*location = *msg_address | (color << 8);
location++;
msg_address++;
}
}
void write_char(char *c, int row, int column)
{
volatile uint16_t * location = (volatile uint16_t *) VGA_MEM_START + (80 * row + column);
*location = *c | (0x1F << 8);
}
/* Draws a rectangle in text mode using blank characters */
void draw_rectangle(uint8_t color, int length, int height, int start_x, int start_y)
{
volatile uint16_t * location = (volatile uint16_t *) VGA_MEM_START + (80 * start_y + start_x);
for(int i = 0; i < height; i++) // Treat it as a matrix
{
for(int j = 0; j < length; j++)
{
if(i == 0 | i == (height - 1) | j == 0 | j == length - 1)
{
*(location + j + i * 80) = ' ' | (color << 8);
}
else
{
*(location + j + i * 80) = ' ' | (0x1f << 8);
}
}
}
}
/* Clears the text buffer */
void clear_text_buffer()
{
char *buffer = (char *) COMMAND_BUFFER;
while(*buffer)
{
*buffer = 0x00;
buffer++;
}
}
void wait_key(char *buffer)
{
char k;
char k_old_state = inb(0x60);
int x = 7;
int y = 5;
char kbd_US [128] = // Keyboard map found on https://stackoverflow.com/questions/61124564/convert-scancodes-to-ascii
{
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', /* <-- Tab */
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
0, /* <-- control key */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
'*',
0, /* Alt */
' ', /* Space bar */
0, /* Caps lock */
0, /* 59 - F1 key ... > */
0, 0, 0, 0, 0, 0, 0, 0,
0, /* < ... F10 */
0, /* 69 - Num lock*/
0, /* Scroll Lock */
0, /* Home key */
0, /* Up Arrow */
0, /* Page Up */
'-',
0, /* Left Arrow */
0,
0, /* Right Arrow */
'+',
0, /* 79 - End key*/
0, /* Down Arrow */
0, /* Page Down */
0, /* Insert Key */
0, /* Delete Key */
0, 0, 0,
0, /* F11 Key */
0, /* F12 Key */
0, /* All other keys are undefined */
};
while((k = inb(0x60)) < 128)
{
if(k != k_old_state && kbd_US[k] != 0) // Something's changed
{
k_old_state = k;
if(k == 28){
*buffer = 0x00;
if(strcmp(buffer, &"print\0")){
write_message(&"Printed", 0x1f, y, x);
}
clear_text_buffer();
buffer = (char *) COMMAND_BUFFER;
}
else {
*buffer = kbd_US[k];
buffer++;
*buffer = 0x00;
write_char(&kbd_US[k], y, x);
x++;
}
if(x == 73)
{
x = 7;
y++;
}
if(y == 20)
{
y = 3;
}
update_cursor(x, y);
}
}
}