diff --git a/README.md b/README.md index 9e976cc2..13e7c1bb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ # SimpleKernel -intr branch +memory branch ## 关键词 @@ -113,27 +113,15 @@ intr branch - riscv64 - 1. 对 CSR 寄存器的抽象 - 2. 寄存器状态打印 - 3. 基于 Direct 的中断处理 - 4. 中断注册函数 - 5. 时钟中断 - + 1. + - X86_64 - 1. cpu 抽象 - 2. 8259A pic 控制器抽象 - 3. 8253/8254 timer 控制器抽象 - 4. gdt 初始化 - 5. 中断处理流程 - 6. 中断注册函数 - 7. 时钟中断 + 1. - TODO - riscv64 PLIC - - x86_64 APIC + - 全局对象 @@ -150,44 +138,37 @@ intr branch ## 已支持特性 - [x] [BUILD] 使用 CMake 的构建系统 - - [x] [BUILD] 使用 gdb remote 调试 - - [x] [BUILD] 第三方资源集成 - - [x] [COMMON] C++ 全局对象的构造 - - [x] [COMMON] C++ 静态局部对象构造 - - [x] [COMMON] C 栈保护支持 - - [x] [COMMON] printf 支持 - - [x] [COMMON] 简单的 C++ 异常支持 - - [x] [COMMON] 带颜色的字符串输出 - - [x] [x86_64] 基于 gnuefi 的 bootloader - - [x] [x86_64] 基于 serial 的基本输出 - - [x] [x86_64] 物理内存信息探测 - - [x] [x86_64] 显示缓冲区探测 - - [x] [x86_64] 调用栈回溯 - - [x] [riscv64] gp 寄存器的初始化 - - [x] [riscv64] 基于 opensbi 的基本输出 - - [x] [riscv64] device tree 硬件信息解析 - - [x] [riscv64] ns16550a 串口驱动 - - [x] [riscv64] 调用栈回溯(仅打印地址) - - [ ] [aarch64] 基于 gnuefi 的 bootloader(调试中) + - [x] [riscv64] 对 CSR 寄存器的抽象 + - [x] [riscv64] 寄存器状态打印 + - [x] [riscv64] 基于 Direct 的中断处理 + - [x] [riscv64] 中断注册函数 + - [x] [riscv64] 时钟中断 + - [x] [x86_64] cpu 抽象 + - [x] [x86_64] 8259A pic 控制器抽象 + - [x] [x86_64] 8253/8254 timer 控制器抽象 + - [x] [x86_64] gdt 初始化 + - [x] [x86_64] 中断处理流程 + - [x] [x86_64] 中断注册函数 + - [x] [x86_64] 时钟中断 ## 使用的第三方资源 diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index bbc0f4ba..605008b9 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -21,11 +21,13 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/driver) add_executable(${PROJECT_NAME} main.cpp + physical_memory_manager.cpp + virtual_memory_manager.cpp ) -# 添加头文件 target_include_directories(kernel PRIVATE include + ../ ) # 添加要链接的库 diff --git a/src/kernel/arch/aarch64/interrupt.cpp b/src/kernel/arch/aarch64/interrupt.cpp index b4fea79d..3988af70 100644 --- a/src/kernel/arch/aarch64/interrupt.cpp +++ b/src/kernel/arch/aarch64/interrupt.cpp @@ -18,7 +18,11 @@ #include "kernel_log.hpp" #include "sk_cstdio" +<<<<<<< HEAD +Interrupt::Interrupt() { log::Info("Interrupt init.\n"); } +======= Interrupt::Interrupt() { klog::Info("Interrupt init.\n"); } +>>>>>>> new_intr void Interrupt::Do(uint64_t cause, uint8_t *context) { (void)cause; @@ -31,7 +35,11 @@ void Interrupt::RegisterInterruptFunc(uint64_t cause, InterruptFunc func) { } uint32_t InterruptInit(uint32_t, uint8_t *) { +<<<<<<< HEAD + log::Info("Hello InterruptInit\n"); +======= klog::Info("Hello InterruptInit\n"); +>>>>>>> new_intr return 0; } diff --git a/src/kernel/arch/riscv64/include/cpu/cpu.hpp b/src/kernel/arch/riscv64/include/cpu/cpu.hpp index 7eebf372..f6d776b3 100644 --- a/src/kernel/arch/riscv64/include/cpu/cpu.hpp +++ b/src/kernel/arch/riscv64/include/cpu/cpu.hpp @@ -27,4 +27,84 @@ #include "sk_cstdio" #include "sk_iostream" +namespace cpu { +namespace vmm { +enum { + VALID_OFFSET = 0, + READ_OFFSET = 1, + WRITE_OFFSET = 2, + EXEC_OFFSET = 3, + USER_OFFSET = 4, + GLOBAL_OFFSET = 5, + ACCESSED_OFFSET = 6, + DIRTY_OFFSET = 7, + VALID = 1 << VALID_OFFSET, + READ = 1 << READ_OFFSET, + WRITE = 1 << WRITE_OFFSET, + EXEC = 1 << EXEC_OFFSET, + USER = 1 << USER_OFFSET, + GLOBAL = 1 << GLOBAL_OFFSET, + ACCESSED = 1 << ACCESSED_OFFSET, + DIRTY = 1 << DIRTY_OFFSET, +}; +/// 有效位 +static constexpr const uint8_t VMM_PAGE_VALID = VALID; +/// 可读位 +static constexpr const uint8_t VMM_PAGE_READABLE = READ; +/// 可写位s +static constexpr const uint8_t VMM_PAGE_WRITABLE = WRITE; +/// 可执行位 +static constexpr const uint8_t VMM_PAGE_EXECUTABLE = EXEC; +/// 用户位 +static constexpr const uint8_t VMM_PAGE_USER = USER; +/// 全局位,我们不会使用 +static constexpr const uint8_t VMM_PAGE_GLOBAL = GLOBAL; +/// 已使用位,用于替换算法 +static constexpr const uint8_t VMM_PAGE_ACCESSED = ACCESSED; +/// 已修改位,用于替换算法 +static constexpr const uint8_t VMM_PAGE_DIRTY = DIRTY; +/// 内核虚拟地址相对物理地址的偏移 +static constexpr const size_t KERNEL_OFFSET = 0x0; +/// PTE 属性位数 +static constexpr const size_t VMM_PTE_PROP_BITS = 10; +/// PTE 页内偏移位数 +static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +/// VPN 位数 +static constexpr const size_t VMM_VPN_BITS = 9; +/// VPN 位数掩码,9 位 VPN +static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; +/// riscv64 使用了三级页表 +static constexpr const size_t VMM_PT_LEVEL = 3; + +// 开启 PG +inline void EnablePage() { + kAllCsr.satp.asid.Write(0); + kAllCsr.satp.mode.Write(register_info::csr::SatpInfo::kSv39); +} +inline void DisablePage() { + kAllCsr.satp.mode.Write(register_info::csr::SatpInfo::kBare); +} + +/** + * @brief 设置 页目录 + * @param _pgd 要设置的页表 + * @return true 成功 + * @return false 失败 + */ +inline void SetPageDirectory(uint64_t pgd) { kAllCsr.satp.ppn.Write(pgd); } + +/** + * @brief 获取页目录 + * @return uint64_t 页目录值 + */ +inline uint64_t GetPageDirectory() { return kAllCsr.satp.ppn.Get(); } + +inline void FlushPage(uint64_t addr) { + (void)addr; + __asm__ volatile("sfence.vma zero, zero"); +} + +} // namespace vmm +} // namespace cpu + #endif // SIMPLEKERNEL_SRC_KERNEL_ARCH_RISCV64_INCLUDE_CPU_CPU_HPP_ diff --git a/src/kernel/arch/riscv64/include/cpu/regs.hpp b/src/kernel/arch/riscv64/include/cpu/regs.hpp index 49103e1f..fe29ec56 100644 --- a/src/kernel/arch/riscv64/include/cpu/regs.hpp +++ b/src/kernel/arch/riscv64/include/cpu/regs.hpp @@ -38,6 +38,37 @@ */ namespace cpu { +// namespace vmm_info { +// /// 有效位 +// static constexpr const uint8_t VMM_PAGE_VALID = CPU::pte_t::VALID; +// /// 可读位 +// static constexpr const uint8_t VMM_PAGE_READABLE = CPU::pte_t::READ; +// /// 可写位s +// static constexpr const uint8_t VMM_PAGE_WRITABLE = CPU::pte_t::WRITE; +// /// 可执行位 +// static constexpr const uint8_t VMM_PAGE_EXECUTABLE = CPU::pte_t::EXEC; +// /// 用户位 +// static constexpr const uint8_t VMM_PAGE_USER = CPU::pte_t::USER; +// /// 全局位,我们不会使用 +// static constexpr const uint8_t VMM_PAGE_GLOBAL = CPU::pte_t::GLOBAL; +// /// 已使用位,用于替换算法 +// static constexpr const uint8_t VMM_PAGE_ACCESSED = CPU::pte_t::ACCESSED; +// /// 已修改位,用于替换算法 +// static constexpr const uint8_t VMM_PAGE_DIRTY = CPU::pte_t::DIRTY; +// /// 内核虚拟地址相对物理地址的偏移 +// static constexpr const size_t KERNEL_OFFSET = 0x0; +// /// PTE 属性位数 +// static constexpr const size_t VMM_PTE_PROP_BITS = 10; +// /// PTE 页内偏移位数 +// static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +// /// VPN 位数 +// static constexpr const size_t VMM_VPN_BITS = 9; +// /// VPN 位数掩码,9 位 VPN +// static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; +// /// riscv64 使用了三级页表 +// static constexpr const size_t VMM_PT_LEVEL = 3; +// }; // namespace vmm_info + // 第一部分:寄存器定义 namespace register_info { diff --git a/src/kernel/arch/x86_64/include/cpu/cpu.hpp b/src/kernel/arch/x86_64/include/cpu/cpu.hpp index c4d045ef..d17790bd 100644 --- a/src/kernel/arch/x86_64/include/cpu/cpu.hpp +++ b/src/kernel/arch/x86_64/include/cpu/cpu.hpp @@ -512,6 +512,53 @@ struct InterruptContextErrorCode { } }; +namespace vmm { +/// P = 1 表示有效; P = 0 表示无效。 +static constexpr const uint8_t VMM_PAGE_VALID = 1 << 0; +/// 如果为 0 表示页面只读或可执行。 +static constexpr const uint8_t VMM_PAGE_READABLE = 0; +static constexpr const uint8_t VMM_PAGE_WRITABLE = 1 << 1; +static constexpr const uint8_t VMM_PAGE_EXECUTABLE = 0; +/// U/S-- 位 2 是用户 / 超级用户 (User/Supervisor) 标志。 +/// 如果为 1 那么运行在任何特权级上的程序都可以访问该页面。 +static constexpr const uint8_t VMM_PAGE_USER = 1 << 2; +/// 内核虚拟地址相对物理地址的偏移 +static constexpr const size_t KERNEL_OFFSET = 0x0; +/// PTE 属性位数 +static constexpr const size_t VMM_PTE_PROP_BITS = 12; +/// PTE 页内偏移位数 +static constexpr const size_t VMM_PAGE_OFF_BITS = 12; +/// VPN 位数 +static constexpr const size_t VMM_VPN_BITS = 9; +/// VPN 位数掩码,9 位 VPN +static constexpr const size_t VMM_VPN_BITS_MASK = 0x1FF; +/// x86_64 使用了四级页表 +static constexpr const size_t VMM_PT_LEVEL = 4; + +// 开启 PG +inline void EnablePage() { kAllCr.cr0.pg.Set(); } +inline void DisablePage() { kAllCr.cr0.pg.Clear(); } + +/** + * @brief 设置 页目录 + * @param _pgd 要设置的页表 + * @return true 成功 + * @return false 失败 + */ +inline void SetPageDirectory(uint64_t pgd) { kAllCr.cr3.Write(pgd); } + +/** + * @brief 获取页目录 CR3 + * @return uint64_t CR3 值 + */ +inline uint64_t GetPageDirectory() { return kAllCr.cr3.Read(); } + +inline void FlushPage(uint64_t addr) { + __asm__ volatile("invlpg (%0)" : : "r"(addr) : "memory"); +} + +}; // namespace vmm + }; // namespace cpu #endif // SIMPLEKERNEL_SRC_KERNEL_ARCH_X86_64_INCLUDE_CPU_CPU_HPP_ diff --git a/src/kernel/arch/x86_64/include/cpu/regs.hpp b/src/kernel/arch/x86_64/include/cpu/regs.hpp index 0b5fc204..0a90ad83 100644 --- a/src/kernel/arch/x86_64/include/cpu/regs.hpp +++ b/src/kernel/arch/x86_64/include/cpu/regs.hpp @@ -999,7 +999,15 @@ class WriteOnlyRegBase { klog::Err("TODO\n"); } else if constexpr (std::is_same::value) { - __asm__ volatile("bts %%cr0, %0" : : "r"(offset) :); + // __asm__ volatile("bts %%cr0, %0" : : "r"(offset) :); + uint64_t value; + __asm__ volatile( + "mov %%cr0, %0\n\t" + "bts %1, %0\n\t" + "mov %0, %%cr0" + : "=r"(value) + : "r"(offset) + : "memory"); } else if constexpr (std::is_same::value) { __asm__ volatile("bts %%cr2, %0" : : "r"(offset) :); @@ -1059,7 +1067,16 @@ class WriteOnlyRegBase { klog::Err("TODO\n"); } else if constexpr (std::is_same::value) { - __asm__ volatile("btr %%cr0, %0" : : "r"(offset) :); + // __asm__ volatile("btr %%cr0, %0" : : "r"(offset) :); + // __asm__ volatile("bts %%cr0, %0" : : "r"(offset) :); + uint64_t value; + __asm__ volatile( + "mov %%cr0, %0\n\t" + "btr %1, %0\n\t" + "mov %0, %%cr0" + : "=r"(value) + : "r"(offset) + : "memory"); } else if constexpr (std::is_same::value) { __asm__ volatile("btr %%cr2, %0" : : "r"(offset) :); diff --git a/src/kernel/include/kernel.h b/src/kernel/include/kernel.h index 70838426..5bb38b1c 100644 --- a/src/kernel/include/kernel.h +++ b/src/kernel/include/kernel.h @@ -43,4 +43,8 @@ uint32_t main(uint32_t argc, uint8_t* argv); uint32_t InterruptInit(uint32_t argc, uint8_t* argv); +uint32_t PhysicalMemoryInit(uint32_t argc, uint8_t* argv); + +uint32_t VirtualMemoryInit(uint32_t argc, uint8_t* argv); + #endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_KERNEL_H_ */ diff --git a/src/kernel/include/memory/allocator_base.hpp b/src/kernel/include/memory/allocator_base.hpp new file mode 100644 index 00000000..8a0e0930 --- /dev/null +++ b/src/kernel/include/memory/allocator_base.hpp @@ -0,0 +1,100 @@ + +/** + * @file allocator_base.hpp + * @brief 内存分配器基类 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_ALLOCATOR_BASE_HPP_ +#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_ALLOCATOR_BASE_HPP_ + +#include +#include + +/** + * @brief 内存分配器基类 + */ +class AllocatorBase { + public: + /** + * @brief 构造函数 + * @param name 分配器名 + * @param addr 要管理的内存开始地址 + * @param length 要管理的内存长度,单位由派生类型指定 + */ + explicit AllocatorBase(const char *name, uint64_t addr, size_t length) { + name_ = name; + addr_ = addr; + length_ = length; + free_length_ = length; + used_length_ = 0; + } + + /// @name 构造/析构函数 + /// @{ + AllocatorBase() = default; + AllocatorBase(const AllocatorBase &) = default; + AllocatorBase(AllocatorBase &&) = default; + auto operator=(const AllocatorBase &) -> AllocatorBase & = default; + auto operator=(AllocatorBase &&) -> AllocatorBase & = default; + virtual ~AllocatorBase() = default; + /// @} + + /** + * @brief 分配 length 内存 + * @param length 要申请的内存长度 + * @return uint64_t 分配到的地址 + */ + virtual uint64_t Alloc(size_t length) = 0; + + /** + * @brief 在指定地址分配 length 长度 + * @param addr 指定的地址 + * @param length 长度 + * @return true 成功 + * @return false 失败 + */ + virtual bool AllocAt(uint64_t addr, size_t length) = 0; + + /** + * @brief 释放内存 + * @param addr 地址 + * @param length 长度 + */ + virtual void Free(uint64_t addr, size_t length) = 0; + + /** + * @brief 已使用内存数量 + * @return size_t 数量 + */ + virtual size_t GetUsedCount() const { return used_length_; } + + /** + * @brief 空闲内存数量 + * @return size_t 数量 + */ + virtual size_t GetFreeCount() const { return free_length_; } + + protected: + /// 分配器名称 + const char *name_; + /// 当前管理的内存区域地址 + uint64_t addr_; + /// 当前管理的内存区域长度 + size_t length_; + /// 空闲内存数量 + size_t free_length_; + /// 已使用内存数量 + size_t used_length_; +}; + +#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_ALLOCATOR_BASE_HPP_ */ diff --git a/src/kernel/include/memory/firstfit_allocator.hpp b/src/kernel/include/memory/firstfit_allocator.hpp new file mode 100644 index 00000000..9b5dbc4f --- /dev/null +++ b/src/kernel/include/memory/firstfit_allocator.hpp @@ -0,0 +1,183 @@ + +/** + * @file firstfit_allocator.hpp + * @brief firstfit 内存分配器头文件 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_FIRSTFIT_ALLOCATOR_HPP_ +#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_FIRSTFIT_ALLOCATOR_HPP_ + +#include +#include +#include + +#include "kernel_log.hpp" +#include "memory/allocator_base.hpp" + +/** + * @brief 使用 first fit 算法的分配器 + * @tparam page_size 页大小,默认 0x1000,即 4096 bytes + */ +template +class FirstFitAllocator : public AllocatorBase { + public: + /** + * @brief 构造函数 + * @param name 分配器名称 + * @param addr 开始地址 + * @param pages_count 页数量 + */ + explicit FirstFitAllocator(const char *name, uint64_t addr, + size_t pages_count) + : AllocatorBase(name, addr, pages_count) { + if (addr % page_size != 0) { + klog::Err("addr not aligned. 0x%lX\n", addr); + throw; + } + printf("%s: 0x%p(0x%X pages) init.\n", name_, addr_, length_); + } + + /// @name 构造/析构函数 + /// @{ + FirstFitAllocator() = default; + FirstFitAllocator(const FirstFitAllocator &) = default; + FirstFitAllocator(FirstFitAllocator &&) = default; + auto operator=(const FirstFitAllocator &) -> FirstFitAllocator & = default; + auto operator=(FirstFitAllocator &&) -> FirstFitAllocator & = default; + ~FirstFitAllocator() = default; + /// @} + + /** + * @brief 分配长度为 pages_count 页的内存 + * @param pages_count 页数 + * @return uint64_t 分配的内存起点地址 + */ + uint64_t Alloc(size_t pages_count) override { + uint64_t res_addr = 0; + // 在位图中寻找连续 pages_count 的位置 + auto [is_found, idx] = Find(pages_count, false); + if (is_found == false) { + klog::Warn("NO ENOUGH MEM %d.\n", pages_count); + return res_addr; + } + // 遍历区域 + for (auto i = idx; i < idx + pages_count; i++) { + // 置位,说明已使用 + map_[i] = 1; + } + // 计算实际地址 + // 分配器起始地址+页长度*第几页 + res_addr = addr_ + (page_size * idx); + // 更新统计信息 + free_length_ -= pages_count; + used_length_ += pages_count; + return res_addr; + } + + /** + * @brief 在 addr 处分配长度为 pages_count 页的内存 + * @param addr 指定的地址 + * @param pages_count 页数 + * @return true 成功 + * @return false 失败 + */ + bool AllocAt(uint64_t addr, size_t pages_count) override { + // 页对齐 + if (addr % page_size != 0) { + klog::Warn("addr not aligned 0x%lX.\n", addr); + return false; + } + // 申请地址超出范围 + if (addr < addr_ || addr > addr_ || + addr + pages_count * page_size > addr_ + length_ * page_size) { + klog::Warn("out of range 0x%lX %d.\n", addr, pages_count); + return false; + } + // 计算 addr 在 map_ 中的索引 + size_t idx = (addr - addr_) / page_size; + // 遍历 + for (auto i = idx; i < idx + pages_count; i++) { + // 如果在范围内有已经分配的内存,返回 false + if (map_[i] == true) { + return false; + } + } + // 到这里说明范围内没有已使用内存 + // 再次遍历 + for (auto i = idx; i < idx + pages_count; i++) { + // 置位 + map_[i] = 1; + } + // 更新统计信息 + free_length_ -= pages_count; + used_length_ += pages_count; + return true; + } + + /** + * @brief 释放 addr 处 pages_count 页的内存 + * @param addr 要释放内存起点地址 + * @param pages_count 页数 + */ + void Free(uint64_t addr, size_t pages_count) override { + // 页对齐 + if (addr % page_size != 0) { + klog::Warn("addr not aligned 0x%lX.\n", addr); + return; + } + // 申请地址超出范围 + if (addr < addr_ || addr > addr_ || + addr + pages_count * page_size > addr_ + length_ * page_size) { + klog::Warn("out of range 0x%lX %d.\n", addr, pages_count); + return; + } + // 计算 addr 在 map_ 中的索引 + size_t idx = (addr - addr_) / page_size; + for (auto i = idx; i < idx + pages_count; i++) { + map_[i] = 0; + } + // 更新统计信息 + free_length_ += pages_count; + used_length_ -= pages_count; + } + + private: + /// 位图,每一位表示一页内存,1 表示已使用,0 表示未使用 + std::bitset map_; + + /** + * @brief 寻找连续 pages_count 个 val 位,返回开始索引 + * @param pages_count 连续页数量 + * @param val 要寻找的页状态 + * @return std::pair 找到返回 ,失败返回 + */ + std::pair Find(size_t pages_count, bool val) const { + size_t count = 0; + size_t idx = 0; + // 遍历位图 + for (uint64_t i = 0; i < length_; i++) { + if (map_[i] != val) { + count = 0; + idx = i + 1; + } else { + count++; + } + if (count == pages_count) { + return {true, idx}; + } + } + return {false, 0}; + } +}; + +#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_FIRSTFIT_ALLOCATOR_HPP_ */ diff --git a/src/kernel/include/memory/physical_memory_manager.h b/src/kernel/include/memory/physical_memory_manager.h new file mode 100644 index 00000000..cdba265b --- /dev/null +++ b/src/kernel/include/memory/physical_memory_manager.h @@ -0,0 +1,188 @@ + +/** + * @file physical_memory_manager.h + * @brief 物理内存管理 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_PHYSICAL_MEMORY_MANAGER_H_ +#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_PHYSICAL_MEMORY_MANAGER_H_ + +#include +#include + +#include "memory/allocator_base.hpp" +#include "singleton.hpp" + +/** + * @brief 物理内存管理接口 + * 对物理内存的管理来说 + * 1. 管理所有的物理内存,不论是否被机器保留/无法访问 + * 2. 内存开始地址与长度由 bootloader 给出: x86 下为 grub, riscv 下为 opensbi + * 3. + * 不关心内存是否被使用,但是默认的物理内存分配空间从内核结束后开始 + * 如果由体系结构需要分配内核开始前内存空间的,则尽量避免 + * 4. 最管理单位为页 + */ +class PhysicalMemoryManager { + public: + /// 页大小 4096 bytes + static constexpr const uint64_t kPageSize = 0x1000; + + /** + * @brief 构造函数 + * @param addr 物理地址起点 + * @param pages_count 物理页数 + */ + explicit PhysicalMemoryManager(uint64_t addr, size_t pages_count); + + /// @name 构造/析构函数 + /// @{ + PhysicalMemoryManager() = default; + PhysicalMemoryManager(const PhysicalMemoryManager &) = default; + PhysicalMemoryManager(PhysicalMemoryManager &&) = default; + auto operator=(const PhysicalMemoryManager &) -> PhysicalMemoryManager & = + default; + auto operator=(PhysicalMemoryManager &&) -> PhysicalMemoryManager & = default; + ~PhysicalMemoryManager() = default; + /// @} + + /** + * @brief 获取物理内存页数 + * @return size_t 物理内存页数 + */ + size_t GetPagesCount() const; + + /** + * @brief 获取内核空间起始地址 + * @return uint64_t 内核空间起始地址 + */ + uint64_t GetKernelSpaceAddr() const; + + /** + * @brief 获取内核空间页数 + * @return size_t 内核空间页数 + */ + size_t GetKernelSpacePagesCount() const; + + /** + * @brief 获取用户间起始地址 + * @return uint64_t 用户间起始地址 + */ + uint64_t GetUserSpaceAddr() const; + + /** + * @brief 获取用户间页数 + * @return size_t 用户间页数 + */ + size_t GetUserSpacePagesCount() const; + + /** + * @brief 获取当前已使用页数 + * @return size_t 已使用页数 + */ + size_t GetUsedPagesCount() const; + + /** + * @brief 获取当前空闲页数 + * @return size_t 空闲页数 + */ + size_t GetFreePagesCount() const; + + /** + * @brief 分配一页 + * @return uint64_t 分配的内存起始地址 + */ + uint64_t AllocUserPage(); + + /** + * @brief 分配多页 + * @param _len 页数 + * @return uint64_t 分配的内存起始地址 + */ + uint64_t AllocUserPages(size_t _len); + + /** + * @brief 分配以指定地址开始的 _len 页 + * @param addr 指定的地址 + * @param _len 页数 + * @return true 成功 + * @return false 失败 + */ + bool AllocUserPagesAt(uint64_t addr, size_t _len); + + /** + * @brief 在内核空间申请一页 + * @return uint64_t 分配的内存起始地址 + */ + uint64_t AllocKernelPage(); + + /** + * @brief 在内核空间分配 pages_count 页 + * @param pages_count 页数 + * @return uint64_t 分配到的内存起始地址 + */ + uint64_t AllocKernelPages(size_t pages_count); + + /** + * @brief 在内核空间分配以指定地址开始的 _len 页 + * @param addr 指定的地址 + * @param pages_count 页数 + * @return true 成功 + * @return false 失败 + */ + bool AllocKernelPagesAt(uint64_t addr, size_t pages_count); + + /** + * @brief 回收一页 + * @param addr 要回收的地址 + */ + void FreePage(uint64_t addr); + + /** + * @brief 回收多页 + * @param addr 要回收的地址 + * @param pages_count 页数 + */ + void FreePages(uint64_t addr, size_t pages_count); + + private: + /// 物理内存开始地址 + uint64_t addr_; + /// 物理内存页数 + size_t pages_count_; + /// 内核空间起始地址 + uint64_t kernel_addr_; + /// 内核页数 + size_t kernel_pages_count_; + /// 用户空间起始地址 + uint64_t user_start_; + /// 用户空间页数 + size_t user_pages_count_; + + /// 内核空间不会位于内存中间,导致出现用户间被切割为两部分的情况 + /// 物理内存分配器,分配内核空间 + AllocatorBase *kernel_allocator_; + /// 物理内存分配器,分配用户空间 + AllocatorBase *user_allocator_; + + /** + * @brief 将 elf 与 dtb + * 信息移动到内核空间,位于内核结束后的下一页,分别占用一页 + */ + void MoveElfDtb(); +}; + +/// 全局物理内存管理器 +[[maybe_unused]] static Singleton kPhysicalMemoryManager; + +#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_PHYSICAL_MEMORY_MANAGER_H_ */ diff --git a/src/kernel/include/memory/virtual_memory_manager.h b/src/kernel/include/memory/virtual_memory_manager.h new file mode 100644 index 00000000..f92c7d11 --- /dev/null +++ b/src/kernel/include/memory/virtual_memory_manager.h @@ -0,0 +1,171 @@ + +/** + * @file virtual_memory_manager.h + * @brief 虚拟内存管理 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#ifndef SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_VIRTUAL_MEMORY_MANAGER_H_ +#define SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_VIRTUAL_MEMORY_MANAGER_H_ + +#include +#include +#include + +#include "cpu/cpu.hpp" +#include "physical_memory_manager.h" +#include "singleton.hpp" + +// TODO: 可以优化 + +/// 页表项,最底层 +typedef uintptr_t pte_t; +/// 页表,也可以是页目录,它们的结构是一样的 +typedef uintptr_t *pt_t; + +/// 每个页表能映射多少页 = 页大小/页表项大小: 2^9 +static constexpr const size_t VMM_PAGES_PRE_PAGE_TABLE = + PhysicalMemoryManager::kPageSize / sizeof(pte_t); + +/// 内核映射的页数 +static constexpr const size_t VMM_KERNEL_SPACE_PAGES = + kKernelSpaceSize / PhysicalMemoryManager::kPageSize; + +/** + * @brief 虚拟内存抽象 + * 设计目标:在内核中存在若干个 VirtualMemoryManager + * 实例,内核拥有一个静态实例,每个进程有独立的 VirtualMemoryManager + * 另外要考虑:每个 cpu 维护自己的页寄存器,调度算法需要考虑到 + * - 页表(保存到寄存器) + * - 一级页表项 + * - 二级页表项 + * - 三级页表项(最低级) + */ +class VirtualMemoryManager { + public: + /** + * @brief 构造函数 + * @param addr 物理地址起点 + * @param pages_count 物理页数 + */ + explicit VirtualMemoryManager(uint32_t, uint8_t *); + + /// @name 构造/析构函数 + /// @{ + VirtualMemoryManager() = default; + VirtualMemoryManager(const VirtualMemoryManager &) = default; + VirtualMemoryManager(VirtualMemoryManager &&) = default; + auto operator=(const VirtualMemoryManager &) -> VirtualMemoryManager & = + default; + auto operator=(VirtualMemoryManager &&) -> VirtualMemoryManager & = default; + ~VirtualMemoryManager() = default; + /// @} + + /** + * @brief 获取当前页目录 + * @return pt_t 当前页目录 + */ + pt_t GetPageDirectory(); + + /** + * @brief 设置当前页目录 + * @param _pgd 要设置的页目录 + */ + void SetPageDirectory(const pt_t _pgd); + + /** + * @brief 映射物理地址到虚拟地址 + * @param _pgd 要使用的页目录 + * @param _va 要映射的虚拟地址 + * @param _pa 物理地址 + * @param _flag 属性 + */ + void Mmap(const pt_t _pgd, uintptr_t _va, uintptr_t _pa, uint32_t _flag); + + /** + * @brief 取消映射 + * @param _pgd 要操作的页目录 + * @param _va 要取消映射的虚拟地址 + */ + void Unmmap(const pt_t _pgd, uintptr_t _va); + + /** + * @brief 获取映射的物理地址 + * @param _pgd 页目录 + * @param _va 虚拟地址 + * @param _pa 如果已经映射,保存映射的物理地址,否则为 nullptr + * @return true 已映射 + * @return false 未映射 + */ + bool GetMmap(const pt_t _pgd, uintptr_t _va, const void *_pa); + + private: + /// @todo + // std::function AllocKernelPage; + uint64_t AllocKernelPage() { + return kPhysicalMemoryManager.GetInstance().AllocKernelPage(); + } + + /** + * @brief 物理地址转换到页表项 + * @param _pa 物理地址 + * @return constexpr uintptr_t 对应的虚拟地址 + * @note 0~11: pte 属性 + * 12~31: 页表的物理页地址 + */ + static constexpr uintptr_t PA2PTE(uintptr_t _pa) { + return (_pa >> cpu::vmm::VMM_PAGE_OFF_BITS) << cpu::vmm::VMM_PTE_PROP_BITS; + } + + /** + * @brief 页表项转换到物理地址 + * @param _pte 页表 + * @return constexpr uintptr_t 对应的物理地址 + */ + static constexpr uintptr_t PTE2PA(const pte_t _pte) { + return (((uintptr_t)_pte) >> cpu::vmm::VMM_PTE_PROP_BITS) + << cpu::vmm::VMM_PAGE_OFF_BITS; + } + + /** + * @brief 计算 X 级页表的位置 + * @param _level 级别 + * @return constexpr uintptr_t 偏移 + */ + static constexpr uintptr_t PXSHIFT(const size_t _level) { + return cpu::vmm::VMM_PAGE_OFF_BITS + (cpu::vmm::VMM_VPN_BITS * _level); + } + + /** + * @brief 获取 _va 的第 _level 级 VPN + * @note 例如虚拟地址右移 12+(10 * _level) 位, + * 得到的就是第 _level 级页表的 VPN + */ + static constexpr uintptr_t PX(size_t _level, uintptr_t _va) { + return (_va >> PXSHIFT(_level)) & cpu::vmm::VMM_VPN_BITS_MASK; + } + + /** + * @brief 在 _pgd 中查找 _va 对应的页表项 + * 如果未找到,_alloc 为真时会进行分配 + * @param _pgd 要查找的页目录 + * @param _va 虚拟地址 + * @param _alloc 是否分配 + * @return pte_t* 未找到返回 nullptr + */ + pte_t *find(const pt_t _pgd, uintptr_t _va, bool _alloc); +}; + +/// 全局虚拟内存管理器 +[[maybe_unused]] static Singleton kVirtualMemoryManager; + +#endif /* SIMPLEKERNEL_SRC_KERNEL_INCLUDE_MEMORY_VIRTUAL_MEMORY_MANAGER_H_ */ diff --git a/src/kernel/libc/CMakeLists.txt b/src/kernel/libc/CMakeLists.txt index f6a5cc91..8cdd84f2 100644 --- a/src/kernel/libc/CMakeLists.txt +++ b/src/kernel/libc/CMakeLists.txt @@ -14,4 +14,5 @@ target_sources(libc INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sk_libc.c ${CMAKE_CURRENT_SOURCE_DIR}/sk_string.c ${CMAKE_CURRENT_SOURCE_DIR}/sk_stdio.c + ${CMAKE_CURRENT_SOURCE_DIR}/bit.c ) diff --git a/src/kernel/libc/bit.c b/src/kernel/libc/bit.c new file mode 100644 index 00000000..5219d80c --- /dev/null +++ b/src/kernel/libc/bit.c @@ -0,0 +1,194 @@ + +/** + * @file bit.c + * @brief 位操作相关函数 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-03-31 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-03-31Zone.N迁移到 doxygen + *
+ */ + +#include + +// These functions return the number of leading 0-bits in a, starting at the +// most significant bit position. If a is zero, the result is undefined. +int __clzsi2(unsigned int a) { + if (a == 0) { + return 32; + } + int count = 0; + while ((a & 0x80000000) == 0) { + a <<= 1; + count++; + } + return count; +} + +int __clzdi2(unsigned long a) { + if (a == 0) { + return 64; + } + int count = 0; + while ((a & 0x8000000000000000UL) == 0) { + a <<= 1; + count++; + } + return count; +} + +int __clzti2(unsigned long long a) { + if (a == 0) { + return 64; + } + int count = 0; + while ((a & 0x8000000000000000ULL) == 0) { + a <<= 1; + count++; + } + return count; +} + +// These functions return the number of trailing 0-bits in a, starting at the +// least significant bit position. If a is zero, the result is undefined. +int __ctzsi2(unsigned int a) { + if (a == 0) { + return 32; // Return 32 if no bits are set + } + int count = 0; + while ((a & 1) == 0) { + a >>= 1; + count++; + } + return count; +} + +int __ctzdi2(unsigned long a) { + if (a == 0) { + return 64; + } + int count = 0; + while ((a & 1) == 0) { + a >>= 1; + count++; + } + return count; +} + +int __ctzti2(unsigned long long a) { + if (a == 0) { + return 64; + } + int count = 0; + while ((a & 1) == 0) { + a >>= 1; + count++; + } + return count; +} + +// These functions return the index of the least significant 1-bit in a, or the +// value zero if a is zero. The least significant bit is index one. +int __ffsdi2(unsigned long a) { + if (a == 0) { + return 0; + } + int index = 1; + while ((a & 1) == 0) { + a >>= 1; + index++; + } + return index; +} + +int __ffsti2(unsigned long long a) { + if (a == 0) { + return 0; + } + int index = 1; + while ((a & 1) == 0) { + a >>= 1; + index++; + } + return index; +} + +// These functions return the value zero if the number of bits set in a is even, +// and the value one otherwise. +int __paritysi2(unsigned int a) { + a ^= a >> 16; + a ^= a >> 8; + a ^= a >> 4; + a ^= a >> 2; + a ^= a >> 1; + return a & 1; +} + +int __paritydi2(unsigned long a) { + a ^= a >> 32; + a ^= a >> 16; + a ^= a >> 8; + a ^= a >> 4; + a ^= a >> 2; + a ^= a >> 1; + return a & 1; +} + +int __parityti2(unsigned long long a) { + a ^= a >> 32; + a ^= a >> 16; + a ^= a >> 8; + a ^= a >> 4; + a ^= a >> 2; + a ^= a >> 1; + return a & 1; +} + +// These functions return the number of bits set in a. +int __popcountsi2(unsigned int a) { + int count = 0; + while (a) { + a &= a - 1; + count++; + } + return count; +} + +int __popcountdi2(unsigned long a) { + int count = 0; + while (a) { + a &= a - 1; + count++; + } + return count; +} + +int __popcountti2(unsigned long long a) { + int count = 0; + while (a) { + a &= a - 1; + count++; + } + return count; +} + +// These functions return the a byteswapped. +int32_t __bswapsi2(int32_t a) { + return (((a & 0xFF000000) >> 24) | ((a & 0x00FF0000) >> 8) | + ((a & 0x0000FF00) << 8) | ((a & 0x000000FF) << 24)); +} + +int64_t __bswapdi2(int64_t a) { + return ( + ((a & 0xFF00000000000000ULL) >> 56) | + ((a & 0x00FF000000000000ULL) >> 40) | + ((a & 0x0000FF0000000000ULL) >> 24) | ((a & 0x000000FF00000000ULL) >> 8) | + ((a & 0x00000000FF000000ULL) << 8) | ((a & 0x0000000000FF0000ULL) << 24) | + ((a & 0x000000000000FF00ULL) << 40) | + ((a & 0x00000000000000FFULL) << 56)); +} diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 6c4b235d..5a5158af 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -16,10 +16,10 @@ #include #include "arch.h" -#include "sk_cstdio" -#include "sk_iostream" #include "kernel.h" #include "kernel_log.hpp" +#include "sk_cstdio" +#include "sk_iostream" #include "sk_libcxx.h" void _start(uint32_t argc, uint8_t *argv) { @@ -53,6 +53,10 @@ uint32_t main(uint32_t argc, uint8_t *argv) { InterruptInit(argc, argv); + PhysicalMemoryInit(argc, argv); + + VirtualMemoryInit(argc, argv); + // 进入死循环 while (1) { for (uint64_t i = 0; i < 99999999; i++) { diff --git a/src/kernel/physical_memory_manager.cpp b/src/kernel/physical_memory_manager.cpp new file mode 100644 index 00000000..88356fa5 --- /dev/null +++ b/src/kernel/physical_memory_manager.cpp @@ -0,0 +1,166 @@ + +/** + * @file physical_memory_manager.cpp + * @brief 物理内存管理 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#include "memory/physical_memory_manager.h" + +#include +#include + +#include "basic_info.hpp" +#include "kernel_elf.hpp" +#include "kernel_fdt.hpp" +#include "kernel_log.hpp" +#include "memory/firstfit_allocator.hpp" +#include "project_config.h" + +PhysicalMemoryManager::PhysicalMemoryManager(uint64_t addr, size_t pages_count) + : addr_(addr), pages_count_(pages_count) { + // 内核空间地址开始 + kernel_addr_ = kBasicInfo.GetInstance().kernel_addr; + // 长度手动指定 + kernel_pages_count_ = kKernelSpaceSize / kPageSize; + // 非内核空间在内核空间结束后 + user_start_ = kBasicInfo.GetInstance().kernel_addr + kKernelSpaceSize; + // 长度为总长度减去内核长度 + user_pages_count_ = pages_count_ - kernel_pages_count_; + + // 创建分配器 + // 内核空间 + static FirstFitAllocator first_fit_allocator_kernel( + "First Fit Allocator(Kernel space)", kernel_addr_, kernel_pages_count_); + kernel_allocator_ = (AllocatorBase*)&first_fit_allocator_kernel; + // 用户空间 + static FirstFitAllocator first_fit_allocator( + "First Fit Allocator(User space)", user_start_, user_pages_count_); + user_allocator_ = (AllocatorBase*)&first_fit_allocator; + + // 内核占用页数 + auto kernel_pages = kBasicInfo.GetInstance().kernel_size / kPageSize; + if (kBasicInfo.GetInstance().kernel_size % kPageSize != 0) { + kernel_pages++; + } + // 将内核已使用部进行分配 + AllocKernelPagesAt(kBasicInfo.GetInstance().kernel_addr, kernel_pages); + MoveElfDtb(); +} + +size_t PhysicalMemoryManager::GetPagesCount() const { return pages_count_; } + +uint64_t PhysicalMemoryManager::GetKernelSpaceAddr() const { + return kernel_addr_; +} + +size_t PhysicalMemoryManager::GetKernelSpacePagesCount() const { + return kernel_pages_count_; +} + +uint64_t PhysicalMemoryManager::GetUserSpaceAddr() const { return user_start_; } + +size_t PhysicalMemoryManager::GetUserSpacePagesCount() const { + return user_pages_count_; +} + +size_t PhysicalMemoryManager::GetUsedPagesCount() const { + return kernel_allocator_->GetUsedCount() + user_allocator_->GetUsedCount(); +} + +size_t PhysicalMemoryManager::GetFreePagesCount() const { + return kernel_allocator_->GetFreeCount() + user_allocator_->GetFreeCount(); +} + +uint64_t PhysicalMemoryManager::AllocUserPage() { + return user_allocator_->Alloc(1); +} + +uint64_t PhysicalMemoryManager::AllocUserPages(size_t pages_count) { + return user_allocator_->Alloc(pages_count); +} + +bool PhysicalMemoryManager::AllocUserPagesAt(uint64_t addr, + size_t pages_count) { + bool ret = user_allocator_->AllocAt(addr, pages_count); + return ret; +} + +uint64_t PhysicalMemoryManager::AllocKernelPage() { + return kernel_allocator_->Alloc(1); +} + +uint64_t PhysicalMemoryManager::AllocKernelPages(size_t pages_count) { + return kernel_allocator_->Alloc(pages_count); +} + +bool PhysicalMemoryManager::AllocKernelPagesAt(uint64_t addr, + size_t pages_count) { + return kernel_allocator_->AllocAt(addr, pages_count); +} + +void PhysicalMemoryManager::FreePage(uint64_t addr) { + // 判断应该使用哪个分配器 + if (addr >= kernel_addr_ && addr < kernel_addr_ + kernel_pages_count_) { + kernel_allocator_->Free(addr, 1); + } else if (addr >= user_start_ && addr < user_start_ + user_pages_count_) { + user_allocator_->Free(addr, 1); + } +} + +void PhysicalMemoryManager::FreePages(uint64_t addr, size_t pages_count) { + // 判断应该使用哪个分配器 + if (addr >= kernel_addr_ && addr < kernel_addr_ + kernel_pages_count_) { + kernel_allocator_->Free(addr, pages_count); + } else if (addr >= user_start_ && addr < user_start_ + user_pages_count_) { + user_allocator_->Free(addr, pages_count); + } +} + +void PhysicalMemoryManager::MoveElfDtb() { + // 重新初始化 + if (kBasicInfo.GetInstance().elf_addr != 0) { + auto old_elf_addr = kBasicInfo.GetInstance().elf_addr; + // 计算需要多少页 + auto elf_pages = kBasicInfo.GetInstance().elf_size / kPageSize; + if (kBasicInfo.GetInstance().elf_size % kPageSize != 0) { + elf_pages++; + } + // 申请空间 + auto new_elf_addr = AllocKernelPages(elf_pages); + // 复制过来,完成后以前的内存就可以使用了 + memcpy((void*)new_elf_addr, (void*)old_elf_addr, elf_pages * kPageSize); + // 更新 kBasicInfo 信息 + kBasicInfo.GetInstance().elf_addr = new_elf_addr; + kKernelElf.GetInstance() = KernelElf(kBasicInfo.GetInstance().elf_addr, + kBasicInfo.GetInstance().elf_size); + } + if (kBasicInfo.GetInstance().fdt_addr != 0) { + auto old_fdt_addr = kBasicInfo.GetInstance().fdt_addr; + auto fdt_pages = 1; + auto new_fdt_addr = AllocKernelPages(fdt_pages); + memcpy((void*)new_fdt_addr, (void*)old_fdt_addr, fdt_pages * kPageSize); + kBasicInfo.GetInstance().fdt_addr = new_fdt_addr; + kKernelFdt.GetInstance() = KernelFdt(kBasicInfo.GetInstance().fdt_addr); + } +} + +uint32_t PhysicalMemoryInit(uint32_t, uint8_t*) { + // 初始化物理内存管理器 + kPhysicalMemoryManager.GetInstance() = + PhysicalMemoryManager(kBasicInfo.GetInstance().physical_memory_addr, + kBasicInfo.GetInstance().physical_memory_size); + + klog::Info("Hello PhysicalMemoryInit\n"); + + return 0; +} diff --git a/src/kernel/virtual_memory_manager.cpp b/src/kernel/virtual_memory_manager.cpp new file mode 100644 index 00000000..cc082ba2 --- /dev/null +++ b/src/kernel/virtual_memory_manager.cpp @@ -0,0 +1,181 @@ + +/** + * @file virtual_memory_manager.cpp + * @brief 虚拟内存管理 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2021-09-18 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2021-09-18digmouse233迁移到 doxygen + *
+ */ + +#include "memory/virtual_memory_manager.h" + +#include + +#include "basic_info.hpp" +#include "kernel_log.hpp" +#include "sk_cstdio" +#include "sk_cstring" + +VirtualMemoryManager::VirtualMemoryManager(uint32_t, uint8_t*) { + // 分配一页用于保存页目录 + pt_t pgd_kernel = (pt_t)AllocKernelPage(); + memset(pgd_kernel, 0, PhysicalMemoryManager::kPageSize); + // 映射内核空间 + for (uint64_t addr = kBasicInfo.GetInstance().kernel_addr; + addr < kBasicInfo.GetInstance().kernel_addr + kKernelSpaceSize; + addr += PhysicalMemoryManager::kPageSize) { + // TODO: 区分代码/数据等段分别映射 + Mmap(pgd_kernel, addr, addr, + cpu::vmm::VMM_PAGE_READABLE | cpu::vmm::VMM_PAGE_WRITABLE | + cpu::vmm::VMM_PAGE_EXECUTABLE); + } + // 设置页目录 + klog::Debug("SetPageDirectory: 0x%X\n", pgd_kernel); + SetPageDirectory(pgd_kernel); + // 开启分页 + cpu::vmm::EnablePage(); +} + +pt_t VirtualMemoryManager::GetPageDirectory() { + return (pt_t)cpu::vmm::GetPageDirectory(); +} + +void VirtualMemoryManager::SetPageDirectory(const pt_t _pgd) { + // 设置页目录 + cpu::vmm::SetPageDirectory((uint64_t)_pgd); + // 刷新缓存 + cpu::vmm::FlushPage(0); +} + +void VirtualMemoryManager::Mmap(const pt_t _pgd, uintptr_t _va, uintptr_t _pa, + uint32_t _flag) { + pte_t* pte = find(_pgd, _va, true); + // 一般情况下不应该为空 + if (pte == nullptr) { + klog::Err("pte == nullptr\n"); + throw; + } + + // 已经映射过了 且 flag 没有变化 + if (((*pte & cpu::vmm::VMM_PAGE_VALID) == cpu::vmm::VMM_PAGE_VALID) && + ((*pte & ((1 << cpu::vmm::VMM_PTE_PROP_BITS) - 1)) == _flag)) { + klog::Warn("remap.\n"); + } + // 没有映射,或更改了 flag + else { + // 那么设置 *pte + // pte 解引用后的值是页表项 + *pte = PA2PTE(_pa) | _flag | + (*pte & ((1 << cpu::vmm::VMM_PTE_PROP_BITS) - 1)) | + cpu::vmm::VMM_PAGE_VALID; + // 刷新缓存 + cpu::vmm::FlushPage(0); + } +} + +void VirtualMemoryManager::Unmmap(const pt_t _pgd, uintptr_t _va) { + pte_t* pte = find(_pgd, _va, false); + // 找到页表项 + // 未找到 + if (pte == nullptr) { + klog::Warn("VirtualMemoryManager::Unmmap: find.\n"); + return; + } + // 找到了,但是并没有被映射 + if ((*pte & cpu::vmm::VMM_PAGE_VALID) == 0) { + klog::Warn("VirtualMemoryManager::Unmmap: not mapped.\n"); + } + // 置零 + *pte = 0x00; + // 刷新缓存 + cpu::vmm::FlushPage(0); + // TODO: 如果一页表都被 unmap,释放占用的物理内存 +} + +bool VirtualMemoryManager::GetMmap(const pt_t _pgd, uintptr_t _va, + const void* _pa) { + pte_t* pte = find(_pgd, _va, false); + bool res = false; + // pte 不为空且有效,说明映射了 + if ((pte != nullptr) && ((*pte & cpu::vmm::VMM_PAGE_VALID) == 1)) { + // 如果 _pa 不为空 + if (_pa != nullptr) { + // 设置 _pa + // 将页表项转换为物理地址 + *(uintptr_t*)_pa = PTE2PA(*pte); + } + // 返回 true + res = true; + } + // 否则说明没有映射 + else { + // 如果 _pa 不为空 + if (_pa != nullptr) { + // 设置 _pa + *(uintptr_t*)_pa = (uintptr_t) nullptr; + } + } + return res; +} + +// 在 _pgd 中查找 _va 对应的页表项 +// 如果未找到,_alloc 为真时会进行分配 +pte_t* VirtualMemoryManager::find(const pt_t _pgd, uintptr_t _va, bool _alloc) { + pt_t pgd = _pgd; + // sv39 共有三级页表,一级一级查找 + // -1 是因为最后一级是具体的某一页,在函数最后直接返回 + for (size_t level = cpu::vmm::VMM_PT_LEVEL - 1; level > 0; level--) { + // 每次循环会找到 _va 的第 level 级页表 pgd + // 相当于 pgd_level[VPN_level],这样相当于得到了第 level 级页表的地址 + pte_t* pte = (pte_t*)&pgd[PX(level, _va)]; + // 解引用 pte,如果有效,获取 level+1 级页表, + if ((*pte & cpu::vmm::VMM_PAGE_VALID) == 1) { + // pgd 指向下一级页表 + // *pte 保存的是页表项,需要转换为对应的物理地址 + pgd = (pt_t)PTE2PA(*pte); + } + // 如果无效 + else { + // 判断是否需要分配 + // 如果需要 + if (_alloc == true) { + // 申请新的物理页 + pgd = (pt_t)AllocKernelPage(); + memset(pgd, 0, PhysicalMemoryManager::kPageSize); + // 申请失败则返回 + if (pgd == nullptr) { + // 如果出现这种情况,说明物理内存不够,一般不会出现 + klog::Err("No Enough Memory\n"); + throw; + return nullptr; + } + // 清零 + memset(pgd, 0, PhysicalMemoryManager::kPageSize); + // 填充页表项 + *pte = PA2PTE((uintptr_t)pgd) | cpu::vmm::VMM_PAGE_VALID; + } + // 不分配的话直接返回 + else { + return nullptr; + } + } + } + // 0 最低级 pt + return &pgd[PX(0, _va)]; +} + +uint32_t VirtualMemoryInit(uint32_t argc, uint8_t* argv) { + // 初始化虚拟内存管理器 + kVirtualMemoryManager.GetInstance() = VirtualMemoryManager(argc, argv); + + klog::Info("Hello VirtualMemoryInit\n"); + + return 0; +} diff --git a/src/project_config.h b/src/project_config.h index 210ff0e9..bf8b37db 100644 --- a/src/project_config.h +++ b/src/project_config.h @@ -25,4 +25,7 @@ #define SIMPLEKERNEL_DEBUG_LOG #endif +/// 内核空间设为 64MB +#define kKernelSpaceSize (0x4000000) + #endif /* SIMPLEKERNEL_SRC_PROJECT_CONFIG_H_ */ diff --git a/test/unit_test/CMakeLists.txt b/test/unit_test/CMakeLists.txt index b447ccef..ab04a782 100644 --- a/test/unit_test/CMakeLists.txt +++ b/test/unit_test/CMakeLists.txt @@ -18,6 +18,10 @@ add_executable(${PROJECT_NAME} aarch64_cpu_test.cpp kernel_elf_test.cpp kernel_fdt_test.cpp + libc_bit_test.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/kernel/firstfit_allocator.cpp + firstfit_allocator_test.cpp ) target_include_directories(${PROJECT_NAME} PRIVATE @@ -36,7 +40,12 @@ target_link_options(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE ${DEFAULT_TEST_LINK_LIB} +<<<<<<< HEAD + ${dtc_BINARY_DIR}/libfdt/libfdt.a + libc +======= dtc-lib +>>>>>>> new_intr ) gtest_discover_tests(${PROJECT_NAME}) diff --git a/test/unit_test/firstfit_allocator_test.cpp b/test/unit_test/firstfit_allocator_test.cpp new file mode 100644 index 00000000..7ba4b45d --- /dev/null +++ b/test/unit_test/firstfit_allocator_test.cpp @@ -0,0 +1,49 @@ + +/** + * @file firstfit_allocator_test.cpp + * @brief firstfit_allocator 相关测试 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-09-02 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-09-02Zone.N创建文件 + *
+ */ + +#include "memory/firstfit_allocator.h" + +#include + +TEST(FirstFitAllocatorTest, AllocAtTest) { + auto allocator = FirstFitAllocator("AllocAtTest", 0, 0x1000); + EXPECT_EQ(allocator.AllocAt(0, 0x1001), 0); + EXPECT_EQ(allocator.AllocAt(0, 0x1000), 1); + EXPECT_EQ(allocator.AllocAt(0, 0x1000), 0); + allocator.Free(0, 0x1000); + EXPECT_EQ(allocator.AllocAt(0, 0xFFF), 1); + EXPECT_EQ(allocator.AllocAt(0x1000, 1), 0); +} + +TEST(FirstFitAllocatorTest, AllocTest) { + auto allocator = FirstFitAllocator("AllocTest", 0x1000, 0x1000); + auto addr1 = allocator.Alloc(0x1001); + EXPECT_EQ(addr1, 0); + + auto addr2 = allocator.Alloc(0x1000); + EXPECT_EQ(addr2, 0x1000); + + auto addr3 = allocator.Alloc(0x1000); + EXPECT_EQ(addr3, 0); + + allocator.Free(addr2, 0x1000); + + auto addr4 = allocator.Alloc(0xFFF); + EXPECT_EQ(addr4, 0x1000); + + auto addr5 = allocator.Alloc(1); + EXPECT_EQ(addr5, 0x1000 + 0xFFF * 0x1000); +} diff --git a/test/unit_test/libc_bit_test.cpp b/test/unit_test/libc_bit_test.cpp new file mode 100644 index 00000000..2f07208f --- /dev/null +++ b/test/unit_test/libc_bit_test.cpp @@ -0,0 +1,1201 @@ + +/** + * @file aarch64_cpu_test.cpp + * @brief aarch64 cpu 相关测试 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-09-02 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleKernel + * @par change log: + * + *
DateAuthorDescription + *
2023-09-02Zone.N创建文件 + *
+ */ + +#include + +extern "C" int __clzsi2(unsigned int a); +extern "C" int __clzdi2(unsigned long a); +extern "C" int __clzti2(unsigned long long a); + +extern "C" int __ctzsi2(unsigned int a); +extern "C" int __ctzdi2(unsigned long a); +extern "C" int __ctzti2(unsigned long long a); + +extern "C" int __ffsdi2(unsigned long a); +extern "C" int __ffsti2(unsigned long long a); + +extern "C" int __paritysi2(unsigned int a); +extern "C" int __paritydi2(unsigned long a); +extern "C" int __parityti2(unsigned long long a); + +extern "C" int __popcountsi2(unsigned int a); +extern "C" int __popcountdi2(unsigned long a); +extern "C" int __popcountti2(unsigned long long a); + +extern "C" int32_t __bswapsi2(int32_t a); +extern "C" int64_t __bswapdi2(int64_t a); + +TEST(BitTest, __clzsi2Test) { + EXPECT_EQ(__clzsi2(0x00000000), 32); + EXPECT_EQ(__clzsi2(0x00000001), 31); + EXPECT_EQ(__clzsi2(0x00000002), 30); + EXPECT_EQ(__clzsi2(0x00000004), 29); + EXPECT_EQ(__clzsi2(0x00000008), 28); + EXPECT_EQ(__clzsi2(0x00000010), 27); + EXPECT_EQ(__clzsi2(0x00000020), 26); + EXPECT_EQ(__clzsi2(0x00000040), 25); + EXPECT_EQ(__clzsi2(0x00000080), 24); + EXPECT_EQ(__clzsi2(0x00000100), 23); + EXPECT_EQ(__clzsi2(0x00000200), 22); + EXPECT_EQ(__clzsi2(0x00000400), 21); + EXPECT_EQ(__clzsi2(0x00000800), 20); + EXPECT_EQ(__clzsi2(0x00001000), 19); + EXPECT_EQ(__clzsi2(0x00002000), 18); + EXPECT_EQ(__clzsi2(0x00004000), 17); + EXPECT_EQ(__clzsi2(0x00008000), 16); + EXPECT_EQ(__clzsi2(0x00010000), 15); + EXPECT_EQ(__clzsi2(0x00020000), 14); + EXPECT_EQ(__clzsi2(0x00040000), 13); + EXPECT_EQ(__clzsi2(0x00080000), 12); + EXPECT_EQ(__clzsi2(0x00100000), 11); + EXPECT_EQ(__clzsi2(0x00200000), 10); + EXPECT_EQ(__clzsi2(0x00400000), 9); + EXPECT_EQ(__clzsi2(0x00800000), 8); + EXPECT_EQ(__clzsi2(0x01000000), 7); + EXPECT_EQ(__clzsi2(0x02000000), 6); + EXPECT_EQ(__clzsi2(0x04000000), 5); + EXPECT_EQ(__clzsi2(0x08000000), 4); + EXPECT_EQ(__clzsi2(0x10000000), 3); + EXPECT_EQ(__clzsi2(0x20000000), 2); + EXPECT_EQ(__clzsi2(0x40000000), 1); + EXPECT_EQ(__clzsi2(0x80000000), 0); + + EXPECT_EQ(__clzsi2(0b00000000000000000000000000000000), 32); + EXPECT_EQ(__clzsi2(0b01000000001111000000000000000000), 1); + EXPECT_EQ(__clzsi2(0b00100000000000000000000000000000), 2); + EXPECT_EQ(__clzsi2(0b00010000000000001111000110000000), 3); + EXPECT_EQ(__clzsi2(0b00001001001000111000000000000000), 4); +} + +TEST(BitTest, __clzdi2Test) { + EXPECT_EQ(__clzdi2(0x0000000000000000), 64); + EXPECT_EQ(__clzdi2(0x0000000000000001), 63); + EXPECT_EQ(__clzdi2(0x0000000000000002), 62); + EXPECT_EQ(__clzdi2(0x0000000000000004), 61); + EXPECT_EQ(__clzdi2(0x0000000000000008), 60); + EXPECT_EQ(__clzdi2(0x0000000000000010), 59); + EXPECT_EQ(__clzdi2(0x0000000000000020), 58); + EXPECT_EQ(__clzdi2(0x0000000000000040), 57); + EXPECT_EQ(__clzdi2(0x0000000000000080), 56); + EXPECT_EQ(__clzdi2(0x0000000000000100), 55); + EXPECT_EQ(__clzdi2(0x0000000000000200), 54); + EXPECT_EQ(__clzdi2(0x0000000000000400), 53); + EXPECT_EQ(__clzdi2(0x0000000000000800), 52); + EXPECT_EQ(__clzdi2(0x0000000000001000), 51); + EXPECT_EQ(__clzdi2(0x0000000000002000), 50); + EXPECT_EQ(__clzdi2(0x0000000000004000), 49); + EXPECT_EQ(__clzdi2(0x0000000000008000), 48); + EXPECT_EQ(__clzdi2(0x0000000000010000), 47); + EXPECT_EQ(__clzdi2(0x0000000000020000), 46); + EXPECT_EQ(__clzdi2(0x0000000000040000), 45); + EXPECT_EQ(__clzdi2(0x0000000000080000), 44); + EXPECT_EQ(__clzdi2(0x0000000000100000), 43); + EXPECT_EQ(__clzdi2(0x0000000000200000), 42); + EXPECT_EQ(__clzdi2(0x0000000000400000), 41); + EXPECT_EQ(__clzdi2(0x0000000000800000), 40); + EXPECT_EQ(__clzdi2(0x0000000001000000), 39); + EXPECT_EQ(__clzdi2(0x0000000002000000), 38); + EXPECT_EQ(__clzdi2(0x0000000004000000), 37); + EXPECT_EQ(__clzdi2(0x0000000008000000), 36); + EXPECT_EQ(__clzdi2(0x0000000010000000), 35); + EXPECT_EQ(__clzdi2(0x0000000020000000), 34); + EXPECT_EQ(__clzdi2(0x0000000040000000), 33); + EXPECT_EQ(__clzdi2(0x0000000080000000), 32); + EXPECT_EQ(__clzdi2(0x0000000100000000), 31); + EXPECT_EQ(__clzdi2(0x0000000200000000), 30); + EXPECT_EQ(__clzdi2(0x0000000400000000), 29); + EXPECT_EQ(__clzdi2(0x0000000800000000), 28); + EXPECT_EQ(__clzdi2(0x0000001000000000), 27); + EXPECT_EQ(__clzdi2(0x0000002000000000), 26); + EXPECT_EQ(__clzdi2(0x0000004000000000), 25); + EXPECT_EQ(__clzdi2(0x0000008000000000), 24); + EXPECT_EQ(__clzdi2(0x0000010000000000), 23); + EXPECT_EQ(__clzdi2(0x0000020000000000), 22); + EXPECT_EQ(__clzdi2(0x0000040000000000), 21); + EXPECT_EQ(__clzdi2(0x0000080000000000), 20); + EXPECT_EQ(__clzdi2(0x0000100000000000), 19); + EXPECT_EQ(__clzdi2(0x0000200000000000), 18); + EXPECT_EQ(__clzdi2(0x0000400000000000), 17); + EXPECT_EQ(__clzdi2(0x0000800000000000), 16); + EXPECT_EQ(__clzdi2(0x0001000000000000), 15); + EXPECT_EQ(__clzdi2(0x0002000000000000), 14); + EXPECT_EQ(__clzdi2(0x0004000000000000), 13); + EXPECT_EQ(__clzdi2(0x0008000000000000), 12); + EXPECT_EQ(__clzdi2(0x0010000000000000), 11); + EXPECT_EQ(__clzdi2(0x0020000000000000), 10); + EXPECT_EQ(__clzdi2(0x0040000000000000), 9); + EXPECT_EQ(__clzdi2(0x0080000000000000), 8); + EXPECT_EQ(__clzdi2(0x0100000000000000), 7); + EXPECT_EQ(__clzdi2(0x0200000000000000), 6); + EXPECT_EQ(__clzdi2(0x0400000000000000), 5); + EXPECT_EQ(__clzdi2(0x0800000000000000), 4); + EXPECT_EQ(__clzdi2(0x1000000000000000), 3); + EXPECT_EQ(__clzdi2(0x2000000000000000), 2); + EXPECT_EQ(__clzdi2(0x4000000000000000), 1); + EXPECT_EQ(__clzdi2(0x8000000000000000), 0); + + EXPECT_EQ( + __clzdi2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 64); + EXPECT_EQ( + __clzdi2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __clzdi2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 2); + EXPECT_EQ( + __clzdi2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 3); + EXPECT_EQ( + __clzdi2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 4); +} + +TEST(BitTest, __clzti2Test) { + EXPECT_EQ(__clzti2(0x0000000000000000), 64); + EXPECT_EQ(__clzti2(0x0000000000000001), 63); + EXPECT_EQ(__clzti2(0x0000000000000002), 62); + EXPECT_EQ(__clzti2(0x0000000000000004), 61); + EXPECT_EQ(__clzti2(0x0000000000000008), 60); + EXPECT_EQ(__clzti2(0x0000000000000010), 59); + EXPECT_EQ(__clzti2(0x0000000000000020), 58); + EXPECT_EQ(__clzti2(0x0000000000000040), 57); + EXPECT_EQ(__clzti2(0x0000000000000080), 56); + EXPECT_EQ(__clzti2(0x0000000000000100), 55); + EXPECT_EQ(__clzti2(0x0000000000000200), 54); + EXPECT_EQ(__clzti2(0x0000000000000400), 53); + EXPECT_EQ(__clzti2(0x0000000000000800), 52); + EXPECT_EQ(__clzti2(0x0000000000001000), 51); + EXPECT_EQ(__clzti2(0x0000000000002000), 50); + EXPECT_EQ(__clzti2(0x0000000000004000), 49); + EXPECT_EQ(__clzti2(0x0000000000008000), 48); + EXPECT_EQ(__clzti2(0x0000000000010000), 47); + EXPECT_EQ(__clzti2(0x0000000000020000), 46); + EXPECT_EQ(__clzti2(0x0000000000040000), 45); + EXPECT_EQ(__clzti2(0x0000000000080000), 44); + EXPECT_EQ(__clzti2(0x0000000000100000), 43); + EXPECT_EQ(__clzti2(0x0000000000200000), 42); + EXPECT_EQ(__clzti2(0x0000000000400000), 41); + EXPECT_EQ(__clzti2(0x0000000000800000), 40); + EXPECT_EQ(__clzti2(0x0000000001000000), 39); + EXPECT_EQ(__clzti2(0x0000000002000000), 38); + EXPECT_EQ(__clzti2(0x0000000004000000), 37); + EXPECT_EQ(__clzti2(0x0000000008000000), 36); + EXPECT_EQ(__clzti2(0x0000000010000000), 35); + EXPECT_EQ(__clzti2(0x0000000020000000), 34); + EXPECT_EQ(__clzti2(0x0000000040000000), 33); + EXPECT_EQ(__clzti2(0x0000000080000000), 32); + EXPECT_EQ(__clzti2(0x0000000100000000), 31); + EXPECT_EQ(__clzti2(0x0000000200000000), 30); + EXPECT_EQ(__clzti2(0x0000000400000000), 29); + EXPECT_EQ(__clzti2(0x0000000800000000), 28); + EXPECT_EQ(__clzti2(0x0000001000000000), 27); + EXPECT_EQ(__clzti2(0x0000002000000000), 26); + EXPECT_EQ(__clzti2(0x0000004000000000), 25); + EXPECT_EQ(__clzti2(0x0000008000000000), 24); + EXPECT_EQ(__clzti2(0x0000010000000000), 23); + EXPECT_EQ(__clzti2(0x0000020000000000), 22); + EXPECT_EQ(__clzti2(0x0000040000000000), 21); + EXPECT_EQ(__clzti2(0x0000080000000000), 20); + EXPECT_EQ(__clzti2(0x0000100000000000), 19); + EXPECT_EQ(__clzti2(0x0000200000000000), 18); + EXPECT_EQ(__clzti2(0x0000400000000000), 17); + EXPECT_EQ(__clzti2(0x0000800000000000), 16); + EXPECT_EQ(__clzti2(0x0001000000000000), 15); + EXPECT_EQ(__clzti2(0x0002000000000000), 14); + EXPECT_EQ(__clzti2(0x0004000000000000), 13); + EXPECT_EQ(__clzti2(0x0008000000000000), 12); + EXPECT_EQ(__clzti2(0x0010000000000000), 11); + EXPECT_EQ(__clzti2(0x0020000000000000), 10); + EXPECT_EQ(__clzti2(0x0040000000000000), 9); + EXPECT_EQ(__clzti2(0x0080000000000000), 8); + EXPECT_EQ(__clzti2(0x0100000000000000), 7); + EXPECT_EQ(__clzti2(0x0200000000000000), 6); + EXPECT_EQ(__clzti2(0x0400000000000000), 5); + EXPECT_EQ(__clzti2(0x0800000000000000), 4); + EXPECT_EQ(__clzti2(0x1000000000000000), 3); + EXPECT_EQ(__clzti2(0x2000000000000000), 2); + EXPECT_EQ(__clzti2(0x4000000000000000), 1); + EXPECT_EQ(__clzti2(0x8000000000000000), 0); + + EXPECT_EQ( + __clzti2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 64); + EXPECT_EQ( + __clzti2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __clzti2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 2); + EXPECT_EQ( + __clzti2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 3); + EXPECT_EQ( + __clzti2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 4); +} + +TEST(BitTest, __ctzsi2Test) { + EXPECT_EQ(__ctzsi2(0x00000000), 32); + EXPECT_EQ(__ctzsi2(0x00000001), 0); + EXPECT_EQ(__ctzsi2(0x00000002), 1); + EXPECT_EQ(__ctzsi2(0x00000004), 2); + EXPECT_EQ(__ctzsi2(0x00000008), 3); + EXPECT_EQ(__ctzsi2(0x00000010), 4); + EXPECT_EQ(__ctzsi2(0x00000020), 5); + EXPECT_EQ(__ctzsi2(0x00000040), 6); + EXPECT_EQ(__ctzsi2(0x00000080), 7); + EXPECT_EQ(__ctzsi2(0x00000100), 8); + EXPECT_EQ(__ctzsi2(0x00000200), 9); + EXPECT_EQ(__ctzsi2(0x00000400), 10); + EXPECT_EQ(__ctzsi2(0x00000800), 11); + EXPECT_EQ(__ctzsi2(0x00001000), 12); + EXPECT_EQ(__ctzsi2(0x00002000), 13); + EXPECT_EQ(__ctzsi2(0x00004000), 14); + EXPECT_EQ(__ctzsi2(0x00008000), 15); + EXPECT_EQ(__ctzsi2(0x00010000), 16); + EXPECT_EQ(__ctzsi2(0x00020000), 17); + EXPECT_EQ(__ctzsi2(0x00040000), 18); + EXPECT_EQ(__ctzsi2(0x00080000), 19); + EXPECT_EQ(__ctzsi2(0x00100000), 20); + EXPECT_EQ(__ctzsi2(0x00200000), 21); + EXPECT_EQ(__ctzsi2(0x00400000), 22); + EXPECT_EQ(__ctzsi2(0x00800000), 23); + EXPECT_EQ(__ctzsi2(0x01000000), 24); + EXPECT_EQ(__ctzsi2(0x02000000), 25); + EXPECT_EQ(__ctzsi2(0x04000000), 26); + EXPECT_EQ(__ctzsi2(0x08000000), 27); + EXPECT_EQ(__ctzsi2(0x10000000), 28); + EXPECT_EQ(__ctzsi2(0x20000000), 29); + EXPECT_EQ(__ctzsi2(0x40000000), 30); + EXPECT_EQ(__ctzsi2(0x80000000), 31); + + EXPECT_EQ(__ctzsi2(0b00000000000000000000000000000000), 32); + EXPECT_EQ(__ctzsi2(0b01000000001111000000000000000000), 18); + EXPECT_EQ(__ctzsi2(0b00100000000000000000000000000000), 29); + EXPECT_EQ(__ctzsi2(0b00010000000000001111000110000000), 7); + EXPECT_EQ(__ctzsi2(0b00001001001000111000000000000000), 15); +} + +TEST(BitTest, __ctzdi2Test) { + EXPECT_EQ(__ctzdi2(0x0000000000000000), 64); + EXPECT_EQ(__ctzdi2(0x0000000000000001), 0); + EXPECT_EQ(__ctzdi2(0x0000000000000002), 1); + EXPECT_EQ(__ctzdi2(0x0000000000000004), 2); + EXPECT_EQ(__ctzdi2(0x0000000000000008), 3); + EXPECT_EQ(__ctzdi2(0x0000000000000010), 4); + EXPECT_EQ(__ctzdi2(0x0000000000000020), 5); + EXPECT_EQ(__ctzdi2(0x0000000000000040), 6); + EXPECT_EQ(__ctzdi2(0x0000000000000080), 7); + EXPECT_EQ(__ctzdi2(0x0000000000000100), 8); + EXPECT_EQ(__ctzdi2(0x0000000000000200), 9); + EXPECT_EQ(__ctzdi2(0x0000000000000400), 10); + EXPECT_EQ(__ctzdi2(0x0000000000000800), 11); + EXPECT_EQ(__ctzdi2(0x0000000000001000), 12); + EXPECT_EQ(__ctzdi2(0x0000000000002000), 13); + EXPECT_EQ(__ctzdi2(0x0000000000004000), 14); + EXPECT_EQ(__ctzdi2(0x0000000000008000), 15); + EXPECT_EQ(__ctzdi2(0x0000000000010000), 16); + EXPECT_EQ(__ctzdi2(0x0000000000020000), 17); + EXPECT_EQ(__ctzdi2(0x0000000000040000), 18); + EXPECT_EQ(__ctzdi2(0x0000000000080000), 19); + EXPECT_EQ(__ctzdi2(0x0000000000100000), 20); + EXPECT_EQ(__ctzdi2(0x0000000000200000), 21); + EXPECT_EQ(__ctzdi2(0x0000000000400000), 22); + EXPECT_EQ(__ctzdi2(0x0000000000800000), 23); + EXPECT_EQ(__ctzdi2(0x0000000001000000), 24); + EXPECT_EQ(__ctzdi2(0x0000000002000000), 25); + EXPECT_EQ(__ctzdi2(0x0000000004000000), 26); + EXPECT_EQ(__ctzdi2(0x0000000008000000), 27); + EXPECT_EQ(__ctzdi2(0x0000000010000000), 28); + EXPECT_EQ(__ctzdi2(0x0000000020000000), 29); + EXPECT_EQ(__ctzdi2(0x0000000040000000), 30); + EXPECT_EQ(__ctzdi2(0x0000000080000000), 31); + EXPECT_EQ(__ctzdi2(0x0000000100000000), 32); + EXPECT_EQ(__ctzdi2(0x0000000200000000), 33); + EXPECT_EQ(__ctzdi2(0x0000000400000000), 34); + EXPECT_EQ(__ctzdi2(0x0000000800000000), 35); + EXPECT_EQ(__ctzdi2(0x0000001000000000), 36); + EXPECT_EQ(__ctzdi2(0x0000002000000000), 37); + EXPECT_EQ(__ctzdi2(0x0000004000000000), 38); + EXPECT_EQ(__ctzdi2(0x0000008000000000), 39); + EXPECT_EQ(__ctzdi2(0x0000010000000000), 40); + EXPECT_EQ(__ctzdi2(0x0000020000000000), 41); + EXPECT_EQ(__ctzdi2(0x0000040000000000), 42); + EXPECT_EQ(__ctzdi2(0x0000080000000000), 43); + EXPECT_EQ(__ctzdi2(0x0000100000000000), 44); + EXPECT_EQ(__ctzdi2(0x0000200000000000), 45); + EXPECT_EQ(__ctzdi2(0x0000400000000000), 46); + EXPECT_EQ(__ctzdi2(0x0000800000000000), 47); + EXPECT_EQ(__ctzdi2(0x0001000000000000), 48); + EXPECT_EQ(__ctzdi2(0x0002000000000000), 49); + EXPECT_EQ(__ctzdi2(0x0004000000000000), 50); + EXPECT_EQ(__ctzdi2(0x0008000000000000), 51); + EXPECT_EQ(__ctzdi2(0x0010000000000000), 52); + EXPECT_EQ(__ctzdi2(0x0020000000000000), 53); + EXPECT_EQ(__ctzdi2(0x0040000000000000), 54); + EXPECT_EQ(__ctzdi2(0x0080000000000000), 55); + EXPECT_EQ(__ctzdi2(0x0100000000000000), 56); + EXPECT_EQ(__ctzdi2(0x0200000000000000), 57); + EXPECT_EQ(__ctzdi2(0x0400000000000000), 58); + EXPECT_EQ(__ctzdi2(0x0800000000000000), 59); + EXPECT_EQ(__ctzdi2(0x1000000000000000), 60); + EXPECT_EQ(__ctzdi2(0x2000000000000000), 61); + EXPECT_EQ(__ctzdi2(0x4000000000000000), 62); + EXPECT_EQ(__ctzdi2(0x8000000000000000), 63); + + EXPECT_EQ( + __ctzdi2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 64); + EXPECT_EQ( + __ctzdi2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 50); + EXPECT_EQ( + __ctzdi2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 61); + EXPECT_EQ( + __ctzdi2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 39); + EXPECT_EQ( + __ctzdi2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 47); +} + +TEST(BitTest, __ctzti2Test) { + EXPECT_EQ(__ctzti2(0x0000000000000000), 64); + EXPECT_EQ(__ctzti2(0x0000000000000001), 0); + EXPECT_EQ(__ctzti2(0x0000000000000002), 1); + EXPECT_EQ(__ctzti2(0x0000000000000004), 2); + EXPECT_EQ(__ctzti2(0x0000000000000008), 3); + EXPECT_EQ(__ctzti2(0x0000000000000010), 4); + EXPECT_EQ(__ctzti2(0x0000000000000020), 5); + EXPECT_EQ(__ctzti2(0x0000000000000040), 6); + EXPECT_EQ(__ctzti2(0x0000000000000080), 7); + EXPECT_EQ(__ctzti2(0x0000000000000100), 8); + EXPECT_EQ(__ctzti2(0x0000000000000200), 9); + EXPECT_EQ(__ctzti2(0x0000000000000400), 10); + EXPECT_EQ(__ctzti2(0x0000000000000800), 11); + EXPECT_EQ(__ctzti2(0x0000000000001000), 12); + EXPECT_EQ(__ctzti2(0x0000000000002000), 13); + EXPECT_EQ(__ctzti2(0x0000000000004000), 14); + EXPECT_EQ(__ctzti2(0x0000000000008000), 15); + EXPECT_EQ(__ctzti2(0x0000000000010000), 16); + EXPECT_EQ(__ctzti2(0x0000000000020000), 17); + EXPECT_EQ(__ctzti2(0x0000000000040000), 18); + EXPECT_EQ(__ctzti2(0x0000000000080000), 19); + EXPECT_EQ(__ctzti2(0x0000000000100000), 20); + EXPECT_EQ(__ctzti2(0x0000000000200000), 21); + EXPECT_EQ(__ctzti2(0x0000000000400000), 22); + EXPECT_EQ(__ctzti2(0x0000000000800000), 23); + EXPECT_EQ(__ctzti2(0x0000000001000000), 24); + EXPECT_EQ(__ctzti2(0x0000000002000000), 25); + EXPECT_EQ(__ctzti2(0x0000000004000000), 26); + EXPECT_EQ(__ctzti2(0x0000000008000000), 27); + EXPECT_EQ(__ctzti2(0x0000000010000000), 28); + EXPECT_EQ(__ctzti2(0x0000000020000000), 29); + EXPECT_EQ(__ctzti2(0x0000000040000000), 30); + EXPECT_EQ(__ctzti2(0x0000000080000000), 31); + EXPECT_EQ(__ctzti2(0x0000000100000000), 32); + EXPECT_EQ(__ctzti2(0x0000000200000000), 33); + EXPECT_EQ(__ctzti2(0x0000000400000000), 34); + EXPECT_EQ(__ctzti2(0x0000000800000000), 35); + EXPECT_EQ(__ctzti2(0x0000001000000000), 36); + EXPECT_EQ(__ctzti2(0x0000002000000000), 37); + EXPECT_EQ(__ctzti2(0x0000004000000000), 38); + EXPECT_EQ(__ctzti2(0x0000008000000000), 39); + EXPECT_EQ(__ctzti2(0x0000010000000000), 40); + EXPECT_EQ(__ctzti2(0x0000020000000000), 41); + EXPECT_EQ(__ctzti2(0x0000040000000000), 42); + EXPECT_EQ(__ctzti2(0x0000080000000000), 43); + EXPECT_EQ(__ctzti2(0x0000100000000000), 44); + EXPECT_EQ(__ctzti2(0x0000200000000000), 45); + EXPECT_EQ(__ctzti2(0x0000400000000000), 46); + EXPECT_EQ(__ctzti2(0x0000800000000000), 47); + EXPECT_EQ(__ctzti2(0x0001000000000000), 48); + EXPECT_EQ(__ctzti2(0x0002000000000000), 49); + EXPECT_EQ(__ctzti2(0x0004000000000000), 50); + EXPECT_EQ(__ctzti2(0x0008000000000000), 51); + EXPECT_EQ(__ctzti2(0x0010000000000000), 52); + EXPECT_EQ(__ctzti2(0x0020000000000000), 53); + EXPECT_EQ(__ctzti2(0x0040000000000000), 54); + EXPECT_EQ(__ctzti2(0x0080000000000000), 55); + EXPECT_EQ(__ctzti2(0x0100000000000000), 56); + EXPECT_EQ(__ctzti2(0x0200000000000000), 57); + EXPECT_EQ(__ctzti2(0x0400000000000000), 58); + EXPECT_EQ(__ctzti2(0x0800000000000000), 59); + EXPECT_EQ(__ctzti2(0x1000000000000000), 60); + EXPECT_EQ(__ctzti2(0x2000000000000000), 61); + EXPECT_EQ(__ctzti2(0x4000000000000000), 62); + EXPECT_EQ(__ctzti2(0x8000000000000000), 63); + + EXPECT_EQ( + __ctzti2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 64); + EXPECT_EQ( + __ctzti2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 50); + EXPECT_EQ( + __ctzti2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 61); + EXPECT_EQ( + __ctzti2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 39); + EXPECT_EQ( + __ctzti2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 47); +} + +TEST(BitTest, __ffsdi2Test) { + EXPECT_EQ(__ffsdi2(0x0000000000000000), 0); + EXPECT_EQ(__ffsdi2(0x0000000000000001), 1); + EXPECT_EQ(__ffsdi2(0x0000000000000002), 2); + EXPECT_EQ(__ffsdi2(0x0000000000000004), 3); + EXPECT_EQ(__ffsdi2(0x0000000000000008), 4); + EXPECT_EQ(__ffsdi2(0x0000000000000010), 5); + EXPECT_EQ(__ffsdi2(0x0000000000000020), 6); + EXPECT_EQ(__ffsdi2(0x0000000000000040), 7); + EXPECT_EQ(__ffsdi2(0x0000000000000080), 8); + EXPECT_EQ(__ffsdi2(0x0000000000000100), 9); + EXPECT_EQ(__ffsdi2(0x0000000000000200), 10); + EXPECT_EQ(__ffsdi2(0x0000000000000400), 11); + EXPECT_EQ(__ffsdi2(0x0000000000000800), 12); + EXPECT_EQ(__ffsdi2(0x0000000000001000), 13); + EXPECT_EQ(__ffsdi2(0x0000000000002000), 14); + EXPECT_EQ(__ffsdi2(0x0000000000004000), 15); + EXPECT_EQ(__ffsdi2(0x0000000000008000), 16); + EXPECT_EQ(__ffsdi2(0x0000000000010000), 17); + EXPECT_EQ(__ffsdi2(0x0000000000020000), 18); + EXPECT_EQ(__ffsdi2(0x0000000000040000), 19); + EXPECT_EQ(__ffsdi2(0x0000000000080000), 20); + EXPECT_EQ(__ffsdi2(0x0000000000100000), 21); + EXPECT_EQ(__ffsdi2(0x0000000000200000), 22); + EXPECT_EQ(__ffsdi2(0x0000000000400000), 23); + EXPECT_EQ(__ffsdi2(0x0000000000800000), 24); + EXPECT_EQ(__ffsdi2(0x0000000001000000), 25); + EXPECT_EQ(__ffsdi2(0x0000000002000000), 26); + EXPECT_EQ(__ffsdi2(0x0000000004000000), 27); + EXPECT_EQ(__ffsdi2(0x0000000008000000), 28); + EXPECT_EQ(__ffsdi2(0x0000000010000000), 29); + EXPECT_EQ(__ffsdi2(0x0000000020000000), 30); + EXPECT_EQ(__ffsdi2(0x0000000040000000), 31); + EXPECT_EQ(__ffsdi2(0x0000000080000000), 32); + EXPECT_EQ(__ffsdi2(0x0000000100000000), 33); + EXPECT_EQ(__ffsdi2(0x0000000200000000), 34); + EXPECT_EQ(__ffsdi2(0x0000000400000000), 35); + EXPECT_EQ(__ffsdi2(0x0000000800000000), 36); + EXPECT_EQ(__ffsdi2(0x0000001000000000), 37); + EXPECT_EQ(__ffsdi2(0x0000002000000000), 38); + EXPECT_EQ(__ffsdi2(0x0000004000000000), 39); + EXPECT_EQ(__ffsdi2(0x0000008000000000), 40); + EXPECT_EQ(__ffsdi2(0x0000010000000000), 41); + EXPECT_EQ(__ffsdi2(0x0000020000000000), 42); + EXPECT_EQ(__ffsdi2(0x0000040000000000), 43); + EXPECT_EQ(__ffsdi2(0x0000080000000000), 44); + EXPECT_EQ(__ffsdi2(0x0000100000000000), 45); + EXPECT_EQ(__ffsdi2(0x0000200000000000), 46); + EXPECT_EQ(__ffsdi2(0x0000400000000000), 47); + EXPECT_EQ(__ffsdi2(0x0000800000000000), 48); + EXPECT_EQ(__ffsdi2(0x0001000000000000), 49); + EXPECT_EQ(__ffsdi2(0x0002000000000000), 50); + EXPECT_EQ(__ffsdi2(0x0004000000000000), 51); + EXPECT_EQ(__ffsdi2(0x0008000000000000), 52); + EXPECT_EQ(__ffsdi2(0x0010000000000000), 53); + EXPECT_EQ(__ffsdi2(0x0020000000000000), 54); + EXPECT_EQ(__ffsdi2(0x0040000000000000), 55); + EXPECT_EQ(__ffsdi2(0x0080000000000000), 56); + EXPECT_EQ(__ffsdi2(0x0100000000000000), 57); + EXPECT_EQ(__ffsdi2(0x0200000000000000), 58); + EXPECT_EQ(__ffsdi2(0x0400000000000000), 59); + EXPECT_EQ(__ffsdi2(0x0800000000000000), 60); + EXPECT_EQ(__ffsdi2(0x1000000000000000), 61); + EXPECT_EQ(__ffsdi2(0x2000000000000000), 62); + EXPECT_EQ(__ffsdi2(0x4000000000000000), 63); + EXPECT_EQ(__ffsdi2(0x8000000000000000), 64); + + EXPECT_EQ( + __ffsdi2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __ffsdi2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 51); + EXPECT_EQ( + __ffsdi2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 62); + EXPECT_EQ( + __ffsdi2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 40); + EXPECT_EQ( + __ffsdi2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 48); +} + +TEST(BitTest, __ffsti2Test) { + EXPECT_EQ(__ffsti2(0x0000000000000000), 0); + EXPECT_EQ(__ffsti2(0x0000000000000001), 1); + EXPECT_EQ(__ffsti2(0x0000000000000002), 2); + EXPECT_EQ(__ffsti2(0x0000000000000004), 3); + EXPECT_EQ(__ffsti2(0x0000000000000008), 4); + EXPECT_EQ(__ffsti2(0x0000000000000010), 5); + EXPECT_EQ(__ffsti2(0x0000000000000020), 6); + EXPECT_EQ(__ffsti2(0x0000000000000040), 7); + EXPECT_EQ(__ffsti2(0x0000000000000080), 8); + EXPECT_EQ(__ffsti2(0x0000000000000100), 9); + EXPECT_EQ(__ffsti2(0x0000000000000200), 10); + EXPECT_EQ(__ffsti2(0x0000000000000400), 11); + EXPECT_EQ(__ffsti2(0x0000000000000800), 12); + EXPECT_EQ(__ffsti2(0x0000000000001000), 13); + EXPECT_EQ(__ffsti2(0x0000000000002000), 14); + EXPECT_EQ(__ffsti2(0x0000000000004000), 15); + EXPECT_EQ(__ffsti2(0x0000000000008000), 16); + EXPECT_EQ(__ffsti2(0x0000000000010000), 17); + EXPECT_EQ(__ffsti2(0x0000000000020000), 18); + EXPECT_EQ(__ffsti2(0x0000000000040000), 19); + EXPECT_EQ(__ffsti2(0x0000000000080000), 20); + EXPECT_EQ(__ffsti2(0x0000000000100000), 21); + EXPECT_EQ(__ffsti2(0x0000000000200000), 22); + EXPECT_EQ(__ffsti2(0x0000000000400000), 23); + EXPECT_EQ(__ffsti2(0x0000000000800000), 24); + EXPECT_EQ(__ffsti2(0x0000000001000000), 25); + EXPECT_EQ(__ffsti2(0x0000000002000000), 26); + EXPECT_EQ(__ffsti2(0x0000000004000000), 27); + EXPECT_EQ(__ffsti2(0x0000000008000000), 28); + EXPECT_EQ(__ffsti2(0x0000000010000000), 29); + EXPECT_EQ(__ffsti2(0x0000000020000000), 30); + EXPECT_EQ(__ffsti2(0x0000000040000000), 31); + EXPECT_EQ(__ffsti2(0x0000000080000000), 32); + EXPECT_EQ(__ffsti2(0x0000000100000000), 33); + EXPECT_EQ(__ffsti2(0x0000000200000000), 34); + EXPECT_EQ(__ffsti2(0x0000000400000000), 35); + EXPECT_EQ(__ffsti2(0x0000000800000000), 36); + EXPECT_EQ(__ffsti2(0x0000001000000000), 37); + EXPECT_EQ(__ffsti2(0x0000002000000000), 38); + EXPECT_EQ(__ffsti2(0x0000004000000000), 39); + EXPECT_EQ(__ffsti2(0x0000008000000000), 40); + EXPECT_EQ(__ffsti2(0x0000010000000000), 41); + EXPECT_EQ(__ffsti2(0x0000020000000000), 42); + EXPECT_EQ(__ffsti2(0x0000040000000000), 43); + EXPECT_EQ(__ffsti2(0x0000080000000000), 44); + EXPECT_EQ(__ffsti2(0x0000100000000000), 45); + EXPECT_EQ(__ffsti2(0x0000200000000000), 46); + EXPECT_EQ(__ffsti2(0x0000400000000000), 47); + EXPECT_EQ(__ffsti2(0x0000800000000000), 48); + EXPECT_EQ(__ffsti2(0x0001000000000000), 49); + EXPECT_EQ(__ffsti2(0x0002000000000000), 50); + EXPECT_EQ(__ffsti2(0x0004000000000000), 51); + EXPECT_EQ(__ffsti2(0x0008000000000000), 52); + EXPECT_EQ(__ffsti2(0x0010000000000000), 53); + EXPECT_EQ(__ffsti2(0x0020000000000000), 54); + EXPECT_EQ(__ffsti2(0x0040000000000000), 55); + EXPECT_EQ(__ffsti2(0x0080000000000000), 56); + EXPECT_EQ(__ffsti2(0x0100000000000000), 57); + EXPECT_EQ(__ffsti2(0x0200000000000000), 58); + EXPECT_EQ(__ffsti2(0x0400000000000000), 59); + EXPECT_EQ(__ffsti2(0x0800000000000000), 60); + EXPECT_EQ(__ffsti2(0x1000000000000000), 61); + EXPECT_EQ(__ffsti2(0x2000000000000000), 62); + EXPECT_EQ(__ffsti2(0x4000000000000000), 63); + EXPECT_EQ(__ffsti2(0x8000000000000000), 64); + + EXPECT_EQ( + __ffsti2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __ffsti2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 51); + EXPECT_EQ( + __ffsti2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 62); + EXPECT_EQ( + __ffsti2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 40); + EXPECT_EQ( + __ffsti2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 48); +} + +TEST(BitTest, __paritysi2Test) { + EXPECT_EQ(__paritysi2(0x00000000), 0); + EXPECT_EQ(__paritysi2(0x00000001), 1); + EXPECT_EQ(__paritysi2(0x00000002), 1); + EXPECT_EQ(__paritysi2(0x00000004), 1); + EXPECT_EQ(__paritysi2(0x00000008), 1); + EXPECT_EQ(__paritysi2(0x00000010), 1); + EXPECT_EQ(__paritysi2(0x00000020), 1); + EXPECT_EQ(__paritysi2(0x00000040), 1); + EXPECT_EQ(__paritysi2(0x00000080), 1); + EXPECT_EQ(__paritysi2(0x00000100), 1); + EXPECT_EQ(__paritysi2(0x00000200), 1); + EXPECT_EQ(__paritysi2(0x00000400), 1); + EXPECT_EQ(__paritysi2(0x00000800), 1); + EXPECT_EQ(__paritysi2(0x00001000), 1); + EXPECT_EQ(__paritysi2(0x00002000), 1); + EXPECT_EQ(__paritysi2(0x00004000), 1); + EXPECT_EQ(__paritysi2(0x00008000), 1); + EXPECT_EQ(__paritysi2(0x00010000), 1); + EXPECT_EQ(__paritysi2(0x00020000), 1); + EXPECT_EQ(__paritysi2(0x00040000), 1); + EXPECT_EQ(__paritysi2(0x00080000), 1); + EXPECT_EQ(__paritysi2(0x00100000), 1); + EXPECT_EQ(__paritysi2(0x00200000), 1); + EXPECT_EQ(__paritysi2(0x00400000), 1); + EXPECT_EQ(__paritysi2(0x00800000), 1); + EXPECT_EQ(__paritysi2(0x01000000), 1); + EXPECT_EQ(__paritysi2(0x02000000), 1); + EXPECT_EQ(__paritysi2(0x04000000), 1); + EXPECT_EQ(__paritysi2(0x08000000), 1); + EXPECT_EQ(__paritysi2(0x10000000), 1); + EXPECT_EQ(__paritysi2(0x20000000), 1); + EXPECT_EQ(__paritysi2(0x40000000), 1); + EXPECT_EQ(__paritysi2(0x80000000), 1); + + EXPECT_EQ(__paritysi2(0b00000000000000000000000000000000), 0); + EXPECT_EQ(__paritysi2(0b01000000001111000000000000000000), 1); + EXPECT_EQ(__paritysi2(0b00100000000000000000000000000000), 1); + EXPECT_EQ(__paritysi2(0b00010000000000001111000110000000), 1); + EXPECT_EQ(__paritysi2(0b00001001001000111000000000000000), 0); +} + +TEST(BitTest, __paritydi2Test) { + EXPECT_EQ(__paritydi2(0x0000000000000000), 0); + EXPECT_EQ(__paritydi2(0x0000000000000001), 1); + EXPECT_EQ(__paritydi2(0x0000000000000002), 1); + EXPECT_EQ(__paritydi2(0x0000000000000004), 1); + EXPECT_EQ(__paritydi2(0x0000000000000008), 1); + EXPECT_EQ(__paritydi2(0x0000000000000010), 1); + EXPECT_EQ(__paritydi2(0x0000000000000020), 1); + EXPECT_EQ(__paritydi2(0x0000000000000040), 1); + EXPECT_EQ(__paritydi2(0x0000000000000080), 1); + EXPECT_EQ(__paritydi2(0x0000000000000100), 1); + EXPECT_EQ(__paritydi2(0x0000000000000200), 1); + EXPECT_EQ(__paritydi2(0x0000000000000400), 1); + EXPECT_EQ(__paritydi2(0x0000000000000800), 1); + EXPECT_EQ(__paritydi2(0x0000000000001000), 1); + EXPECT_EQ(__paritydi2(0x0000000000002000), 1); + EXPECT_EQ(__paritydi2(0x0000000000004000), 1); + EXPECT_EQ(__paritydi2(0x0000000000008000), 1); + EXPECT_EQ(__paritydi2(0x0000000000010000), 1); + EXPECT_EQ(__paritydi2(0x0000000000020000), 1); + EXPECT_EQ(__paritydi2(0x0000000000040000), 1); + EXPECT_EQ(__paritydi2(0x0000000000080000), 1); + EXPECT_EQ(__paritydi2(0x0000000000100000), 1); + EXPECT_EQ(__paritydi2(0x0000000000200000), 1); + EXPECT_EQ(__paritydi2(0x0000000000400000), 1); + EXPECT_EQ(__paritydi2(0x0000000000800000), 1); + EXPECT_EQ(__paritydi2(0x0000000001000000), 1); + EXPECT_EQ(__paritydi2(0x0000000002000000), 1); + EXPECT_EQ(__paritydi2(0x0000000004000000), 1); + EXPECT_EQ(__paritydi2(0x0000000008000000), 1); + EXPECT_EQ(__paritydi2(0x0000000010000000), 1); + EXPECT_EQ(__paritydi2(0x0000000020000000), 1); + EXPECT_EQ(__paritydi2(0x0000000040000000), 1); + EXPECT_EQ(__paritydi2(0x0000000080000000), 1); + EXPECT_EQ(__paritydi2(0x0000000100000000), 1); + EXPECT_EQ(__paritydi2(0x0000000200000000), 1); + EXPECT_EQ(__paritydi2(0x0000000400000000), 1); + EXPECT_EQ(__paritydi2(0x0000000800000000), 1); + EXPECT_EQ(__paritydi2(0x0000001000000000), 1); + EXPECT_EQ(__paritydi2(0x0000002000000000), 1); + EXPECT_EQ(__paritydi2(0x0000004000000000), 1); + EXPECT_EQ(__paritydi2(0x0000008000000000), 1); + EXPECT_EQ(__paritydi2(0x0000010000000000), 1); + EXPECT_EQ(__paritydi2(0x0000020000000000), 1); + EXPECT_EQ(__paritydi2(0x0000040000000000), 1); + EXPECT_EQ(__paritydi2(0x0000080000000000), 1); + EXPECT_EQ(__paritydi2(0x0000100000000000), 1); + EXPECT_EQ(__paritydi2(0x0000200000000000), 1); + EXPECT_EQ(__paritydi2(0x0000400000000000), 1); + EXPECT_EQ(__paritydi2(0x0000800000000000), 1); + EXPECT_EQ(__paritydi2(0x0001000000000000), 1); + EXPECT_EQ(__paritydi2(0x0002000000000000), 1); + EXPECT_EQ(__paritydi2(0x0004000000000000), 1); + EXPECT_EQ(__paritydi2(0x0008000000000000), 1); + EXPECT_EQ(__paritydi2(0x0010000000000000), 1); + EXPECT_EQ(__paritydi2(0x0020000000000000), 1); + EXPECT_EQ(__paritydi2(0x0040000000000000), 1); + EXPECT_EQ(__paritydi2(0x0080000000000000), 1); + EXPECT_EQ(__paritydi2(0x0100000000000000), 1); + EXPECT_EQ(__paritydi2(0x0200000000000000), 1); + EXPECT_EQ(__paritydi2(0x0400000000000000), 1); + EXPECT_EQ(__paritydi2(0x0800000000000000), 1); + EXPECT_EQ(__paritydi2(0x1000000000000000), 1); + EXPECT_EQ(__paritydi2(0x2000000000000000), 1); + EXPECT_EQ(__paritydi2(0x4000000000000000), 1); + EXPECT_EQ(__paritydi2(0x8000000000000000), 1); + + EXPECT_EQ( + __paritydi2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __paritydi2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __paritydi2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __paritydi2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __paritydi2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 0); +} + +TEST(BitTest, __parityti2Test) { + EXPECT_EQ(__parityti2(0x0000000000000000), 0); + EXPECT_EQ(__parityti2(0x0000000000000001), 1); + EXPECT_EQ(__parityti2(0x0000000000000002), 1); + EXPECT_EQ(__parityti2(0x0000000000000004), 1); + EXPECT_EQ(__parityti2(0x0000000000000008), 1); + EXPECT_EQ(__parityti2(0x0000000000000010), 1); + EXPECT_EQ(__parityti2(0x0000000000000020), 1); + EXPECT_EQ(__parityti2(0x0000000000000040), 1); + EXPECT_EQ(__parityti2(0x0000000000000080), 1); + EXPECT_EQ(__parityti2(0x0000000000000100), 1); + EXPECT_EQ(__parityti2(0x0000000000000200), 1); + EXPECT_EQ(__parityti2(0x0000000000000400), 1); + EXPECT_EQ(__parityti2(0x0000000000000800), 1); + EXPECT_EQ(__parityti2(0x0000000000001000), 1); + EXPECT_EQ(__parityti2(0x0000000000002000), 1); + EXPECT_EQ(__parityti2(0x0000000000004000), 1); + EXPECT_EQ(__parityti2(0x0000000000008000), 1); + EXPECT_EQ(__parityti2(0x0000000000010000), 1); + EXPECT_EQ(__parityti2(0x0000000000020000), 1); + EXPECT_EQ(__parityti2(0x0000000000040000), 1); + EXPECT_EQ(__parityti2(0x0000000000080000), 1); + EXPECT_EQ(__parityti2(0x0000000000100000), 1); + EXPECT_EQ(__parityti2(0x0000000000200000), 1); + EXPECT_EQ(__parityti2(0x0000000000400000), 1); + EXPECT_EQ(__parityti2(0x0000000000800000), 1); + EXPECT_EQ(__parityti2(0x0000000001000000), 1); + EXPECT_EQ(__parityti2(0x0000000002000000), 1); + EXPECT_EQ(__parityti2(0x0000000004000000), 1); + EXPECT_EQ(__parityti2(0x0000000008000000), 1); + EXPECT_EQ(__parityti2(0x0000000010000000), 1); + EXPECT_EQ(__parityti2(0x0000000020000000), 1); + EXPECT_EQ(__parityti2(0x0000000040000000), 1); + EXPECT_EQ(__parityti2(0x0000000080000000), 1); + EXPECT_EQ(__parityti2(0x0000000100000000), 1); + EXPECT_EQ(__parityti2(0x0000000200000000), 1); + EXPECT_EQ(__parityti2(0x0000000400000000), 1); + EXPECT_EQ(__parityti2(0x0000000800000000), 1); + EXPECT_EQ(__parityti2(0x0000001000000000), 1); + EXPECT_EQ(__parityti2(0x0000002000000000), 1); + EXPECT_EQ(__parityti2(0x0000004000000000), 1); + EXPECT_EQ(__parityti2(0x0000008000000000), 1); + EXPECT_EQ(__parityti2(0x0000010000000000), 1); + EXPECT_EQ(__parityti2(0x0000020000000000), 1); + EXPECT_EQ(__parityti2(0x0000040000000000), 1); + EXPECT_EQ(__parityti2(0x0000080000000000), 1); + EXPECT_EQ(__parityti2(0x0000100000000000), 1); + EXPECT_EQ(__parityti2(0x0000200000000000), 1); + EXPECT_EQ(__parityti2(0x0000400000000000), 1); + EXPECT_EQ(__parityti2(0x0000800000000000), 1); + EXPECT_EQ(__parityti2(0x0001000000000000), 1); + EXPECT_EQ(__parityti2(0x0002000000000000), 1); + EXPECT_EQ(__parityti2(0x0004000000000000), 1); + EXPECT_EQ(__parityti2(0x0008000000000000), 1); + EXPECT_EQ(__parityti2(0x0010000000000000), 1); + EXPECT_EQ(__parityti2(0x0020000000000000), 1); + EXPECT_EQ(__parityti2(0x0040000000000000), 1); + EXPECT_EQ(__parityti2(0x0080000000000000), 1); + EXPECT_EQ(__parityti2(0x0100000000000000), 1); + EXPECT_EQ(__parityti2(0x0200000000000000), 1); + EXPECT_EQ(__parityti2(0x0400000000000000), 1); + EXPECT_EQ(__parityti2(0x0800000000000000), 1); + EXPECT_EQ(__parityti2(0x1000000000000000), 1); + EXPECT_EQ(__parityti2(0x2000000000000000), 1); + EXPECT_EQ(__parityti2(0x4000000000000000), 1); + EXPECT_EQ(__parityti2(0x8000000000000000), 1); + + EXPECT_EQ( + __parityti2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __parityti2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __parityti2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __parityti2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __parityti2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 0); +} + +TEST(BitTest, __popcountsi2Test) { + EXPECT_EQ(__popcountsi2(0x00000000), 0); + EXPECT_EQ(__popcountsi2(0x00000001), 1); + EXPECT_EQ(__popcountsi2(0x00000002), 1); + EXPECT_EQ(__popcountsi2(0x00000004), 1); + EXPECT_EQ(__popcountsi2(0x00000008), 1); + EXPECT_EQ(__popcountsi2(0x00000010), 1); + EXPECT_EQ(__popcountsi2(0x00000020), 1); + EXPECT_EQ(__popcountsi2(0x00000040), 1); + EXPECT_EQ(__popcountsi2(0x00000080), 1); + EXPECT_EQ(__popcountsi2(0x00000100), 1); + EXPECT_EQ(__popcountsi2(0x00000200), 1); + EXPECT_EQ(__popcountsi2(0x00000400), 1); + EXPECT_EQ(__popcountsi2(0x00000800), 1); + EXPECT_EQ(__popcountsi2(0x00001000), 1); + EXPECT_EQ(__popcountsi2(0x00002000), 1); + EXPECT_EQ(__popcountsi2(0x00004000), 1); + EXPECT_EQ(__popcountsi2(0x00008000), 1); + EXPECT_EQ(__popcountsi2(0x00010000), 1); + EXPECT_EQ(__popcountsi2(0x00020000), 1); + EXPECT_EQ(__popcountsi2(0x00040000), 1); + EXPECT_EQ(__popcountsi2(0x00080000), 1); + EXPECT_EQ(__popcountsi2(0x00100000), 1); + EXPECT_EQ(__popcountsi2(0x00200000), 1); + EXPECT_EQ(__popcountsi2(0x00400000), 1); + EXPECT_EQ(__popcountsi2(0x00800000), 1); + EXPECT_EQ(__popcountsi2(0x01000000), 1); + EXPECT_EQ(__popcountsi2(0x02000000), 1); + EXPECT_EQ(__popcountsi2(0x04000000), 1); + EXPECT_EQ(__popcountsi2(0x08000000), 1); + EXPECT_EQ(__popcountsi2(0x10000000), 1); + EXPECT_EQ(__popcountsi2(0x20000000), 1); + EXPECT_EQ(__popcountsi2(0x40000000), 1); + EXPECT_EQ(__popcountsi2(0x80000000), 1); + + EXPECT_EQ(__popcountsi2(0b00000000000000000000000000000000), 0); + EXPECT_EQ(__popcountsi2(0b01000000001111000000000000000000), 5); + EXPECT_EQ(__popcountsi2(0b00100000000000000000000000000000), 1); + EXPECT_EQ(__popcountsi2(0b00010000000000001111000110000000), 7); + EXPECT_EQ(__popcountsi2(0b00001001001000111000000000000000), 6); +} + +TEST(BitTest, __popcountdi2Test) { + EXPECT_EQ(__popcountdi2(0x0000000000000000), 0); + EXPECT_EQ(__popcountdi2(0x0000000000000001), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000002), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000004), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000008), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000010), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000020), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000040), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000080), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000100), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000200), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000400), 1); + EXPECT_EQ(__popcountdi2(0x0000000000000800), 1); + EXPECT_EQ(__popcountdi2(0x0000000000001000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000002000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000004000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000008000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000010000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000020000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000040000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000080000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000100000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000200000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000400000), 1); + EXPECT_EQ(__popcountdi2(0x0000000000800000), 1); + EXPECT_EQ(__popcountdi2(0x0000000001000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000002000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000004000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000008000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000010000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000020000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000040000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000080000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000100000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000200000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000400000000), 1); + EXPECT_EQ(__popcountdi2(0x0000000800000000), 1); + EXPECT_EQ(__popcountdi2(0x0000001000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000002000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000004000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000008000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000010000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000020000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000040000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000080000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000100000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000200000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000400000000000), 1); + EXPECT_EQ(__popcountdi2(0x0000800000000000), 1); + EXPECT_EQ(__popcountdi2(0x0001000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0002000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0004000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0008000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0010000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0020000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0040000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0080000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0100000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0200000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0400000000000000), 1); + EXPECT_EQ(__popcountdi2(0x0800000000000000), 1); + EXPECT_EQ(__popcountdi2(0x1000000000000000), 1); + EXPECT_EQ(__popcountdi2(0x2000000000000000), 1); + EXPECT_EQ(__popcountdi2(0x4000000000000000), 1); + EXPECT_EQ(__popcountdi2(0x8000000000000000), 1); + + EXPECT_EQ( + __popcountdi2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __popcountdi2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 5); + EXPECT_EQ( + __popcountdi2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __popcountdi2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 7); + EXPECT_EQ( + __popcountdi2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 6); +} + +TEST(BitTest, __popcountti2Test) { + EXPECT_EQ(__popcountti2(0x0000000000000000), 0); + EXPECT_EQ(__popcountti2(0x0000000000000001), 1); + EXPECT_EQ(__popcountti2(0x0000000000000002), 1); + EXPECT_EQ(__popcountti2(0x0000000000000004), 1); + EXPECT_EQ(__popcountti2(0x0000000000000008), 1); + EXPECT_EQ(__popcountti2(0x0000000000000010), 1); + EXPECT_EQ(__popcountti2(0x0000000000000020), 1); + EXPECT_EQ(__popcountti2(0x0000000000000040), 1); + EXPECT_EQ(__popcountti2(0x0000000000000080), 1); + EXPECT_EQ(__popcountti2(0x0000000000000100), 1); + EXPECT_EQ(__popcountti2(0x0000000000000200), 1); + EXPECT_EQ(__popcountti2(0x0000000000000400), 1); + EXPECT_EQ(__popcountti2(0x0000000000000800), 1); + EXPECT_EQ(__popcountti2(0x0000000000001000), 1); + EXPECT_EQ(__popcountti2(0x0000000000002000), 1); + EXPECT_EQ(__popcountti2(0x0000000000004000), 1); + EXPECT_EQ(__popcountti2(0x0000000000008000), 1); + EXPECT_EQ(__popcountti2(0x0000000000010000), 1); + EXPECT_EQ(__popcountti2(0x0000000000020000), 1); + EXPECT_EQ(__popcountti2(0x0000000000040000), 1); + EXPECT_EQ(__popcountti2(0x0000000000080000), 1); + EXPECT_EQ(__popcountti2(0x0000000000100000), 1); + EXPECT_EQ(__popcountti2(0x0000000000200000), 1); + EXPECT_EQ(__popcountti2(0x0000000000400000), 1); + EXPECT_EQ(__popcountti2(0x0000000000800000), 1); + EXPECT_EQ(__popcountti2(0x0000000001000000), 1); + EXPECT_EQ(__popcountti2(0x0000000002000000), 1); + EXPECT_EQ(__popcountti2(0x0000000004000000), 1); + EXPECT_EQ(__popcountti2(0x0000000008000000), 1); + EXPECT_EQ(__popcountti2(0x0000000010000000), 1); + EXPECT_EQ(__popcountti2(0x0000000020000000), 1); + EXPECT_EQ(__popcountti2(0x0000000040000000), 1); + EXPECT_EQ(__popcountti2(0x0000000080000000), 1); + EXPECT_EQ(__popcountti2(0x0000000100000000), 1); + EXPECT_EQ(__popcountti2(0x0000000200000000), 1); + EXPECT_EQ(__popcountti2(0x0000000400000000), 1); + EXPECT_EQ(__popcountti2(0x0000000800000000), 1); + EXPECT_EQ(__popcountti2(0x0000001000000000), 1); + EXPECT_EQ(__popcountti2(0x0000002000000000), 1); + EXPECT_EQ(__popcountti2(0x0000004000000000), 1); + EXPECT_EQ(__popcountti2(0x0000008000000000), 1); + EXPECT_EQ(__popcountti2(0x0000010000000000), 1); + EXPECT_EQ(__popcountti2(0x0000020000000000), 1); + EXPECT_EQ(__popcountti2(0x0000040000000000), 1); + EXPECT_EQ(__popcountti2(0x0000080000000000), 1); + EXPECT_EQ(__popcountti2(0x0000100000000000), 1); + EXPECT_EQ(__popcountti2(0x0000200000000000), 1); + EXPECT_EQ(__popcountti2(0x0000400000000000), 1); + EXPECT_EQ(__popcountti2(0x0000800000000000), 1); + EXPECT_EQ(__popcountti2(0x0001000000000000), 1); + EXPECT_EQ(__popcountti2(0x0002000000000000), 1); + EXPECT_EQ(__popcountti2(0x0004000000000000), 1); + EXPECT_EQ(__popcountti2(0x0008000000000000), 1); + EXPECT_EQ(__popcountti2(0x0010000000000000), 1); + EXPECT_EQ(__popcountti2(0x0020000000000000), 1); + EXPECT_EQ(__popcountti2(0x0040000000000000), 1); + EXPECT_EQ(__popcountti2(0x0080000000000000), 1); + EXPECT_EQ(__popcountti2(0x0100000000000000), 1); + EXPECT_EQ(__popcountti2(0x0200000000000000), 1); + EXPECT_EQ(__popcountti2(0x0400000000000000), 1); + EXPECT_EQ(__popcountti2(0x0800000000000000), 1); + EXPECT_EQ(__popcountti2(0x1000000000000000), 1); + EXPECT_EQ(__popcountti2(0x2000000000000000), 1); + EXPECT_EQ(__popcountti2(0x4000000000000000), 1); + EXPECT_EQ(__popcountti2(0x8000000000000000), 1); + + EXPECT_EQ( + __popcountti2( + 0b0000000000000000000000000000000000000000000000000000000000000000), + 0); + EXPECT_EQ( + __popcountti2( + 0b0100000000111100000000000000000000000000000000000000000000000000), + 5); + EXPECT_EQ( + __popcountti2( + 0b0010000000000000000000000000000000000000000000000000000000000000), + 1); + EXPECT_EQ( + __popcountti2( + 0b0001000000000000111100011000000000000000000000000000000000000000), + 7); + EXPECT_EQ( + __popcountti2( + 0b0000100100100011100000000000000000000000000000000000000000000000), + 6); +} + +TEST(BitTest, __bswapsi2Test) { + EXPECT_EQ(__bswapsi2(0x00000000), 0x00000000); + EXPECT_EQ(__bswapsi2(0x00000001), 0x01000000); + EXPECT_EQ(__bswapsi2(0x00000002), 0x02000000); + EXPECT_EQ(__bswapsi2(0x00000004), 0x04000000); + EXPECT_EQ(__bswapsi2(0x00000008), 0x08000000); + EXPECT_EQ(__bswapsi2(0x00000010), 0x10000000); + EXPECT_EQ(__bswapsi2(0x00000020), 0x20000000); + EXPECT_EQ(__bswapsi2(0x00000040), 0x40000000); + EXPECT_EQ(__bswapsi2(0x00000080), 0x80000000); + EXPECT_EQ(__bswapsi2(0x00000100), 0x00010000); + EXPECT_EQ(__bswapsi2(0x00000200), 0x00020000); + EXPECT_EQ(__bswapsi2(0x00000400), 0x00040000); + EXPECT_EQ(__bswapsi2(0x00000800), 0x00080000); + EXPECT_EQ(__bswapsi2(0x00001000), 0x00100000); + EXPECT_EQ(__bswapsi2(0x00002000), 0x00200000); + EXPECT_EQ(__bswapsi2(0x00004000), 0x00400000); + EXPECT_EQ(__bswapsi2(0x00008000), 0x00800000); + EXPECT_EQ(__bswapsi2(0x00010000), 0x00000100); + EXPECT_EQ(__bswapsi2(0x00020000), 0x00000200); + EXPECT_EQ(__bswapsi2(0x00040000), 0x00000400); + EXPECT_EQ(__bswapsi2(0x00080000), 0x00000800); + EXPECT_EQ(__bswapsi2(0x00100000), 0x00001000); + EXPECT_EQ(__bswapsi2(0x00200000), 0x00002000); + EXPECT_EQ(__bswapsi2(0x00400000), 0x00004000); + EXPECT_EQ(__bswapsi2(0x00800000), 0x00008000); + EXPECT_EQ(__bswapsi2(0x01000000), 0x00000001); + EXPECT_EQ(__bswapsi2(0x02000000), 0x00000002); + EXPECT_EQ(__bswapsi2(0x04000000), 0x00000004); + EXPECT_EQ(__bswapsi2(0x08000000), 0x00000008); + EXPECT_EQ(__bswapsi2(0x10000000), 0x00000010); + EXPECT_EQ(__bswapsi2(0x20000000), 0x00000020); + EXPECT_EQ(__bswapsi2(0x40000000), 0x00000040); + EXPECT_EQ(__bswapsi2(0x80000000), 0x00000080); +} + +TEST(BitTest, __bswapdi2Test) { + EXPECT_EQ(__bswapdi2(0x0000000000000000), 0x0000000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000001), 0x0100000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000002), 0x0200000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000004), 0x0400000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000008), 0x0800000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000010), 0x1000000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000020), 0x2000000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000040), 0x4000000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000080), 0x8000000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000100), 0x0001000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000200), 0x0002000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000400), 0x0004000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000000800), 0x0008000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000001000), 0x0010000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000002000), 0x0020000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000004000), 0x0040000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000008000), 0x0080000000000000); + EXPECT_EQ(__bswapdi2(0x0000000000010000), 0x0000010000000000); + EXPECT_EQ(__bswapdi2(0x0000000000020000), 0x0000020000000000); + EXPECT_EQ(__bswapdi2(0x0000000000040000), 0x0000040000000000); + EXPECT_EQ(__bswapdi2(0x0000000000080000), 0x0000080000000000); + EXPECT_EQ(__bswapdi2(0x0000000000100000), 0x0000100000000000); + EXPECT_EQ(__bswapdi2(0x0000000000200000), 0x0000200000000000); + EXPECT_EQ(__bswapdi2(0x0000000000400000), 0x0000400000000000); + EXPECT_EQ(__bswapdi2(0x0000000000800000), 0x0000800000000000); + EXPECT_EQ(__bswapdi2(0x0000000001000000), 0x0000000100000000); + EXPECT_EQ(__bswapdi2(0x0000000002000000), 0x0000000200000000); + EXPECT_EQ(__bswapdi2(0x0000000004000000), 0x0000000400000000); + EXPECT_EQ(__bswapdi2(0x0000000008000000), 0x0000000800000000); + EXPECT_EQ(__bswapdi2(0x0000000010000000), 0x0000001000000000); + EXPECT_EQ(__bswapdi2(0x0000000020000000), 0x0000002000000000); + EXPECT_EQ(__bswapdi2(0x0000000040000000), 0x0000004000000000); + EXPECT_EQ(__bswapdi2(0x0000000080000000), 0x0000008000000000); + EXPECT_EQ(__bswapdi2(0x0000000100000000), 0x0000000001000000); + EXPECT_EQ(__bswapdi2(0x0000000200000000), 0x0000000002000000); + EXPECT_EQ(__bswapdi2(0x0000000400000000), 0x0000000004000000); + EXPECT_EQ(__bswapdi2(0x0000000800000000), 0x0000000008000000); + EXPECT_EQ(__bswapdi2(0x0000001000000000), 0x0000000010000000); + EXPECT_EQ(__bswapdi2(0x0000002000000000), 0x0000000020000000); + EXPECT_EQ(__bswapdi2(0x0000004000000000), 0x0000000040000000); + EXPECT_EQ(__bswapdi2(0x0000008000000000), 0x0000000080000000); + EXPECT_EQ(__bswapdi2(0x0000010000000000), 0x0000000000010000); + EXPECT_EQ(__bswapdi2(0x0000020000000000), 0x0000000000020000); + EXPECT_EQ(__bswapdi2(0x0000040000000000), 0x0000000000040000); + EXPECT_EQ(__bswapdi2(0x0000080000000000), 0x0000000000080000); + EXPECT_EQ(__bswapdi2(0x0000100000000000), 0x0000000000100000); + EXPECT_EQ(__bswapdi2(0x0000200000000000), 0x0000000000200000); + EXPECT_EQ(__bswapdi2(0x0000400000000000), 0x0000000000400000); + EXPECT_EQ(__bswapdi2(0x0000800000000000), 0x0000000000800000); + EXPECT_EQ(__bswapdi2(0x0001000000000000), 0x0000000000000100); + EXPECT_EQ(__bswapdi2(0x0002000000000000), 0x0000000000000200); + EXPECT_EQ(__bswapdi2(0x0004000000000000), 0x0000000000000400); + EXPECT_EQ(__bswapdi2(0x0008000000000000), 0x0000000000000800); + EXPECT_EQ(__bswapdi2(0x0010000000000000), 0x0000000000001000); + EXPECT_EQ(__bswapdi2(0x0020000000000000), 0x0000000000002000); + EXPECT_EQ(__bswapdi2(0x0040000000000000), 0x0000000000004000); + EXPECT_EQ(__bswapdi2(0x0080000000000000), 0x0000000000008000); + EXPECT_EQ(__bswapdi2(0x0100000000000000), 0x0000000000000001); + EXPECT_EQ(__bswapdi2(0x0200000000000000), 0x0000000000000002); + EXPECT_EQ(__bswapdi2(0x0400000000000000), 0x0000000000000004); + EXPECT_EQ(__bswapdi2(0x0800000000000000), 0x0000000000000008); + EXPECT_EQ(__bswapdi2(0x1000000000000000), 0x0000000000000010); + EXPECT_EQ(__bswapdi2(0x2000000000000000), 0x0000000000000020); + EXPECT_EQ(__bswapdi2(0x4000000000000000), 0x0000000000000040); + EXPECT_EQ(__bswapdi2(0x8000000000000000), 0x0000000000000080); +} diff --git a/tools/project_config.h.in b/tools/project_config.h.in index 2dc0831d..e9ee5237 100644 --- a/tools/project_config.h.in +++ b/tools/project_config.h.in @@ -25,4 +25,7 @@ #define SIMPLEKERNEL_DEBUG_LOG #endif +/// 内核空间设为 64MB +#define kKernelSpaceSize (0x4000000) + #endif /* SIMPLEKERNEL_SRC_PROJECT_CONFIG_H_ */