WIP: paging and better malloc.

This commit is contained in:
Patrick 2024-01-26 15:02:30 +01:00
parent 75ec3751fe
commit 836d589c9b
19 changed files with 1230 additions and 56 deletions

View File

@ -15,6 +15,7 @@ target = GetOption('target')
env = Environment(tools = ['default', 'compilation_db']) env = Environment(tools = ['default', 'compilation_db'])
env.Append(CCFLAGS = ['-g', '-O0']) env.Append(CCFLAGS = ['-g', '-O0'])
env.Append(CPPDEFINES = ['BASTL_EXTENSIONS=1'])
# env.Append(CCFLAGS = ['-O2']) # env.Append(CCFLAGS = ['-O2'])
env['ISO_FILES'] = [] env['ISO_FILES'] = []

View File

@ -4,6 +4,10 @@
#if !defined(BAD_APPLE_OS_ALGORITHM_INCLUDED) #if !defined(BAD_APPLE_OS_ALGORITHM_INCLUDED)
#define BAD_APPLE_OS_ALGORITHM_INCLUDED #define BAD_APPLE_OS_ALGORITHM_INCLUDED
#include <cstddef>
#include <iterator>
#include <utility>
namespace std namespace std
{ {
template<typename T> template<typename T>
@ -17,6 +21,76 @@ constexpr const T& max(const T& left, const T& right)
{ {
return right > left ? right : left; return right > left ? right : left;
} }
template<typename RandomIt, class Compare>
constexpr void sort(RandomIt first, RandomIt last, Compare comp)
{
// TODO: be smarter
const size_t size = last - first;
size_t sorted = 1;
while (sorted < size)
{
// find insertion pos
size_t pos = 0;
while (pos < sorted)
{
if (comp(*(first + sorted), *(first + pos)))
{
break;
}
++pos;
}
// bail if already sorted
if (pos == sorted)
{
++sorted;
continue;
}
// insert at pos
for (size_t idx = pos; idx < sorted; ++idx)
{
swap(*(first + idx), *(first + sorted));
}
++sorted;
}
}
template<typename RandomIt>
constexpr void sort(RandomIt first, RandomIt last)
{
sort(first, last, [](auto left, auto right) { return left < right; });
}
template<typename ForwardIt, typename UnaryPredicate>
constexpr ForwardIt find_if(ForwardIt first, ForwardIt last, UnaryPredicate pred)
{
for (auto it = first; it != last; ++it)
{
if (pred(*it))
{
return it;
}
}
return last;
}
template<typename ForwardIt, typename UnaryPredicate>
constexpr ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate pred)
{
auto found = find_if(first, last, pred);
if (found != last)
{
for (auto tomove = next(found); tomove != last; ++tomove)
{
if (!pred(*tomove))
{
*found = move(*tomove);
++found;
}
}
}
return found;
}
} }
#endif // !defined(BAD_APPLE_OS_ALGORITHM_INCLUDED) #endif // !defined(BAD_APPLE_OS_ALGORITHM_INCLUDED)

18
bastl/include/iterator Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#if !defined(BAD_APPLE_OS_ITERATOR_HPP_INCLUDED)
#define BAD_APPLE_OS_ITERATOR_HPP_INCLUDED
#include <cstddef>
namespace std
{
template<typename InputIt>
InputIt next(InputIt it, std::ptrdiff_t n = 1) // TODO: this is not really correct...
{
return it + n;
}
}
#endif // !defined(BAD_APPLE_OS_ITERATOR_HPP_INCLUDED)

44
bastl/include/memory Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#if !defined(BAD_APPLE_OS_MEMORY_HPP_INCLUDED)
#define BAD_APPLE_OS_MEMORY_HPP_INCLUDED
#include <cstddef>
namespace std
{
constexpr void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space) noexcept
{
if (space < size) {
return nullptr;
}
std::size_t addr = __builtin_bit_cast(std::size_t, ptr);
if (addr % alignment != 0)
{
std::size_t offset = alignment + (addr % alignment);
if (space < size + offset)
{
return nullptr;
}
addr += offset;
space -= offset;
ptr = __builtin_bit_cast(void*, addr);
}
return ptr;
}
#if defined(BASTL_EXTENSIONS)
template<typename T>
constexpr T alignUp(T value, T alignTo) noexcept
{
if (value % alignTo != 0)
{
return value + alignTo - (value % alignTo);
}
return value;
}
#endif
}
#endif // !defined(BAD_APPLE_OS_MEMORY_HPP_INCLUDED)

93
bastl/include/span Normal file
View File

@ -0,0 +1,93 @@
#pragma once
#if !defined(BAD_APPLE_OS_SPAN_HPP_INCLUDED)
#define BAD_APPLE_OS_SPAN_HPP_INCLUDED
#include <array>
#include <cstddef>
#include <initializer_list>
#include <stdexcept>
#include <type_traits>
namespace std
{
inline constexpr size_t dynamic_extent = size_t(-1);
template<typename T, size_t Extent = dynamic_extent> // TODO: use the extent?
class span
{
public:
using element_type = T;
using value_type = remove_cv_t<T>;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = element_type&;
using const_reference = const element_type&;
using pointer = element_type*;
using const_pointer = const element_type*;
using iterator = pointer;
using const_iterator = const_pointer;
static constexpr size_t extent = Extent;
private:
pointer _first = nullptr;
pointer _last = nullptr;
public:
constexpr span() noexcept = default;
constexpr span(const span&) noexcept = default;
template<typename It>
explicit(extent != dynamic_extent)
constexpr span(It first, size_type count) : _first(&*first), _last(&*(_first + count)) {}
template<typename It>
explicit(extent != dynamic_extent)
constexpr span(It first, It last) : _first(&*first), _last(&*last) {}
template<size_t N>
constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept : span(&arr[0], N) {}
template<typename U, size_t N>
constexpr span(array<U, N>& arr) noexcept : span(&arr[0], N) {}
template<typename U, size_t N>
constexpr span(const array<U, N>& arr) noexcept : span(&arr[0], N) {}
explicit(Extent != dynamic_extent)
constexpr span(initializer_list<value_type> il) noexcept : span(il.begin(), il.size()) {}
template<typename U, size_t N>
explicit(extent != dynamic_extent && N != dynamic_extent)
constexpr span(const span<U, N>& source) noexcept : span(source.begin(), source.end()) {}
constexpr span& operator=(const span&) noexcept = default;
constexpr reference operator[](size_type idx) const { return _first[idx]; }
constexpr iterator begin() const noexcept { return _first; }
constexpr const_iterator cbegin() const noexcept { return _first; }
constexpr iterator end() const noexcept { return _last; }
constexpr const_iterator cend() const noexcept { return _last; }
constexpr reference front() const { return *_first; }
constexpr reference back() const { return *(_last - 1); }
constexpr reference at(size_type pos) const
{
if (pos >= size()) {
__ba_throw std::out_of_range();
}
return (*this)[pos];
}
constexpr pointer data() const noexcept { return _first; }
constexpr size_type size() const noexcept { return _last - _first; }
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
constexpr bool empty() const noexcept { return size() == 0; }
// TODO: subspans
};
}
#endif // !defined(BAD_APPLE_OS_SPAN_HPP_INCLUDED)

View File

@ -26,6 +26,66 @@ struct remove_reference<T&&>
template<typename T> template<typename T>
using remove_reference_t = typename remove_reference<T>::type; using remove_reference_t = typename remove_reference<T>::type;
template<typename T>
struct remove_const
{
using type = T;
};
template<typename T>
struct remove_const<const T>
{
using type = T;
};
template<typename T>
using remove_const_t = typename remove_const<T>::type;
template<typename T>
struct remove_volatile
{
using type = T;
};
template<typename T>
struct remove_volatile<volatile T>
{
using type = T;
};
template<typename T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<typename T>
struct remove_cv
{
using type = T;
};
template<typename T>
struct remove_cv<const T>
{
using type = T;
};
template<typename T>
struct remove_cv<const volatile T>
{
using type = T;
};
template<typename T>
using remove_cv_t = typename remove_cv<T>::type;
template<typename T>
struct type_identity
{
using type = T;
};
template<typename T>
using type_identity_t = type_identity<T>::type;
} }
#endif // !defined(BAD_APPLE_OS_TYPE_TRAITS_INCLUDED) #endif // !defined(BAD_APPLE_OS_TYPE_TRAITS_INCLUDED)

View File

@ -4,6 +4,7 @@
#if !defined(BAD_APPLE_OS_VECTOR_INCLUDED) #if !defined(BAD_APPLE_OS_VECTOR_INCLUDED)
#define BAD_APPLE_OS_VECTOR_INCLUDED #define BAD_APPLE_OS_VECTOR_INCLUDED
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <new> #include <new>
#include <stdexcept> #include <stdexcept>
@ -11,13 +12,13 @@
namespace std namespace std
{ {
template<typename T> // TODO: allocator template<typename T, typename TAlloc = void> // TODO: allocator
class vector class vector
{ {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
using difference_type = std::ptrdiff_t; using difference_type = ptrdiff_t;
using reference = value_type&; using reference = value_type&;
using const_reference = const value_type&; using const_reference = const value_type&;
using pointer = value_type*; using pointer = value_type*;
@ -210,7 +211,7 @@ public:
constexpr void push_back(value_type&& value) constexpr void push_back(value_type&& value)
{ {
reserve(size() + 1); reserve(size() + 1);
::new (&_elements[size()]) T(std::move(value)); ::new (&_elements[size()]) T(move(value));
++_size; ++_size;
} }
@ -223,7 +224,7 @@ public:
constexpr reference emplace_back(TArgs&&... args) constexpr reference emplace_back(TArgs&&... args)
{ {
reserve(size() + 1); reserve(size() + 1);
::new (&_elements[size()]) T(std::forward<TArgs>(args)...); ::new (&_elements[size()]) T(forward<TArgs>(args)...);
++_size; ++_size;
} }
@ -274,6 +275,27 @@ public:
} }
_size = newSize; _size = newSize;
} }
constexpr iterator erase(const_iterator first, const_iterator last)
{
// the spec wants the parameters to be const iterators...
iterator realFirst = begin() + (first - begin());
iterator realLast = begin() + (last - begin());
const size_t newSize = size() - (last - first);
for (auto it = realLast; it != end(); ++it)
{
*realFirst = move(*it);
++realFirst;
}
resize(newSize);
return realFirst;
}
constexpr iterator erase(const_iterator pos)
{
return erase(pos, pos + 1);
}
private: private:
void updateCapacity(size_type newCapacity) void updateCapacity(size_type newCapacity)
{ {
@ -281,6 +303,10 @@ private:
return; return;
} }
T* newElements = static_cast<T*>(malloc(newCapacity * sizeof(T))); T* newElements = static_cast<T*>(malloc(newCapacity * sizeof(T)));
if (newElements == nullptr)
{
__ba_throw bad_alloc();
}
for (size_type idx = 0; idx < size(); ++idx) for (size_type idx = 0; idx < size(); ++idx)
{ {
::new (&newElements[idx]) T(move(_elements[idx])); ::new (&newElements[idx]) T(move(_elements[idx]));
@ -291,6 +317,16 @@ private:
_capacity = newCapacity; _capacity = newCapacity;
} }
}; };
template<typename T, typename TAlloc, typename Pred>
constexpr vector<T, TAlloc>::size_type erase_if(vector<T, TAlloc>& vec, Pred pred)
{
auto it = remove_if(vec.begin(), vec.end(), pred);
auto removed = vec.end() - it;
vec.erase(it, vec.end());
return removed;
}
} }
#endif // !defined(BAD_APPLE_OS_VECTOR_INCLUDED) #endif // !defined(BAD_APPLE_OS_VECTOR_INCLUDED)

View File

@ -1,8 +1,24 @@
#!/bin/bash #!/bin/bash
QEMU_ARGS=()
WAIT=true
while [ ! -z "$1" ] ; do
case "$1" in
"--detach")
WAIT=false
;;
*)
QEMU_ARGS+=("$1")
;;
esac
shift
done
qemu-system-x86_64 \ qemu-system-x86_64 \
--bios /usr/share/edk2/x64/OVMF.fd \ --bios /usr/share/edk2/x64/OVMF.fd \
-vga virtio \ -vga virtio \
-serial stdio \ -serial stdio \
-drive if=none,id=stick,format=raw,file=staging/x86_64_iso/fat.img \ -drive if=none,id=stick,format=raw,file=staging/x86_64_iso/fat.img \
-device nec-usb-xhci,id=xhci \ -device nec-usb-xhci,id=xhci \
-device usb-storage,bus=xhci.0,drive=stick "$@" -device usb-storage,bus=xhci.0,drive=stick "${QEMU_ARGS[@]}" &
if ${WAIT} ; then
wait
fi

View File

@ -42,10 +42,12 @@ any_target_sources = Split('''
src/app/main.cpp src/app/main.cpp
src/drivers/pci.cpp src/drivers/pci.cpp
src/drivers/usb.cpp
src/libs/psf.cpp src/libs/psf.cpp
src/os/draw.cpp src/os/draw.cpp
src/os/memory.cpp
src/os/panic.cpp src/os/panic.cpp
src/os/tty.cpp src/os/tty.cpp
src/os/resources/lat9-08.psf.s src/os/resources/lat9-08.psf.s

View File

@ -0,0 +1,17 @@
#pragma once
#if !defined(BAD_APPLE_OS_DRIVERS_USB_HPP_INCLUDED)
#define BAD_APPLE_OS_DRIVERS_USB_HPP_INCLUDED
namespace baos::pci
{
struct Header;
}
namespace baos::usb
{
[[nodiscard]] bool initController(const pci::Header& pciHeader) noexcept;
}
#endif // !defined(BAD_APPLE_OS_DRIVERS_USB_HPP_INCLUDED)

View File

@ -0,0 +1,72 @@
#pragma once
#if !defined(BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED)
#define BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED
#include <bit>
#include <cstdint>
#include <span>
extern "C" int gKernelStart;
extern "C" int gKernelEnd;
namespace baos
{
struct PageTableEntry
{
bool present : 1;
bool writable : 1;
bool user : 1;
bool writeThrough : 1;
bool cacheDisabled : 1;
bool accessed : 1;
bool dirty : 1;
bool pageSize : 1;
bool global : 1;
std::uint8_t avl : 3;
std::uint64_t address : 40;
std::uint16_t avl2 : 11;
bool executeDisable : 1;
};
enum class MemoryType
{
USABLE,
UNUSABLE,
MMIO,
RESERVED
};
struct MemoryRange
{
std::uint64_t pageBase;
std::uint64_t numPages;
MemoryType type = MemoryType::USABLE;
MemoryRange& operator=(const MemoryRange&) noexcept = default;
bool operator<(const MemoryRange& other) const noexcept
{
return pageBase < other.pageBase;
}
};
void setupPaging(std::span<const MemoryRange> memoryRanges) noexcept;
[[nodiscard]] const char* memoryTypeName(MemoryType type) noexcept;
[[nodiscard]] void* allocatePages(unsigned numConsecutive) noexcept;
[[nodiscard]] inline void* allocatePage() noexcept { return allocatePages(1); }
void setupIdentityPaging(std::uint64_t page) noexcept;
void setupIdentityPaging2M(std::uint64_t page) noexcept;
void setupIdentityPaging(std::uint64_t firstPage, std::uint64_t lastPage) noexcept;
inline void identityMapRegion(void* start, std::size_t bytes) noexcept
{
std::uint64_t firstPage = std::bit_cast<std::uint64_t>(start) / 4096;
std::uint64_t lastPage = std::bit_cast<std::uint64_t>(static_cast<std::uint8_t*>(start) + bytes) / 4096 + 1;
setupIdentityPaging(firstPage, lastPage);
}
}
#endif // !defined(BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED)

View File

@ -1,8 +1,10 @@
#include <bit>
#include <cstdio> #include <cstdio>
#include "drivers/pci.hpp" #include "drivers/pci.hpp"
#include "drivers/ps2.hpp" #include "drivers/ps2.hpp"
#include "os/memory.hpp"
namespace namespace
{ {
@ -49,6 +51,61 @@ void cmdShowKeys() noexcept
} }
} }
} }
void cmdDumpPageTable() noexcept
{
std::uint64_t cr3 = 0;
__asm__ __volatile__(
"mov %%cr3, %0"
: "=a"(cr3)
:
);
std::uint64_t pml4Addr = cr3 & ~0xFFF;
std::printf("pml4 address: 0x%lX\n", pml4Addr);
baos::PageTableEntry* pml4 = std::bit_cast<baos::PageTableEntry*>(pml4Addr);
auto printPDE = [](const baos::PageTableEntry& pde)
{
std::printf("%s%s%s%s%s%s%s%s%s, address=%lX\n",
pde.present ? " P" : "",
pde.writable ? " W" : "",
pde.user ? " U" : "",
pde.writeThrough ? " WT" : "",
pde.cacheDisabled ? " CD" : "",
pde.accessed ? " A" : "",
pde.dirty ? " D" : "",
pde.pageSize ? " PS" : "",
pde.executeDisable ? " XD" : "",
pde.address * 4096);
};
for (unsigned pml4e = 0; pml4e < 512; ++pml4e)
{
if (!pml4[pml4e].present) {
continue;
}
std::printf("%d]", pml4e);
printPDE(pml4[pml4e]);
baos::PageTableEntry* pdp = std::bit_cast<baos::PageTableEntry*>(pml4[pml4e].address * 4096);
for (unsigned pdpe = 0; pdpe < 512; ++pdpe)
{
if (!pdp[pdpe].present) {
continue;
}
std::printf("%d.%d]", pml4e, pdpe);
printPDE(pdp[pdpe]);
baos::PageTableEntry* pd = std::bit_cast<baos::PageTableEntry*>(pdp[pdpe].address * 4096);
for (unsigned pde = 0; pde < 512; ++pde)
{
if (!pd[pde].present) {
continue;
}
std::printf("%d.%d.%d]", pml4e, pdpe, pde);
printPDE(pd[pde]);
}
}
}
}
} }
extern "C" void main() extern "C" void main()
@ -72,6 +129,11 @@ extern "C" void main()
cmdShowKeys(); cmdShowKeys();
continue; continue;
} }
else if (cmd == "dump-pages")
{
cmdDumpPageTable();
continue;
}
std::printf("Unknown command: %s.\n", cmd.c_str()); std::printf("Unknown command: %s.\n", cmd.c_str());
} }
} }

View File

@ -7,7 +7,7 @@
namespace namespace
{ {
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024 * 1024; inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024 * 1024;
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t); inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * alignof(max_align_t);
max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS]; max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS];
@ -20,8 +20,8 @@ struct AllocInfo
{ {
size_t elements; size_t elements;
}; };
static_assert(sizeof(MallocBlock) <= sizeof(max_align_t)); static_assert(sizeof(MallocBlock) <= alignof(max_align_t));
static_assert(sizeof(AllocInfo) <= sizeof(max_align_t)); static_assert(sizeof(AllocInfo) <= alignof(max_align_t));
MallocBlock* gNextBlock = []() MallocBlock* gNextBlock = []()
{ {

View File

@ -0,0 +1,272 @@
#include "drivers/usb.hpp"
#include <algorithm>
#include <array>
#include <bit>
#include <cassert>
#include <cstdio>
#include "drivers/pci.hpp"
namespace baos::usb
{
namespace
{
inline constexpr std::uint8_t USB_PROGIF_UHCI_CONTROLLER = 0x0;
inline constexpr std::uint8_t USB_PROGIF_OHCI_CONTROLLER = 0x10;
inline constexpr std::uint8_t USB_PROGIF_EHCI_CONTROLLER = 0x20;
inline constexpr std::uint8_t USB_PROGIF_XHCI_CONTROLLER = 0x30;
#define BAOS_MEMORY_REGISTER_RO(offset, type, name) \
[[nodiscard]] const Register<type> name() const noexcept { return Register(*reinterpret_cast<type*>(base + offset)); }
#define BAOS_MEMORY_REGISTER_RW(offset, type, name) \
[[nodiscard]] Register<type> name() const noexcept { return Register(*reinterpret_cast<type*>(base + offset)); }
#define BAOS_MEMORY_REGISTER_RO_PARAM(offset, type, name, paramType, paramName) \
[[nodiscard]] const Register<type> name(paramType paramName) const noexcept { return Register(*reinterpret_cast<type*>(base + offset)); }
#define BAOS_MEMORY_REGISTER_RW_PARAM(offset, type, name, paramType, paramName) \
[[nodiscard]] Register<type> name(paramType paramName) const noexcept { return Register(*reinterpret_cast<type*>(base + offset)); }
struct XHCIHCSParams1
{
std::uint8_t maxSlots;
std::uint16_t maxInterrupts : 11;
std::uint8_t reserved : 5;
std::uint8_t maxPorts;
} __attribute__((packed));
static_assert(sizeof(XHCIHCSParams1) == 4);
#define BAOS_MEMORY_BARRIER() __asm__ __volatile__ ("" : : : "memory")
#define BAOS_STORE_FENCE() __asm__ __volatile__ ("sfence" : : : "memory")
#define BAOS_LOAD_FENCE() __asm__ __volatile__ ("lfence" : : : "memory")
#define BAOS_MEMORY_FENCE() __asm__ __volatile__ ("mfence" : : : "memory")
template<typename T>
class Register
{
private:
T& mMemory;
public:
explicit Register(T& memory) noexcept : mMemory(memory) {}
Register& operator=(const T& value) noexcept
{
set(value);
return *this;
}
operator T() const noexcept { return get(); }
void set(const T& value) noexcept
{
BAOS_STORE_FENCE();
mMemory = value;
}
[[nodiscard]] T get() const noexcept
{
BAOS_MEMORY_BARRIER();
T value = mMemory;
BAOS_LOAD_FENCE();
return value;
}
};
struct XHCICapabilityRegisters
{
std::uint64_t base;
BAOS_MEMORY_REGISTER_RO(0x00, std::uint8_t, caplength)
BAOS_MEMORY_REGISTER_RO(0x02, std::uint16_t, ifaceVersion)
BAOS_MEMORY_REGISTER_RO(0x04, XHCIHCSParams1, hcsParams1)
BAOS_MEMORY_REGISTER_RO(0x08, std::uint32_t, hcsParams2)
BAOS_MEMORY_REGISTER_RO(0x0C, std::uint32_t, hcsParams3)
BAOS_MEMORY_REGISTER_RO(0x10, std::uint32_t, hccParams1)
BAOS_MEMORY_REGISTER_RO(0x14, std::uint32_t, dbOff)
BAOS_MEMORY_REGISTER_RO(0x18, std::uint32_t, rtsOff)
BAOS_MEMORY_REGISTER_RO(0x1C, std::uint32_t, hccParams2)
BAOS_MEMORY_REGISTER_RO(0x20, std::uint32_t, vtiosOff)
};
struct XHCIUSBCommand
{
/* 0 */ bool runStop : 1;
/* 1 */ bool hostControllerReset : 1;
/* 2 */ bool interrupterEnable : 1;
/* 3 */ bool hostSystemErrorEnable : 1;
/* 4 */ std::uint8_t reserved0 : 3;
/* 7 */ bool lightHostControllerReset : 1;
/* 8 */ bool controllerSaveState : 1;
/* 9 */ bool controllerRestoreState : 1;
/* 10 */ bool enableWrapEvent : 1;
/* 11 */ bool enableU3MFINDEXStop : 1;
/* 12 */ std::uint8_t reserved1 : 1;
/* 13 */ bool cemEnable : 1;
/* 14 */ bool extendedTBCEnable : 1;
/* 15 */ bool extendedTBCTRBStatusEnable : 1;
/* 16 */ bool vtioEnable : 1;
/* 17 */ std::uint16_t reserved2 : 15;
};
static_assert(sizeof(XHCIUSBCommand) == 4);
struct XHCIUSBStatus
{
/* 0 */ bool hcHalted : 1;
/* 1 */ std::uint8_t reserved0 : 1;
/* 2 */ bool hostSystemError : 1;
/* 3 */ bool eventInterrupt : 1;
/* 4 */ bool portChangeDetect : 1;
/* 5 */ std::uint8_t reserved1 : 3;
/* 8 */ const bool saveStateStatus : 1;
/* 9 */ const bool restoreStateStatus : 1;
/* 10 */ bool saveRestoreError : 1;
/* 11 */ const bool controllerNotReady : 1;
/* 12 */ const bool hostControllerError : 1;
/* 13 */ std::uint32_t reserved2 : 19;
};
static_assert(sizeof(XHCIUSBStatus) == 4);
struct XHCIConfig
{
std::uint8_t maxDeviceSlotsEnabled : 7;
bool u3EntryEnable : 1;
bool configurationInformationEnable : 1;
std::uint32_t reserved : 22;
};
static_assert(sizeof(XHCIConfig) == 4);
struct XHCIOperationalRegisters
{
std::uint64_t base;
BAOS_MEMORY_REGISTER_RW(0x00, XHCIUSBCommand, usbCmd)
BAOS_MEMORY_REGISTER_RW(0x04, XHCIUSBStatus, usbStatus)
BAOS_MEMORY_REGISTER_RO(0x08, std::uint32_t, pageSize)
BAOS_MEMORY_REGISTER_RW(0x14, std::uint32_t, dnCtrl)
BAOS_MEMORY_REGISTER_RW(0x18, std::uint64_t, crcr)
BAOS_MEMORY_REGISTER_RW(0x30, std::uint64_t, dcbaap)
BAOS_MEMORY_REGISTER_RW(0x38, XHCIConfig, config)
BAOS_MEMORY_REGISTER_RW_PARAM(0x400 + 0x10 * (port-1), std::uint32_t, portSC, std::uint32_t, port)
BAOS_MEMORY_REGISTER_RW_PARAM(0x404 + 0x10 * (port-1), std::uint32_t, portPMSC, std::uint32_t, port)
BAOS_MEMORY_REGISTER_RO_PARAM(0x408 + 0x10 * (port-1), std::uint32_t, portLI, std::uint32_t, port)
BAOS_MEMORY_REGISTER_RW_PARAM(0x40C + 0x10 * (port-1), std::uint32_t, portHLPMC, std::uint32_t, port)
};
struct XHCIHostControllerRuntimeRegisters
{
std::uint64_t base;
BAOS_MEMORY_REGISTER_RO(0x00, std::uint32_t, mfIndex)
BAOS_MEMORY_REGISTER_RW_PARAM(0x20 + (32 * interrupter), std::uint32_t, iman, std::uint32_t, interrupter)
BAOS_MEMORY_REGISTER_RW_PARAM(0x24 + (32 * interrupter), std::uint32_t, imod, std::uint32_t, interrupter)
BAOS_MEMORY_REGISTER_RW_PARAM(0x28 + (32 * interrupter), std::uint32_t, erstsz, std::uint32_t, interrupter)
BAOS_MEMORY_REGISTER_RW_PARAM(0x30 + (32 * interrupter), std::uint64_t, erstba, std::uint32_t, interrupter)
BAOS_MEMORY_REGISTER_RW_PARAM(0x38 + (32 * interrupter), std::uint64_t, erdp, std::uint32_t, interrupter)
};
struct XHCIHostController
{
XHCICapabilityRegisters capabilityRegs = {};
XHCIOperationalRegisters operationalRegs = {};
XHCIHostControllerRuntimeRegisters controllerRuntimeRegs = {};
explicit XHCIHostController(std::uint64_t base) noexcept : capabilityRegs(base)
{
operationalRegs.base = capabilityRegs.base + capabilityRegs.caplength();
controllerRuntimeRegs.base = capabilityRegs.base + capabilityRegs.rtsOff();
}
XHCIHostController(const XHCIHostController&) noexcept = default;
XHCIHostController& operator=(const XHCIHostController&) noexcept = default;
};
bool initUHCIController(const pci::Header& pciHeader) noexcept
{
(void) pciHeader;
// TODO: not implemented yet
return false;
}
bool initOHCIController(const pci::Header& pciHeader) noexcept
{
(void) pciHeader;
// TODO: not implemented yet
return false;
}
bool initEHCIController(const pci::Header& pciHeader) noexcept
{
(void) pciHeader;
// TODO: not implemented yet
return false;
}
std::array<void*, 32> gDeviceContextBasePointers alignas(64);
bool initXHCIController(const pci::Header& pciHeader) noexcept
{
return false;
pci::GeneralDeviceHeader gdHeader = {};
if (!pci::getGeneralDeviceHeader(pciHeader, gdHeader)) {
return false;
}
const std::uint64_t registerMemory = static_cast<std::uint64_t>(gdHeader.bar1) << 32 | gdHeader.bar0;
std::printf("XHCI register memory: 0x%lX\n", registerMemory);
XHCIHostController controller(registerMemory);
// see chapter 4.2 (Host Controller Initialization) of the XHCI spec
// https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf
// 1. wait until the controller is ready
while (controller.operationalRegs.usbStatus().get().controllerNotReady);
// 2. set maximum enabled slots
const XHCIHCSParams1 hcsParams1 = controller.capabilityRegs.hcsParams1();
XHCIConfig config = controller.operationalRegs.config();
config.maxDeviceSlotsEnabled = std::min(hcsParams1.maxSlots, static_cast<std::uint8_t>(gDeviceContextBasePointers.size() - 1));
controller.operationalRegs.config() = config;
// 3. setup the device context base address pointer
const std::uint64_t pointer = std::bit_cast<std::uint64_t>(gDeviceContextBasePointers.data());
assert((pointer & 0b11111) == 0);
controller.operationalRegs.dcbaap() = pointer;
XHCIUSBCommand cmd = controller.operationalRegs.usbCmd();
cmd.runStop = true;
controller.operationalRegs.usbCmd() = cmd;
cmd = controller.operationalRegs.usbCmd();
while (true)
{
const XHCIUSBStatus status = controller.operationalRegs.usbStatus();
if (!status.hcHalted) {
break;
}
}
std::printf("MaxSlots: %d, MaxInterrupts: %d, MaxPorts: %d\n", hcsParams1.maxSlots, hcsParams1.maxInterrupts, hcsParams1.maxPorts);
//const XHCIOperationalRegisters operationalRegisters{registerMemory + capabilityRegisters.caplength()};
// TODO: not implemented yet
return false;
}
}
bool initController(const pci::Header& pciHeader) noexcept
{
switch (pciHeader.progIf)
{
case USB_PROGIF_UHCI_CONTROLLER:
return initUHCIController(pciHeader);
case USB_PROGIF_OHCI_CONTROLLER:
return initOHCIController(pciHeader);
case USB_PROGIF_EHCI_CONTROLLER:
return initEHCIController(pciHeader);
case USB_PROGIF_XHCI_CONTROLLER:
return initXHCIController(pciHeader);
default:
return false; // what is this?
}
}
}

View File

@ -3,6 +3,7 @@
#include <cstring> #include <cstring>
#include "libs/psf.hpp" #include "libs/psf.hpp"
#include "os/memory.hpp"
namespace draw namespace draw
{ {

View File

@ -31,6 +31,15 @@ void iprintf(const char* format, ...) noexcept
PrintFHelper<InterruptPrinter>().vprintf(format, parameters); PrintFHelper<InterruptPrinter>().vprintf(format, parameters);
va_end(parameters); va_end(parameters);
} }
__attribute__((no_caller_saved_registers))
void splitPageToIndices(std::uint64_t page, std::uint16_t& outPML4Entry, std::uint16_t& outPDPEntry, std::uint16_t& outPDEntry, std::uint16_t& outPTEntry) noexcept
{
outPML4Entry = (page >> 27);
outPDPEntry = (page >> 18) & 0x1FF;
outPDEntry = (page >> 9) & 0x1FF;
outPTEntry = page & 0x1FF;
}
} }
extern "C" [[noreturn]] void __halt(); extern "C" [[noreturn]] void __halt();
@ -110,6 +119,37 @@ void isrGeneralProtectionFault(InterruptFrame* interruptFrame, interrupt_error_c
__attribute__((interrupt)) __attribute__((interrupt))
void isrPageFault(InterruptFrame* interruptFrame, interrupt_error_code_t errorCode) noexcept void isrPageFault(InterruptFrame* interruptFrame, interrupt_error_code_t errorCode) noexcept
{ {
static constexpr std::uint64_t PRESENT_BIT = (1 << 0);
static constexpr std::uint64_t WRITE_BIT = (1 << 1);
static constexpr std::uint64_t USER_BIT = (1 << 2);
static constexpr std::uint64_t RESERVED_WRITE_BIT = (1 << 3);
static constexpr std::uint64_t INSTRUCTION_FETCH_BIT = (1 << 4);
static constexpr std::uint64_t PROTECTION_KEY_BIT = (1 << 5);
static constexpr std::uint64_t SHADOW_STACK_BIT = (1 << 6);
static constexpr std::uint64_t SGX_BIT = (1 << 7);
std::uint64_t cr2 = 0;
__asm__ __volatile__(
"mov %%cr2, %0"
: "=a"(cr2)
:
);
iprintf("address: 0x%lX\n", cr2);
std::uint16_t pml4Index = 0;
std::uint16_t pdpIndex = 0;
std::uint16_t pdIndex = 0;
std::uint16_t ptIndex = 0;
splitPageToIndices(cr2 >> 12, pml4Index, pdpIndex, pdIndex, ptIndex);
iprintf("page: %d.%d.%d.%d\n", pml4Index, pdpIndex, pdIndex, ptIndex);
iprintf("present: %s\n", (errorCode & PRESENT_BIT) ? "yes" : "no");
iprintf("access: %s\n", (errorCode & WRITE_BIT) ? "write" : "read");
iprintf("mode: %s\n", (errorCode & USER_BIT) ? "user" : "supervisor");
iprintf("reserved write: %s\n", (errorCode & RESERVED_WRITE_BIT) ? "yes" : "no");
iprintf("instruction fetch: %s\n", (errorCode & INSTRUCTION_FETCH_BIT) ? "yes" : "no");
iprintf("protection key: %s\n", (errorCode & PROTECTION_KEY_BIT) ? "yes" : "no");
iprintf("shadow stack: %s\n", (errorCode & SHADOW_STACK_BIT) ? "yes" : "no");
iprintf("software guard extensions: %s\n", (errorCode & SGX_BIT) ? "yes" : "no");
handleException("PageFault", interruptFrame); handleException("PageFault", interruptFrame);
} }

View File

@ -0,0 +1,326 @@
#include "os/memory.hpp"
#include <array>
#include <bit>
#include <cstdio>
#include <memory>
#include <new>
namespace baos
{
namespace
{
using PageTable = std::array<PageTableEntry, 512>;
constinit PageTable gPageMapLevel4 alignas(4096);
struct MemoryRangeAllocationInfo
{
std::array<std::uint8_t, 4086> usedPages;
std::uint16_t numFreePages = 0;
MemoryRangeAllocationInfo* next = nullptr;
};
static_assert(sizeof(MemoryRangeAllocationInfo) == 4096);
inline constexpr unsigned MAX_USABLE_RANGES = 32;
std::array<MemoryRange, MAX_USABLE_RANGES> gUsableMemoryRanges;
std::array<MemoryRangeAllocationInfo, MAX_USABLE_RANGES> gRangeAllocationInfo;
std::uint8_t gNumUsableRanges = 0;
// initial 2MB page for setting up the page table
// std::array<std::uint8_t, 2ul << 20> gInitPage alignas(2ul << 20);
std::span<std::uint8_t> gPageTableSpace;
std::span<std::uint8_t> gNextPageTableSpace;
void splitPageToIndices(std::uint64_t page, std::uint16_t& outPML4Entry, std::uint16_t& outPDPEntry, std::uint16_t& outPDEntry, std::uint16_t& outPTEntry) noexcept
{
outPML4Entry = (page >> 27);
outPDPEntry = (page >> 18) & 0x1FF;
outPDEntry = (page >> 9) & 0x1FF;
outPTEntry = page & 0x1FF;
}
PageTable& allocatePageTable() noexcept
{
PageTable* pageTable = std::bit_cast<PageTable*>(&*gPageTableSpace.begin());
if (!pageTable)
{
int i = 5;
}
::new(pageTable) PageTable;
gPageTableSpace = {gPageTableSpace.begin() + sizeof(PageTable), gPageTableSpace.end()};
return *pageTable;
}
PageTableEntry& getOrCreatePageTableEntry(PageTable& pageTable, std::uint16_t index)
{
PageTableEntry& entry = pageTable[index];
if (!entry.present)
{
PageTable& childTable = allocatePageTable();
entry.address = std::bit_cast<std::uint64_t>(&childTable) >> 12;
entry.writable = true;
entry.present = true;
}
return entry;
}
PageTableEntry& getOrCreatePage(std::uint64_t page, bool bigPage = false)
{
std::uint16_t pml4Index = 0;
std::uint16_t pdpIndex = 0;
std::uint16_t pdIndex = 0;
std::uint16_t ptIndex = 0;
splitPageToIndices(page, pml4Index, pdpIndex, pdIndex, ptIndex);
PageTableEntry& pml4Entry = getOrCreatePageTableEntry(gPageMapLevel4, pml4Index);
PageTable& pdp = *std::bit_cast<PageTable*>(pml4Entry.address << 12);
PageTableEntry& pdpEntry = getOrCreatePageTableEntry(pdp, pdpIndex);
PageTable& pd = *std::bit_cast<PageTable*>(pdpEntry.address << 12);
PageTableEntry& pdEntry = getOrCreatePageTableEntry(pd, pdIndex);
if (bigPage)
{
pdEntry.pageSize = true;
return pdEntry;
}
PageTable& pt = *std::bit_cast<PageTable*>(pdEntry.address << 12);
return getOrCreatePageTableEntry(pt, ptIndex);
}
void addUsableRange(const MemoryRange& range) noexcept
{
if (gNumUsableRanges >= MAX_USABLE_RANGES) {
return;
}
gUsableMemoryRanges[gNumUsableRanges] = range;
gRangeAllocationInfo[gNumUsableRanges].numFreePages = range.numPages;
++gNumUsableRanges;
}
std::uint64_t findFreePages(unsigned numConsecutive) noexcept
{
if (numConsecutive == 0 || numConsecutive > 4086) {
return 0;
}
if (numConsecutive != 1) {
return 0; // TODO!!!
}
for (std::uint8_t rangeIdx = 0; rangeIdx < gNumUsableRanges; ++rangeIdx)
{
std::uint64_t page = gUsableMemoryRanges[rangeIdx].pageBase;
for (MemoryRangeAllocationInfo* allocInfo = &gRangeAllocationInfo[rangeIdx]; allocInfo != nullptr; page += allocInfo->usedPages.size(), allocInfo = allocInfo->next)
{
if (allocInfo->numFreePages < numConsecutive) {
continue;
}
for (unsigned pagesIdx = 0; pagesIdx < allocInfo->usedPages.size(); ++pagesIdx)
{
if (allocInfo->usedPages[pagesIdx] != 0xFF)
{
for (unsigned bit = 0; bit < 8; ++bit)
{
if ((allocInfo->usedPages[pagesIdx] & (1 << bit)) == 0)
{
allocInfo->usedPages[pagesIdx] |= (1 << bit);
return page + (8 * pagesIdx) + bit;
}
}
}
}
}
}
return 0;
}
PageTable& setupPageTableEntry(PageTableEntry& entry, std::uint64_t page) noexcept
{
entry.address = page;
entry.present = true;
entry.writable = true;
return *(::new(std::bit_cast<void*>(entry.address << 12)) PageTable);
}
void cmdDumpPageTable() noexcept
{
std::uint64_t pml4Addr = std::bit_cast<std::uint64_t>(&gPageMapLevel4);
std::printf("pml4 address: 0x%lX\n", pml4Addr);
baos::PageTableEntry* pml4 = std::bit_cast<baos::PageTableEntry*>(pml4Addr);
auto printPDE = [](const baos::PageTableEntry& pde)
{
std::printf("%s%s%s%s%s%s%s%s%s, address=%lX\n",
pde.present ? " P" : "",
pde.writable ? " W" : "",
pde.user ? " U" : "",
pde.writeThrough ? " WT" : "",
pde.cacheDisabled ? " CD" : "",
pde.accessed ? " A" : "",
pde.dirty ? " D" : "",
pde.pageSize ? " PS" : "",
pde.executeDisable ? " XD" : "",
pde.address * 4096);
};
for (unsigned pml4e = 0; pml4e < 512; ++pml4e)
{
if (!pml4[pml4e].present) {
continue;
}
std::printf("%d]", pml4e);
printPDE(pml4[pml4e]);
baos::PageTableEntry* pdp = std::bit_cast<baos::PageTableEntry*>(pml4[pml4e].address * 4096);
for (unsigned pdpe = 0; pdpe < 512; ++pdpe)
{
if (!pdp[pdpe].present) {
continue;
}
std::printf("%d.%d]", pml4e, pdpe);
printPDE(pdp[pdpe]);
baos::PageTableEntry* pd = std::bit_cast<baos::PageTableEntry*>(pdp[pdpe].address * 4096);
for (unsigned pde = 0; pde < 512; ++pde)
{
if (!pd[pde].present) {
continue;
}
std::printf("%d.%d.%d]", pml4e, pdpe, pde);
printPDE(pd[pde]);
}
}
}
}
bool canFitPageTableSpace(MemoryRange range, std::uint64_t& outBase) noexcept
{
if (range.type != MemoryType::USABLE) {
return false;
}
const std::uint64_t possibleBase = std::alignUp(range.pageBase, 512ul); // needs to be 2MB aligned
if (range.numPages - (possibleBase - range.pageBase) >= 512)
{
outBase = possibleBase;
return true;
}
return false;
}
}
void setupPaging(std::span<const MemoryRange> memoryRanges) noexcept
{
// addUsableRange({
// .pageBase = std::bit_cast<std::uint64_t>(gInitPages.data()) >> 12,
// .numPages = gInitPages.size() / 4096,
// .type = MemoryType::USABLE
// });
std::uint64_t firstKernelPage = std::bit_cast<std::uint64_t>(&gKernelStart) / 4096;
std::uint64_t lastKernelPage = std::bit_cast<std::uint64_t>(&gKernelEnd) / 4096 + 1;
for (MemoryRange range : memoryRanges)
{
if (range.type == MemoryType::USABLE) // ignore anything before the kernel
{
if (range.pageBase < lastKernelPage)
{
if (range.numPages < (lastKernelPage - range.pageBase))
{
continue;
}
range.numPages -= (lastKernelPage - range.pageBase);
range.pageBase = lastKernelPage;
}
addUsableRange(range);
std::uint64_t tableSpaceBase = 0;
if (gPageTableSpace.empty() && canFitPageTableSpace(range, tableSpaceBase))
{
std::uint8_t* tableSpacePtr = std::bit_cast<std::uint8_t*>(tableSpaceBase * 4096);
gPageTableSpace = {tableSpacePtr, 2ul << 30};
setupIdentityPaging2M(tableSpaceBase);
}
}
}
// start by setting up identity paging for the kernel
// __get_cpuid()
setupIdentityPaging(firstKernelPage, lastKernelPage);
// std::printf("Kernel pages: %ld-%ld\n", firstKernelPage, lastKernelPage);
// setup identity paging for all reserved ranges so we can continue using them
// for (const MemoryRange& range : memoryRanges)
// {
// if (range.type == MemoryType::RESERVED || range.type == MemoryType::MMIO)
// {
// setupIdentityPaging(range.pageBase, range.pageBase + range.numPages);
// }
// }
// cmdDumpPageTable();
std::uint64_t cr3 = std::bit_cast<std::uint64_t>(gPageMapLevel4.data());
__asm__ __volatile__ (
"mov %0, %%cr3"
:
: "a"(cr3)
);
}
const char* memoryTypeName(MemoryType type) noexcept
{
switch (type)
{
case MemoryType::USABLE:
return "USABLE";
case MemoryType::UNUSABLE:
return "UNUSABLE";
case MemoryType::MMIO:
return "MMIO";
case MemoryType::RESERVED:
return "RESERVED";
}
return "<INVALID>";
}
void* allocatePages(unsigned numConsecutive) noexcept
{
const std::uint64_t firstPage = findFreePages(numConsecutive);
if (firstPage == 0)
{
return nullptr;
}
setupIdentityPaging(firstPage, firstPage + numConsecutive);
return std::bit_cast<void*>(firstPage << 12);
}
void setupIdentityPaging(std::uint64_t page) noexcept
{
PageTableEntry& pageTableEntry = getOrCreatePage(page);
pageTableEntry.address = page;
}
void setupIdentityPaging2M(std::uint64_t page) noexcept
{
PageTableEntry& pageTableEntry = getOrCreatePage(page, true);
pageTableEntry.address = page;
}
void setupIdentityPaging(std::uint64_t firstPage, std::uint64_t lastPage) noexcept
{
for (std::uint64_t page = firstPage; page != lastPage; ++page)
{
if (page % 512 == 0 && (lastPage - page) >= 512)
{
setupIdentityPaging2M(page);
page += 511; // loop will add the last 1
}
else
{
setupIdentityPaging(page);
}
}
}
}

View File

@ -18,6 +18,7 @@ SECTIONS
work around this issue. This does not use that feature, so 2M was work around this issue. This does not use that feature, so 2M was
chosen as a safer option than the traditional 1M. */ chosen as a safer option than the traditional 1M. */
. = 2M; . = 2M;
gKernelStart = .;
/* First put the multiboot header, as it is required to be put very early /* First put the multiboot header, as it is required to be put very early
in the image or the bootloader won't recognize the file format. in the image or the bootloader won't recognize the file format.

View File

@ -1,19 +1,22 @@
#include "boot.hpp" #include "boot.hpp"
#include <algorithm>
#include <bit> #include <bit>
#include <cassert>
#include <cstdio> #include <cstdio>
#include <memory>
#include "os/draw.hpp" #include "os/draw.hpp"
#include "os/memory.hpp"
#include "os/serial.hpp" #include "os/serial.hpp"
#include "os/tty.hpp" #include "os/tty.hpp"
#include "drivers/pci.hpp" #include "drivers/pci.hpp"
#include "drivers/pic.hpp" #include "drivers/pic.hpp"
#include "drivers/ps2.hpp" #include "drivers/ps2.hpp"
#include "drivers/usb.hpp"
#include "./x86_64.hpp" #include "./x86_64.hpp"
extern "C" int gKernelEnd;
namespace namespace
{ {
inline constexpr std::uint8_t MASTER_PIC_OFFSET = 0x20; inline constexpr std::uint8_t MASTER_PIC_OFFSET = 0x20;
@ -67,61 +70,67 @@ inline constexpr std::uint16_t SEGIDX_TSS = 5 << 3;
constinit std::array<InterruptDescriptor, 256> IDT alignas(16); constinit std::array<InterruptDescriptor, 256> IDT alignas(16);
void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
inline baos::MemoryType mapEfiMemoryType(UINT32 type) noexcept
{ {
const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd); switch (type)
{
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
return baos::MemoryType::USABLE;
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiUnusableMemory:
case EfiACPIReclaimMemory:
case EfiMaxMemoryType:
default:
return baos::MemoryType::UNUSABLE;
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
return baos::MemoryType::MMIO;
case EfiACPIMemoryNVS:
case EfiPalCode:
case EfiReservedMemoryType:
return baos::MemoryType::RESERVED;
}
}
std::vector<baos::MemoryRange> detectMemoryRangesFromEfi(const EfiMemoryMap& memoryMap) noexcept
{
std::vector<baos::MemoryRange> ranges;
ranges.reserve(memoryMap.mapSize / memoryMap.descriptorSize);
for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap) for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap)
{ {
if (!isEfiMemoryTypeUsable(descriptor.Type)) const baos::MemoryType type = mapEfiMemoryType(descriptor.Type);
{
continue;
}
uint64_t addr = descriptor.PhysicalStart; assert(descriptor.PhysicalStart % 4096 == 0);
uint64_t len = descriptor.NumberOfPages * 4096; // TODO: is this the correct page size? uint64_t pageBase = descriptor.PhysicalStart / 4096;
// anything before the kernel we ignore uint64_t numPages = descriptor.NumberOfPages;
if (addr < minAddr) ranges.push_back({.pageBase = pageBase, .numPages = numPages, .type = type});
{
// if the entire entry is before the kernel, continue
if (addr + len <= minAddr)
{
continue;
} }
// otherwise shrink it and use the rest std::sort(ranges.begin(), ranges.end());
len -= (minAddr - addr);
addr = minAddr;
}
__ba_registerAllocatableMemory(reinterpret_cast<void*>(addr), len);
}
#if 0
const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd);
for (uint32_t addr = firstEntryAddr; addr < firstEntryAddr + bufferLength;)
{
multiboot_memory_map_t entry = *reinterpret_cast<multiboot_memory_map_t*>(addr);
if(entry.type == MULTIBOOT_MEMORY_AVAILABLE) // merge adjacent ranges
for (std::size_t idx = ranges.size() - 1; idx > 0; --idx)
{ {
std::printf("Start Addr: %X | Length: %b\n", baos::MemoryRange& left = ranges[idx-1];
static_cast<unsigned>(entry.addr), static_cast<size_t>(entry.len)); baos::MemoryRange& right = ranges[idx];
// anything before the kernel we ignore if (left.type == right.type && left.pageBase + left.numPages == right.pageBase)
if (entry.addr < minAddr)
{ {
// if the entire entry is before the kernel, continue left.numPages += right.numPages;
if (entry.addr + entry.len <= minAddr) right.numPages = 0;
}
}
std::erase_if(ranges, [](const baos::MemoryRange& range)
{ {
addr += sizeof(entry.size) + entry.size; return range.numPages == 0;
continue; });
} return ranges;
// otherwise shrink it and use the rest
entry.len -= (minAddr - entry.addr);
entry.addr = minAddr;
}
__ba_registerAllocatableMemory(reinterpret_cast<void*>(entry.addr), entry.len);
}
addr += sizeof(entry.size) + entry.size;
}
#endif
} }
using initfunc_t = void *(); using initfunc_t = void *();
@ -161,6 +170,21 @@ void setupInterrupt(std::uint8_t index, THandler handler) noexcept
.offsetHigh = (offset >> 16) .offsetHigh = (offset >> 16)
}; };
} }
void initializePCIDevice(const baos::pci::Header& header) noexcept
{
using namespace baos;
switch (header.baseClass)
{
case pci::BaseClass::SERIAL_BUS_CONTROLLER:
switch (header.subClass)
{
case pci::SubClass::USB_CONTROLLER:
(void) usb::initController(header); // TODO: print something on error?
break;
}
}
}
} }
extern "C" extern "C"
@ -210,6 +234,11 @@ void kernel_main()
initGlobals(); initGlobals();
// init the heap (required for the double buffer) // init the heap (required for the double buffer)
const std::vector<MemoryRange> ranges = detectMemoryRangesFromEfi(gBootInfo->memoryMap);
setupPaging({ranges.begin(), ranges.end()}); // TODO: move this up when it's done
identityMapRegion(gBootInfo, sizeof(*gBootInfo));
identityMapRegion(gBootInfo->displayInfo.frameBufferBase, gBootInfo->displayInfo.frameBufferPitch * gBootInfo->displayInfo.frameBufferHeight);
// initHeapFromEfiMemoryMap(gBootInfo->memoryMap); // initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
// initialize the framebuffer // initialize the framebuffer
@ -223,6 +252,11 @@ void kernel_main()
// initialize terminal interface // initialize terminal interface
tty::initialize(); tty::initialize();
for (const MemoryRange& range : ranges)
{
std::printf("Start: 0x%lX, Pages: %ld, Type: %s\n", range.pageBase << 12, range.numPages, memoryTypeName(range.type));
}
if (!initSerialPort(PORT_COM1)) if (!initSerialPort(PORT_COM1))
{ {
tty::write("Error initializing serial port.\n"); tty::write("Error initializing serial port.\n");
@ -242,6 +276,11 @@ void kernel_main()
return; return;
} }
for (const pci::Header header : pci::enumerateDevices())
{
initializePCIDevice(header);
}
std::puts("This is BadAppleOS and everything is fine!\n"); std::puts("This is BadAppleOS and everything is fine!\n");
// __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main); // __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);