LF OS
Hobby operating system for amd64 with high ambitions
Loading...
Searching...
No Matches
string.c
Go to the documentation of this file.
1#include <stdint.h>
2#include <stdbool.h>
3#include <string.h>
4#include <efi.h>
5
6static bool uart_out = false;
7static EFI_SYSTEM_TABLE* st;
8EFI_BOOT_SERVICES* BS;
9
10static void outb(uint16_t port, uint8_t data) {
11 asm volatile("outb %0, %1"::"a"(data), "d"(port));
12}
13
14static uint8_t inb(uint16_t port) {
15 uint8_t data = 0;
16 asm volatile("inb %1, %0":"=a"(data):"d"(port));
17 return data;
18}
19
20static int is_transmit_empty() {
21 return inb(0x3F8 + 5) & 0x20;
22}
23
24static void uart_write(char* msg, size_t len) {
25 for(size_t i = 0; i < len; ++i) {
26 if(msg[i] == '\n') {
27 while(!is_transmit_empty()) { }
28 outb(0x3F8, '\r');
29 }
30
31 while(!is_transmit_empty()) { }
32 outb(0x3F8, msg[i]);
33 }
34}
35
36static void conwrite(CHAR16* s) {
37 st->ConOut->OutputString(st->ConOut, s);
38
39 size_t len = wcslen(s);
40 char* msg = malloc(len + 1);
41 len = wcstombs(msg, s, len);
42
43 if(len > 1 && len != (size_t)-1) {
44 if(uart_out) {
45 uart_write(msg, len - 1);
46 }
47 }
48
49 free(msg);
50}
51
52void* memset(void* s, int c, size_t n) {
53 for(size_t i = 0; i < n; ++i) {
54 *((char*)s + i) = c;
55 }
56
57 return s;
58}
59
60void* memcpy(void* dest, const void* src, size_t n) {
61 for(size_t i = 0; i < n; ++i) {
62 *((char*)dest + i) = *((char*)src + i);
63 }
64
65 return dest;
66}
67
68int memcmp(const void* a, const void* b, size_t n) {
69 for(size_t i = 0; i < n; ++i) {
70 int diff = ((const char*)a)[i] - ((const char*)b)[i];
71
72 if(diff) {
73 return diff;
74 }
75 }
76
77 return 0;
78}
79
80size_t strlen(const char* s) {
81 size_t len = 0;
82 while(s[len++]);
83 return len - 1;
84}
85
86size_t strcpy(char* d, const char* s) {
87 size_t len = 0;
88 while(s[len]) {
89 d[len] = s[len];
90 ++len;
91 }
92 return len;
93}
94
95size_t wcslen(const CHAR16* s) {
96 size_t len = 0;
97 while(s[len++]);
98 return len - 1;
99}
100
101int wcscpy(CHAR16* d, const CHAR16* s) {
102 size_t len = 0;
103 while(s[len]) {
104 d[len] = s[len];
105 ++len;
106 }
107 return len;
108}
109
110int wcscmp(const CHAR16* s1, const CHAR16* s2) {
111 size_t i = 0;
112 while(*(s1 + i) && *(s1 + i) == *(s2 + i)) {
113 ++i;
114 }
115
116 return *(s2 + i) - *(s1 + i);
117}
118
119CHAR16 towlower(CHAR16 c) {
120 if(c >= 'a' && c <= 'z') {
121 return c - ('a' - 'A');
122 }
123
124 return c;
125}
126
127int wcscasecmp(const CHAR16* s1, const CHAR16* s2) {
128 size_t i = 0;
129 while(s1[i] && s2[i]) {
130 CHAR16 a = s1[i];
131 CHAR16 b = s2[i];
132
133 ++i;
134
135 if(
136 (a != b) &&
137 (towlower(a) != towlower(b))
138 ) {
139 break;
140 }
141 }
142
143 return *(s2 + i) - *(s1 + i);
144}
145
146
147size_t wcstombs(char* dest, const CHAR16* src, size_t n) {
148 size_t len = wcslen(src);
149 size_t i;
150 for(i = 0; i < len && i < n; ++i) {
151 CHAR16 c = src[i];
152
153 if(c > 127) {
154 return (size_t)-1;
155 }
156
157 if(dest) {
158 dest[i] = c;
159 }
160 }
161
162 if(i < n - 1) {
163 dest[i++] = 0;
164 }
165
166 return i;
167}
168
169void* malloc(size_t size) {
170 void* mem;
171 if(BS->AllocatePool(EfiLoaderData, size + sizeof(size_t), &mem) == EFI_SUCCESS) {
172 *(size_t*)mem = size;
173 return mem + sizeof(size_t);
174 }
175 else {
176 return 0;
177 }
178}
179
180void free(void* ptr) {
181 BS->FreePool(ptr - sizeof(size_t));
182}
183
184void* realloc(void* ptr, size_t size) {
185 if(!ptr) {
186 return malloc(size);
187 }
188
189 size_t orig = *(size_t*)(ptr - sizeof(size_t));
190 void* new = malloc(size);
191 memcpy(new, ptr, orig);
192 free(ptr);
193 return new;
194}
195
196size_t wprintui(unsigned long long int i, unsigned char base) {
197 const CHAR16* chars = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
198
199 const size_t buffer_size = 65;
200 CHAR16 buffer[buffer_size];
201 buffer[buffer_size - 1] = 0;
202
203 size_t len = 0;
204
205 do {
206 buffer[buffer_size - 1 -++len] = chars[i % base];
207 i /= base;
208 } while(i);
209
210 conwrite(buffer + (buffer_size - len) - 1);
211
212 return len;
213}
214
215size_t wprinti(long long int i, unsigned char base) {
216 int neg = i < 0;
217
218 if(neg) {
219 i *= -1;
220 conwrite(L"-");
221 }
222
223 return wprintui(i, base) + (neg ? 1 : 0);
224}
225
226int wprintf(const CHAR16* fmt, ...) {
227 __builtin_va_list args;
228 __builtin_va_start(args, fmt);
229
230 CHAR16 c;
231 int placeholder = 0;
232 int long_counter = 0;
233 size_t i = 0;
234 size_t len = 0;
235 while((c = *(fmt + i))) {
236 ++i;
237
238 if(!placeholder) {
239 if(c == '%') {
240 placeholder = 1;
241 }
242 else if(c == '\n') {
243 conwrite(L"\r\n");
244 len += 2;
245 }
246 else {
247 len += 1;
248 CHAR16 buffer[2];
249 buffer[0] = c;
250 buffer[1] =0;
251 conwrite(buffer);
252 }
253 }
254 else {
255 switch(c) {
256 case '%':
257 conwrite(L"%");
258 ++len;
259 break;
260 case 'b':
261 CHAR16* b = __builtin_va_arg(args, int) ? L"true" : L"false";
262 conwrite(b);
263 len += wcslen(b);
264 break;
265 case 's':
266 CHAR16* s = __builtin_va_arg(args, CHAR16*);
267 conwrite(s);
268 len += wcslen(s);
269 break;
270 case 'u':
271 unsigned long long int u;
272
273 if(long_counter == 2) {
274 u = __builtin_va_arg(args, unsigned long long int);
275 }
276 else {
277 u = __builtin_va_arg(args, unsigned int);
278 }
279
280 len += wprintui(u, 10);
281 break;
282 case 'd':
283 long long int d;
284
285 if(long_counter == 2) {
286 d = __builtin_va_arg(args, long long int);
287 }
288 else {
289 d = __builtin_va_arg(args, int);
290 }
291
292 len += wprinti(d, 10);
293 break;
294 case 'x':
295 long long int x;
296
297 if(long_counter == 2) {
298 x = __builtin_va_arg(args, long long int);
299 }
300 else {
301 x = __builtin_va_arg(args, int);
302 }
303
304 len += wprintui(x, 16);
305 break;
306 case 'l':
307 ++long_counter;
308 continue;
309 }
310
311 placeholder = 0;
312 }
313 }
314
315 __builtin_va_end(args);
316 return len;
317}
318
319static void init_uart() {
320 // stolen from osdev
321 outb(0x3F8 + 1, 0x00); // Disable all interrupts
322 outb(0x3F8 + 3, 0x80); // Enable DLAB (set baud rate divisor)
323 outb(0x3F8 + 0, 0x0c); // Set divisor to 12 (lo byte) 9600 baud
324 outb(0x3F8 + 1, 0x00); // (hi byte)
325 outb(0x3F8 + 3, 0x03); // 8 bits, no parity, one stop bit
326
327 outb(0x3F8 + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold
328
329 // configure for loopback and check if actually present
330 uint8_t mcr = inb(0x3F8 + 4);
331
332 outb(0x3F8 + 4, mcr | 0x10); // Set to loopback mode
333 outb(0x3F8 + 0, '\n'); // send LF and read it back next line
334 if(inb(0x3F8) == '\n') {
335 outb(0x3F8 + 4, mcr); // configure for normal operation
336
337 // .. some firmwares already log everything to serial already but I
338 // don't have a way to recognize this so I had the workaround to check
339 // if the vendor is "EDK II", since all of those seem to do that and
340 // good enough for debugging - but then Debian decided to change the
341 // vendor string, annoying me in my test runs so this test is now
342 // awfully specific.
343 if(wcscmp(st->FirmwareVendor, L"Debian distribution of EDK II") != 0) {
344 uart_out = true;
345 }
346
347 wprintf(L"UART configured and output%senabled\n", uart_out ? L" " : L" NOT ");
348 wprintf(L"Firmware vendor: %s\n", st->FirmwareVendor);
349 }
350}
351
352void init_stdlib(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE* system_table) {
353 st = system_table;
354 BS = st->BootServices;
355 st->ConOut->ClearScreen(st->ConOut);
356
357 init_uart();
358}
uint64_t size_t
Definition arch.h:18
unsigned short uint16_t
Definition arch.h:8
unsigned char uint8_t
Definition arch.h:5
size_t strlen(const char *str)
Definition string.c:30
void * memcpy(void *dest, void const *source, size_t size)
Definition string.c:80
void * memset(void *dest, int c, size_t size)
Definition string.c:72
int memcmp(const void *a, const void *b, size_t n)
Definition string.c:91
size_t wcslen(const wchar_t *str)
Definition string.c:54
static uint8_t inb(uint16_t port)
Definition string.c:14
static void conwrite(CHAR16 *s)
Definition string.c:36
static EFI_SYSTEM_TABLE * st
Definition string.c:7
static void init_uart()
Definition string.c:319
EFI_BOOT_SERVICES * BS
Definition string.c:8
size_t wprinti(long long int i, unsigned char base)
Definition string.c:215
CHAR16 towlower(CHAR16 c)
Definition string.c:119
size_t wprintui(unsigned long long int i, unsigned char base)
Definition string.c:196
static bool uart_out
Definition string.c:6
static void outb(uint16_t port, uint8_t data)
Definition string.c:10
void * malloc(size_t size)
Definition string.c:169
size_t strcpy(char *d, const char *s)
Definition string.c:86
int wprintf(const CHAR16 *fmt,...)
Definition string.c:226
void init_stdlib(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
Definition string.c:352
int wcscpy(CHAR16 *d, const CHAR16 *s)
Definition string.c:101
void * realloc(void *ptr, size_t size)
Definition string.c:184
size_t wcstombs(char *dest, const CHAR16 *src, size_t n)
Definition string.c:147
int wcscmp(const CHAR16 *s1, const CHAR16 *s2)
Definition string.c:110
static int is_transmit_empty()
Definition string.c:20
static void uart_write(char *msg, size_t len)
Definition string.c:24
int wcscasecmp(const CHAR16 *s1, const CHAR16 *s2)
Definition string.c:127
void free(void *ptr)
Definition string.c:180
uint16_t size
Size of the loaded file.
Definition loader.h:5
uint64_t base
Definition sc.c:1