My Project
Loading...
Searching...
No Matches
gop.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: GOP Driver to draw onto screen Implementation (8×16 font)
5 */
6
7#include "gop.h"
8#define FONT8X16_IMPLEMENTATION
9#include "font8x16.h"
11#include "../../includes/me.h"
13
14 // integer font scale (1 = native 8×16, 2 = 16×32, etc)
15#define FONT_SCALE 1
16
17volatile void* ExclusiveOwnerShip = NULL;
18
19static inline bool gop_params_valid(const GOP_PARAMS* gop) {
20 if (!gop) return false;
21 if (!gop->FrameBufferBase) return false;
22 if (gop->Width == 0 || gop->Height == 0) return false;
23 if (gop->PixelsPerScanLine == 0) return false;
24 return true;
25}
26
27static inline void plot_pixel(GOP_PARAMS* gop, uint32_t x, uint32_t y, uint32_t color) {
28 if (!gop_params_valid(gop)) return;
29 if (x >= gop->Width || y >= gop->Height) return; // safeguard
30 uint32_t* fb = (uint32_t*)(uintptr_t)gop->FrameBufferBase;
31 uint32_t stride = gop->PixelsPerScanLine;
32 fb[y * stride + x] = color;
33}
34
35static inline uint32_t char_width(void) { return 8 * FONT_SCALE; }
36static inline uint32_t line_height(void) { return 16 * FONT_SCALE; }
37
38bool gop_bold_enabled = false; // default
39uint32_t cursor_x = 0, cursor_y = 0;
41
42static void draw_char(GOP_PARAMS* gop, char c_, uint32_t x, uint32_t y, uint32_t color) {
43 uint8_t c = (uint8_t)c_;
44 if (c > 0x7F) return;
45
46 const uint8_t* bitmap = font8x16[c];
47 for (int row = 0; row < 16; row++) {
48 uint8_t bits = bitmap[row];
49 for (int col = 0; col < 8; col++) {
50 // PSF bitmaps are MSB-first
51 if (!(bits & (1 << (7 - col))))
52 continue;
53
54 // scale each pixel up to FONT_SCALE×FONT_SCALE
55 for (int dy = 0; dy < FONT_SCALE; dy++) {
56 uint32_t py = y + row * FONT_SCALE + dy;
57 if (py >= gop->Height) continue;
58 for (int dx = 0; dx < FONT_SCALE; dx++) {
59 uint32_t px = x + col * FONT_SCALE + dx;
60 if (px < gop->Width) {
61 if (gop_bold_enabled) {
62 // ensure we do not write out of bounds when bold is enabled
63 if (px < gop->Width && py < gop->Height) plot_pixel(gop, px, py, color);
64 if ((px + 1) < gop->Width && py < gop->Height) plot_pixel(gop, px + 1, py, color);
65 if (px < gop->Width && (py + 1) < gop->Height) plot_pixel(gop, px, py + 1, color);
66 if ((px + 1) < gop->Width && (py + 1) < gop->Height) plot_pixel(gop, px + 1, py + 1, color);
67 }
68 else {
69 plot_pixel(gop, px, py, color);
70 }
71 }
72 }
73 }
74 }
75 }
76}
77
78static void draw_string(GOP_PARAMS* gop, const char* s, uint32_t x, uint32_t y, uint32_t color) {
79 while (*s) {
80 draw_char(gop, *s, x, y, color);
81 x += char_width();
82 s++;
83 }
84}
85
86static void fb_memmove32(uint32_t* dest, uint32_t* src, size_t count) {
87 if (dest < src) {
88 // forward copy
89 for (size_t i = 0; i < count; i++) dest[i] = src[i];
90 }
91 else if (dest > src) {
92 // backward copy
93 for (size_t i = count; i-- > 0; ) dest[i] = src[i];
94 }
95}
96
97static void gop_scroll(GOP_PARAMS* gop) {
98 uint32_t* fb = (uint32_t*)(uintptr_t)gop->FrameBufferBase;
99 uint32_t stride = gop->PixelsPerScanLine;
100 uint32_t h = gop->Height;
101 uint32_t w = gop->Width;
102 uint32_t lines = line_height();
103
104 // scroll up - removed kmemcpy as the gop is also used in the bugcheck, and kmemcpy has Max IRQL of DISPATCH_LEVEL, while a bugcheck is HIGH_LEVEL.
105 size_t count = (h - lines) * (size_t)stride;
106 fb_memmove32(&fb[0], &fb[lines * stride], count);
107
108 // clear bottom
109 for (uint32_t yy = h - lines; yy < h; yy++)
110 for (uint32_t xx = 0; xx < w; xx++)
111 fb[yy * stride + xx] = 0;
112
113 cursor_y = (cursor_y >= lines) ? (cursor_y - lines) : 0;
114}
115
116static void gop_put_char(GOP_PARAMS* gop, char c, uint32_t color) {
117 if (!gop_params_valid(gop)) return; // defensive
118 if (c == '\b') {
119 // move cursor back one character (and clear it)
120 if (cursor_x >= char_width()) {
121 cursor_x -= char_width();
122 }
123 else {
124 // if at start of line, wrap to end of previous line
125 if (cursor_y >= line_height()) {
126 cursor_y -= line_height();
127 cursor_x = gop->Width - char_width();
128 }
129 }
130 // clear the old glyph cell:
131 for (uint32_t yy = cursor_y; yy < cursor_y + line_height(); yy++) {
132 for (uint32_t xx = cursor_x; xx < cursor_x + char_width(); xx++) {
133 plot_pixel(gop, xx, yy, color);
134 }
135 }
136 return;
137 }
138 if (c == '\n') {
139 cursor_x = 0;
140 cursor_y += line_height();
141 if (cursor_y + line_height() > gop->Height) gop_scroll(gop);
142 return;
143 }
144 if (c == '\r') {
145 cursor_x = 0;
146 return;
147 }
148
149 draw_char(gop, c, cursor_x, cursor_y, color);
150 cursor_x += char_width();
151 if (cursor_x + char_width() > gop->Width) {
152 cursor_x = 0;
153 cursor_y += line_height();
154 if (cursor_y + line_height() > gop->Height) gop_scroll(gop);
155 }
156}
157
158static void gop_puts(GOP_PARAMS* gop, const char* s, uint32_t color) {
159 while (*s) {
160 gop_put_char(gop, *s++, color);
161 }
162}
163
164static void sprint_dec(char* buf, int64_t v) {
165 char* p = buf;
166
167 if (v == 0) {
168 *p++ = '0';
169 *p = 0;
170 return;
171 }
172
173 bool neg = false;
174 if (v < 0) {
175 neg = true;
176 v = -v;
177 }
178
179 char tmp[20];
180 int i = 0;
181
182 while (v > 0) {
183 tmp[i++] = '0' + (v % 10);
184 v /= 10;
185 }
186
187 if (neg) *p++ = '-';
188
189 while (i--) {
190 *p++ = tmp[i];
191 }
192
193 *p = 0;
194}
195
196
197static void gop_print_dec(GOP_PARAMS* gop, int64_t val, uint32_t color) {
198 char buf[20];
199 sprint_dec(buf, val);
200 gop_puts(gop, buf, color);
201}
202
203static void buf_print_udec64(char* buf, size_t size, size_t* written, uint64_t value);
204static void gop_print_udec(GOP_PARAMS* gop, uint64_t val, uint32_t color) {
205 char buf[32];
206 size_t written = 0;
207 buf_print_udec64(buf, sizeof(buf), &written, val);
208 gop_puts(gop, buf, color);
209}
210
211static void gop_print_hex(GOP_PARAMS* gop, uint64_t val, uint32_t color) {
212 char buf[19] = "0x0000000000000000"; // 64 bit addressing
213 for (int i = 0; i < 16; i++) {
214 unsigned nib = (val >> ((15 - i) * 4)) & 0xF;
215 buf[2 + i] = (nib < 10 ? '0' + nib : 'a' + nib - 10);
216 }
217 buf[18] = '\0'; // null terminator
218 gop_puts(gop, buf, color);
219}
220
221static void gop_print_hex_minimal(GOP_PARAMS* gop, uint64_t val, uint32_t color) {
222 if (val == 0) {
223 gop_puts(gop, "0x0", color);
224 return;
225 }
226
227 char buf[19]; // "0x" + up to 16 hex digits + null
228 buf[0] = '0';
229 buf[1] = 'x';
230
231 int pos = 2;
232 bool started = false;
233
234 for (int i = 0; i < 16; i++) {
235 unsigned nib = (val >> ((15 - i) * 4)) & 0xF;
236 if (nib != 0 || started) {
237 started = true;
238 buf[pos++] = (nib < 10 ? '0' + nib : 'a' + nib - 10);
239 }
240 }
241
242 buf[pos] = '\0';
243 gop_puts(gop, buf, color);
244}
245
246
248
249void gop_clear_screen(GOP_PARAMS* gop, uint32_t color) {
250 for (uint32_t y = 0; y < gop->Height; y++)
251 for (uint32_t x = 0; x < gop->Width; x++)
252 plot_pixel(gop, x, y, color);
253}
254
255static inline void buf_put_char(char* buf, size_t size, size_t* written, char c) {
256 if (size > 0 && *written + 1 < size) {
257 buf[*written] = c;
258 }
259 (*written)++;
260}
261
262static void buf_puts(char* buf, size_t size, size_t* written, const char* s) {
263 while (*s) {
264 buf_put_char(buf, size, written, *s++);
265 }
266}
267
268static void buf_print_dec64(char* buf, size_t size, size_t* written, int64_t value) {
269 char tmp[32]; // enough for -2^63 and NUL
270 char* t = tmp + sizeof(tmp) - 1;
271 bool neg = (value < 0);
272 uint64_t u;
273 *t = '\0';
274
275 if (!neg) {
276 u = (uint64_t)value;
277 }
278 else {
279 // compute absolute value safely (avoid UB on INT64_MIN)
280 u = (uint64_t)(-(value + 1)) + 1;
281 }
282
283 if (u == 0) {
284 *--t = '0';
285 }
286 else {
287 while (u) {
288 *--t = '0' + (u % 10);
289 u /= 10;
290 }
291 }
292 if (neg) *--t = '-';
293 buf_puts(buf, size, written, t);
294}
295
296static void buf_print_udec64(char* buf, size_t size, size_t* written, uint64_t value) {
297 char tmp[32];
298 char* t = tmp + sizeof(tmp) - 1;
299 *t = '\0';
300 if (value == 0) {
301 *--t = '0';
302 }
303 else {
304 while (value) {
305 *--t = '0' + (value % 10);
306 value /= 10;
307 }
308 }
309 buf_puts(buf, size, written, t);
310}
311
312static void buf_print_hex64(char* buf, size_t size, size_t* written, uint64_t value) {
313 char tmp[17];
314 char* t = tmp + sizeof(tmp) - 1;
315 const char* hex = "0123456789abcdef";
316 *t = '\0';
317 if (value == 0) {
318 *--t = '0';
319 }
320 else {
321 while (value) {
322 *--t = hex[value & 0xF];
323 value >>= 4;
324 }
325 }
326 buf_puts(buf, size, written, t);
327}
328
329static void buf_print_binary64(char* buf, size_t size, size_t* written, uint64_t value) {
330 char tmp[65];
331 char* t = tmp + sizeof(tmp) - 1;
332 *t = '\0';
333 if (value == 0) {
334 *--t = '0';
335 }
336 else {
337 while (value) {
338 *--t = (value & 1) ? '1' : '0';
339 value >>= 1;
340 }
341 }
342 buf_puts(buf, size, written, t);
343}
344
345//-----------------------------------------------------------------------------
346// Helper: simple strchr for delimiter scanning
347//-----------------------------------------------------------------------------
348static char* strchr(const char* s, int c) {
349 while (*s) {
350 if (*s == (char)c) {
351 return (char*)s;
352 }
353 s++;
354 }
355 return NULL;
356}
357
365char* kstrncat(char* dest, const char* src, size_t max_len) {
366 if (!dest || !src || max_len == 0) return dest;
367
368 // Move dest_ptr to the end of the current string
369 size_t dest_len = 0;
370 while (dest_len < max_len && dest[dest_len] != '\0') {
371 dest_len++;
372 }
373
374 if (dest_len == max_len) {
375 // dest is already full, cannot append
376 return dest;
377 }
378
379 size_t i = 0;
380 while (dest_len + i < max_len - 1 && src[i] != '\0') {
381 dest[dest_len + i] = src[i];
382 i++;
383 }
384
385 // Null-terminate
386 dest[dest_len + i] = '\0';
387 return dest;
388}
389
390//-----------------------------------------------------------------------------
391// kstrlen: Return length of string (excluding null terminator).
392//-----------------------------------------------------------------------------
393size_t kstrlen(const char* str) {
394 size_t len = 0;
395 while (str && str[len] != '\0') {
396 len++;
397 }
398 return len;
399}
400
401//-----------------------------------------------------------------------------
402// kstrcpy: Copy string from src to dst. Assumes dst is large enough.
403//-----------------------------------------------------------------------------
404char* kstrcpy(char* dst, const char* src) {
405 char* ret = dst;
406 while ((*dst++ = *src++)) {
407 // copy until null terminator
408 }
409 return ret;
410}
411
412//-----------------------------------------------------------------------------
413// kstrncpy: Copy up to n characters from src to dst.
414// Assumes dst is large enough.
415//-----------------------------------------------------------------------------
416char* kstrncpy(char* dst, const char* src, size_t n) {
417 if (n == 0) return dst;
418 size_t i = 0;
419 while (i + 1 < n && src[i]) {
420 dst[i] = src[i];
421 i++;
422 }
423 dst[i] = '\0';
424 return dst;
425}
426
427static inline size_t kstrlcpy(char* dst, const char* src, size_t dst_size)
428{
429 const char* s = src;
430 size_t n = dst_size;
431
432 if (n != 0) {
433 while (--n != 0) {
434 char c = *s++;
435 *dst++ = c;
436 if (c == '\0') {
437 return (size_t)(s - src - 1);
438 }
439 }
440 /* out of space; NUL-terminate if possible */
441 *dst = '\0';
442 }
443
444 /* continue walking src to compute its length */
445 while (*s++)
446 ;
447 return (size_t)(s - src - 1);
448}
449
450/* -------------------
451 * kstrspn - like strspn
452 * -------------------
453 * Returns length of the initial segment of s consisting only of characters in accept.
454 */
455static inline size_t kstrspn(const char* s, const char* accept)
456{
457 const char* p = s;
458 for (; *p != '\0'; ++p) {
459 const char* a;
460 for (a = accept; *a != '\0' && *a != *p; ++a)
461 ;
462 if (*a == '\0') /* char p is NOT in accept */
463 break;
464 }
465 return (size_t)(p - s);
466}
467
468/* --------------------
469 * kstrcspn - like strcspn
470 * --------------------
471 * Returns length of the initial segment of s consisting of characters NOT in reject.
472 */
473static inline size_t kstrcspn(const char* s, const char* reject)
474{
475 const char* p = s;
476 for (; *p != '\0'; ++p) {
477 const char* r;
478 for (r = reject; *r != '\0' && *r != *p; ++r)
479 ;
480 if (*r != '\0') /* p matched a reject char */
481 break;
482 }
483 return (size_t)(p - s);
484}
485
486//-----------------------------------------------------------------------------
487// kstrtok: Tokenize string with delimiters.
488// Works like strtok, but without libc.
489// Keeps static state across calls unless str != NULL.
490//-----------------------------------------------------------------------------
491char* kstrtok_r(char* str, const char* delim, char** save_ptr)
492{
493 char* token_start;
494
495 if (!save_ptr) return NULL; /* defensive */
496
497 if (str != NULL) {
498 token_start = str;
499 }
500 else if (*save_ptr != NULL) {
501 token_start = *save_ptr;
502 }
503 else {
504 return NULL;
505 }
506
507 /* skip leading delimiters */
508 token_start += kstrspn(token_start, delim);
509
510 if (*token_start == '\0') {
511 *save_ptr = NULL;
512 return NULL;
513 }
514
515 char* token_end = token_start + kstrcspn(token_start, delim);
516
517 if (*token_end == '\0') {
518 *save_ptr = NULL;
519 }
520 else {
521 *token_end = '\0';
522 *save_ptr = token_end + 1;
523 }
524
525 return token_start;
526}
527
528static void buf_print_hex64_minimal(char* buf, size_t size, size_t* written, uint64_t value) {
529 char tmp[17];
530 char* t = tmp + sizeof(tmp) - 1;
531 const char* hex = "0123456789abcdef";
532 *t = '\0';
533 if (value == 0) {
534 *--t = '0';
535 }
536 else {
537 while (value) {
538 *--t = hex[value & 0xF];
539 value >>= 4;
540 }
541 }
542 buf_puts(buf, size, written, "0x");
543 buf_puts(buf, size, written, t);
544}
545
546int ksnprintf(char* buf, size_t bufsize, const char* fmt, ...) {
547 size_t written = 0;
548 va_list ap;
549 va_start(ap, fmt);
550
551 for (const char* p = fmt; *p; p++) {
552 if (*p == '%' && p[1]) {
553 p++;
554 // support optional length modifiers: 'l' and 'll'
555 int len = 0;
556 while (*p == 'l') {
557 len++;
558 p++;
559 if (len >= 2) break;
560 }
561 char spec = *p;
562 switch (spec) {
563 case 'd':
564 if (len >= 2) {
565 buf_print_dec64(buf, bufsize, &written, va_arg(ap, long long));
566 }
567 else if (len == 1) {
568 buf_print_dec64(buf, bufsize, &written, va_arg(ap, long));
569 }
570 else {
571 buf_print_dec64(buf, bufsize, &written, (int64_t)va_arg(ap, int));
572 }
573 break;
574 case 'u':
575 if (len >= 2) {
576 buf_print_udec64(buf, bufsize, &written, va_arg(ap, unsigned long long));
577 }
578 else if (len == 1) {
579 buf_print_udec64(buf, bufsize, &written, va_arg(ap, unsigned long));
580 }
581 else {
582 buf_print_udec64(buf, bufsize, &written, (uint64_t)va_arg(ap, unsigned int));
583 }
584 break;
585 case 'x':
586 if (len >= 2) {
587 buf_print_hex64(buf, bufsize, &written, va_arg(ap, unsigned long long));
588 }
589 else if (len == 1) {
590 buf_print_hex64(buf, bufsize, &written, va_arg(ap, unsigned long));
591 }
592 else {
593 buf_print_hex64(buf, bufsize, &written, (uint64_t)va_arg(ap, unsigned int));
594 }
595 break;
596 case 'p':
597 buf_puts(buf, bufsize, &written, "0x");
598 buf_print_hex64(buf, bufsize, &written, (uint64_t)(uintptr_t)va_arg(ap, void*));
599 break;
600 case 'c':
601 buf_put_char(buf, bufsize, &written, (char)va_arg(ap, int)); /* chars promoted to int */
602 break;
603 case 'b':
604 // 'b' - binary, treat as 64-bit if ll, otherwise adapt
605 if (len >= 2) {
606 buf_print_binary64(buf, bufsize, &written, va_arg(ap, unsigned long long));
607 }
608 else if (len == 1) {
609 buf_print_binary64(buf, bufsize, &written, va_arg(ap, unsigned long));
610 }
611 else {
612 buf_print_binary64(buf, bufsize, &written, (uint64_t)va_arg(ap, unsigned int));
613 }
614 break;
615 case 's': {
616 const char* s = va_arg(ap, const char*);
617 buf_puts(buf, bufsize, &written, s ? s : "(null)");
618 break;
619 }
620 case '%':
621 buf_put_char(buf, bufsize, &written, '%');
622 break;
623 default:
624 buf_put_char(buf, bufsize, &written, '%');
625 buf_put_char(buf, bufsize, &written, spec);
626 }
627 }
628 else {
629 buf_put_char(buf, bufsize, &written, *p);
630 }
631 }
632
633 va_end(ap);
634 if (bufsize > 0) {
635 buf[written < bufsize ? written : bufsize - 1] = '\0';
636 }
637
638 return (int)written;
639}
640
641static inline bool interrupts_enabled(void) {
642 unsigned long flags;
643 __asm__ __volatile__("pushfq; popq %0" : "=r"(flags));
644 return (flags & (1UL << 9)) != 0; // IF is bit 9
645}
646
647static void gop_print_binary(GOP_PARAMS* gop, uint64_t val, uint32_t color) {
648 char buf[65]; // 64 bits + null terminator
649 for (int i = 0; i < 64; i++) {
650 // fill buffer from MSB to LSB
651 buf[i] = (val & (1ULL << (63 - i))) ? '1' : '0';
652 }
653 buf[64] = '\0';
654 gop_puts(gop, buf, color);
655}
656
657int kstrcmp(const char* s1, const char* s2) {
658 while (*s1 && *s2) {
659 if (*s1 != *s2) return (int)((unsigned char)*s1 - (unsigned char)*s2);
660 s1++;
661 s2++;
662 }
663 return (int)((unsigned char)*s1 - (unsigned char)*s2);
664}
665
666int kstrncmp(const char* s1, const char* s2, size_t length) {
667 if (!length) return length;
668 for (size_t i = 0; i < length; i++, s1++, s2++) {
669 if (*s1 != *s2) return (int)((unsigned char)*s1 - (unsigned char)*s2);
670 if (*s1 == '\0') return 0;
671 }
672 return 0;
673}
674
676
677static void acquire_tmp_lock(SPINLOCK* lock) {
678 if (!lock) return;
679 // spin until we grab the lock.
680 while (__sync_lock_test_and_set(&lock->locked, 1)) {
681 __asm__ volatile("pause" ::: "memory"); /* x86 pause — CPU relax hint */
682 }
683 // Memory barrier to prevent instruction reordering
684 __asm__ volatile("" ::: "memory");
685}
686
687static void release_tmp_lock(SPINLOCK* lock) {
688 if (!lock) return;
689 // Memory barrier before release
690 __asm__ __volatile("" ::: "memory");
691 __sync_lock_release(&lock->locked);
692}
693
694void gop_printf(uint32_t color, const char* fmt, ...) {
695 // Check for exclusive ownership, if there is none, continue, if we are the owner, continue, if we are not the owner, return.
696 // Used with unlikely macro since this is only present in bugchecking or other high level scenarios.
697 void* owner = InterlockedCompareExchangePointer((volatile void* volatile*)&ExclusiveOwnerShip, NULL, NULL);
698 if (unlikely(owner && owner != MeGetCurrentProcessor())) return;
699
700 bool prev_if = interrupts_enabled();
701 acquire_tmp_lock(&gop_lock);
702 __cli();
703 GOP_PARAMS* gop = &gop_local;
704 va_list ap;
705 va_start(ap, fmt);
706 for (const char* p = fmt; *p; p++) {
707 if (*p == '*' && p[1] == '*') {
708 gop_bold_enabled = !gop_bold_enabled; // Toggle bold
709 p++; // skip the second '*'
710 continue;
711 }
712 if (*p == '%' && p[1]) {
713 p++;
714 // support optional length modifiers: 'l' and 'll'
715 int len = 0;
716 while (*p == 'l') {
717 len++;
718 p++;
719 if (len >= 2) break;
720 }
721 char spec = *p;
722 switch (spec) {
723 case 'd':
724 if (len >= 2) {
725 gop_print_dec(gop, (int64_t)va_arg(ap, long long), color);
726 }
727 else if (len == 1) {
728 gop_print_dec(gop, (int64_t)va_arg(ap, long), color);
729 }
730 else {
731 gop_print_dec(gop, (int64_t)va_arg(ap, int), color);
732 }
733 break;
734 case 'u':
735 if (len >= 2) {
736 gop_print_udec(gop, (uint64_t)va_arg(ap, unsigned long long), color);
737 }
738 else if (len == 1) {
739 gop_print_udec(gop, (uint64_t)va_arg(ap, unsigned long), color);
740 }
741 else {
742 gop_print_udec(gop, (uint64_t)va_arg(ap, unsigned int), color);
743 }
744 break;
745 case 'x':
746 if (len >= 2) {
747 gop_print_hex_minimal(gop, (uint64_t)va_arg(ap, unsigned long long), color);
748 }
749 else if (len == 1) {
750 gop_print_hex_minimal(gop, (uint64_t)va_arg(ap, unsigned long), color);
751 }
752 else {
753 gop_print_hex_minimal(gop, (uint64_t)va_arg(ap, unsigned int), color);
754 }
755 break;
756 case 'p':
757 gop_print_hex(gop, (uint64_t)(uintptr_t)va_arg(ap, void*), color);
758 break;
759 case 'c': {
760 int ch = va_arg(ap, int);
761 gop_put_char(gop, (char)ch, color); // chars promoted to int
762 } break;
763 case 'b':
764 // binary: accept width modifiers, default to unsigned long long for no ambiguity
765 if (len >= 2) {
766 gop_print_binary(gop, (uint64_t)va_arg(ap, unsigned long long), color);
767 }
768 else if (len == 1) {
769 gop_print_binary(gop, (uint64_t)va_arg(ap, unsigned long), color);
770 }
771 else {
772 gop_print_binary(gop, (uint64_t)va_arg(ap, unsigned int), color);
773 }
774 break;
775 case 's': {
776 const char* str = va_arg(ap, const char*);
777 if (str) gop_puts(gop, str, color);
778 } break;
779 case '%': gop_put_char(gop, '%', color); break;
780 default:
781 gop_put_char(gop, '%', color);
782 gop_put_char(gop, spec, color);
783 }
784 }
785 else {
786 gop_put_char(gop, *p, color);
787 }
788 }
789 va_end(ap);
790 release_tmp_lock(&gop_lock);
791 if (prev_if) __sti();
792}
793
795 void* me = (void*)MeGetCurrentProcessor();
796
797 for (;;) {
799 if (prev == NULL)
800 return; // acquired
801
802 __pause();
803 }
804}
805
807 // Trust the caller, just set the ExclusiveOwnerShip pointer to NULL.
809}
FORCEINLINE void * InterlockedCompareExchangePointer(volatile void *volatile *target, void *value, void *comparand)
Definition atomic.h:171
FORCEINLINE void * InterlockedExchangePointer(volatile void *volatile *target, void *value)
Definition atomic.h:170
uint32_t cursor_y
Definition gop.c:39
GOP_PARAMS gop_local
Definition gop.c:247
uint32_t cursor_x
Definition gop.c:39
struct _GOP_PARAMS GOP_PARAMS
const uint8_t font8x16[256][16]
void MgAcquireExclusiveGopOwnerShip(void)
Definition gop.c:794
volatile void * ExclusiveOwnerShip
Definition gop.c:17
char * kstrncat(char *dest, const char *src, size_t max_len)
Concatenates src onto dest, up to max_len total bytes in dest.
Definition gop.c:365
#define FONT_SCALE
Definition gop.c:15
size_t kstrlen(const char *str)
Definition gop.c:393
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
int ksnprintf(char *buf, size_t bufsize, const char *fmt,...)
Definition gop.c:546
void MgReleaseExclusiveGopOwnerShip(void)
Definition gop.c:806
char * kstrtok_r(char *str, const char *delim, char **save_ptr)
Definition gop.c:491
char * kstrcpy(char *dst, const char *src)
Definition gop.c:404
char * kstrncpy(char *dst, const char *src, size_t n)
Definition gop.c:416
SPINLOCK gop_lock
Definition gop.c:675
void gop_clear_screen(GOP_PARAMS *gop, uint32_t color)
Definition gop.c:249
bool gop_bold_enabled
Definition gop.c:38
int kstrncmp(const char *s1, const char *s2, size_t length)
Definition gop.c:666
int kstrcmp(const char *s1, const char *s2)
Definition gop.c:657
FORCEINLINE void __pause(void)
Definition intrin.h:224
FORCEINLINE void __sti(void)
Definition intrin.h:44
FORCEINLINE void __cli(void)
Definition intrin.h:38
#define unlikely(x)
Definition macros.h:47
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
uint32_t flags
Definition mh.h:2
struct _ACPI_SDT_HEADER h
Definition mh.h:0
struct _SPINLOCK SPINLOCK
#define va_arg(ap, type)
Definition stdarg_myos.h:12
#define va_end(ap)
Definition stdarg_myos.h:13
#define va_start(ap, last)
Definition stdarg_myos.h:11
__builtin_va_list va_list
Definition stdarg_myos.h:9
uint64_t FrameBufferBase
Definition efi.h:43
uint32_t Height
Definition efi.h:46
uint32_t Width
Definition efi.h:45
uint32_t PixelsPerScanLine
Definition efi.h:47
volatile uint32_t locked
Definition ms.h:37