Compare commits
19 Commits
d52ad29afa
...
f429e8c7bb
| Author | SHA1 | Date | |
|---|---|---|---|
| f429e8c7bb | |||
| cba2e8cfef | |||
| 3ad67614aa | |||
| 14aa28b043 | |||
| 6045726e41 | |||
| 45e55d8907 | |||
| e9d6431728 | |||
| aa8be130f9 | |||
| a19e6938eb | |||
| 32206069bc | |||
| 46a1903f8d | |||
| a3ca49ff1f | |||
| 94f92d982c | |||
| 4f5f84bb5b | |||
| 5cb5ae2dfe | |||
| 7704e3c5c0 | |||
| 376e4b4c45 | |||
| 24c37e7381 | |||
| fb9c67ab15 |
@@ -11,6 +11,7 @@ set(KERNEL_SOURCES
|
||||
kernel/Audio/Controller.cpp
|
||||
kernel/Audio/HDAudio/AudioFunctionGroup.cpp
|
||||
kernel/Audio/HDAudio/Controller.cpp
|
||||
kernel/Banos.cpp
|
||||
kernel/BootInfo.cpp
|
||||
kernel/CPUID.cpp
|
||||
kernel/Credentials.cpp
|
||||
@@ -121,6 +122,7 @@ set(KERNEL_SOURCES
|
||||
kernel/USB/USBManager.cpp
|
||||
kernel/USB/XHCI/Controller.cpp
|
||||
kernel/USB/XHCI/Device.cpp
|
||||
kernel/UserCopy.cpp
|
||||
icxxabi.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace Kernel
|
||||
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
||||
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
||||
|
||||
static bool s_is_initialized = false;
|
||||
|
||||
static PageTable* s_kernel = nullptr;
|
||||
static bool s_has_nxe = false;
|
||||
static bool s_has_pge = false;
|
||||
@@ -260,7 +258,11 @@ namespace Kernel
|
||||
|
||||
ASSERT(index < 512);
|
||||
ASSERT(s_fast_page_pt);
|
||||
|
||||
if (index < reserved_fast_pages)
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
else
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
ASSERT(!(s_fast_page_pt[index] & Flags::Present));
|
||||
s_fast_page_pt[index] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
@@ -274,7 +276,11 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(index < 512);
|
||||
ASSERT(s_fast_page_pt);
|
||||
|
||||
if (index < reserved_fast_pages)
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
else
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
ASSERT((s_fast_page_pt[index] & Flags::Present));
|
||||
s_fast_page_pt[index] = 0;
|
||||
@@ -341,32 +347,10 @@ namespace Kernel
|
||||
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||
if (is_userspace && this != &PageTable::current())
|
||||
;
|
||||
else if (pages <= 32 || !s_is_initialized)
|
||||
{
|
||||
for (size_t i = 0; i < pages; i++)
|
||||
else if (pages >= full_tlb_flush_threshold)
|
||||
invalidate_full_address_space(!is_userspace);
|
||||
else for (size_t i = 0; i < pages; i++)
|
||||
asm volatile("invlpg (%0)" :: "r"(vaddr + i * PAGE_SIZE));
|
||||
}
|
||||
else if (is_userspace || !s_has_pge)
|
||||
{
|
||||
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||
}
|
||||
else
|
||||
{
|
||||
asm volatile(
|
||||
"movl %%cr4, %%eax;"
|
||||
|
||||
"andl $~0x80, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
|
||||
"movl %0, %%cr3;"
|
||||
|
||||
"orl $0x80, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
:
|
||||
: "r"(static_cast<uint32_t>(m_highest_paging_struct))
|
||||
: "eax"
|
||||
);
|
||||
}
|
||||
|
||||
if (send_smp_message)
|
||||
{
|
||||
@@ -381,6 +365,34 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void PageTable::invalidate_full_address_space(bool global)
|
||||
{
|
||||
if (!global || !s_has_pge)
|
||||
{
|
||||
asm volatile(
|
||||
"movl %%cr3, %%eax;"
|
||||
"movl %%eax, %%cr3;"
|
||||
::: "eax"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
asm volatile(
|
||||
"movl %%cr4, %%eax;"
|
||||
|
||||
"andl $~0x80, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
|
||||
"movl %%cr3, %%ecx;"
|
||||
"movl %%ecx, %%cr3;"
|
||||
|
||||
"orl $0x80, %%eax;"
|
||||
"movl %%eax, %%cr4;"
|
||||
::: "eax", "ecx"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
@@ -597,30 +609,24 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
||||
void PageTable::reserve_page(vaddr_t vaddr)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
||||
return true;
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(is_page_free(vaddr));
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, false);
|
||||
}
|
||||
|
||||
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
||||
void PageTable::reserve_range(vaddr_t vaddr, size_t bytes)
|
||||
{
|
||||
if (size_t rem = bytes % PAGE_SIZE)
|
||||
bytes += PAGE_SIZE - rem;
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
ASSERT(is_range_free(vaddr, bytes));
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
reserve_page(vaddr + offset, true, false);
|
||||
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||
|
||||
return true;
|
||||
reserve_page(vaddr + offset);
|
||||
}
|
||||
|
||||
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
|
||||
@@ -675,7 +681,7 @@ namespace Kernel
|
||||
vaddr |= (vaddr_t)pdpte << 30;
|
||||
vaddr |= (vaddr_t)pde << 21;
|
||||
vaddr |= (vaddr_t)pte << 12;
|
||||
ASSERT(reserve_page(vaddr));
|
||||
reserve_page(vaddr);
|
||||
return vaddr;
|
||||
}
|
||||
unmap_fast_page(2);
|
||||
@@ -693,7 +699,7 @@ namespace Kernel
|
||||
{
|
||||
if (is_page_free(vaddr))
|
||||
{
|
||||
ASSERT(reserve_page(vaddr));
|
||||
reserve_page(vaddr);
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
@@ -726,7 +732,7 @@ namespace Kernel
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
||||
reserve_range(vaddr, page_count * PAGE_SIZE);
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace Kernel
|
||||
SpinLock PageTable::s_fast_page_lock;
|
||||
|
||||
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
|
||||
static bool s_is_initialized = false;
|
||||
|
||||
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
||||
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
||||
@@ -383,7 +382,11 @@ namespace Kernel
|
||||
|
||||
ASSERT(index < 512);
|
||||
ASSERT(s_fast_page_pt);
|
||||
|
||||
if (index < reserved_fast_pages)
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
else
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
ASSERT(!(s_fast_page_pt[index] & Flags::Present));
|
||||
s_fast_page_pt[index] = paddr | Flags::ReadWrite | Flags::Present;
|
||||
@@ -397,7 +400,11 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(index < 512);
|
||||
ASSERT(s_fast_page_pt);
|
||||
|
||||
if (index < reserved_fast_pages)
|
||||
ASSERT(s_fast_page_lock.current_processor_has_lock());
|
||||
else
|
||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||
|
||||
ASSERT((s_fast_page_pt[index] & Flags::Present));
|
||||
s_fast_page_pt[index] = 0;
|
||||
@@ -470,32 +477,10 @@ namespace Kernel
|
||||
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||
if (is_userspace && this != &PageTable::current())
|
||||
;
|
||||
else if (pages <= 32 || !s_is_initialized)
|
||||
{
|
||||
for (size_t i = 0; i < pages; i++)
|
||||
else if (pages >= full_tlb_flush_threshold)
|
||||
invalidate_full_address_space(!is_userspace);
|
||||
else for (size_t i = 0; i < pages; i++)
|
||||
asm volatile("invlpg (%0)" :: "r"(vaddr + i * PAGE_SIZE));
|
||||
}
|
||||
else if (is_userspace || !s_has_pge)
|
||||
{
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
asm volatile(
|
||||
"movq %%cr4, %%rax;"
|
||||
|
||||
"andq $~0x80, %%rax;"
|
||||
"movq %%rax, %%cr4;"
|
||||
|
||||
"movq %0, %%cr3;"
|
||||
|
||||
"orq $0x80, %%rax;"
|
||||
"movq %%rax, %%cr4;"
|
||||
:
|
||||
: "r"(m_highest_paging_struct)
|
||||
: "rax"
|
||||
);
|
||||
}
|
||||
|
||||
if (send_smp_message)
|
||||
{
|
||||
@@ -510,6 +495,34 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void PageTable::invalidate_full_address_space(bool global)
|
||||
{
|
||||
if (!global || !s_has_pge)
|
||||
{
|
||||
asm volatile(
|
||||
"movq %%cr3, %%rax;"
|
||||
"movq %%rax, %%cr3;"
|
||||
::: "rax"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
asm volatile(
|
||||
"movq %%cr4, %%rax;"
|
||||
|
||||
"andq $~0x80, %%rax;"
|
||||
"movq %%rax, %%cr4;"
|
||||
|
||||
"movq %%cr3, %%rcx;"
|
||||
"movq %%rcx, %%cr3;"
|
||||
|
||||
"orq $0x80, %%rax;"
|
||||
"movq %%rax, %%cr4;"
|
||||
::: "rax", "rcx"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||
{
|
||||
ASSERT(vaddr);
|
||||
@@ -551,12 +564,70 @@ namespace Kernel
|
||||
{
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
const size_t page_count = range_page_count(vaddr, size);
|
||||
ASSERT(is_canonical(vaddr));
|
||||
ASSERT(is_canonical(vaddr + size - 1));
|
||||
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(vaddr);
|
||||
const vaddr_t uc_vaddr_end = uncanonicalize(vaddr + size - 1);
|
||||
|
||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
|
||||
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
|
||||
|
||||
const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF;
|
||||
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
|
||||
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
|
||||
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
for (vaddr_t page = 0; page < page_count; page++)
|
||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||
invalidate_range(vaddr, page_count, true);
|
||||
|
||||
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||
for (; pml4e <= e_pml4e; pml4e++)
|
||||
{
|
||||
#define UNALLOCATE_TABLE_IF_EMPTY(outer, inner) \
|
||||
if (old_##inner##e == 0 && inner##e == 512) { \
|
||||
unallocate_page(outer[outer##e] & s_page_addr_mask); \
|
||||
outer[outer##e] = 0; \
|
||||
}
|
||||
if (!(pml4[pml4e] & Flags::Present))
|
||||
continue;
|
||||
const uint16_t old_pdpte = pdpte;
|
||||
uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
||||
for (; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
||||
break;
|
||||
if (!(pdpt[pdpte] & Flags::Present))
|
||||
continue;
|
||||
const uint16_t old_pde = pde;
|
||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||
for (; pde < 512; pde++)
|
||||
{
|
||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
|
||||
break;
|
||||
if (!(pd[pde] & Flags::Present))
|
||||
continue;
|
||||
const uint16_t old_pte = pte;
|
||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||
for (; pte < 512; pte++)
|
||||
{
|
||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||
break;
|
||||
pt[pte] = 0;
|
||||
}
|
||||
UNALLOCATE_TABLE_IF_EMPTY(pd, pt);
|
||||
pte = 0;
|
||||
}
|
||||
UNALLOCATE_TABLE_IF_EMPTY(pdpt, pd);
|
||||
pde = 0;
|
||||
}
|
||||
UNALLOCATE_TABLE_IF_EMPTY(pml4, pdpt);
|
||||
pdpte = 0;
|
||||
#undef UNALLOCATE_TABLE_IF_EMPTY
|
||||
}
|
||||
|
||||
invalidate_range(vaddr, range_page_count(vaddr, size), true);
|
||||
}
|
||||
|
||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||
@@ -746,29 +817,71 @@ namespace Kernel
|
||||
return get_page_data(addr) & s_page_addr_mask;
|
||||
}
|
||||
|
||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool invalidate)
|
||||
void PageTable::reserve_page(vaddr_t vaddr)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
if (only_free && !is_page_free(vaddr))
|
||||
return false;
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, invalidate);
|
||||
return true;
|
||||
SpinLockGuard _(m_lock);
|
||||
ASSERT(is_page_free(vaddr));
|
||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, false);
|
||||
}
|
||||
|
||||
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
|
||||
void PageTable::reserve_range(vaddr_t vaddr, size_t bytes)
|
||||
{
|
||||
if (size_t rem = bytes % PAGE_SIZE)
|
||||
bytes += PAGE_SIZE - rem;
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
|
||||
ASSERT(is_canonical(vaddr));
|
||||
ASSERT(is_canonical(vaddr + bytes - 1));
|
||||
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(vaddr);
|
||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
|
||||
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
|
||||
|
||||
size_t pages_to_reserve = bytes / PAGE_SIZE;
|
||||
ASSERT(pages_to_reserve);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
if (only_free && !is_range_free(vaddr, bytes))
|
||||
return false;
|
||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||
reserve_page(vaddr + offset, true, false);
|
||||
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||
return true;
|
||||
|
||||
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||
for (;; pml4e++)
|
||||
{
|
||||
#define CHECK_IF_PRESENT(expr) \
|
||||
if (!((expr) & Flags::Present)) { \
|
||||
const paddr_t paddr = allocate_zeroed_page_aligned_page(); \
|
||||
ASSERT(paddr); \
|
||||
(expr) = paddr | Flags::Present; \
|
||||
}
|
||||
CHECK_IF_PRESENT(pml4[pml4e]);
|
||||
uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
||||
for (; pdpte < 512; pdpte++)
|
||||
{
|
||||
CHECK_IF_PRESENT(pdpt[pdpte]);
|
||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||
for (; pde < 512; pde++)
|
||||
{
|
||||
CHECK_IF_PRESENT(pd[pde]);
|
||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||
for (; pte < 512; pte++)
|
||||
{
|
||||
ASSERT(!(pt[pte] & Flags::Used));
|
||||
pt[pte] = Flags::Reserved;
|
||||
|
||||
pages_to_reserve--;
|
||||
if (pages_to_reserve == 0)
|
||||
return;
|
||||
}
|
||||
pte = 0;
|
||||
}
|
||||
pde = 0;
|
||||
}
|
||||
pdpte = 0;
|
||||
#undef CHECK_IF_PRESENT
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
|
||||
@@ -782,6 +895,7 @@ namespace Kernel
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address - 1));
|
||||
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address - 1);
|
||||
|
||||
@@ -831,7 +945,7 @@ namespace Kernel
|
||||
vaddr |= static_cast<uint64_t>(pde) << 21;
|
||||
vaddr |= static_cast<uint64_t>(pte) << 12;
|
||||
vaddr = canonicalize(vaddr);
|
||||
ASSERT(reserve_page(vaddr));
|
||||
reserve_page(vaddr);
|
||||
return vaddr;
|
||||
}
|
||||
pte = 0;
|
||||
@@ -845,7 +959,7 @@ namespace Kernel
|
||||
{
|
||||
if (vaddr_t vaddr = canonicalize(uc_vaddr); is_page_free(vaddr))
|
||||
{
|
||||
ASSERT(reserve_page(vaddr));
|
||||
reserve_page(vaddr);
|
||||
return vaddr;
|
||||
}
|
||||
}
|
||||
@@ -855,44 +969,90 @@ namespace Kernel
|
||||
|
||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||
{
|
||||
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
|
||||
first_address = (vaddr_t)g_kernel_start;
|
||||
if (size_t rem = first_address % PAGE_SIZE)
|
||||
if (first_address >= KERNEL_OFFSET && first_address < reinterpret_cast<vaddr_t>(g_kernel_start))
|
||||
first_address = reinterpret_cast<vaddr_t>(g_kernel_start);
|
||||
if (const auto rem = first_address % PAGE_SIZE)
|
||||
first_address += PAGE_SIZE - rem;
|
||||
if (size_t rem = last_address % PAGE_SIZE)
|
||||
if (const auto rem = last_address % PAGE_SIZE)
|
||||
last_address -= rem;
|
||||
|
||||
ASSERT(is_canonical(first_address));
|
||||
ASSERT(is_canonical(last_address - 1));
|
||||
|
||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address - 1);
|
||||
|
||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
|
||||
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
|
||||
|
||||
const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF;
|
||||
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
|
||||
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
|
||||
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
|
||||
|
||||
vaddr_t vaddr = first_address;
|
||||
size_t free_count = 0;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
for (vaddr_t vaddr = first_address; vaddr < last_address;)
|
||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||
for (; pml4e <= e_pml4e; pml4e++)
|
||||
{
|
||||
bool valid { true };
|
||||
for (size_t page = 0; page < page_count; page++)
|
||||
#define CHECK_IF_PRESENT(expr, advance) \
|
||||
if (!((expr) & Flags::Present)) { \
|
||||
if ((free_count += advance) >= page_count) \
|
||||
goto found_free_region; \
|
||||
continue; \
|
||||
}
|
||||
CHECK_IF_PRESENT(pml4[pml4e], 512 * 512 * 512);
|
||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
||||
for (; pdpte < 512; pdpte++)
|
||||
{
|
||||
if (!is_canonical(vaddr + page * PAGE_SIZE))
|
||||
{
|
||||
vaddr = canonicalize(uncanonicalize(vaddr + page * PAGE_SIZE));
|
||||
valid = false;
|
||||
if (pml4e == e_pml4e && pdpte > e_pdpte)
|
||||
break;
|
||||
}
|
||||
if (!is_page_free(vaddr + page * PAGE_SIZE))
|
||||
CHECK_IF_PRESENT(pdpt[pdpte], 512 * 512);
|
||||
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||
for (; pde < 512; pde++)
|
||||
{
|
||||
vaddr += (page + 1) * PAGE_SIZE;
|
||||
valid = false;
|
||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
CHECK_IF_PRESENT(pd[pde], 512);
|
||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||
for (; pte < 512; pte++)
|
||||
{
|
||||
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
|
||||
return vaddr;
|
||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||
break;
|
||||
if (!(pt[pte] & Flags::Used))
|
||||
{
|
||||
if (++free_count >= page_count)
|
||||
goto found_free_region;
|
||||
}
|
||||
else
|
||||
{
|
||||
vaddr = 0;
|
||||
vaddr |= static_cast<uint64_t>(pml4e) << 39;
|
||||
vaddr |= static_cast<uint64_t>(pdpte) << 30;
|
||||
vaddr |= static_cast<uint64_t>(pde) << 21;
|
||||
vaddr |= static_cast<uint64_t>(pte) << 12;
|
||||
vaddr = canonicalize(vaddr + PAGE_SIZE);
|
||||
free_count = 0;
|
||||
}
|
||||
}
|
||||
pte = 0;
|
||||
}
|
||||
pde = 0;
|
||||
}
|
||||
pdpte = 0;
|
||||
#undef CHECK_IF_PRESENT
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
found_free_region:
|
||||
reserve_range(vaddr, page_count * PAGE_SIZE);
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
bool PageTable::is_page_free(vaddr_t page) const
|
||||
|
||||
@@ -41,7 +41,18 @@ SECTIONS
|
||||
{
|
||||
g_kernel_writable_start = .;
|
||||
*(.data)
|
||||
|
||||
. = ALIGN(8);
|
||||
g_drv_builtin_begin = .;
|
||||
KEEP(*(.banos-driver))
|
||||
g_drv_builtin_end = .;
|
||||
. = ALIGN(8);
|
||||
g_banos_export = .;
|
||||
KEEP(*(.banos-export))
|
||||
g_banos_export_end = .;
|
||||
}
|
||||
|
||||
|
||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||
{
|
||||
g_kernel_bss_start = .;
|
||||
|
||||
27
kernel/include/banos/driver.h
Normal file
27
kernel/include/banos/driver.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2026 Dcraftbg
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include "version.h"
|
||||
#include "revision.h"
|
||||
|
||||
#define BANOS_DRIVER_REVISION_CURRENT 0
|
||||
|
||||
typedef struct Banos_Driver Banos_Driver;
|
||||
struct Banos_Driver {
|
||||
unsigned long driver_size;
|
||||
banos_version_t minimal_banos_version;
|
||||
const char* name;
|
||||
const char* license;
|
||||
banos_version_t version;
|
||||
|
||||
// NOTE: checkout BANOS_DRIVER_INSTANCE_SIZE.
|
||||
// You may use this instance data for anything you wish to store.
|
||||
// If you need more than that just allocate it on the heap or
|
||||
// globally if you add the proper verification of having your driver run only
|
||||
// within a single instance
|
||||
int (*init)(Banos_Driver* drv);
|
||||
int (*uninit)(Banos_Driver* drv);
|
||||
};
|
||||
#define BANOS_DRIVER_API static __attribute__((section(".banos-driver"), used, aligned(8)))
|
||||
15
kernel/include/banos/export.h
Normal file
15
kernel/include/banos/export.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2026 Dcraftbg
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
typedef struct Banos_Symbol {
|
||||
const char* name;
|
||||
void* arg;
|
||||
} Banos_Symbol;
|
||||
#define BANOS_EXPORT_SYMBOL(symname, str, ptr) \
|
||||
static __attribute__((section(".banos-export"), used, aligned(8))) Banos_Symbol __symbol_##symname = {\
|
||||
.name = str, \
|
||||
.arg = ptr \
|
||||
};
|
||||
#define BANOS_EXPORT(name) BANOS_EXPORT_SYMBOL(name, #name, (void*)&name)
|
||||
13
kernel/include/banos/print.h
Normal file
13
kernel/include/banos/print.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2026 Dcraftbg
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void banos_dprintln(const char* str);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
2
kernel/include/banos/revision.h
Normal file
2
kernel/include/banos/revision.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
typedef unsigned long banos_revision_t;
|
||||
28
kernel/include/banos/version.h
Normal file
28
kernel/include/banos/version.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
// Copyright (c) 2026 Dcraftbg
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// [ 8 bit major ] [ 8 minor ] [ 16 patch]
|
||||
typedef unsigned int banos_version_t;
|
||||
#define BANOS_VERSION_MAJOR_SHIFT 24
|
||||
#define BANOS_VERSION_MINOR_SHIFT 16
|
||||
#define BANOS_VERSION_PATCH_SHIFT 0
|
||||
|
||||
#define BANOS_VERSION_MAJOR_MASK 0xFF
|
||||
#define BANOS_VERSION_MINOR_MASK 0xFF
|
||||
#define BANOS_VERSION_PATCH_MASK 0xFFFF
|
||||
|
||||
#define BANOS_VERSION_MAKE(major, minor, patch) \
|
||||
(banos_version_t)( \
|
||||
(((major) & BANOS_VERSION_MAJOR_MASK) << BANOS_VERSION_MAJOR_SHIFT) | \
|
||||
(((minor) & BANOS_VERSION_MINOR_MASK) << BANOS_VERSION_MINOR_SHIFT) | \
|
||||
(((patch) & BANOS_VERSION_PATCH_MASK) << BANOS_VERSION_PATCH_SHIFT) \
|
||||
)
|
||||
|
||||
#define BANOS_VERSION_CURRENT BANOS_VERSION_MAKE(0, 0, 1)
|
||||
|
||||
#define BANOS_VERSION_GET_MAJOR(v) (((v) >> BANOS_VERSION_MAJOR_SHIFT) & BANOS_VERSION_MAJOR_MASK)
|
||||
#define BANOS_VERSION_GET_MINOR(v) (((v) >> BANOS_VERSION_MINOR_SHIFT) & BANOS_VERSION_MINOR_MASK)
|
||||
#define BANOS_VERSION_GET_PATCH(v) (((v) >> BANOS_VERSION_PATCH_SHIFT) & BANOS_VERSION_PATCH_MASK)
|
||||
10
kernel/include/kernel/Banos.h
Normal file
10
kernel/include/kernel/Banos.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/StringView.h>
|
||||
typedef struct Banos_Symbol Banos_Symbol;
|
||||
namespace Banos {
|
||||
void* resolve_symbol(const char* name);
|
||||
void import_symbols(Banos_Symbol* symbols, size_t count);
|
||||
void initialize_initial_drivers(void);
|
||||
BAN::ErrorOr<size_t> load_driver_from_image(const char* u_image);
|
||||
}
|
||||
@@ -35,8 +35,6 @@ namespace Kernel
|
||||
virtual bool has_error_impl() const override { return m_reading_count == 0; }
|
||||
virtual bool has_hungup_impl() const override { return m_writing_count == 0; }
|
||||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
|
||||
private:
|
||||
Pipe(const struct stat&);
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Kernel
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||
static BAN::ErrorOr<void> initialize_tty_thread();
|
||||
|
||||
void notify();
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace Kernel
|
||||
requires BAN::is_same_v<decltype(func()), void>;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
concept with_per_cpu_fast_page_callback = requires(F func, void* addr)
|
||||
{
|
||||
requires BAN::is_same_v<decltype(func(addr)), void>;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
concept with_fast_page_callback_error = requires(F func)
|
||||
{
|
||||
@@ -45,6 +51,10 @@ namespace Kernel
|
||||
WriteThrough,
|
||||
};
|
||||
|
||||
static constexpr bool full_tlb_flush_threshold = 32;
|
||||
|
||||
static constexpr size_t reserved_fast_pages = 0x10;
|
||||
|
||||
public:
|
||||
static void initialize_fast_page();
|
||||
static void initialize_and_load();
|
||||
@@ -72,6 +82,18 @@ namespace Kernel
|
||||
unmap_fast_page();
|
||||
}
|
||||
|
||||
template<with_per_cpu_fast_page_callback F>
|
||||
static void with_per_cpu_fast_page(paddr_t paddr, F callback)
|
||||
{
|
||||
const auto state = Processor::get_interrupt_state();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
const size_t index = Processor::current_index() + reserved_fast_pages;
|
||||
void* addr = map_fast_page(index, paddr);
|
||||
callback(addr);
|
||||
unmap_fast_page(index);
|
||||
Processor::set_interrupt_state(state);
|
||||
}
|
||||
|
||||
template<with_fast_page_callback_error F>
|
||||
static BAN::ErrorOr<void> with_fast_page(paddr_t paddr, F callback)
|
||||
{
|
||||
@@ -123,8 +145,8 @@ namespace Kernel
|
||||
bool is_page_free(vaddr_t) const;
|
||||
bool is_range_free(vaddr_t, size_t bytes) const;
|
||||
|
||||
bool reserve_page(vaddr_t, bool only_free = true, bool invalidate = true);
|
||||
bool reserve_range(vaddr_t, size_t bytes, bool only_free = true);
|
||||
void reserve_page(vaddr_t);
|
||||
void reserve_range(vaddr_t, size_t bytes);
|
||||
|
||||
vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
|
||||
vaddr_t reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
|
||||
@@ -133,6 +155,7 @@ namespace Kernel
|
||||
|
||||
void invalidate_page(vaddr_t addr, bool send_smp_message) { invalidate_range(addr, 1, send_smp_message); }
|
||||
void invalidate_range(vaddr_t addr, size_t pages, bool send_smp_message);
|
||||
void invalidate_full_address_space(bool global);
|
||||
|
||||
InterruptState lock() const { return m_lock.lock(); }
|
||||
void unlock(InterruptState state) const { m_lock.unlock(state); }
|
||||
|
||||
@@ -221,6 +221,8 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<long> sys_load_keymap(const char* path);
|
||||
|
||||
BAN::ErrorOr<long> sys_banos_install(const char* object);
|
||||
|
||||
BAN::RefPtr<TTY> controlling_terminal() { return m_controlling_terminal; }
|
||||
|
||||
static Process& current() { return Thread::current().process(); }
|
||||
@@ -278,13 +280,12 @@ namespace Kernel
|
||||
// You must hold reader end of m_mapped_region_lock when calling this.
|
||||
size_t find_mapped_region(vaddr_t) const;
|
||||
|
||||
BAN::ErrorOr<AddressRange> find_free_address_range(size_t size);
|
||||
|
||||
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const;
|
||||
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
|
||||
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
|
||||
|
||||
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
|
||||
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
|
||||
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
|
||||
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
|
||||
|
||||
uint64_t signal_pending_mask() const
|
||||
|
||||
@@ -29,6 +29,13 @@ namespace Kernel
|
||||
BAN_NON_MOVABLE(Processor);
|
||||
|
||||
public:
|
||||
struct TLBEntry
|
||||
{
|
||||
vaddr_t vaddr;
|
||||
size_t page_count;
|
||||
class PageTable* page_table;
|
||||
};
|
||||
|
||||
struct SMPMessage
|
||||
{
|
||||
enum class Type
|
||||
@@ -43,12 +50,7 @@ namespace Kernel
|
||||
Type type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uintptr_t vaddr;
|
||||
size_t page_count;
|
||||
void* page_table;
|
||||
} flush_tlb;
|
||||
TLBEntry flush_tlb;
|
||||
SchedulerQueue::Node* new_thread;
|
||||
SchedulerQueue::Node* unblock_thread;
|
||||
bool dummy;
|
||||
@@ -130,7 +132,7 @@ namespace Kernel
|
||||
static void handle_ipi();
|
||||
|
||||
static void handle_smp_messages();
|
||||
static void send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true);
|
||||
static bool send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true);
|
||||
static void broadcast_smp_message(const SMPMessage&);
|
||||
|
||||
static void load_segments();
|
||||
@@ -178,6 +180,9 @@ namespace Kernel
|
||||
asm volatile("mov %[value], %%gs:%a[offset]" :: [value]"r"(value), [offset]"ir"(offset) : "memory");
|
||||
}
|
||||
|
||||
void lock_tlb_lock();
|
||||
void unlock_tlb_lock();
|
||||
|
||||
private:
|
||||
static ProcessorID s_bsp_id;
|
||||
static BAN::Atomic<uint8_t> s_processor_count;
|
||||
@@ -211,6 +216,11 @@ namespace Kernel
|
||||
BAN::Atomic<SMPMessage*> m_smp_free { nullptr };
|
||||
SMPMessage* m_smp_message_storage { nullptr };
|
||||
|
||||
BAN::Atomic<bool> m_tlb_lock { false };
|
||||
size_t m_tlb_entry_count { 0 };
|
||||
BAN::Array<TLBEntry, 32> m_tlb_entries;
|
||||
bool m_tlb_global { false };
|
||||
|
||||
void* m_current_page_table { nullptr };
|
||||
|
||||
friend class BAN::Array<Processor, 0xFF>;
|
||||
|
||||
7
kernel/include/kernel/UserCopy.h
Normal file
7
kernel/include/kernel/UserCopy.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <BAN/Errors.h>
|
||||
namespace Kernel {
|
||||
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
|
||||
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
|
||||
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
|
||||
};
|
||||
215
kernel/kernel/Banos.cpp
Normal file
215
kernel/kernel/Banos.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/Banos.h>
|
||||
#include <BAN/Assert.h>
|
||||
#include <banos/driver.h>
|
||||
#include <banos/print.h>
|
||||
#include <banos/export.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/ELF.h>
|
||||
#include <LibELF/Types.h>
|
||||
#include <LibELF/Values.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
using namespace LibELF;
|
||||
using namespace Kernel;
|
||||
|
||||
extern "C" {
|
||||
void banos_dprintln(const char* str) {
|
||||
dprintln("{}", str);
|
||||
}
|
||||
void* banos_lookup_symbol(const char* str) {
|
||||
return Banos::resolve_symbol(str);
|
||||
}
|
||||
}
|
||||
BANOS_EXPORT(banos_dprintln);
|
||||
BANOS_EXPORT(banos_lookup_symbol);
|
||||
|
||||
BAN::HashMap<BAN::StringView, void*> g_banos_symbols;
|
||||
void* Banos::resolve_symbol(const char* name) {
|
||||
auto it = g_banos_symbols.find(name);
|
||||
return it == g_banos_symbols.end() ? NULL : it->value;
|
||||
}
|
||||
void Banos::import_symbols(Banos_Symbol* symbols, size_t count) {
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
auto sym = symbols + i;
|
||||
MUST(g_banos_symbols.insert(sym->name, sym->arg));
|
||||
}
|
||||
}
|
||||
// TODO: driver unloading with a reference counter
|
||||
struct Driver_Instance {
|
||||
Banos_Driver* drv;
|
||||
};
|
||||
static BAN::Vector<Driver_Instance> s_driver_instaces;
|
||||
static SpinLock s_driver_instaces_lock;
|
||||
|
||||
extern Banos_Symbol g_banos_export[],
|
||||
g_banos_export_end[];
|
||||
static void load_drv(Banos_Driver* drv) {
|
||||
ASSERT(drv->driver_size >= sizeof(Banos_Driver));
|
||||
dprintln("Loading driver:");
|
||||
dprintln(" name: {}", drv->name);
|
||||
if(drv->license) dprintln(" license: {}", drv->license);
|
||||
dprintln(" version: {}.{}.{}", BANOS_VERSION_GET_MAJOR(drv->version), BANOS_VERSION_GET_MINOR(drv->version), BANOS_VERSION_GET_PATCH(drv->version));
|
||||
int e = drv->init(drv);
|
||||
if(e < 0) dprintln(" Failed to init {} => {}", drv->name, -e);
|
||||
}
|
||||
BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image) {
|
||||
if(!Process::current().credentials().is_superuser()) return BAN::Error::from_errno(EPERM);
|
||||
// TODO: permission verification. Only root should be allowed to do this
|
||||
LibELF::ElfNativeFileHeader header;
|
||||
|
||||
const unsigned char elf_class =
|
||||
#if ARCH(i686)
|
||||
ELFCLASS32;
|
||||
#elif ARCH(x86_64)
|
||||
ELFCLASS64;
|
||||
#else
|
||||
# error update elf class
|
||||
#endif
|
||||
|
||||
// TODO: is banan-os really ever gonna be running on MSB machines?
|
||||
const unsigned char elf_data = ELFDATA2LSB;
|
||||
// TODO: do we need to verify e_machine? I mean we do not really care.
|
||||
// But I'm leaving this todo:
|
||||
// Look up EM_X86_64 and EM_360|EM_860|EM_960
|
||||
TRY(read_from_user(u_image, &header, sizeof header));
|
||||
if( header.e_ident[EI_MAG0] != ELFMAG0 ||
|
||||
header.e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
header.e_ident[EI_MAG2] != ELFMAG2 ||
|
||||
header.e_ident[EI_MAG3] != ELFMAG3 ||
|
||||
header.e_ident[EI_CLASS] != elf_class ||
|
||||
header.e_ident[EI_DATA] != elf_data ||
|
||||
header.e_ident[EI_VERSION] != EV_CURRENT ||
|
||||
header.e_type != ET_REL ||
|
||||
header.e_version != EV_CURRENT ||
|
||||
header.e_ehsize != sizeof(header) ||
|
||||
header.e_shentsize != sizeof(ElfNativeSectionHeader))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
|
||||
BAN::Vector<LibELF::ElfNativeSectionHeader> secs(header.e_shnum);
|
||||
TRY(read_from_user(u_image + header.e_shoff, secs.data(), secs.size() * sizeof(*secs.data())));
|
||||
auto shstr = secs[header.e_shstrndx];
|
||||
|
||||
size_t total_size = 0;
|
||||
|
||||
LibELF::ElfNativeSectionHeader *strtab = nullptr,
|
||||
*symtab = nullptr,
|
||||
*driver_section = nullptr;
|
||||
|
||||
for(auto& sec : secs) {
|
||||
if(sec.sh_flags & LibELF::SHF_ALLOC) {
|
||||
sec.sh_addr = total_size;
|
||||
total_size += sec.sh_size;
|
||||
}
|
||||
if(sec.sh_name == 0) continue;
|
||||
char name[256];
|
||||
TRY(read_string_from_user(u_image + shstr.sh_offset + sec.sh_name, name, sizeof name));
|
||||
BAN::StringView name_sv(name);
|
||||
|
||||
if(sec.sh_type == LibELF::SHT_SYMTAB) {
|
||||
symtab = &sec;
|
||||
}
|
||||
// TODO: verify sh_type for both of these?
|
||||
if(name_sv == ".strtab") {
|
||||
strtab = &sec;
|
||||
} else if(name_sv == ".banos-driver") {
|
||||
driver_section = &sec;
|
||||
}
|
||||
}
|
||||
if(!symtab || !strtab || !driver_section)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
total_size += PAGE_SIZE;
|
||||
total_size &= ~(PAGE_SIZE-1);
|
||||
auto driver = TRY(VirtualRange::create_to_vaddr_range(PageTable::kernel(), { KERNEL_OFFSET, UINTPTR_MAX }, total_size, PageTable::Execute | PageTable::ReadWrite | PageTable::Present, true));
|
||||
|
||||
for(auto& sec : secs) {
|
||||
if(sec.sh_flags & LibELF::SHF_ALLOC) {
|
||||
sec.sh_addr += driver->vaddr();
|
||||
}
|
||||
}
|
||||
Banos_Driver* banos_driver = reinterpret_cast<Banos_Driver*>(driver_section->sh_addr);
|
||||
for(auto& sec : secs) {
|
||||
if(sec.sh_name == 0) continue;
|
||||
if(sec.sh_flags & LibELF::SHF_ALLOC) {
|
||||
TRY(read_from_user(u_image + sec.sh_offset, reinterpret_cast<char*>(sec.sh_addr), sec.sh_size));
|
||||
}
|
||||
if(sec.sh_type == LibELF::SHT_RELA) {
|
||||
auto& link_sec = secs[sec.sh_info];
|
||||
size_t rela_count = sec.sh_size/sizeof(LibELF::ElfNativeRelocationA);
|
||||
BAN::Vector<LibELF::ElfNativeRelocationA> rela_data(rela_count);
|
||||
TRY(read_from_user(u_image + sec.sh_offset, rela_data.data(), rela_count * sizeof *rela_data.data()));
|
||||
|
||||
for(auto rela : rela_data) {
|
||||
auto type = ELF64_R_TYPE(rela.r_info);
|
||||
auto symbol = ELF64_R_SYM(rela.r_info);
|
||||
|
||||
vaddr_t value = 0;
|
||||
|
||||
LibELF::ElfNativeSymbol sym;
|
||||
TRY(read_from_user(u_image + symtab->sh_offset + sizeof(sym) * symbol, &sym, sizeof sym));
|
||||
|
||||
if(sym.st_shndx) {
|
||||
value = secs[sym.st_shndx].sh_addr;
|
||||
} else {
|
||||
char name[256];
|
||||
TRY(read_string_from_user(u_image + strtab->sh_offset + sym.st_name, name, sizeof name));
|
||||
|
||||
value = reinterpret_cast<vaddr_t>(Banos::resolve_symbol(name));
|
||||
if(!value) {
|
||||
derrorln("Failed to find symbol {}", name);
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
}
|
||||
vaddr_t at = link_sec.sh_addr + rela.r_offset;
|
||||
size_t size = 0;
|
||||
switch(type) {
|
||||
case LibELF::R_X86_64_PLT32:
|
||||
case LibELF::R_X86_64_PC32:
|
||||
value -= at;
|
||||
// fallthrough
|
||||
case LibELF::R_X86_64_32:
|
||||
case LibELF::R_X86_64_32S:
|
||||
value += rela.r_addend;
|
||||
size = sizeof(uint32_t);
|
||||
break;
|
||||
case LibELF::R_X86_64_64:
|
||||
value += rela.r_addend;
|
||||
size = sizeof(uint64_t);
|
||||
break;
|
||||
default:
|
||||
derrorln("TODO: Unsupported relocation type {}", type);
|
||||
return BAN::Error::from_errno(ENOSYS);
|
||||
}
|
||||
|
||||
switch(size) {
|
||||
case 4: *reinterpret_cast<uint32_t*>(at) = value; break;
|
||||
case 8: *reinterpret_cast<uint64_t*>(at) = value; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Driver_Instance instance;
|
||||
instance.drv = banos_driver;
|
||||
load_drv(instance.drv);
|
||||
SpinLockGuard _(s_driver_instaces_lock);
|
||||
TRY(s_driver_instaces.push_back(instance));
|
||||
// TODO: import symbols and resolve redefintions :)
|
||||
return s_driver_instaces.size() - 1;
|
||||
}
|
||||
// NOTE: should be more than plenty ;)
|
||||
extern char g_drv_builtin_begin[];
|
||||
extern char g_drv_builtin_end[];
|
||||
void Banos::initialize_initial_drivers(void) {
|
||||
import_symbols(g_banos_export, g_banos_export_end - g_banos_export);
|
||||
char* head = g_drv_builtin_begin;
|
||||
while(head < g_drv_builtin_end) {
|
||||
Banos_Driver* drv = (Banos_Driver*)head;
|
||||
load_drv(drv);
|
||||
head += drv->driver_size;
|
||||
}
|
||||
}
|
||||
@@ -230,13 +230,11 @@ namespace Kernel
|
||||
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
RWLockRDGuard _0(m_lock);
|
||||
RWLockRDGuard _(m_lock);
|
||||
|
||||
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= static_cast<size_t>(m_size))
|
||||
return 0;
|
||||
|
||||
ScopedSync _1(*this);
|
||||
|
||||
uint32_t count = buffer.size();
|
||||
if (offset + buffer.size() > static_cast<size_t>(m_size))
|
||||
count = m_size - offset;
|
||||
@@ -283,7 +281,7 @@ namespace Kernel
|
||||
if (static_cast<size_t>(m_size) < offset + buffer.size())
|
||||
TRY(truncate_impl(offset + buffer.size()));
|
||||
|
||||
ScopedSync _(*this);
|
||||
ScopedSync _1(*this);
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <kernel/Memory/FileBackedRegion.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
namespace Kernel
|
||||
@@ -317,7 +318,22 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
|
||||
{
|
||||
return ioctl_impl(request, arg);
|
||||
auto ret = ioctl_impl(request, arg);
|
||||
if (!ret.is_error() || ret.error().get_error_code() != ENOTSUP)
|
||||
return BAN::move(ret);
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case TIOCGWINSZ:
|
||||
case TIOCSWINSZ:
|
||||
case TCGETS:
|
||||
case TCSETS:
|
||||
case TCSETSW:
|
||||
case TCSETSF:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
default:
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::add_epoll(class Epoll* epoll)
|
||||
|
||||
@@ -268,19 +268,4 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Pipe::ioctl_impl(int cmd, void* arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case TIOCGWINSZ:
|
||||
case TIOCSWINSZ:
|
||||
case TCGETS:
|
||||
case TCSETS:
|
||||
case TCSETSW:
|
||||
case TCSETSF:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
return Inode::ioctl_impl(cmd, arg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <BAN/CircularQueue.h>
|
||||
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
|
||||
#include <LibInput/Joystick.h>
|
||||
#include <LibInput/KeyEvent.h>
|
||||
@@ -24,6 +27,10 @@ namespace Kernel
|
||||
static SpinLock s_joystick_lock;
|
||||
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks;
|
||||
|
||||
static SpinLock s_tty_keyboard_event_lock;
|
||||
static ThreadBlocker s_tty_keyboard_event_blocker;
|
||||
static BAN::CircularQueue<LibInput::RawKeyEvent, 128> s_tty_keyboard_events;
|
||||
|
||||
static const char* get_name_format(InputDevice::Type type)
|
||||
{
|
||||
switch (type)
|
||||
@@ -201,6 +208,15 @@ namespace Kernel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (TTY::current()->should_receive_input())
|
||||
{
|
||||
SpinLockGuard _(s_tty_keyboard_event_lock);
|
||||
if (!s_tty_keyboard_events.full())
|
||||
s_tty_keyboard_events.push(key_event);
|
||||
s_tty_keyboard_event_blocker.unblock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_event_count == m_max_event_count)
|
||||
@@ -261,6 +277,41 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
static void tty_keyboard_thread(void*)
|
||||
{
|
||||
static BAN::Atomic<bool> initialized = false;
|
||||
[[maybe_unused]] bool old_initialized = initialized.exchange(true);
|
||||
ASSERT(old_initialized == false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
LibInput::RawKeyEvent event;
|
||||
|
||||
{
|
||||
SpinLockGuard guard(s_tty_keyboard_event_lock);
|
||||
|
||||
if (s_tty_keyboard_events.empty())
|
||||
{
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
s_tty_keyboard_event_blocker.block_indefinite(&smutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
event = s_tty_keyboard_events.front();
|
||||
s_tty_keyboard_events.pop();
|
||||
}
|
||||
|
||||
TTY::current()->on_key_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> KeyboardDevice::initialize_tty_thread()
|
||||
{
|
||||
auto* thread = TRY(Thread::create_kernel(tty_keyboard_thread, nullptr));
|
||||
ASSERT(thread);
|
||||
TRY(Processor::scheduler().add_thread(thread));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> KeyboardDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
|
||||
@@ -97,8 +97,8 @@ namespace Kernel
|
||||
return;
|
||||
|
||||
uint8_t page_buffer[PAGE_SIZE];
|
||||
PageTable::with_fast_page(pages[page_index], [&] {
|
||||
memcpy(page_buffer, PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(pages[page_index], [&](void* addr) {
|
||||
memcpy(page_buffer, addr, PAGE_SIZE);
|
||||
});
|
||||
|
||||
const size_t write_size = BAN::Math::min<size_t>(PAGE_SIZE, inode->size() - page_index * PAGE_SIZE);
|
||||
@@ -162,8 +162,8 @@ namespace Kernel
|
||||
m_shared_data->pages[shared_page_index] = Heap::get().take_free_page();
|
||||
if (m_shared_data->pages[shared_page_index] == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
PageTable::with_fast_page(m_shared_data->pages[shared_page_index], [&] {
|
||||
memcpy(PageTable::fast_page_as_ptr(), page_buffer, PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(m_shared_data->pages[shared_page_index], [&](void* addr) {
|
||||
memcpy(addr, page_buffer, PAGE_SIZE);
|
||||
});
|
||||
shared_data_has_correct_page = true;
|
||||
}
|
||||
@@ -181,12 +181,12 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
if (!shared_data_has_correct_page)
|
||||
{
|
||||
PageTable::with_fast_page(m_shared_data->pages[shared_page_index], [&] {
|
||||
memcpy(page_buffer, PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(m_shared_data->pages[shared_page_index], [&](void* addr) {
|
||||
memcpy(page_buffer, addr, PAGE_SIZE);
|
||||
});
|
||||
}
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(PageTable::fast_page_as_ptr(), page_buffer, PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [&](void* addr) {
|
||||
memcpy(addr, page_buffer, PAGE_SIZE);
|
||||
});
|
||||
m_dirty_pages[local_page_index] = paddr;
|
||||
m_page_table.map_page_at(paddr, vaddr, m_flags);
|
||||
@@ -210,8 +210,8 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
ASSERT(&m_page_table == &PageTable::current());
|
||||
PageTable::with_fast_page(paddr, [vaddr] {
|
||||
memcpy(PageTable::fast_page_as_ptr(), reinterpret_cast<void*>(vaddr), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [vaddr](void* addr) {
|
||||
memcpy(addr, reinterpret_cast<void*>(vaddr), PAGE_SIZE);
|
||||
});
|
||||
|
||||
m_dirty_pages[local_page_index] = paddr;
|
||||
@@ -240,8 +240,8 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
ASSERT(&m_page_table == &PageTable::current() || &m_page_table == &PageTable::kernel());
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(PageTable::fast_page_as_ptr(), reinterpret_cast<void*>(vaddr), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [&](void* addr) {
|
||||
memcpy(addr, reinterpret_cast<void*>(vaddr), PAGE_SIZE);
|
||||
});
|
||||
|
||||
result->m_page_table.map_page_at(paddr, vaddr, m_flags);
|
||||
|
||||
@@ -64,8 +64,8 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
m_page_table.map_page_at(paddr, vaddr, m_flags);
|
||||
PageTable::with_fast_page(paddr, [] {
|
||||
memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [](void* addr) {
|
||||
memset(addr, 0x00, PAGE_SIZE);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -93,8 +93,8 @@ namespace Kernel
|
||||
m_page_table.map_page_at(paddr, vaddr, m_flags);
|
||||
|
||||
ASSERT(&m_page_table == &PageTable::current());
|
||||
PageTable::with_fast_page(physical_page->paddr, [vaddr] {
|
||||
memcpy(reinterpret_cast<void*>(vaddr), PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(physical_page->paddr, [vaddr](void* addr) {
|
||||
memcpy(reinterpret_cast<void*>(vaddr), addr, PAGE_SIZE);
|
||||
});
|
||||
|
||||
if (--physical_page->ref_count == 0)
|
||||
@@ -164,9 +164,9 @@ namespace Kernel
|
||||
size_t written = 0;
|
||||
while (written < buffer_size)
|
||||
{
|
||||
vaddr_t write_vaddr = m_vaddr + offset_into_region + written;
|
||||
vaddr_t page_offset = write_vaddr % PAGE_SIZE;
|
||||
size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
|
||||
const vaddr_t write_vaddr = m_vaddr + offset_into_region + written;
|
||||
const vaddr_t page_offset = write_vaddr % PAGE_SIZE;
|
||||
const size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
|
||||
|
||||
if (!(m_page_table.get_page_flags(write_vaddr & PAGE_ADDR_MASK) & PageTable::ReadWrite))
|
||||
{
|
||||
@@ -180,8 +180,8 @@ namespace Kernel
|
||||
const paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
|
||||
ASSERT(paddr);
|
||||
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(PageTable::fast_page_as_ptr(page_offset), (void*)(buffer + written), bytes);
|
||||
PageTable::with_per_cpu_fast_page(paddr, [&](void* addr) {
|
||||
memcpy(static_cast<uint8_t*>(addr) + page_offset, (void*)(buffer + written), bytes);
|
||||
});
|
||||
|
||||
written += bytes;
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace Kernel
|
||||
const size_t bitmap_page_count = BAN::Math::div_round_up<size_t>(m_page_count, bits_per_page);
|
||||
for (size_t i = 0; i < bitmap_page_count; i++)
|
||||
{
|
||||
PageTable::with_fast_page(paddr + i * PAGE_SIZE, [] {
|
||||
memset(PageTable::fast_page_as_ptr(), 0, PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(paddr + i * PAGE_SIZE, [](void* addr) {
|
||||
memset(addr, 0, PAGE_SIZE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,15 +40,15 @@ namespace Kernel
|
||||
BAN::Optional<size_t> page_matched_bit;
|
||||
|
||||
const paddr_t current_paddr = m_paddr + i * PAGE_SIZE;
|
||||
PageTable::with_fast_page(current_paddr, [&page_matched_bit] {
|
||||
PageTable::with_per_cpu_fast_page(current_paddr, [&page_matched_bit](void* addr) {
|
||||
for (size_t j = 0; j < PAGE_SIZE / sizeof(size_t); j++)
|
||||
{
|
||||
static_assert(sizeof(size_t) == sizeof(long));
|
||||
const size_t current = PageTable::fast_page_as_sized<volatile size_t>(j);
|
||||
auto& current = static_cast<size_t*>(addr)[j];
|
||||
if (current == BAN::numeric_limits<size_t>::max())
|
||||
continue;
|
||||
const int ctz = __builtin_ctzl(~current);
|
||||
PageTable::fast_page_as_sized<volatile size_t>(j) = current | (static_cast<size_t>(1) << ctz);
|
||||
current |= static_cast<size_t>(1) << ctz;
|
||||
page_matched_bit = j * sizeof(size_t) * 8 + ctz;
|
||||
return;
|
||||
}
|
||||
@@ -75,15 +75,14 @@ namespace Kernel
|
||||
|
||||
const size_t paddr_index = (paddr - m_paddr) / PAGE_SIZE;
|
||||
|
||||
PageTable::with_fast_page(m_paddr + paddr_index / bits_per_page * PAGE_SIZE, [paddr_index] {
|
||||
PageTable::with_per_cpu_fast_page(m_paddr + paddr_index / bits_per_page * PAGE_SIZE, [paddr_index] (void* addr) {
|
||||
const size_t bitmap_bit = paddr_index % bits_per_page;
|
||||
const size_t byte = bitmap_bit / 8;
|
||||
const size_t bit = bitmap_bit % 8;
|
||||
|
||||
volatile uint8_t& bitmap_byte = PageTable::fast_page_as_sized<volatile uint8_t>(byte);
|
||||
uint8_t& bitmap_byte = static_cast<uint8_t*>(addr)[byte];
|
||||
ASSERT(bitmap_byte & (1u << bit));
|
||||
|
||||
bitmap_byte = bitmap_byte & ~(1u << bit);
|
||||
bitmap_byte &= ~(1u << bit);
|
||||
});
|
||||
|
||||
m_free_pages++;
|
||||
@@ -103,8 +102,8 @@ namespace Kernel
|
||||
const size_t bit = bit_index % 8;
|
||||
|
||||
uint8_t current;
|
||||
PageTable::with_fast_page(m_paddr + page_index * PAGE_SIZE, [¤t, byte] {
|
||||
current = PageTable::fast_page_as_sized<volatile uint8_t>(byte);
|
||||
PageTable::with_per_cpu_fast_page(m_paddr + page_index * PAGE_SIZE, [¤t, byte](void* addr) {
|
||||
current = static_cast<uint8_t*>(addr)[byte];
|
||||
});
|
||||
|
||||
return current & (1u << bit);
|
||||
@@ -117,9 +116,9 @@ namespace Kernel
|
||||
const size_t bit_index = buffer_bit % bits_per_page;
|
||||
const size_t byte = bit_index / 8;
|
||||
const size_t bit = bit_index % 8;
|
||||
PageTable::with_fast_page(m_paddr + page_index * PAGE_SIZE, [byte, bit] {
|
||||
volatile uint8_t& current = PageTable::fast_page_as_sized<volatile uint8_t>(byte);
|
||||
current = current | (1u << bit);
|
||||
PageTable::with_per_cpu_fast_page(m_paddr + page_index * PAGE_SIZE, [byte, bit](void* addr) {
|
||||
uint8_t& current = static_cast<uint8_t*>(addr)[byte];
|
||||
current |= 1u << bit;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/OpenFileDescriptorSet.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
@@ -254,7 +255,7 @@ namespace Kernel
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK)
|
||||
{
|
||||
struct flock flock;
|
||||
TRY(Process::current().read_from_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
TRY(read_from_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
flock.l_pid = Process::current().pid();
|
||||
|
||||
BAN::RefPtr<Inode> inode;
|
||||
@@ -307,7 +308,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
if (cmd == F_GETLK)
|
||||
TRY(Process::current().write_to_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
TRY(write_to_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include <kernel/Storage/StorageDevice.h>
|
||||
#include <kernel/Terminal/PseudoTerminal.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
#include <kernel/Banos.h>
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
@@ -483,6 +485,26 @@ namespace Kernel
|
||||
return l;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<AddressRange> Process::find_free_address_range(size_t size)
|
||||
{
|
||||
if (auto rem = size % PAGE_SIZE)
|
||||
size += PAGE_SIZE - rem;
|
||||
|
||||
vaddr_t vaddr = m_shared_page_vaddr ? m_shared_page_vaddr + PAGE_SIZE : 0x400000;
|
||||
for (size_t i = find_mapped_region(vaddr); i < m_mapped_regions.size(); i++)
|
||||
{
|
||||
const auto& region = m_mapped_regions[i];
|
||||
if (!region->overlaps(vaddr, size))
|
||||
return AddressRange { vaddr, vaddr + size };
|
||||
|
||||
vaddr = region->vaddr() + region->size();
|
||||
if (auto rem = vaddr % PAGE_SIZE)
|
||||
vaddr += PAGE_SIZE - rem;
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
}
|
||||
|
||||
size_t Process::proc_meminfo(off_t offset, BAN::ByteSpan buffer) const
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
@@ -2470,7 +2492,7 @@ namespace Kernel
|
||||
|
||||
RWLockWRGuard _(m_memory_region_lock);
|
||||
|
||||
AddressRange address_range { .start = 0x400000, .end = USERSPACE_END };
|
||||
AddressRange address_range;
|
||||
if (args.flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))
|
||||
{
|
||||
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(args.addr);
|
||||
@@ -2509,9 +2531,12 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (const vaddr_t vaddr = reinterpret_cast<vaddr_t>(args.addr); vaddr == 0)
|
||||
;
|
||||
else if (vaddr % PAGE_SIZE)
|
||||
else
|
||||
{
|
||||
bool use_address_hint = false;
|
||||
|
||||
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(args.addr);
|
||||
if (vaddr == 0 || vaddr % PAGE_SIZE)
|
||||
;
|
||||
else if (!PageTable::is_valid_pointer(vaddr))
|
||||
;
|
||||
@@ -2521,12 +2546,17 @@ namespace Kernel
|
||||
;
|
||||
else
|
||||
{
|
||||
use_address_hint = true;
|
||||
address_range = {
|
||||
.start = vaddr,
|
||||
.end = vaddr + args.len,
|
||||
};
|
||||
}
|
||||
|
||||
if (!use_address_hint)
|
||||
address_range = TRY(find_free_address_range(args.len));
|
||||
}
|
||||
|
||||
if (args.flags & MAP_ANONYMOUS)
|
||||
{
|
||||
auto region = TRY(MemoryBackedRegion::create(
|
||||
@@ -3857,47 +3887,6 @@ namespace Kernel
|
||||
return region->allocate_page_containing(address, wants_write);
|
||||
}
|
||||
|
||||
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
|
||||
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
|
||||
|
||||
static inline bool is_valid_user_address(const void* user_addr, size_t size)
|
||||
{
|
||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
||||
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
|
||||
return false;
|
||||
if (user_vaddr + size > USERSPACE_END)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
|
||||
{
|
||||
if (!is_valid_user_address(user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_memcpy(out, user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
||||
{
|
||||
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
|
||||
if (!is_valid_user_address(user_addr, max_size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_strncpy(out, user_addr, max_size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
|
||||
{
|
||||
if (!is_valid_user_address(user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_memcpy(user_addr, in, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
||||
{
|
||||
// TODO: allow pinning multiple regions?
|
||||
@@ -3962,4 +3951,7 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_banos_install(const char* u_image) {
|
||||
return TRY(Banos::load_driver_from_image(u_image));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +351,51 @@ namespace Kernel
|
||||
handle_smp_messages();
|
||||
}
|
||||
|
||||
void Processor::load_segments()
|
||||
{
|
||||
load_fsbase();
|
||||
load_gsbase();
|
||||
}
|
||||
|
||||
void Processor::load_fsbase()
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_fsbase();
|
||||
#if ARCH(x86_64)
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_FS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_fsbase(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Processor::load_gsbase()
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_gsbase();
|
||||
#if ARCH(x86_64)
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_gsbase(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Processor::lock_tlb_lock()
|
||||
{
|
||||
bool expected = false;
|
||||
while (!m_tlb_lock.compare_exchange(expected, true, BAN::MemoryOrder::memory_order_acquire))
|
||||
{
|
||||
__builtin_ia32_pause();
|
||||
expected = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::unlock_tlb_lock()
|
||||
{
|
||||
m_tlb_lock.store(false, BAN::MemoryOrder::memory_order_release);
|
||||
}
|
||||
|
||||
void Processor::handle_smp_messages()
|
||||
{
|
||||
auto state = get_interrupt_state();
|
||||
@@ -386,10 +431,7 @@ namespace Kernel
|
||||
switch (message->type)
|
||||
{
|
||||
case SMPMessage::Type::FlushTLB:
|
||||
if (message->flush_tlb.page_table && message->flush_tlb.page_table != processor.m_current_page_table)
|
||||
break;
|
||||
PageTable::current().invalidate_range(message->flush_tlb.vaddr, message->flush_tlb.page_count, false);
|
||||
break;
|
||||
ASSERT_NOT_REACHED();
|
||||
case SMPMessage::Type::NewThread:
|
||||
processor.m_scheduler->add_thread(message->new_thread);
|
||||
break;
|
||||
@@ -420,46 +462,64 @@ namespace Kernel
|
||||
last_handled->next = processor.m_smp_free;
|
||||
}
|
||||
|
||||
{
|
||||
processor.lock_tlb_lock();
|
||||
const size_t tlb_entry_count = processor.m_tlb_entry_count;
|
||||
const auto tlb_entries = processor.m_tlb_entries;
|
||||
const bool tlb_global = processor.m_tlb_global;
|
||||
processor.m_tlb_entry_count = 0;
|
||||
processor.m_tlb_global = false;
|
||||
processor.unlock_tlb_lock();
|
||||
|
||||
auto& page_table = PageTable::current();
|
||||
|
||||
size_t pages = 0;
|
||||
for (size_t i = 0; i < tlb_entry_count; i++)
|
||||
if (tlb_entries[i].page_table == nullptr || tlb_entries[i].page_table == &page_table)
|
||||
pages += tlb_entries[i].page_count;
|
||||
|
||||
if (pages >= PageTable::full_tlb_flush_threshold || tlb_entry_count >= processor.m_tlb_entries.size())
|
||||
page_table.invalidate_full_address_space(tlb_global);
|
||||
else for (size_t i = 0; i < tlb_entry_count; i++)
|
||||
if (tlb_entries[i].page_table == nullptr || tlb_entries[i].page_table == &page_table)
|
||||
page_table.invalidate_range(tlb_entries[i].vaddr, tlb_entries[i].page_count, false);
|
||||
}
|
||||
|
||||
set_interrupt_state(state);
|
||||
}
|
||||
|
||||
void Processor::load_segments()
|
||||
{
|
||||
load_fsbase();
|
||||
load_gsbase();
|
||||
}
|
||||
|
||||
void Processor::load_fsbase()
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_fsbase();
|
||||
#if ARCH(x86_64)
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_FS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_fsbase(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Processor::load_gsbase()
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_gsbase();
|
||||
#if ARCH(x86_64)
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_gsbase(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi)
|
||||
bool Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi)
|
||||
{
|
||||
auto state = get_interrupt_state();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
auto& processor = s_processors[processor_id.m_id];
|
||||
|
||||
if (message.type == SMPMessage::Type::FlushTLB)
|
||||
{
|
||||
processor.lock_tlb_lock();
|
||||
|
||||
const bool is_first_entry = (processor.m_tlb_entry_count == 0);
|
||||
|
||||
const auto& tlb_msg = message.flush_tlb;
|
||||
|
||||
processor.m_tlb_global |= (tlb_msg.page_table == nullptr);
|
||||
|
||||
if (processor.m_tlb_entry_count < processor.m_tlb_entries.size())
|
||||
{
|
||||
processor.m_tlb_entries[processor.m_tlb_entry_count++] = {
|
||||
.vaddr = tlb_msg.vaddr,
|
||||
.page_count = tlb_msg.page_count,
|
||||
.page_table = static_cast<PageTable*>(tlb_msg.page_table),
|
||||
};
|
||||
}
|
||||
|
||||
processor.unlock_tlb_lock();
|
||||
set_interrupt_state(state);
|
||||
|
||||
return is_first_entry;
|
||||
}
|
||||
|
||||
// find a slot for message
|
||||
auto* storage = processor.m_smp_free.exchange(nullptr);
|
||||
while (storage == nullptr)
|
||||
@@ -499,15 +559,19 @@ namespace Kernel
|
||||
storage->next = processor.m_smp_pending;
|
||||
}
|
||||
|
||||
const bool needs_ipi = (storage->next == nullptr);
|
||||
|
||||
if (send_ipi)
|
||||
{
|
||||
if (processor_id == current_id())
|
||||
handle_smp_messages();
|
||||
else
|
||||
else if (needs_ipi)
|
||||
InterruptController::get().send_ipi(processor_id);
|
||||
}
|
||||
|
||||
set_interrupt_state(state);
|
||||
|
||||
return needs_ipi;
|
||||
}
|
||||
|
||||
void Processor::broadcast_smp_message(const SMPMessage& message)
|
||||
@@ -518,14 +582,17 @@ namespace Kernel
|
||||
const auto state = get_interrupt_state();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
||||
bool needs_ipi = false;
|
||||
|
||||
const auto current_id = Processor::current_id();
|
||||
for (size_t i = 0; i < Processor::count(); i++)
|
||||
{
|
||||
const auto processor_id = s_processor_ids[i];
|
||||
if (processor_id != current_id)
|
||||
send_smp_message(processor_id, message, false);
|
||||
needs_ipi |= send_smp_message(processor_id, message, false);
|
||||
}
|
||||
|
||||
if (needs_ipi)
|
||||
InterruptController::get().broadcast_ipi();
|
||||
|
||||
set_interrupt_state(state);
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace Kernel
|
||||
if (!(cache.sector_mask & (1 << page_cache_offset)))
|
||||
return false;
|
||||
|
||||
PageTable::with_fast_page(cache.paddr, [&] {
|
||||
memcpy(buffer.data(), PageTable::fast_page_as_ptr(page_cache_offset * m_sector_size), m_sector_size);
|
||||
PageTable::with_per_cpu_fast_page(cache.paddr, [&](void* addr) {
|
||||
memcpy(buffer.data(), static_cast<uint8_t*>(addr) + page_cache_offset * m_sector_size, m_sector_size);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -107,8 +107,8 @@ namespace Kernel
|
||||
|
||||
auto& cache = m_cache[index];
|
||||
|
||||
PageTable::with_fast_page(cache.paddr, [&] {
|
||||
memcpy(PageTable::fast_page_as_ptr(page_cache_offset * m_sector_size), buffer.data(), m_sector_size);
|
||||
PageTable::with_per_cpu_fast_page(cache.paddr, [&](void* addr) {
|
||||
memcpy(static_cast<uint8_t*>(addr) + page_cache_offset * m_sector_size, buffer.data(), m_sector_size);
|
||||
});
|
||||
|
||||
cache.sector_mask |= 1 << page_cache_offset;
|
||||
@@ -133,8 +133,8 @@ namespace Kernel
|
||||
if (cache.dirty_mask == 0)
|
||||
return {};
|
||||
|
||||
PageTable::with_fast_page(cache.paddr, [&] {
|
||||
memcpy(m_sync_cache.data(), PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
PageTable::with_per_cpu_fast_page(cache.paddr, [&](void* addr) {
|
||||
memcpy(m_sync_cache.data(), addr, PAGE_SIZE);
|
||||
});
|
||||
|
||||
temp_cache = cache;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||
#include <kernel/Process.h>
|
||||
@@ -117,40 +118,9 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
void TTY::keyboard_task(void*)
|
||||
{
|
||||
BAN::RefPtr<Inode> keyboard_inode;
|
||||
if (auto ret = DevFileSystem::get().root_inode()->find_inode("keyboard"_sv); !ret.is_error())
|
||||
keyboard_inode = ret.release_value();
|
||||
else
|
||||
{
|
||||
dprintln("could not open keyboard device: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (TTY::current()->m_tty_ctrl.receive_input)
|
||||
{
|
||||
if (!keyboard_inode->can_read())
|
||||
{
|
||||
SystemTimer::get().sleep_ms(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
LibInput::RawKeyEvent event;
|
||||
[[maybe_unused]] const size_t read = MUST(keyboard_inode->read(0, BAN::ByteSpan::from(event)));
|
||||
ASSERT(read == sizeof(event));
|
||||
|
||||
TTY::current()->on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TTY::initialize_devices()
|
||||
{
|
||||
auto* thread = MUST(Thread::create_kernel(&TTY::keyboard_task, nullptr));
|
||||
MUST(Processor::scheduler().add_thread(thread));
|
||||
MUST(KeyboardDevice::initialize_tty_thread());
|
||||
|
||||
DevFileSystem::get().add_inode("tty", MUST(DevTTY::create(0666, 0, 0)));
|
||||
}
|
||||
@@ -268,7 +238,7 @@ namespace Kernel
|
||||
if (ch == _POSIX_VDISABLE)
|
||||
return;
|
||||
|
||||
LockGuard _0(m_mutex);
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
const auto termios = get_termios();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -727,7 +728,7 @@ namespace Kernel
|
||||
{
|
||||
static_assert(sizeof(T) >= sizeof(uintptr_t));
|
||||
sp -= sizeof(T);
|
||||
if (m_process->write_to_user(reinterpret_cast<void*>(sp), &value, sizeof(T)).is_error())
|
||||
if (write_to_user(reinterpret_cast<void*>(sp), &value, sizeof(T)).is_error())
|
||||
m_process->exit(128 + SIGSEGV, SIGSEGV | 0x80);
|
||||
};
|
||||
|
||||
|
||||
40
kernel/kernel/UserCopy.cpp
Normal file
40
kernel/kernel/UserCopy.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
|
||||
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
|
||||
static inline bool is_valid_user_address(const void* user_addr, size_t size)
|
||||
{
|
||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
||||
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
|
||||
return false;
|
||||
if (user_vaddr + size > USERSPACE_END)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
BAN::ErrorOr<void> Kernel::read_from_user(const void* user_addr, void* out, size_t size)
|
||||
{
|
||||
if (!is_valid_user_address(user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_memcpy(out, user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Kernel::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
||||
{
|
||||
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
|
||||
if (!is_valid_user_address(user_addr, max_size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_strncpy(out, user_addr, max_size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Kernel::write_to_user(void* user_addr, const void* in, size_t size)
|
||||
{
|
||||
if (!is_valid_user_address(user_addr, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
if (!safe_user_memcpy(user_addr, in, size))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return {};
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <kernel/Terminal/VirtualTTY.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/USB/USBManager.h>
|
||||
#include <kernel/Banos.h>
|
||||
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
@@ -261,6 +262,8 @@ static void init2(void*)
|
||||
|
||||
TTY::initialize_devices();
|
||||
|
||||
Banos::initialize_initial_drivers();
|
||||
|
||||
auto console_path = MUST(BAN::String::formatted("/dev/{}", cmdline.console));
|
||||
auto console_path_sv = console_path.sv();
|
||||
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"_sv, BAN::Span<BAN::StringView>(&console_path_sv, 1)));
|
||||
|
||||
@@ -117,6 +117,7 @@ __BEGIN_DECLS
|
||||
O(SYS_SETGROUPS, setgroups) \
|
||||
O(SYS_CHROOT, chroot) \
|
||||
O(SYS_EVENTFD, eventfd) \
|
||||
O(SYS_BANOS_INSTALL, banos_install) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
||||
@@ -809,7 +809,7 @@ static qsort_pair qsort_partition(uint8_t* pbegin, uint8_t* pend, size_t width,
|
||||
|
||||
while (eq < gt)
|
||||
{
|
||||
const int comp = compar(eq, pivot);
|
||||
const int comp = (eq == pivot) ? 0 : compar(eq, pivot);
|
||||
|
||||
if (comp < 0)
|
||||
{
|
||||
|
||||
@@ -57,6 +57,7 @@ set(USERSPACE_PROGRAMS
|
||||
whoami
|
||||
WindowServer
|
||||
yes
|
||||
driver-install
|
||||
)
|
||||
|
||||
foreach(project ${USERSPACE_PROGRAMS})
|
||||
|
||||
@@ -700,54 +700,20 @@ static void relocate_elf(LoadedElf& elf, bool lazy_load)
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t pltrelent = (elf.pltrel == DT_REL)
|
||||
? sizeof(ElfNativeRelocation)
|
||||
: sizeof(ElfNativeRelocationA);
|
||||
|
||||
for (size_t i = 0; i < elf.pltrelsz / pltrelent; i++)
|
||||
{
|
||||
const auto info = (elf.pltrel == DT_REL)
|
||||
? reinterpret_cast<ElfNativeRelocation*>(elf.jmprel)[i].r_info
|
||||
: reinterpret_cast<ElfNativeRelocationA*>(elf.jmprel)[i].r_info;
|
||||
const auto offset = (elf.pltrel == DT_REL)
|
||||
? reinterpret_cast<ElfNativeRelocation*>(elf.jmprel)[i].r_offset
|
||||
: reinterpret_cast<ElfNativeRelocationA*>(elf.jmprel)[i].r_offset;
|
||||
|
||||
#if defined(__x86_64__)
|
||||
if (ELF64_R_TYPE(info) != R_X86_64_JUMP_SLOT)
|
||||
print_error_and_exit("jmprel relocation not R_X86_64_JUMP_SLOT", 0);
|
||||
#elif defined(__i686__)
|
||||
if (ELF32_R_TYPE(info) != R_386_JMP_SLOT)
|
||||
print_error_and_exit("jmprel relocation not R_386_JMP_SLOT", 0);
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
|
||||
bool do_relocation = false;
|
||||
|
||||
if (const uint32_t symbol_index = ELF_R_SYM(info))
|
||||
{
|
||||
const auto& symbol = *reinterpret_cast<ElfNativeSymbol*>(elf.symtab + symbol_index * elf.syment);
|
||||
const char* symbol_name = reinterpret_cast<const char*>(elf.strtab + symbol.st_name);
|
||||
if (strcmp(symbol_name, "__tls_get_addr") == 0 || strcmp(symbol_name, "___tls_get_addr") == 0)
|
||||
do_relocation = true;
|
||||
}
|
||||
|
||||
if (!do_relocation)
|
||||
*reinterpret_cast<uintptr_t*>(elf.base + offset) += elf.base;
|
||||
else switch (elf.pltrel)
|
||||
switch (elf.pltrel)
|
||||
{
|
||||
case DT_REL:
|
||||
handle_relocation(elf, reinterpret_cast<ElfNativeRelocation*>(elf.jmprel)[i], true);
|
||||
for (size_t i = 0; i < elf.pltrelsz / sizeof(ElfNativeRelocation); i++)
|
||||
*reinterpret_cast<uintptr_t*>(elf.base + reinterpret_cast<ElfNativeRelocation*>(elf.jmprel)[i].r_offset) += elf.base;
|
||||
break;
|
||||
case DT_RELA:
|
||||
handle_relocation(elf, reinterpret_cast<ElfNativeRelocationA*>(elf.jmprel)[i], true);
|
||||
for (size_t i = 0; i < elf.pltrelsz / sizeof(ElfNativeRelocationA); i++)
|
||||
*reinterpret_cast<uintptr_t*>(elf.base + reinterpret_cast<ElfNativeRelocationA*>(elf.jmprel)[i].r_offset) += elf.base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
__attribute__((used))
|
||||
@@ -1279,6 +1245,28 @@ static MasterTLS initialize_master_tls()
|
||||
module_count++;
|
||||
}
|
||||
|
||||
{
|
||||
const sys_mmap_t mmap_args {
|
||||
.addr = nullptr,
|
||||
.len = sizeof(_dynamic_tls_t) + s_max_loaded_files * sizeof(_dynamic_tls_entry_t),
|
||||
.prot = PROT_READ | PROT_WRITE,
|
||||
.flags = MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
.fildes = -1,
|
||||
.off = 0,
|
||||
};
|
||||
|
||||
const auto ret = syscall(SYS_MMAP, &mmap_args);
|
||||
if (ret < 0)
|
||||
print_error_and_exit("failed to allocate dynamic TLS", ret);
|
||||
s_dynamic_tls = reinterpret_cast<_dynamic_tls_t*>(ret);
|
||||
|
||||
*s_dynamic_tls = {
|
||||
.lock = 0,
|
||||
.entry_count = 0,
|
||||
.entries = reinterpret_cast<_dynamic_tls_entry_t*>(s_dynamic_tls + 1),
|
||||
};
|
||||
}
|
||||
|
||||
if (module_count == 0)
|
||||
return { .addr = nullptr, .size = 0, .module_count = 0 };
|
||||
|
||||
@@ -1329,28 +1317,6 @@ static MasterTLS initialize_master_tls()
|
||||
elf.tls_offset = tls_offset;
|
||||
}
|
||||
|
||||
{
|
||||
const sys_mmap_t mmap_args {
|
||||
.addr = nullptr,
|
||||
.len = sizeof(_dynamic_tls_t) + s_max_loaded_files * sizeof(_dynamic_tls_entry_t),
|
||||
.prot = PROT_READ | PROT_WRITE,
|
||||
.flags = MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
.fildes = -1,
|
||||
.off = 0,
|
||||
};
|
||||
|
||||
const auto ret = syscall(SYS_MMAP, &mmap_args);
|
||||
if (ret < 0)
|
||||
print_error_and_exit("failed to allocate dynamic TLS", ret);
|
||||
s_dynamic_tls = reinterpret_cast<_dynamic_tls_t*>(ret);
|
||||
|
||||
*s_dynamic_tls = {
|
||||
.lock = 0,
|
||||
.entry_count = 0,
|
||||
.entries = reinterpret_cast<_dynamic_tls_entry_t*>(s_dynamic_tls + 1),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
.addr = master_tls_addr,
|
||||
.size = master_tls_size,
|
||||
|
||||
9
userspace/programs/driver-install/CMakeLists.txt
Normal file
9
userspace/programs/driver-install/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(driver-install ${SOURCES})
|
||||
banan_link_library(driver-install ban)
|
||||
banan_link_library(driver-install libc)
|
||||
|
||||
install(TARGETS driver-install OPTIONAL)
|
||||
93
userspace/programs/driver-install/main.cpp
Normal file
93
userspace/programs/driver-install/main.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
|
||||
char* g_exe;
|
||||
char* shift_args(int *argc, char ***argv) {
|
||||
return (assert((*argc) > 0), ((*argc)--, *((*argv)++)));
|
||||
}
|
||||
void help(FILE* sink) {
|
||||
fprintf(sink, "%s <input filename>\n", g_exe);
|
||||
}
|
||||
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define eprintfln(fmt, ...) eprintf(fmt "\n", ## __VA_ARGS__)
|
||||
char* read_entire_file(const char* path) {
|
||||
char* result = NULL;
|
||||
char* head = NULL;
|
||||
char* end = NULL;
|
||||
size_t buf_size = 0;
|
||||
long at = 0;
|
||||
FILE *f = fopen(path, "rb");
|
||||
|
||||
if(!f) {
|
||||
fprintf(stderr, "ERROR Could not open file %s: %s\n",path,strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if(fseek(f, 0, SEEK_END) != 0) {
|
||||
fprintf(stderr, "ERROR Could not fseek on file %s: %s\n",path,strerror(errno));
|
||||
result = NULL; goto DEFER;
|
||||
}
|
||||
at = ftell(f);
|
||||
if(at == -1L) {
|
||||
fprintf(stderr, "ERROR Could not ftell on file %s: %s\n",path,strerror(errno));
|
||||
result = NULL; goto DEFER;
|
||||
}
|
||||
buf_size = at+1;
|
||||
rewind(f);
|
||||
result = (char*)malloc(buf_size);
|
||||
assert(result && "Ran out of memory");
|
||||
head = result;
|
||||
end = result+buf_size-1;
|
||||
while(head != end) {
|
||||
head += fread(head, 1, end-head, f);
|
||||
if(ferror(f)) {
|
||||
fprintf(stderr, "ERROR Could not fread on file %s: %s\n",path,strerror(errno));
|
||||
free(result);
|
||||
result = NULL; goto DEFER;
|
||||
}
|
||||
}
|
||||
result[buf_size-1] = '\0';
|
||||
DEFER:
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int banos_install(const void* driver_image) {
|
||||
return syscall(SYS_BANOS_INSTALL, driver_image);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
g_exe = shift_args(&argc, &argv);
|
||||
char* input_filename = NULL;
|
||||
while(argc > 0) {
|
||||
char* arg = shift_args(&argc, &argv);
|
||||
if(!input_filename) input_filename = arg;
|
||||
else {
|
||||
eprintfln("ERROR: Unexpected argument `%s'", arg);
|
||||
help(stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(!input_filename) {
|
||||
eprintfln("ERROR: Missing input filename!");
|
||||
help(stderr);
|
||||
return 1;
|
||||
}
|
||||
char* data = read_entire_file(input_filename);
|
||||
if(!data) return 1;
|
||||
int id = banos_install(data);
|
||||
if(id == -1) {
|
||||
eprintfln("ERROR: Failed to install driver `%s': %s", input_filename, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("%d\n", id);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user