diff --git a/SConstruct b/SConstruct index b33ae9f..4ed02fd 100644 --- a/SConstruct +++ b/SConstruct @@ -15,6 +15,7 @@ target = GetOption('target') env = Environment(tools = ['default', 'compilation_db']) env.Append(CCFLAGS = ['-g', '-O0']) +env.Append(CPPDEFINES = ['BASTL_EXTENSIONS=1']) # env.Append(CCFLAGS = ['-O2']) env['ISO_FILES'] = [] diff --git a/bastl/include/algorithm b/bastl/include/algorithm index 0ff3a3e..74dd803 100644 --- a/bastl/include/algorithm +++ b/bastl/include/algorithm @@ -4,6 +4,10 @@ #if !defined(BAD_APPLE_OS_ALGORITHM_INCLUDED) #define BAD_APPLE_OS_ALGORITHM_INCLUDED +#include +#include +#include + namespace std { template @@ -17,6 +21,76 @@ constexpr const T& max(const T& left, const T& right) { return right > left ? right : left; } + +template +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 +constexpr void sort(RandomIt first, RandomIt last) +{ + sort(first, last, [](auto left, auto right) { return left < right; }); +} + +template +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 +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) diff --git a/bastl/include/iterator b/bastl/include/iterator new file mode 100644 index 0000000..0fe0062 --- /dev/null +++ b/bastl/include/iterator @@ -0,0 +1,18 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_ITERATOR_HPP_INCLUDED) +#define BAD_APPLE_OS_ITERATOR_HPP_INCLUDED + +#include + +namespace std +{ +template +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) diff --git a/bastl/include/memory b/bastl/include/memory new file mode 100644 index 0000000..6c9b923 --- /dev/null +++ b/bastl/include/memory @@ -0,0 +1,44 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_MEMORY_HPP_INCLUDED) +#define BAD_APPLE_OS_MEMORY_HPP_INCLUDED + +#include + +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 +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) diff --git a/bastl/include/span b/bastl/include/span new file mode 100644 index 0000000..2e9dd07 --- /dev/null +++ b/bastl/include/span @@ -0,0 +1,93 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_SPAN_HPP_INCLUDED) +#define BAD_APPLE_OS_SPAN_HPP_INCLUDED + +#include +#include +#include +#include +#include + +namespace std +{ +inline constexpr size_t dynamic_extent = size_t(-1); + +template // TODO: use the extent? +class span +{ +public: + using element_type = T; + using value_type = remove_cv_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 + explicit(extent != dynamic_extent) + constexpr span(It first, size_type count) : _first(&*first), _last(&*(_first + count)) {} + + template + explicit(extent != dynamic_extent) + constexpr span(It first, It last) : _first(&*first), _last(&*last) {} + + template + constexpr span(type_identity_t (&arr)[N]) noexcept : span(&arr[0], N) {} + + template + constexpr span(array& arr) noexcept : span(&arr[0], N) {} + + template + constexpr span(const array& arr) noexcept : span(&arr[0], N) {} + + explicit(Extent != dynamic_extent) + constexpr span(initializer_list il) noexcept : span(il.begin(), il.size()) {} + + template + explicit(extent != dynamic_extent && N != dynamic_extent) + constexpr span(const span& 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) diff --git a/bastl/include/type_traits b/bastl/include/type_traits index 68dc6df..0cafa81 100644 --- a/bastl/include/type_traits +++ b/bastl/include/type_traits @@ -26,6 +26,66 @@ struct remove_reference template using remove_reference_t = typename remove_reference::type; + +template +struct remove_const +{ + using type = T; +}; + +template +struct remove_const +{ + using type = T; +}; + +template +using remove_const_t = typename remove_const::type; + +template +struct remove_volatile +{ + using type = T; +}; + +template +struct remove_volatile +{ + using type = T; +}; + +template +using remove_volatile_t = typename remove_volatile::type; + +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv +{ + using type = T; +}; + +template +struct remove_cv +{ + using type = T; +}; + +template +using remove_cv_t = typename remove_cv::type; + +template +struct type_identity +{ + using type = T; +}; + +template +using type_identity_t = type_identity::type; } #endif // !defined(BAD_APPLE_OS_TYPE_TRAITS_INCLUDED) diff --git a/bastl/include/vector b/bastl/include/vector index 9e95d55..422851b 100644 --- a/bastl/include/vector +++ b/bastl/include/vector @@ -4,6 +4,7 @@ #if !defined(BAD_APPLE_OS_VECTOR_INCLUDED) #define BAD_APPLE_OS_VECTOR_INCLUDED +#include #include #include #include @@ -11,13 +12,13 @@ namespace std { -template // TODO: allocator +template // TODO: allocator class vector { public: using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; + using size_type = size_t; + using difference_type = ptrdiff_t; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; @@ -210,7 +211,7 @@ public: constexpr void push_back(value_type&& value) { reserve(size() + 1); - ::new (&_elements[size()]) T(std::move(value)); + ::new (&_elements[size()]) T(move(value)); ++_size; } @@ -223,7 +224,7 @@ public: constexpr reference emplace_back(TArgs&&... args) { reserve(size() + 1); - ::new (&_elements[size()]) T(std::forward(args)...); + ::new (&_elements[size()]) T(forward(args)...); ++_size; } @@ -274,6 +275,27 @@ public: } _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: void updateCapacity(size_type newCapacity) { @@ -281,6 +303,10 @@ private: return; } T* newElements = static_cast(malloc(newCapacity * sizeof(T))); + if (newElements == nullptr) + { + __ba_throw bad_alloc(); + } for (size_type idx = 0; idx < size(); ++idx) { ::new (&newElements[idx]) T(move(_elements[idx])); @@ -291,6 +317,16 @@ private: _capacity = newCapacity; } }; + +template +constexpr vector::size_type erase_if(vector& 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) diff --git a/start.sh b/start.sh index d11276b..2d76e0b 100644 --- a/start.sh +++ b/start.sh @@ -1,8 +1,24 @@ #!/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 \ --bios /usr/share/edk2/x64/OVMF.fd \ -vga virtio \ -serial stdio \ -drive if=none,id=stick,format=raw,file=staging/x86_64_iso/fat.img \ -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 diff --git a/targets/_any/SConscript b/targets/_any/SConscript index 9b2330d..bb83a35 100644 --- a/targets/_any/SConscript +++ b/targets/_any/SConscript @@ -42,10 +42,12 @@ any_target_sources = Split(''' src/app/main.cpp src/drivers/pci.cpp + src/drivers/usb.cpp src/libs/psf.cpp src/os/draw.cpp + src/os/memory.cpp src/os/panic.cpp src/os/tty.cpp src/os/resources/lat9-08.psf.s diff --git a/targets/_any/include/drivers/usb.hpp b/targets/_any/include/drivers/usb.hpp new file mode 100644 index 0000000..a1af0bb --- /dev/null +++ b/targets/_any/include/drivers/usb.hpp @@ -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) diff --git a/targets/_any/include/os/memory.hpp b/targets/_any/include/os/memory.hpp new file mode 100644 index 0000000..5d40d33 --- /dev/null +++ b/targets/_any/include/os/memory.hpp @@ -0,0 +1,72 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED) +#define BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED + +#include +#include +#include + +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 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(start) / 4096; + std::uint64_t lastPage = std::bit_cast(static_cast(start) + bytes) / 4096 + 1; + setupIdentityPaging(firstPage, lastPage); +} +} + +#endif // !defined(BAD_APPLE_OS_OS_MEMORY_HPP_INCLUDED) diff --git a/targets/_any/src/app/main.cpp b/targets/_any/src/app/main.cpp index 743ea19..8c043c1 100644 --- a/targets/_any/src/app/main.cpp +++ b/targets/_any/src/app/main.cpp @@ -1,8 +1,10 @@ +#include #include #include "drivers/pci.hpp" #include "drivers/ps2.hpp" +#include "os/memory.hpp" 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(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(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(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() @@ -72,6 +129,11 @@ extern "C" void main() cmdShowKeys(); continue; } + else if (cmd == "dump-pages") + { + cmdDumpPageTable(); + continue; + } std::printf("Unknown command: %s.\n", cmd.c_str()); } } diff --git a/targets/_any/src/cstdlib/stdlib.cpp b/targets/_any/src/cstdlib/stdlib.cpp index 97b2e4e..43d1d70 100644 --- a/targets/_any/src/cstdlib/stdlib.cpp +++ b/targets/_any/src/cstdlib/stdlib.cpp @@ -7,7 +7,7 @@ namespace { 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]; @@ -20,8 +20,8 @@ struct AllocInfo { size_t elements; }; -static_assert(sizeof(MallocBlock) <= sizeof(max_align_t)); -static_assert(sizeof(AllocInfo) <= sizeof(max_align_t)); +static_assert(sizeof(MallocBlock) <= alignof(max_align_t)); +static_assert(sizeof(AllocInfo) <= alignof(max_align_t)); MallocBlock* gNextBlock = []() { diff --git a/targets/_any/src/drivers/usb.cpp b/targets/_any/src/drivers/usb.cpp new file mode 100644 index 0000000..2b267a7 --- /dev/null +++ b/targets/_any/src/drivers/usb.cpp @@ -0,0 +1,272 @@ + +#include "drivers/usb.hpp" + +#include +#include +#include +#include +#include +#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 name() const noexcept { return Register(*reinterpret_cast(base + offset)); } +#define BAOS_MEMORY_REGISTER_RW(offset, type, name) \ + [[nodiscard]] Register name() const noexcept { return Register(*reinterpret_cast(base + offset)); } +#define BAOS_MEMORY_REGISTER_RO_PARAM(offset, type, name, paramType, paramName) \ + [[nodiscard]] const Register name(paramType paramName) const noexcept { return Register(*reinterpret_cast(base + offset)); } +#define BAOS_MEMORY_REGISTER_RW_PARAM(offset, type, name, paramType, paramName) \ + [[nodiscard]] Register name(paramType paramName) const noexcept { return Register(*reinterpret_cast(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 +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 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(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(gDeviceContextBasePointers.size() - 1)); + controller.operationalRegs.config() = config; + + // 3. setup the device context base address pointer + const std::uint64_t pointer = std::bit_cast(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? + } +} +} \ No newline at end of file diff --git a/targets/_any/src/os/draw.cpp b/targets/_any/src/os/draw.cpp index ecb3666..acc6cba 100644 --- a/targets/_any/src/os/draw.cpp +++ b/targets/_any/src/os/draw.cpp @@ -3,6 +3,7 @@ #include #include "libs/psf.hpp" +#include "os/memory.hpp" namespace draw { diff --git a/targets/_any/src/os/interrupt.cpp b/targets/_any/src/os/interrupt.cpp index 517e91d..ce2f36e 100644 --- a/targets/_any/src/os/interrupt.cpp +++ b/targets/_any/src/os/interrupt.cpp @@ -31,6 +31,15 @@ void iprintf(const char* format, ...) noexcept PrintFHelper().vprintf(format, 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(); @@ -110,6 +119,37 @@ void isrGeneralProtectionFault(InterruptFrame* interruptFrame, interrupt_error_c __attribute__((interrupt)) 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); } diff --git a/targets/_any/src/os/memory.cpp b/targets/_any/src/os/memory.cpp new file mode 100644 index 0000000..bfdee4c --- /dev/null +++ b/targets/_any/src/os/memory.cpp @@ -0,0 +1,326 @@ + +#include "os/memory.hpp" + +#include +#include +#include +#include +#include + +namespace baos +{ +namespace +{ +using PageTable = std::array; +constinit PageTable gPageMapLevel4 alignas(4096); + +struct MemoryRangeAllocationInfo +{ + std::array usedPages; + std::uint16_t numFreePages = 0; + MemoryRangeAllocationInfo* next = nullptr; +}; +static_assert(sizeof(MemoryRangeAllocationInfo) == 4096); + +inline constexpr unsigned MAX_USABLE_RANGES = 32; +std::array gUsableMemoryRanges; +std::array gRangeAllocationInfo; +std::uint8_t gNumUsableRanges = 0; + +// initial 2MB page for setting up the page table +// std::array gInitPage alignas(2ul << 20); +std::span gPageTableSpace; +std::span 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(&*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(&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(pml4Entry.address << 12); + PageTableEntry& pdpEntry = getOrCreatePageTableEntry(pdp, pdpIndex); + + PageTable& pd = *std::bit_cast(pdpEntry.address << 12); + PageTableEntry& pdEntry = getOrCreatePageTableEntry(pd, pdIndex); + + if (bigPage) + { + pdEntry.pageSize = true; + return pdEntry; + } + + PageTable& pt = *std::bit_cast(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(entry.address << 12)) PageTable); +} + + + + +void cmdDumpPageTable() noexcept +{ + std::uint64_t pml4Addr = std::bit_cast(&gPageMapLevel4); + std::printf("pml4 address: 0x%lX\n", pml4Addr); + baos::PageTableEntry* pml4 = std::bit_cast(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(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(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 memoryRanges) noexcept +{ + // addUsableRange({ + // .pageBase = std::bit_cast(gInitPages.data()) >> 12, + // .numPages = gInitPages.size() / 4096, + // .type = MemoryType::USABLE + // }); + std::uint64_t firstKernelPage = std::bit_cast(&gKernelStart) / 4096; + std::uint64_t lastKernelPage = std::bit_cast(&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(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(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 ""; +} + +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(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); + } + } +} +} diff --git a/targets/x86_64/linker.ld b/targets/x86_64/linker.ld index 8c1bd32..33584b2 100644 --- a/targets/x86_64/linker.ld +++ b/targets/x86_64/linker.ld @@ -18,6 +18,7 @@ SECTIONS work around this issue. This does not use that feature, so 2M was chosen as a safer option than the traditional 1M. */ . = 2M; + gKernelStart = .; /* 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. diff --git a/targets/x86_64/src/kernel/startup.cpp b/targets/x86_64/src/kernel/startup.cpp index 4ffe780..fd7a674 100644 --- a/targets/x86_64/src/kernel/startup.cpp +++ b/targets/x86_64/src/kernel/startup.cpp @@ -1,19 +1,22 @@ #include "boot.hpp" +#include #include +#include #include +#include #include "os/draw.hpp" +#include "os/memory.hpp" #include "os/serial.hpp" #include "os/tty.hpp" #include "drivers/pci.hpp" #include "drivers/pic.hpp" #include "drivers/ps2.hpp" +#include "drivers/usb.hpp" #include "./x86_64.hpp" -extern "C" int gKernelEnd; - namespace { 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 IDT alignas(16); -void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept + +inline baos::MemoryType mapEfiMemoryType(UINT32 type) noexcept { - const uint64_t minAddr = reinterpret_cast(&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 detectMemoryRangesFromEfi(const EfiMemoryMap& memoryMap) noexcept +{ + std::vector ranges; + + ranges.reserve(memoryMap.mapSize / memoryMap.descriptorSize); for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap) { - if (!isEfiMemoryTypeUsable(descriptor.Type)) - { - continue; - } + const baos::MemoryType type = mapEfiMemoryType(descriptor.Type); - uint64_t addr = descriptor.PhysicalStart; - uint64_t len = descriptor.NumberOfPages * 4096; // TODO: is this the correct page size? - // anything before the kernel we ignore - if (addr < minAddr) - { - // if the entire entry is before the kernel, continue - if (addr + len <= minAddr) - { - continue; - } - // otherwise shrink it and use the rest - len -= (minAddr - addr); - addr = minAddr; - } - __ba_registerAllocatableMemory(reinterpret_cast(addr), len); + assert(descriptor.PhysicalStart % 4096 == 0); + uint64_t pageBase = descriptor.PhysicalStart / 4096; + uint64_t numPages = descriptor.NumberOfPages; + ranges.push_back({.pageBase = pageBase, .numPages = numPages, .type = type}); } -#if 0 - const uint64_t minAddr = reinterpret_cast(&gKernelEnd); - for (uint32_t addr = firstEntryAddr; addr < firstEntryAddr + bufferLength;) + std::sort(ranges.begin(), ranges.end()); + + // merge adjacent ranges + for (std::size_t idx = ranges.size() - 1; idx > 0; --idx) { - multiboot_memory_map_t entry = *reinterpret_cast(addr); + baos::MemoryRange& left = ranges[idx-1]; + baos::MemoryRange& right = ranges[idx]; - if(entry.type == MULTIBOOT_MEMORY_AVAILABLE) + if (left.type == right.type && left.pageBase + left.numPages == right.pageBase) { - std::printf("Start Addr: %X | Length: %b\n", - static_cast(entry.addr), static_cast(entry.len)); - - // anything before the kernel we ignore - if (entry.addr < minAddr) - { - // if the entire entry is before the kernel, continue - if (entry.addr + entry.len <= minAddr) - { - addr += sizeof(entry.size) + entry.size; - continue; - } - // otherwise shrink it and use the rest - entry.len -= (minAddr - entry.addr); - entry.addr = minAddr; - } - __ba_registerAllocatableMemory(reinterpret_cast(entry.addr), entry.len); + left.numPages += right.numPages; + right.numPages = 0; } - addr += sizeof(entry.size) + entry.size; } -#endif + std::erase_if(ranges, [](const baos::MemoryRange& range) + { + return range.numPages == 0; + }); + return ranges; } using initfunc_t = void *(); @@ -161,6 +170,21 @@ void setupInterrupt(std::uint8_t index, THandler handler) noexcept .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" @@ -210,6 +234,11 @@ void kernel_main() initGlobals(); // init the heap (required for the double buffer) + const std::vector 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); // initialize the framebuffer @@ -223,6 +252,11 @@ void kernel_main() // initialize terminal interface 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)) { tty::write("Error initializing serial port.\n"); @@ -242,6 +276,11 @@ void kernel_main() return; } + for (const pci::Header header : pci::enumerateDevices()) + { + initializePCIDevice(header); + } + std::puts("This is BadAppleOS and everything is fine!\n"); // __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);