summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/HALKit/AMD64/HalKernelMain.cc
blob: 5de1b8e4013f5276637207f56a19fdab7d1042f2 (plain)
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
/* -------------------------------------------

  Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved.

------------------------------------------- */

#include <ArchKit/ArchKit.h>
#include <CFKit/Property.h>
#include <FirmwareKit/EFI/API.h>
#include <FirmwareKit/EFI/EFI.h>
#include <KernelKit/CodeMgr.h>
#include <KernelKit/HardwareThreadScheduler.h>
#include <KernelKit/ProcessScheduler.h>
#include <KernelKit/Timer.h>
#include <NetworkKit/IPC.h>
#include <StorageKit/AHCI.h>
#include <modules/ACPI/ACPIFactoryInterface.h>
#include <modules/CoreGfx/TextGfx.h>

#ifndef __NE_MODULAR_KERNEL_COMPONENTS__
EXTERN_C Kernel::VoidPtr kInterruptVectorTable[];

STATIC Kernel::Void hal_pre_init_scheduler() noexcept {
  for (Kernel::SizeT i = 0U;
       i < Kernel::UserProcessScheduler::The().CurrentTeam().AsArray().Count(); ++i) {
    Kernel::UserProcessScheduler::The().CurrentTeam().AsArray()[i] = Kernel::USER_PROCESS();
  }
}

/// @brief Kernel init function.
/// @param handover_hdr Handover boot header.
EXTERN_C Int32 hal_init_platform(Kernel::HEL::BootInfoHeader* handover_hdr) {
  if (handover_hdr->f_Magic != kHandoverMagic && handover_hdr->f_Version != kHandoverVersion) {
    return kEfiFail;
  }

  kHandoverHeader = handover_hdr;

  FB::fb_clear_video();

  fw_init_efi((EfiSystemTable*) handover_hdr->f_FirmwareCustomTables[1]);

  Boot::ExitBootServices(handover_hdr->f_HardwareTables.f_ImageKey,
                         handover_hdr->f_HardwareTables.f_ImageHandle);

  kKernelCR3 = kHandoverHeader->f_PageStart;

  hal_write_cr3(kKernelCR3);

  /************************************** */
  /*     INITIALIZE BIT MAP.              */
  /************************************** */

  kKernelBitMpSize  = kHandoverHeader->f_BitMapSize;
  kKernelBitMpStart = reinterpret_cast<Kernel::VoidPtr>(
      reinterpret_cast<Kernel::UIntPtr>(kHandoverHeader->f_BitMapStart));

  /************************************** */
  /*     INITIALIZE GDT AND SEGMENTS. */
  /************************************** */

  STATIC CONST auto kGDTEntriesCount = 6;

  /* GDT, mostly descriptors for user and kernel segments. */
  STATIC Kernel::HAL::Detail::NE_GDT_ENTRY ALIGN(0x08) kGDTArray[kGDTEntriesCount] = {
      {.fLimitLow   = 0,
       .fBaseLow    = 0,
       .fBaseMid    = 0,
       .fAccessByte = 0x00,
       .fFlags      = 0x00,
       .fBaseHigh   = 0},  // Null entry
      {.fLimitLow   = 0x0,
       .fBaseLow    = 0,
       .fBaseMid    = 0,
       .fAccessByte = 0x9A,
       .fFlags      = 0xAF,
       .fBaseHigh   = 0},  // Kernel code
      {.fLimitLow   = 0x0,
       .fBaseLow    = 0,
       .fBaseMid    = 0,
       .fAccessByte = 0x92,
       .fFlags      = 0xCF,
       .fBaseHigh   = 0},  // Kernel data
      {.fLimitLow   = 0x0,
       .fBaseLow    = 0,
       .fBaseMid    = 0,
       .fAccessByte = 0xFA,
       .fFlags      = 0xAF,
       .fBaseHigh   = 0},  // User code
      {.fLimitLow   = 0x0,
       .fBaseLow    = 0,
       .fBaseMid    = 0,
       .fAccessByte = 0xF2,
       .fFlags      = 0xCF,
       .fBaseHigh   = 0},  // User data
  };

  // Load memory descriptors.
  Kernel::HAL::Register64 gdt_reg;

  gdt_reg.Base  = reinterpret_cast<Kernel::UIntPtr>(kGDTArray);
  gdt_reg.Limit = (sizeof(Kernel::HAL::Detail::NE_GDT_ENTRY) * kGDTEntriesCount) - 1;

  //! GDT will load hal_read_init after it successfully loads the segments.
  Kernel::HAL::GDTLoader gdt_loader;
  gdt_loader.Load(gdt_reg);

  return kEfiFail;
}

EXTERN_C Kernel::Void hal_real_init(Kernel::Void) noexcept {
  hal_pre_init_scheduler();

#ifdef __FSKIT_INCLUDES_HEFS__
  Kernel::HeFS::fs_init_hefs();
#elif defined(__FSKIT_INCLUDES_NEFS__)
  Kernel::NeFS::fs_init_nefs();
#endif

  Kernel::HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr);

  Kernel::HAL::Register64 idt_reg;
  idt_reg.Base = (Kernel::UIntPtr) kInterruptVectorTable;

  Kernel::HAL::IDTLoader idt_loader;

  idt_loader.Load(idt_reg);

  /// after the scheduler runs, we must look over teams, every 5000s in order to schedule every
  /// process according to their affinity fairly.

  auto constexpr kSchedTeamSwitchMS = 5U;  /// @brief Team switch time in milliseconds.

  Kernel::HardwareTimer timer(rtl_milliseconds(kSchedTeamSwitchMS));

  STATIC Kernel::Array<UserProcessTeam, kSchedTeamCount> kTeams;

  SizeT team_index = 0U;

  /// @brief This just loops over the teams and switches between them.
  /// @details Not even round-robin, just a simple loop in this boot core we're at.
  while (YES) {
    if (team_index > (kSchedTeamCount - 1)) {
      team_index = 0U;
    }

    kTeams[team_index].Id() = team_index;

    while (!UserProcessScheduler::The().SwitchTeam(kTeams[team_index]));

    timer.Wait();

    ++team_index;
  }
}
#endif  // ifndef __NE_MODULAR_KERNEL_COMPONENTS__