aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/kernel/main.cpp
blob: bdf530cf5cbdb3f6c8c3bc9e20d1ca3ad86dfe59 (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
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
#include "arch/kernel/main.hpp"

#include "arch/boot/pointers.hpp"
#include "arch/memory/frame_allocator.hpp"
#include "arch/memory/multiboot.hpp"
#include "arch/video/vga/text.hpp"

namespace teachos::arch::kernel
{
  auto assert(bool condition) -> void
  {
    if (condition)
    {
      return;
    }

    video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black);
    for (;;)
    {
      // Trick the compiler into thinking the variable is changes at run time,
      // to prevent the while loop being optimized away
      // See
      // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can
      // for more information.
      asm volatile("" : "+g"(condition));
    }
  }

  auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area *& memory_areas,
                          uint8_t & area_count) -> void
  {
    auto expected_entry_size = mminfo->entry_size;
    constexpr auto actual_entry_size = sizeof(arch::memory::memory_area);
    assert(expected_entry_size == actual_entry_size);

    auto total_size = mminfo->tag.size;
    auto total_entries_size = total_size - sizeof(arch::memory::memory_map) + actual_entry_size;
    auto number_of_entries = total_entries_size / actual_entry_size;

    memory_areas = &mminfo->entries;
    area_count = number_of_entries;
  }

  auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t & kernel_start,
                            uint64_t & kernel_end) -> void
  {
    auto expected_entry_size = symbol->entry_size;
    constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header);
    assert(expected_entry_size == actual_entry_size);

    auto expected_total_size = symbol->tag.size;
    auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections;
    constexpr auto actual_total_section_size = sizeof(arch::memory::elf_symbols_section) - sizeof(uint32_t);
    auto actual_total_size = actual_total_entry_size + actual_total_section_size;
    assert(expected_total_size == actual_total_size);

    auto begin = reinterpret_cast<arch::memory::elf_section_header *>(&symbol->end);
    auto end = begin + symbol->number_of_sections;
    assert(begin->is_null());

    std::size_t symbol_table_section_count = 0U;
    std::size_t dynamic_section_count = 0U;

    for (auto section = begin; section != end; ++section)
    {
      bool const writeable = section->flags.writeable();
      bool const occupies_memory = section->flags.occupies_memory();
      bool const is_executable = section->flags.is_executable();
      bool const contains_duplicate_data = section->flags.contains_duplicate_data();
      bool const contains_strings = section->flags.contains_strings();
      bool const section_header_info_is_section_header_table_index =
          section->flags.section_header_info_is_section_header_table_index();
      bool const preserve_ordering_after_combination = section->flags.preserve_ordering_after_combination();
      bool const requires_special_os_processing = section->flags.requires_special_os_processing();
      bool const is_section_group_member = section->flags.is_section_group_member();
      bool const holds_thread_local_data = section->flags.holds_thread_local_data();
      bool const is_compressed = section->flags.is_compressed();
      bool const has_special_ordering_requirements = section->flags.has_special_ordering_requirements();
      bool const is_excluded_unless_referenced_or_allocated =
          section->flags.is_excluded_unless_referenced_or_allocated();

      if (writeable && occupies_memory && is_executable && contains_duplicate_data && contains_strings &&
          section_header_info_is_section_header_table_index && preserve_ordering_after_combination &&
          requires_special_os_processing && is_section_group_member && holds_thread_local_data && is_compressed &&
          has_special_ordering_requirements && is_excluded_unless_referenced_or_allocated)
      {
      }

      switch (section->type)
      {
        case arch::memory::elf_section_type::PROGRAMM: {
          if (section->virtual_address < kernel_start)
          {
            kernel_start = section->virtual_address;
          }
          auto virtual_address_end = section->virtual_address + section->section_size;
          if (virtual_address_end > kernel_end)
          {
            kernel_end = virtual_address_end;
          }
          break;
        }
        case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE:
        case arch::memory::elf_section_type::SYMBOL_TABLE:
          symbol_table_section_count++;
          break;
        case arch::memory::elf_section_type::DYNAMIC:
          dynamic_section_count++;
          break;
        default:
          // All other cases are not important and can be ignored
          break;
      }
    }

    assert(symbol_table_section_count == 1U);
    assert(dynamic_section_count <= 1U);
  }

  template<typename T>
    requires std::is_pointer<T>::value
  auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T
  {
    return reinterpret_cast<T>(reinterpret_cast<uint8_t *>(ptr) + ((size + 7) & ~7));
  }

  auto main() -> void
  {
    using namespace video::vga;

    text::clear();
    text::cursor(false);
    text::write("TeachOS is starting up...", text::common_attributes::green_on_black);

    auto * multiboot_information_pointer =
        reinterpret_cast<arch::memory::multi_boot_info *>(arch::boot::multiboot_information_pointer);
    auto multiboot_tag = &(multiboot_information_pointer->tags);

    uint64_t kernel_start = UINT64_MAX;
    uint64_t kernel_end = 0;
    uint64_t multiboot_start = arch::boot::multiboot_information_pointer;
    uint64_t multiboot_end = multiboot_start + multiboot_information_pointer->total_size;
    arch::memory::memory_area * memory_areas = nullptr;
    uint8_t area_count = 0;

    /*
     * Loop over the multiboot2 tags to access the information needed.
     * Tags are defined in the header file and are padded so that each
     * Tag starts at an 8-bytes aligned adress.
     *
     * The increment part aligns the size to an 8-byte address.
     */
    for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END;
         tag = align_to_8_byte_boundary(tag, tag->size))
    {
      switch (tag->type)
      {
        case arch::memory::multi_boot_tag_type::ELF_SECTIONS: {
          auto symbol = reinterpret_cast<teachos::arch::memory::elf_symbols_section *>(tag);
          process_elf_sections(symbol, kernel_start, kernel_end);
          break;
        }
        case arch::memory::multi_boot_tag_type::MEMORY_MAP: {
          auto mminfo = reinterpret_cast<teachos::arch::memory::memory_map *>(tag);
          process_memory_map(mminfo, memory_areas, area_count);
          break;
        }
        default:
          // All other cases are not important and can be ignored
          break;
      }
    }

    // Kernel start       0x100000
    // Kernel end         0x23E943
    //    Kernel Size       0x13E943 -> 1'304'899
    // Multiboot start    0x241AA0
    // Multiboot end      0x242280
    //    Multiboot Size    0x7E0 -> 2'016
    // Memory area start  0x241b10
    //
    // Address of Frame:  0x203F00
    auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end,
                                                        memory_areas, area_count);
    auto allocated = allocator.allocate_frame();

    // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling
    if (allocated.has_value())
    {
      video::vga::text::write("Allocated Frame address: ", video::vga::text::common_attributes::green_on_black);
      video::vga::text::write_number(reinterpret_cast<uint64_t>(&allocated->frame_number),
                                     video::vga::text::common_attributes::green_on_black);
      video::vga::text::write("Allocated Frame number: ", video::vga::text::common_attributes::green_on_black);
      video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black);
    }
    else
    {
      video::vga::text::write("NO VALUE", video::vga::text::common_attributes::green_on_black);
    }
  }
}  // namespace teachos::arch::kernel