-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel.cpp
More file actions
802 lines (665 loc) · 27.1 KB
/
Copy pathkernel.cpp
File metadata and controls
802 lines (665 loc) · 27.1 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
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
/**
* @file kernel.cpp
* @brief Main Kernel of #x86
*
* @date 24/02/2025
* @version 1.2.0-beta
*/
#define KDBG_COMPONENT "KERNEL"
#include <kernel.h>
#define DEBUG_ENABLED TRUE;
#define PIT_COMMAND_PORT 0x43
#define PIT_CHANNEL0_PORT 0x40
KERNEL_MEMORY_MAP g_kmap;
extern "C" uint32_t pci_find_bar0(uint16_t vendor, uint16_t device);
extern "C" void __cxa_pure_virtual() {
HALT("Pure Virtual Function Called! System Halted.");
}
namespace {
constexpr int BOOTMSG_CHAR_W = 8;
constexpr int BOOTMSG_CHAR_H = 8;
constexpr int BOOTMSG_CHAR_SPACING = 1;
constexpr int BOOTMSG_LINE_SPACING = 2;
constexpr int BOOTMSG_MARGIN_X = 10;
constexpr int BOOTMSG_MARGIN_Y = 10;
constexpr int BOOTMSG_PANEL_PADDING = 6;
constexpr int BOOTMSG_MAX_LINES = 12;
constexpr int BOOTMSG_MAX_COLS = 192;
constexpr uint32_t BOOTMSG_PANEL_COLOR = 0xFF000000;
char g_bootMsgLines[BOOTMSG_MAX_LINES][BOOTMSG_MAX_COLS];
int g_bootMsgLineCount = 0;
int min_int(int a, int b) {
return (a < b) ? a : b;
}
void PushBootMsgLine(const char* text) {
if (!text) return;
if (g_bootMsgLineCount >= BOOTMSG_MAX_LINES) {
for (int i = 1; i < BOOTMSG_MAX_LINES; i++) {
strcpy(g_bootMsgLines[i - 1], g_bootMsgLines[i]);
}
g_bootMsgLineCount = BOOTMSG_MAX_LINES - 1;
}
int dst = g_bootMsgLineCount;
int i = 0;
for (; text[i] != '\0' && i < BOOTMSG_MAX_COLS - 1; i++) {
g_bootMsgLines[dst][i] = text[i];
}
g_bootMsgLines[dst][i] = '\0';
g_bootMsgLineCount++;
}
void DrawBootRect(GraphicsDriver* driver, int x, int y, int w, int h, uint32_t color) {
if (!driver || w <= 0 || h <= 0) return;
int x0 = x;
int y0 = y;
int x1 = x + w;
int y1 = y + h;
if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0;
if (x1 > (int)driver->GetWidth()) x1 = (int)driver->GetWidth();
if (y1 > (int)driver->GetHeight()) y1 = (int)driver->GetHeight();
for (int py = y0; py < y1; py++) {
for (int px = x0; px < x1; px++) {
driver->PutPixel(px, py, color);
}
}
}
void DrawBootGlyph(GraphicsDriver* driver, int x, int y, char c, uint32_t color) {
const uint8_t* glyph = GetGlyph(c);
for (int row = 0; row < BOOTMSG_CHAR_H; row++) {
uint8_t bits = glyph[row];
for (int col = 0; col < BOOTMSG_CHAR_W; col++) {
if (bits & (1 << (7 - col))) {
driver->PutPixel(x + col, y + row, color);
}
}
}
}
void DrawBootLine(GraphicsDriver* driver, int x, int y, const char* text, uint32_t color,
int maxCols) {
if (!driver || !text || maxCols <= 0) return;
int penX = x;
int cols = 0;
for (int i = 0; text[i] != '\0' && cols < maxCols; i++) {
if (text[i] == '\n') break;
DrawBootGlyph(driver, penX, y, text[i], color);
penX += BOOTMSG_CHAR_W + BOOTMSG_CHAR_SPACING;
cols++;
}
}
} // namespace
void bootMSG(const char* msg) {
if (!msg || !g_GraphicsDriver) {
KDBG1("Graphics driver is not initialized.");
return;
}
const int screenW = (int)g_GraphicsDriver->GetWidth();
const int screenH = (int)g_GraphicsDriver->GetHeight();
const int lineStep = BOOTMSG_CHAR_H + BOOTMSG_LINE_SPACING;
int maxCols = (screenW - (BOOTMSG_MARGIN_X * 2) - (BOOTMSG_PANEL_PADDING * 2)) /
(BOOTMSG_CHAR_W + BOOTMSG_CHAR_SPACING);
if (maxCols <= 0) return;
if (maxCols > BOOTMSG_MAX_COLS - 1) maxCols = BOOTMSG_MAX_COLS - 1;
char lineBuf[BOOTMSG_MAX_COLS];
int lineLen = 0;
for (int i = 0;; i++) {
char c = msg[i];
if (c == '\r') {
continue;
}
if (c == '\0' || c == '\n') {
lineBuf[lineLen] = '\0';
PushBootMsgLine(lineBuf);
lineLen = 0;
if (c == '\0') break;
continue;
}
if (lineLen >= maxCols) {
lineBuf[lineLen] = '\0';
PushBootMsgLine(lineBuf);
lineLen = 0;
if (c == ' ') continue;
}
if (lineLen < BOOTMSG_MAX_COLS - 1) {
lineBuf[lineLen++] = c;
}
}
int maxVisible = (screenH / 3 - BOOTMSG_PANEL_PADDING * 2) / lineStep;
if (maxVisible < 1) maxVisible = 1;
if (maxVisible > BOOTMSG_MAX_LINES) maxVisible = BOOTMSG_MAX_LINES;
int visible = min_int(g_bootMsgLineCount, maxVisible);
int panelH = visible * lineStep + BOOTMSG_PANEL_PADDING * 2;
int panelW = maxCols * (BOOTMSG_CHAR_W + BOOTMSG_CHAR_SPACING) + BOOTMSG_PANEL_PADDING * 2;
int panelX = BOOTMSG_MARGIN_X;
int panelY = screenH - BOOTMSG_MARGIN_Y - panelH;
DrawBootRect(g_GraphicsDriver, panelX, panelY, panelW, panelH, BOOTMSG_PANEL_COLOR);
int firstLine = g_bootMsgLineCount - visible;
for (int i = 0; i < visible; i++) {
int y = panelY + BOOTMSG_PANEL_PADDING + i * lineStep;
DrawBootLine(g_GraphicsDriver, panelX + BOOTMSG_PANEL_PADDING, y,
g_bootMsgLines[firstLine + i], 0xFFFFFFFF, maxCols);
}
g_GraphicsDriver->Flush();
}
int get_kernel_memory_map(KERNEL_MEMORY_MAP* kmap, MultibootInfo* mboot_info) {
if (kmap == NULL) return -1;
kmap->kernel.k_start_addr = (uint32_t)&__kernel_section_start;
kmap->kernel.k_end_addr = (uint32_t)&__kernel_section_end;
kmap->kernel.k_len = ((uint32_t)&__kernel_section_end - (uint32_t)&__kernel_section_start);
kmap->kernel.text_start_addr = (uint32_t)&__kernel_text_section_start;
kmap->kernel.text_end_addr = (uint32_t)&__kernel_text_section_end;
kmap->kernel.text_len =
((uint32_t)&__kernel_text_section_end - (uint32_t)&__kernel_text_section_start);
kmap->kernel.data_start_addr = (uint32_t)&__kernel_data_section_start;
kmap->kernel.data_end_addr = (uint32_t)&__kernel_data_section_end;
kmap->kernel.data_len =
((uint32_t)&__kernel_data_section_end - (uint32_t)&__kernel_data_section_start);
kmap->kernel.rodata_start_addr = (uint32_t)&__kernel_rodata_section_start;
kmap->kernel.rodata_end_addr = (uint32_t)&__kernel_rodata_section_end;
kmap->kernel.rodata_len =
((uint32_t)&__kernel_rodata_section_end - (uint32_t)&__kernel_rodata_section_start);
kmap->kernel.bss_start_addr = (uint32_t)&__kernel_bss_section_start;
kmap->kernel.bss_end_addr = (uint32_t)&__kernel_bss_section_end;
kmap->kernel.bss_len =
((uint32_t)&__kernel_bss_section_end - (uint32_t)&__kernel_bss_section_start);
kmap->system.total_memory = mboot_info->mem_lower + mboot_info->mem_upper;
for (int i = 0; i < mboot_info->mmap_length; i += sizeof(MULTIBOOT_MEMORY_MAP)) {
MULTIBOOT_MEMORY_MAP* mmap = (MULTIBOOT_MEMORY_MAP*)(mboot_info->mmap_addr + i);
if (mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
// make sure kernel is loaded at 0x100000 by bootloader(see linker.ld)
if (mmap->addr_low == kmap->kernel.text_start_addr) {
// set available memory starting from end of our kernel, leaving 1MB size for functions
// exceution
kmap->available.start_addr = kmap->kernel.k_end_addr + 1024 * 1024;
kmap->available.end_addr = mmap->addr_low + mmap->len_low;
// get availabel memory in bytes
kmap->available.size = kmap->available.end_addr - kmap->available.start_addr;
return 0;
}
}
return -1;
}
void display_kernel_memory_map(KERNEL_MEMORY_MAP* kmap) {
KDBG2("MemoryMap section=KERNEL start=0x%x end=0x%x len=%d", kmap->kernel.k_start_addr,
kmap->kernel.k_end_addr, kmap->kernel.k_len);
KDBG2("MemoryMap section=TEXT start=0x%x end=0x%x len=%d", kmap->kernel.text_start_addr,
kmap->kernel.text_end_addr, kmap->kernel.text_len);
KDBG2("MemoryMap section=DATA start=0x%x end=0x%x len=%d", kmap->kernel.data_start_addr,
kmap->kernel.data_end_addr, kmap->kernel.data_len);
KDBG2("MemoryMap section=RODATA start=0x%x end=0x%x len=%d", kmap->kernel.rodata_start_addr,
kmap->kernel.rodata_end_addr, kmap->kernel.rodata_len);
KDBG2("MemoryMap section=BSS start=0x%x end=0x%x len=%d", kmap->kernel.bss_start_addr,
kmap->kernel.bss_end_addr, kmap->kernel.bss_len);
KDBG1("SystemMemory total=%d KB available_size=%d", kmap->system.total_memory,
kmap->available.size);
KDBG1("AvailableRAM start=0x%x end=0x%x", kmap->available.start_addr, kmap->available.end_addr);
}
void init_memory(MultibootInfo* mbinfo) {
memset(&g_kmap, 0, sizeof(KERNEL_MEMORY_MAP));
get_kernel_memory_map(&g_kmap, mbinfo);
// Initialize PMM at end of Kernel (Respect BSS/Stack)
// Use bss_end_addr to ensure we are past the stack
uint32_t heap_start_addr = g_kmap.kernel.bss_end_addr;
// Safety Fallback: Use k_end_addr if bss calc seems wrong
if (g_kmap.kernel.k_end_addr > heap_start_addr) {
heap_start_addr = g_kmap.kernel.k_end_addr;
}
if (heap_start_addr < 0x200000) {
heap_start_addr = 0x200000;
}
// Add 4MB padding to be safe.
heap_start_addr += 4 * 1024 * 1024;
struct multiboot_module* modules = (struct multiboot_module*)mbinfo->mods_addr;
if (mbinfo->mods_count > 0) {
for (int mod_idx = 0; mod_idx < mbinfo->mods_count; mod_idx++) {
uint32_t mod_end = modules[mod_idx].mod_end;
if (mod_end > heap_start_addr) {
heap_start_addr = mod_end;
}
}
}
// Align to Page Boundary
if ((heap_start_addr & 0xFFF) != 0) {
heap_start_addr = (heap_start_addr & 0xFFFFF000) + 0x1000;
}
// initialize PMM
pmm_init(heap_start_addr, g_kmap.available.end_addr);
// Calculate how big the bitmap
uint32_t bitmap_size = (g_kmap.available.end_addr / PMM_BLOCK_SIZE) / 8;
// Mark FREE Region, but SKIP the bitmap!
pmm_init_region(heap_start_addr + bitmap_size, g_kmap.available.end_addr);
// HEAP ALLOCATION
uint32_t actual_heap_start = heap_start_addr + bitmap_size;
if ((actual_heap_start & 0xFFF) != 0) {
actual_heap_start = (actual_heap_start & 0xFFFFF000) + 0x1000;
}
// Define the Hard Ceiling (224 MB)
// Reserve 32MB (224-256MB) of identity-mapped space for PMM allocations
// (page tables, user stacks, process directories, ELF loading pages).
// These MUST stay below 256MB because the kernel accesses them via
// identity-mapped physical addresses after paging is activated.
uint32_t paging_limit = 224 * 1024 * 1024;
// Define the Physical Ceiling
uint32_t physical_limit = g_kmap.available.end_addr;
// Determine the Safe Limit
uint32_t safe_limit = (paging_limit < physical_limit) ? paging_limit : physical_limit;
// Apply a Safety Buffer
safe_limit -= 4096;
// Calculate Exact Size Needed
if (safe_limit <= actual_heap_start) {
HALT("CRITICAL: No memory left for Heap! (Kernel + PMM > Limit)\n");
}
uint32_t heap_size_bytes = safe_limit - actual_heap_start;
uint32_t blocks_needed = heap_size_bytes / PMM_BLOCK_SIZE;
KDBG1("Maximizing PMM Heap: Start=0x%x Limit=0x%x Size=%d MB", actual_heap_start, safe_limit,
(int32_t)(heap_size_bytes / (1024 * 1024)));
// Allocate
void* heap_start = pmm_alloc_blocks(blocks_needed);
if (heap_start == NULL) {
HALT("CRITICAL: Failed to allocate calculated heap!\n");
}
// Force Heap Alignment (Crucial for Paging)
uint32_t heap_val = (uint32_t)heap_start;
if ((heap_val & 0xFFF) != 0) {
heap_val = (heap_val + 0xFFF) & ~0xFFF;
blocks_needed--;
}
heap_start = (void*)heap_val;
size_t heap_size = blocks_needed * PMM_BLOCK_SIZE;
void* heap_end = (void*)((uint32_t)heap_start + heap_size);
KDBG1("Kernel Heap: 0x%x - 0x%x (%d MB)", heap_start, heap_end, heap_size / 1024 / 1024);
kheap_init(heap_start, heap_end);
}
void InitializePIT(uint32_t frequency) {
// The PIT's input clock is approximately 1.193182 MHz
uint32_t divisor = 1193180 / frequency;
// Send the command byte.
// 0x36 = 00 11 01 10
// 00 (Channel 0)
// 11 (Access mode: lobyte/hibyte)
// 011 (Mode 3: Square Wave Generator)
// 0 (Binary mode)
outb(PIT_COMMAND_PORT, 0x36);
// Divisor has to be sent byte-wise, so split it into Low and High bytes.
uint8_t low = (uint8_t)(divisor & 0xFF);
uint8_t high = (uint8_t)((divisor >> 8) & 0xFF);
// Send the frequency divisor
outb(PIT_CHANNEL0_PORT, low);
outb(PIT_CHANNEL0_PORT, high);
KDBG1("PIT Initialized at %d Hz", (int32_t)frequency);
}
void init_pci(FAT32* boot_partition, DriverManager* driverManager) {
KDBG1("Initializing Drivers (PCI Scan)...");
// ---------------------------------------------------------
// Dynamic Graphics Loading (with PCI)
// ---------------------------------------------------------
// Scan for known BGA/SVGA Vendors
// 0x1234:0x1111 = Bochs / QEMU
// 0x80EE:0xBEEF = VirtualBox Graphics Adapter
// 0x15AD:0x0405 = VMware SVGA II (often used by VBox)
// Check if BGA Hardware Exists via PCI
PeripheralComponentInterconnectController* pciCheck =
new PeripheralComponentInterconnectController();
if (!pciCheck) {
HALT("CRITICAL: Failed to allocate PCI controller!\n");
}
PeripheralComponentInterconnectDeviceDescriptor* dev = nullptr;
if (dev == nullptr) dev = pciCheck->FindHardwareDevice(0x1234, 0x1111);
if (!dev) {
HALT("CRITICAL: PCI scan failed while searching for BGA hardware!\n");
}
if (dev->vendor_id == 0) {
delete dev;
dev = pciCheck->FindHardwareDevice(0x80EE, 0xBEEF);
if (!dev) {
HALT("CRITICAL: PCI scan failed while searching for VBox graphics hardware!\n");
}
}
if (dev->vendor_id == 0) {
delete dev;
dev = pciCheck->FindHardwareDevice(0x15AD, 0x0405);
if (!dev) {
HALT("CRITICAL: PCI scan failed while searching for VMware graphics hardware!\n");
}
}
// Only Proceed if Device Found
if (dev->vendor_id != 0) {
char* BGAfilename = "DRIVERS/BGA.SYS";
KDBG1("BGA Hardware Detected (ID: %x:%x). Loading Driver... [%s]", dev->vendor_id,
dev->device_id, BGAfilename);
File* bgaFile = boot_partition->Open(BGAfilename);
if (bgaFile) {
void* entryPoint =
ModuleLoader::LoadMatchingDriver(bgaFile, dev->vendor_id, dev->device_id);
if (entryPoint) {
GetDriverInstancePtr createDriver = (GetDriverInstancePtr)entryPoint;
void* raw = createDriver(); // Create the object
if (raw) {
Driver* drv = (Driver*)raw;
drv->Activate();
driverManager->AddDriver(drv);
// SAFE CAST
GraphicsDriver* newScreen = drv->AsGraphicsDriver();
if (newScreen) {
GraphicsDriver* oldDR = g_GraphicsDriver;
// Update Local Reference
g_GraphicsDriver = newScreen;
// UPDATE GLOBAL VARIABLE
g_GraphicsDriver = newScreen;
// Copy Old Screen to New Screen
int32_t x, y;
g_GraphicsDriver->GetScreenCenter(oldDR->GetWidth(), oldDR->GetHeight(), x,
y);
if (oldDR->GetBackBuffer()) {
g_GraphicsDriver->DrawBitmap(x, y, oldDR->GetBackBuffer(),
oldDR->GetWidth(), oldDR->GetHeight());
}
g_GraphicsDriver->Flush();
KDBG1("BGA Module Loaded Successfully.");
} else {
KDBG1("Error: Driver loaded, but is not a GraphicsDriver!");
}
}
}
bgaFile->Close();
delete bgaFile;
} else {
KDBG1("Hardware found, but %s missing!", BGAfilename);
}
} else {
KDBG1("No BGA Hardware found. Skipping driver load.");
}
// Clean up dev for next search
if (dev) delete dev;
dev = nullptr;
// ---------------------------------------------------------
// 2. Dynamic Audio Loading
// ---------------------------------------------------------
// Check for AC97 (0x8086:0x2415)
KDBG1("PCI graphics scan complete. Scanning audio hardware...");
dev = pciCheck->FindHardwareDevice(0x8086, 0x2415);
if (!dev) {
KDBG1("PCI audio scan failed (null descriptor). Skipping audio init.");
delete pciCheck;
return;
}
if (dev->vendor_id != 0) {
char* driverName = "DRIVERS/ac97.sys";
KDBG1("Audio Hardware Detected. Loading... [%s]", driverName);
File* drvFile = boot_partition->Open(driverName);
if (drvFile) {
void* entryPoint =
ModuleLoader::LoadMatchingDriver(drvFile, dev->vendor_id, dev->device_id);
if (entryPoint) {
GetDriverInstancePtr createDriver = (GetDriverInstancePtr)entryPoint;
void* raw = createDriver();
if (raw) {
Driver* drv = (Driver*)raw;
// CRITICAL: Activate() registers the IRQ.
// InterruptManager MUST exist before this line runs.
drv->Activate();
driverManager->AddDriver(drv);
AudioDriver* audio = drv->AsAudioDriver();
if (audio) {
KDBG1("Initializing Audio Mixer...");
// Create the Mixer and link it to the driver
g_AudioMixer = new AudioMixer(audio);
if (!g_AudioMixer) {
HALT("CRITICAL: Failed to allocate AudioMixer!\n");
}
// Set Master Volume
audio->SetVolume(90);
}
}
}
drvFile->Close();
delete drvFile;
}
} else {
KDBG1("No AC97 audio hardware found.");
}
delete dev;
KDBG1("PCI init complete.");
delete pciCheck;
};
void pDesktop(void* arg) {
DesktopArgs* args = (DesktopArgs*)arg;
#ifdef DEBUG_ENABLED
KDBG1("GUI task started");
if (!args) {
HALT("Error: args is null");
}
if (!args->screen) {
HALT("Error: args->vga is null");
}
if (!args->desktop) {
HALT("Error: args->desktop is null");
}
#endif
GraphicsDriver* screen = args->screen;
Desktop* desktop = args->desktop;
Font* VBE_font = FontManager::activeInstance->getNewFont();
VBE_font->setSize(MEDIUM);
while (true) {
// Only swap buffers if something actually changed
uint32_t start = timerTicks;
// If a fullscreen app is running, skip desktop drawing
if (g_stop_gui_rendering) {
screen->Flush();
Scheduler::activeInstance->Sleep(16);
continue;
}
// Periodic clock update check for taskbar
static uint32_t lastClockTick = 0;
if (timerTicks - lastClockTick >= 1000) {
lastClockTick = timerTicks;
desktop->MarkDirty();
}
if (desktop->isDirty || desktop->MouseMoved()) {
screen->ResetFlushStats();
desktop->Draw(screen);
uint32_t end = timerTicks;
uint32_t diff = (uint32_t)(end - start);
char buf[32];
itoa(buf, 16, diff);
screen->FillRectangle(5, 5, 50, 35, 0x0);
screen->DrawString(10, 10, buf, VBE_font, 0xFFFFFFFF);
screen->DrawString(25, 10, "ms", VBE_font, 0xFFFFFFFF);
desktop->Flush(screen);
} else {
Scheduler::activeInstance->Sleep(16);
}
}
}
extern "C" void kernelMain(void* multiboot_structure, uint32_t magicnumber) {
initSerial();
if (magicnumber != 0x2BADB002) {
#ifdef DEBUG_ENABLED
KDBG1("Invalid magic number : [%x], Ignoring...", magicnumber);
#endif
// return;
}
MultibootInfo* mbinfo = (MultibootInfo*)multiboot_structure;
#ifdef DEBUG_ENABLED
KDBG1("Initializing Hardware");
#endif
gdt_init();
// tss_init();
// Initialize PMM and Kheap
init_memory(mbinfo);
InitializePIT(1000);
#ifdef DEBUG_ENABLED
KDBG1("Initializing paging...");
#endif
g_paging = new Paging();
if (!g_paging) {
HALT("CRITICAL: Failed to allocate Paging object!\n");
}
g_paging->Activate();
// Initialize ATA
AdvancedTechnologyAttachment* ata = nullptr;
AdvancedTechnologyAttachment* SATAList[] = {
new AdvancedTechnologyAttachment(true, 0x1F0), // Primary Master
new AdvancedTechnologyAttachment(false, 0x1F0), // Primary Slave
new AdvancedTechnologyAttachment(true, 0x170), // Secondary Master
new AdvancedTechnologyAttachment(false, 0x170), // Secondary Slave
0};
for (int i = 0; i < 4; i++) {
if (!SATAList[i]) {
HALT("CRITICAL: Failed to allocate ATA object!\n");
}
}
for (int i = 0; SATAList[i] != 0; i++) {
KDBG3("Checking Drive %d...", i);
uint32_t ata_size = SATAList[i]->Identify();
if (ata_size == 0) continue; // No Drive detected
ata = SATAList[i];
// Use the FIRST drive found.
KDBG1("Using ATA drive %d (Master/Slave)", i);
break;
}
if (ata == nullptr) {
HALT(
"Error: No ATA drive detected!\nPlease connect an ATA drive and restart the system.\n");
}
// Initialize MBR and Partitions
MSDOSPartitionTable* MSDOS = new MSDOSPartitionTable(ata);
if (!MSDOS) {
HALT("CRITICAL: Failed to allocate MSDOSPartitionTable!\n");
}
MSDOS->ReadPartitions();
// Get Boot Partition
g_bootPartition = MSDOS->partitions[0];
if (!g_bootPartition) {
HALT("Error: No valid boot partition found!\nPlease reinstall the OS using 'make hdd'.\n");
}
g_bootPartition->ListRoot();
KDBG1("Boot partition mounted. Root listed.");
KernelSymbolTable::Load(g_bootPartition, "kernel.map");
KDBG1("Kernel symbols loaded from kernel.map");
g_GraphicsDriver =
new VESA_BIOS_Extensions(mbinfo->framebuffer_width, mbinfo->framebuffer_height, 32,
(uint32_t*)mbinfo->framebuffer_addr);
if (!g_GraphicsDriver) {
HALT("CRITICAL: Failed to allocate VESA_BIOS_Extensions!\n");
}
// Load Boot Image
char* bootImageName = (char*)"BITMAPS/BOOT.BMP";
Bitmap* bootImg = new Bitmap(bootImageName);
if (!bootImg) {
HALT("CRITICAL: Failed to allocate Bitmap for boot image!\n");
}
if (bootImg->IsValid()) {
int32_t x, y;
g_GraphicsDriver->GetScreenCenter(bootImg->GetWidth(), bootImg->GetHeight(), x, y);
g_GraphicsDriver->DrawBitmap(x, (int32_t)((g_GraphicsDriver->GetHeight() * 1) / 3),
bootImg->GetBuffer(), bootImg->GetWidth(),
bootImg->GetHeight());
g_GraphicsDriver->Flush();
}
bootMSG("[BOOT] Graphics initialized");
delete bootImg;
// Load Font File
bootMSG("[BOOT] Loading fonts");
g_fManager = new FontManager();
if (!g_fManager) {
HALT("CRITICAL: Failed to allocate FontManager!\n");
}
char* fontFileName = (char*)"FONTS/SEGOEUI.BIN";
File* fontFile = g_bootPartition->Open(fontFileName);
if (fontFile->size == 0) {
KDBG1("Font error, file not found or empty: %s. Please reinstall the OS using 'make hdd'.",
fontFile);
while (1) {
asm volatile("hlt");
}
}
g_fManager->LoadFile(fontFile);
fontFile->Close();
delete fontFile;
Font* BOOT = g_fManager->getNewFont();
if (BOOT != nullptr) {
BOOT->setSize(XLARGE);
int32_t x, y;
g_GraphicsDriver->GetScreenCenter(BOOT->getStringLength("Hash x86"), 0, x, y);
g_GraphicsDriver->DrawString(x, (int32_t)((g_GraphicsDriver->GetHeight() * 1) / 3 + 300),
"Hash x86", BOOT, 0xFFFFFFFF);
g_GraphicsDriver->Flush();
}
bootMSG("[BOOT] UI assets ready");
// Load Desktop //
bootMSG("[BOOT] Initializing kernel services");
Desktop* desktop = new Desktop(GUI_SCREEN_WIDTH, GUI_SCREEN_HEIGHT);
if (!desktop) {
HALT("CRITICAL: Failed to allocate Desktop!\n");
}
// gameSDK* desktop = new gameSDK(GUI_SCREEN_WIDTH, GUI_SCREEN_HEIGHT, g_bootPartition);
g_scheduler = new Scheduler(g_paging);
if (!g_scheduler) {
HALT("CRITICAL: Failed to allocate Scheduler!\n");
}
g_interrupts = new InterruptManager(g_scheduler, g_paging);
if (!g_interrupts) {
HALT("CRITICAL: Failed to allocate InterruptManager!\n");
}
g_sysCalls = new SyscallHandler(0x80, g_interrupts);
if (!g_sysCalls) {
HALT("CRITICAL: Failed to allocate SyscallHandler!\n");
}
HguiHandler* guiCalls = new HguiHandler(0x81, g_interrupts); // Needs desktop initialized
if (!guiCalls) {
HALT("CRITICAL: Failed to allocate HguiHandler!\n");
}
g_driverManager = new DriverManager();
if (!g_driverManager) {
HALT("CRITICAL: Failed to allocate DriverManager!\n");
}
bootMSG("[BOOT] Initializing PCI devices");
init_pci(g_bootPartition, g_driverManager);
bootMSG("[BOOT] Starting input drivers");
MouseDriver* mouse = new MouseDriver(g_interrupts, desktop);
if (!mouse) {
HALT("CRITICAL: Failed to allocate MouseDriver!\n");
}
g_driverManager->AddDriver(mouse);
KeyboardDriver* keyboard = new KeyboardDriver(g_interrupts, desktop);
if (!keyboard) {
HALT("CRITICAL: Failed to allocate KeyboardDriver!\n");
}
g_driverManager->AddDriver(keyboard);
// PROCESS MAIN //
bootMSG("[BOOT] Loading desktop");
DesktopArgs* desktopArgs = new DesktopArgs{g_GraphicsDriver, desktop, g_bootPartition};
if (!desktopArgs) {
HALT("CRITICAL: Failed to allocate DesktopArgs!\n");
}
ProcessControlBlock* process1 = g_scheduler->CreateProcess(true, pDesktop, desktopArgs);
if (mbinfo->mods_count > 0) {
KDBG1("Found %d Modules", mbinfo->mods_count);
struct multiboot_module* modules = (struct multiboot_module*)mbinfo->mods_addr;
// fManager.LoadFile(modules[0].mod_start, modules[0].mod_end); // load font file
} else {
KDBG1("No modules found");
}
// Load and start sample programs
g_elfLoader = new ELFLoader(g_paging, g_scheduler);
if (!g_elfLoader) {
HALT("CRITICAL: Failed to allocate ELFLoader!\n");
}
if (g_AudioMixer) {
Wav* sound = new Wav("audio/boot.wav");
if (!sound) {
HALT("CRITICAL: Failed to allocate Wav object for boot sound!\n");
}
sound->Play();
}
KDBG1("Welcome to #x86!");
bootMSG("[BOOT] Activating system drivers");
g_driverManager->ActivateAll();
KDBG1("System Drivers Activated.");
g_interrupts->Activate();
bootMSG("[BOOT] System ready");
KDBG1("Interrupts Enabled. Entering Halt Loop.");
while (1) {
asm volatile("hlt");
}
}