Compare commits
97 Commits
684fa1c4b0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f527aca9d0 | ||
|
|
5fce3b64cc | ||
| c04ad65f7f | |||
| af17b29414 | |||
| 7badcf80cf | |||
| 7f122d9e89 | |||
| 984c7c0a89 | |||
| ce318c7930 | |||
| eff6c79e9e | |||
| aaade52146 | |||
| 1bf5e6a051 | |||
| 394719a909 | |||
| 3ebadc5c74 | |||
| d471bbf856 | |||
| c849293f3d | |||
| 0156d06cdc | |||
| ad12bf3e1d | |||
| 42964ad0b4 | |||
| 87979b1627 | |||
| fed9dbefdf | |||
| 2984927be5 | |||
| 2e654b53fa | |||
| ac6e6f3ec1 | |||
| 2b97587e9f | |||
| 4bde088b28 | |||
| 2a9dad2dd8 | |||
| d11160d2f7 | |||
| 7333008f40 | |||
| cd7d309fd1 | |||
| a4ba1da65a | |||
| 2f9b8b6fc9 | |||
| 279ac6b2b6 | |||
| 9084d9305c | |||
| 80c4213501 | |||
| e0af23a924 | |||
| 7e907b70f6 | |||
| 7fb27b16e8 | |||
| 3fb903d991 | |||
| 2a4a688c2d | |||
| 1487c86262 | |||
| 4d3751028b | |||
| e4c6539964 | |||
| 34b59f062b | |||
| ec4aa8d0b6 | |||
| 1eebe85071 | |||
| db0507e670 | |||
| 1e3ca7dc18 | |||
| 8ca3c5d778 | |||
| df257755f7 | |||
| d7e292a9f8 | |||
| 9fce114e8e | |||
| 9d83424346 | |||
| a29681a524 | |||
| 47d85eb281 | |||
| 85f676c30a | |||
| 8c5fa1c0b8 | |||
| c7690053ae | |||
| 3f55be638d | |||
| 664c824bc0 | |||
| e239d9ca55 | |||
| bf1d9662d7 | |||
| 675c215e6a | |||
| c09bca56f9 | |||
| 7d8f7753d5 | |||
| f77aa65dc5 | |||
| 9589b5984d | |||
| 32806a5af3 | |||
| 876fbe3d7c | |||
| c1b8f5e475 | |||
| cf31ea9cbe | |||
| 7e6b8c93b4 | |||
| dd2bbe4588 | |||
| e01e35713b | |||
| 82d5d9ba58 | |||
| d168492462 | |||
| 6f2e8320a9 | |||
| bf4831f468 | |||
| 5647cf24d2 | |||
| 85f61aded5 | |||
| 21639071c2 | |||
| 68506a789a | |||
| d9ca25b796 | |||
| e9c81477d7 | |||
| 5c20d5e291 | |||
| f89d690716 | |||
| c563efcd1c | |||
| dedeebbfbe | |||
| 35e2a70de0 | |||
| 81d5c86a7a | |||
| db6644bae9 | |||
| 14f1c1a358 | |||
| 5be9bc64a2 | |||
| 64d3a5c8b7 | |||
| ccb4d13a82 | |||
| cbe835a2c8 | |||
| 6a77754adf | |||
| 7d7d5ba734 |
46
BAN/include/BAN/MacroUtils.h
Normal file
46
BAN/include/BAN/MacroUtils.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _ban_count_args_impl(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
|
||||||
|
#define _ban_count_args(...) _ban_count_args_impl(__VA_ARGS__ __VA_OPT__(,) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
|
|
||||||
|
#define _ban_concat_impl(a, b) a##b
|
||||||
|
#define _ban_concat(a, b) _ban_concat_impl(a, b)
|
||||||
|
|
||||||
|
#define _ban_stringify_impl(x) #x
|
||||||
|
#define _ban_stringify(x) _ban_stringify_impl(x)
|
||||||
|
|
||||||
|
#define _ban_fe_0(f)
|
||||||
|
#define _ban_fe_1(f, _0) f(0, _0)
|
||||||
|
#define _ban_fe_2(f, _0, _1) f(0, _0) f(1, _1)
|
||||||
|
#define _ban_fe_3(f, _0, _1, _2) f(0, _0) f(1, _1) f(2, _2)
|
||||||
|
#define _ban_fe_4(f, _0, _1, _2, _3) f(0, _0) f(1, _1) f(2, _2) f(3, _3)
|
||||||
|
#define _ban_fe_5(f, _0, _1, _2, _3, _4) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4)
|
||||||
|
#define _ban_fe_6(f, _0, _1, _2, _3, _4, _5) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5)
|
||||||
|
#define _ban_fe_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6)
|
||||||
|
#define _ban_fe_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7)
|
||||||
|
#define _ban_fe_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7) f(8, _8)
|
||||||
|
#define _ban_for_each(f, ...) _ban_concat(_ban_fe_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define _ban_fe_comma_0(f)
|
||||||
|
#define _ban_fe_comma_1(f, _0) f(0, _0)
|
||||||
|
#define _ban_fe_comma_2(f, _0, _1) f(0, _0), f(1, _1)
|
||||||
|
#define _ban_fe_comma_3(f, _0, _1, _2) f(0, _0), f(1, _1), f(2, _2)
|
||||||
|
#define _ban_fe_comma_4(f, _0, _1, _2, _3) f(0, _0), f(1, _1), f(2, _2), f(3, _3)
|
||||||
|
#define _ban_fe_comma_5(f, _0, _1, _2, _3, _4) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4)
|
||||||
|
#define _ban_fe_comma_6(f, _0, _1, _2, _3, _4, _5) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5)
|
||||||
|
#define _ban_fe_comma_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6)
|
||||||
|
#define _ban_fe_comma_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7)
|
||||||
|
#define _ban_fe_comma_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7), f(8, _8)
|
||||||
|
#define _ban_for_each_comma(f, ...) _ban_concat(_ban_fe_comma_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define _ban_get_0(a0, ...) a0
|
||||||
|
#define _ban_get_1(a0, a1, ...) a1
|
||||||
|
#define _ban_get_2(a0, a1, a2, ...) a2
|
||||||
|
#define _ban_get_3(a0, a1, a2, a3, ...) a3
|
||||||
|
#define _ban_get_4(a0, a1, a2, a3, a4, ...) a4
|
||||||
|
#define _ban_get_5(a0, a1, a2, a3, a4, a5, ...) a5
|
||||||
|
#define _ban_get_6(a0, a1, a2, a3, a4, a5, a6, ...) a6
|
||||||
|
#define _ban_get_7(a0, a1, a2, a3, a4, a5, a6, a7, ...) a7
|
||||||
|
#define _ban_get_8(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) a8
|
||||||
|
#define _ban_get_9(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
|
||||||
|
#define _ban_get(n, ...) _ban_concat(_ban_get_, n)(__VA_ARGS__)
|
||||||
@@ -6,19 +6,6 @@
|
|||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
// This is ugly but my clangd does not like including
|
|
||||||
// intrinsic headers at all
|
|
||||||
#if !defined(__SSE__) || !defined(__SSE2__)
|
|
||||||
#pragma GCC push_options
|
|
||||||
#ifndef __SSE__
|
|
||||||
#pragma GCC target("sse")
|
|
||||||
#endif
|
|
||||||
#ifndef __SSE2__
|
|
||||||
#pragma GCC target("sse2")
|
|
||||||
#endif
|
|
||||||
#define BAN_MATH_POP_OPTIONS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace BAN::Math
|
namespace BAN::Math
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -49,12 +36,11 @@ namespace BAN::Math
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr T gcd(T a, T b)
|
inline constexpr T gcd(T a, T b)
|
||||||
{
|
{
|
||||||
T t;
|
|
||||||
while (b)
|
while (b)
|
||||||
{
|
{
|
||||||
t = b;
|
T temp = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
a = t;
|
a = temp;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -79,25 +65,20 @@ namespace BAN::Math
|
|||||||
return (x & (x - 1)) == 0;
|
return (x & (x - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<BAN::integral T>
|
template<integral T>
|
||||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||||
{
|
{
|
||||||
if (a == 0 || b == 0)
|
T dummy;
|
||||||
return false;
|
return __builtin_mul_overflow(a, b, &dummy);
|
||||||
if ((a > 0) == (b > 0))
|
|
||||||
return a > BAN::numeric_limits<T>::max() / b;
|
|
||||||
else
|
|
||||||
return a < BAN::numeric_limits<T>::min() / b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<BAN::integral T>
|
template<integral T>
|
||||||
static constexpr bool will_addition_overflow(T a, T b)
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_addition_overflow(T a, T b)
|
||||||
{
|
{
|
||||||
if (a > 0 && b > 0)
|
T dummy;
|
||||||
return a > BAN::numeric_limits<T>::max() - b;
|
return __builtin_add_overflow(a, b, &dummy);
|
||||||
if (a < 0 && b < 0)
|
|
||||||
return a < BAN::numeric_limits<T>::min() - b;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -111,6 +92,19 @@ namespace BAN::Math
|
|||||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is ugly but my clangd does not like including
|
||||||
|
// intrinsic headers at all
|
||||||
|
#if !defined(__SSE__) || !defined(__SSE2__)
|
||||||
|
#pragma GCC push_options
|
||||||
|
#ifndef __SSE__
|
||||||
|
#pragma GCC target("sse")
|
||||||
|
#endif
|
||||||
|
#ifndef __SSE2__
|
||||||
|
#pragma GCC target("sse2")
|
||||||
|
#endif
|
||||||
|
#define BAN_MATH_POP_OPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T floor(T x)
|
inline constexpr T floor(T x)
|
||||||
{
|
{
|
||||||
@@ -172,7 +166,23 @@ namespace BAN::Math
|
|||||||
"jne 1b;"
|
"jne 1b;"
|
||||||
: "+t"(a)
|
: "+t"(a)
|
||||||
: "u"(b)
|
: "u"(b)
|
||||||
: "ax"
|
: "ax", "cc"
|
||||||
|
);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T remainder(T a, T b)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"1:"
|
||||||
|
"fprem1;"
|
||||||
|
"fnstsw %%ax;"
|
||||||
|
"testb $4, %%ah;"
|
||||||
|
"jne 1b;"
|
||||||
|
: "+t"(a)
|
||||||
|
: "u"(b)
|
||||||
|
: "ax", "cc"
|
||||||
);
|
);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -447,9 +457,9 @@ namespace BAN::Math
|
|||||||
return sqrt<T>(x * x + y * y);
|
return sqrt<T>(x * x + y * y);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BAN_MATH_POP_OPTIONS
|
#ifdef BAN_MATH_POP_OPTIONS
|
||||||
#undef BAN_MATH_POP_OPTIONS
|
#undef BAN_MATH_POP_OPTIONS
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -25,6 +25,7 @@ set(KERNEL_SOURCES
|
|||||||
kernel/Epoll.cpp
|
kernel/Epoll.cpp
|
||||||
kernel/Errors.cpp
|
kernel/Errors.cpp
|
||||||
kernel/FS/DevFS/FileSystem.cpp
|
kernel/FS/DevFS/FileSystem.cpp
|
||||||
|
kernel/FS/EventFD.cpp
|
||||||
kernel/FS/Ext2/FileSystem.cpp
|
kernel/FS/Ext2/FileSystem.cpp
|
||||||
kernel/FS/Ext2/Inode.cpp
|
kernel/FS/Ext2/Inode.cpp
|
||||||
kernel/FS/FAT/FileSystem.cpp
|
kernel/FS/FAT/FileSystem.cpp
|
||||||
@@ -138,6 +139,7 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
arch/x86_64/Syscall.S
|
arch/x86_64/Syscall.S
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
|
arch/x86_64/User.S
|
||||||
arch/x86_64/Yield.S
|
arch/x86_64/Yield.S
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
@@ -149,6 +151,7 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
|
|||||||
arch/i686/Signal.S
|
arch/i686/Signal.S
|
||||||
arch/i686/Syscall.S
|
arch/i686/Syscall.S
|
||||||
arch/i686/Thread.S
|
arch/i686/Thread.S
|
||||||
|
arch/i686/User.S
|
||||||
arch/i686/Yield.S
|
arch/i686/Yield.S
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
@@ -165,10 +168,7 @@ set(BAN_SOURCES
|
|||||||
set(KLIBC_SOURCES
|
set(KLIBC_SOURCES
|
||||||
klibc/ctype.cpp
|
klibc/ctype.cpp
|
||||||
klibc/string.cpp
|
klibc/string.cpp
|
||||||
|
klibc/arch/${BANAN_ARCH}/string.S
|
||||||
# Ehhh don't do this but for now libc uses the same stuff kernel can use
|
|
||||||
# This won't work after libc starts using sse implemetations tho
|
|
||||||
../userspace/libraries/LibC/arch/${BANAN_ARCH}/string.S
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBDEFLATE_SOURCE
|
set(LIBDEFLATE_SOURCE
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
|
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
||||||
|
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
||||||
|
|
||||||
|
static bool s_is_post_heap_done = false;
|
||||||
|
|
||||||
static PageTable* s_kernel = nullptr;
|
static PageTable* s_kernel = nullptr;
|
||||||
static bool s_has_nxe = false;
|
static bool s_has_nxe = false;
|
||||||
static bool s_has_pge = false;
|
static bool s_has_pge = false;
|
||||||
@@ -67,7 +72,7 @@ namespace Kernel
|
|||||||
|
|
||||||
void PageTable::initialize_post_heap()
|
void PageTable::initialize_post_heap()
|
||||||
{
|
{
|
||||||
// NOTE: this is no-op as our 32 bit target does not use hhdm
|
s_is_post_heap_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initial_load()
|
void PageTable::initial_load()
|
||||||
@@ -141,9 +146,9 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static vaddr_t P2V(const T paddr)
|
static uint64_t* P2V(const T paddr)
|
||||||
{
|
{
|
||||||
return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET;
|
return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::initialize_kernel()
|
void PageTable::initialize_kernel()
|
||||||
@@ -193,13 +198,18 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
|
||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
ASSERT(pdpt[pdpte] & Flags::Present);
|
ASSERT(pdpt[pdpte] & Flags::Present);
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
ASSERT(!(pd[pde] & Flags::Present));
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
ASSERT(pt[pte] == 0);
|
||||||
|
pt[pte] = Flags::Reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
@@ -214,9 +224,9 @@ namespace Kernel
|
|||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
ASSERT(!(pt[pte] & Flags::Present));
|
ASSERT(!(pt[pte] & Flags::Present));
|
||||||
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
|
||||||
@@ -234,12 +244,12 @@ namespace Kernel
|
|||||||
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
|
||||||
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
|
uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
ASSERT(pt[pte] & Flags::Present);
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
pt[pte] = 0;
|
pt[pte] = Flags::Reserved;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
}
|
}
|
||||||
@@ -263,7 +273,7 @@ namespace Kernel
|
|||||||
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
|
||||||
ASSERT(m_highest_paging_struct);
|
ASSERT(m_highest_paging_struct);
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
pdpt[0] = 0;
|
pdpt[0] = 0;
|
||||||
pdpt[1] = 0;
|
pdpt[1] = 0;
|
||||||
pdpt[2] = 0;
|
pdpt[2] = 0;
|
||||||
@@ -276,18 +286,17 @@ namespace Kernel
|
|||||||
if (m_highest_paging_struct == 0)
|
if (m_highest_paging_struct == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
|
||||||
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint32_t pde = 0; pde < 512; pde++)
|
for (uint32_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
|
kfree(P2V(pd[pde] & s_page_addr_mask));
|
||||||
}
|
}
|
||||||
kfree(pd);
|
kfree(pd);
|
||||||
}
|
}
|
||||||
@@ -298,15 +307,43 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(m_highest_paging_struct < 0x100000000);
|
ASSERT(m_highest_paging_struct < 0x100000000);
|
||||||
const uint32_t pdpt_lo = m_highest_paging_struct;
|
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
|
||||||
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
|
|
||||||
Processor::set_current_page_table(this);
|
Processor::set_current_page_table(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message)
|
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
|
||||||
|
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||||
|
if (is_userspace && this != &PageTable::current())
|
||||||
|
;
|
||||||
|
else if (pages <= 32 || !s_is_post_heap_done)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
||||||
|
}
|
||||||
|
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)
|
if (send_smp_message)
|
||||||
{
|
{
|
||||||
@@ -314,14 +351,14 @@ namespace Kernel
|
|||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
.flush_tlb = {
|
.flush_tlb = {
|
||||||
.vaddr = vaddr,
|
.vaddr = vaddr,
|
||||||
.page_count = 1,
|
.page_count = pages,
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message)
|
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
@@ -340,16 +377,16 @@ namespace Kernel
|
|||||||
if (is_page_free(vaddr))
|
if (is_page_free(vaddr))
|
||||||
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
pt[pte] = 0;
|
pt[pte] = 0;
|
||||||
|
|
||||||
if (old_paddr != 0)
|
if (invalidate && old_paddr != 0)
|
||||||
invalidate(vaddr, send_smp_message);
|
invalidate_page(vaddr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
@@ -361,18 +398,10 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (vaddr_t page = 0; page < page_count; page++)
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
Processor::broadcast_smp_message({
|
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = page_count,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -407,11 +436,11 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
|
||||||
|
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
if ((pd[pde] & uwr_flags) != uwr_flags)
|
if ((pd[pde] & uwr_flags) != uwr_flags)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -422,14 +451,14 @@ namespace Kernel
|
|||||||
if (!(flags & Flags::Present))
|
if (!(flags & Flags::Present))
|
||||||
uwr_flags &= ~Flags::Present;
|
uwr_flags &= ~Flags::Present;
|
||||||
|
|
||||||
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
|
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
|
||||||
|
|
||||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
if (old_paddr != 0)
|
if (invalidate && old_paddr != 0)
|
||||||
invalidate(vaddr, send_smp_message);
|
invalidate_page(vaddr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
@@ -443,15 +472,49 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
Processor::broadcast_smp_message({
|
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
{
|
||||||
.flush_tlb = {
|
ASSERT(vaddr);
|
||||||
.vaddr = vaddr,
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
.page_count = page_count,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
uint32_t pdpte = (vaddr >> 30) & 0x1FF;
|
||||||
|
uint32_t pde = (vaddr >> 21) & 0x1FF;
|
||||||
|
uint32_t pte = (vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF;
|
||||||
|
const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF;
|
||||||
|
const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
|
{
|
||||||
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
|
continue;
|
||||||
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
|
for (; pde < 512; pde++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
|
break;
|
||||||
|
if (!(pd[pde] & Flags::ReadWrite))
|
||||||
|
continue;
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
for (; pte < 512; pte++)
|
||||||
|
{
|
||||||
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
|
break;
|
||||||
|
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
}
|
}
|
||||||
});
|
pde = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
@@ -464,15 +527,15 @@ namespace Kernel
|
|||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (!(pt[pte] & Flags::Used))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -486,8 +549,7 @@ namespace Kernel
|
|||||||
|
|
||||||
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
|
||||||
{
|
{
|
||||||
uint64_t page_data = get_page_data(vaddr);
|
return get_page_data(vaddr) & s_page_addr_mask;
|
||||||
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t vaddr) const
|
bool PageTable::is_page_free(vaddr_t vaddr) const
|
||||||
@@ -529,14 +591,8 @@ namespace Kernel
|
|||||||
return false;
|
return false;
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
reserve_page(vaddr + offset, true, false);
|
reserve_page(vaddr + offset, true, false);
|
||||||
Processor::broadcast_smp_message({
|
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = bytes / PAGE_SIZE,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,48 +605,47 @@ namespace Kernel
|
|||||||
if (size_t rem = last_address % PAGE_SIZE)
|
if (size_t rem = last_address % PAGE_SIZE)
|
||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
|
uint32_t pdpte = (first_address >> 30) & 0x1FF;
|
||||||
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
|
uint32_t pde = (first_address >> 21) & 0x1FF;
|
||||||
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
|
uint32_t pte = (first_address >> 12) & 0x1FF;
|
||||||
|
|
||||||
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
|
const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
|
||||||
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
|
const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
|
||||||
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
|
const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
// Try to find free page that can be mapped without
|
// Try to find free page that can be mapped without
|
||||||
// allocations (page table with unused entries)
|
// allocations (page table with unused entries)
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
|
for (; pdpte <= e_pdpte; pdpte++)
|
||||||
{
|
{
|
||||||
if (pdpte > e_pdpte)
|
|
||||||
break;
|
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint32_t pde = s_pde; pde < 512; pde++)
|
for (; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde > e_pde)
|
if (pdpte == e_pdpte && pde > e_pde)
|
||||||
break;
|
break;
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
for (uint32_t pte = s_pte; pte < 512; pte++)
|
for (; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
break;
|
break;
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (pt[pte] & Flags::Used)
|
||||||
{
|
continue;
|
||||||
vaddr_t vaddr = 0;
|
vaddr_t vaddr = 0;
|
||||||
vaddr |= (vaddr_t)pdpte << 30;
|
vaddr |= (vaddr_t)pdpte << 30;
|
||||||
vaddr |= (vaddr_t)pde << 21;
|
vaddr |= (vaddr_t)pde << 21;
|
||||||
vaddr |= (vaddr_t)pte << 12;
|
vaddr |= (vaddr_t)pte << 12;
|
||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pte = 0;
|
||||||
}
|
}
|
||||||
|
pde = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any free page
|
// Find any free page
|
||||||
@@ -603,7 +658,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
@@ -636,7 +691,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
|
||||||
@@ -659,7 +714,7 @@ namespace Kernel
|
|||||||
flags_t flags = 0;
|
flags_t flags = 0;
|
||||||
vaddr_t start = 0;
|
vaddr_t start = 0;
|
||||||
|
|
||||||
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
|
const uint64_t* pdpt = P2V(m_highest_paging_struct);
|
||||||
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
|
||||||
{
|
{
|
||||||
if (!(pdpt[pdpte] & Flags::Present))
|
if (!(pdpt[pdpte] & Flags::Present))
|
||||||
@@ -668,7 +723,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
|
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
for (uint64_t pde = 0; pde < 512; pde++)
|
for (uint64_t pde = 0; pde < 512; pde++)
|
||||||
{
|
{
|
||||||
if (!(pd[pde] & Flags::Present))
|
if (!(pd[pde] & Flags::Present))
|
||||||
@@ -677,7 +732,7 @@ namespace Kernel
|
|||||||
start = 0;
|
start = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
for (uint64_t pte = 0; pte < 512; pte++)
|
for (uint64_t pte = 0; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (parse_flags(pt[pte]) != flags)
|
if (parse_flags(pt[pte]) != flags)
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
.section .userspace, "ax"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// return address
|
// (4 bytes) return address (on return stack)
|
||||||
// return stack
|
// (4 bytes) return stack
|
||||||
// return rflags
|
// (4 bytes) return rflags
|
||||||
// siginfo_t
|
// (8 bytes) restore sigmask
|
||||||
// signal number
|
// (36 bytes) siginfo_t
|
||||||
// signal handler
|
// (4 bytes) signal number
|
||||||
|
// (4 bytes) signal handler
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
@@ -18,6 +19,10 @@ signal_trampoline:
|
|||||||
pushl %eax
|
pushl %eax
|
||||||
pushl %ebp
|
pushl %ebp
|
||||||
|
|
||||||
|
movl 80(%esp), %eax
|
||||||
|
pushl %eax; addl $4, (%esp)
|
||||||
|
pushl (%eax)
|
||||||
|
|
||||||
// FIXME: populate these
|
// FIXME: populate these
|
||||||
xorl %eax, %eax
|
xorl %eax, %eax
|
||||||
pushl %eax // stack
|
pushl %eax // stack
|
||||||
@@ -28,9 +33,9 @@ signal_trampoline:
|
|||||||
pushl %eax // link
|
pushl %eax // link
|
||||||
|
|
||||||
movl %esp, %edx // ucontext
|
movl %esp, %edx // ucontext
|
||||||
leal 60(%esp), %esi // siginfo
|
leal 68(%esp), %esi // siginfo
|
||||||
movl 56(%esp), %edi // signal number
|
movl 64(%esp), %edi // signal number
|
||||||
movl 52(%esp), %eax // handlers
|
movl 60(%esp), %eax // handlers
|
||||||
|
|
||||||
// align stack to 16 bytes
|
// align stack to 16 bytes
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
@@ -53,7 +58,15 @@ signal_trampoline:
|
|||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
addl $24, %esp
|
addl $24, %esp
|
||||||
|
|
||||||
|
// restore sigmask
|
||||||
|
movl $83, %eax // SYS_SIGPROCMASK
|
||||||
|
movl $3, %ebx // SIG_SETMASK
|
||||||
|
leal 72(%esp), %ecx // set
|
||||||
|
xorl %edx, %edx // oset
|
||||||
|
int $0xF0
|
||||||
|
|
||||||
// restore registers
|
// restore registers
|
||||||
|
addl $8, %esp
|
||||||
popl %ebp
|
popl %ebp
|
||||||
popl %eax
|
popl %eax
|
||||||
popl %ebx
|
popl %ebx
|
||||||
@@ -62,8 +75,8 @@ signal_trampoline:
|
|||||||
popl %edi
|
popl %edi
|
||||||
popl %esi
|
popl %esi
|
||||||
|
|
||||||
// skip handler, number, siginfo_t
|
// skip handler, number, siginfo_t, sigmask
|
||||||
addl $44, %esp
|
addl $52, %esp
|
||||||
|
|
||||||
// restore flags
|
// restore flags
|
||||||
popf
|
popf
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testl %eax, %eax
|
testl %eax, %eax
|
||||||
jz .reload_stack
|
jz .done
|
||||||
|
|
||||||
movl %esp, %ebx
|
movl %esp, %ebx
|
||||||
|
|
||||||
@@ -79,9 +79,3 @@ sys_fork_trampoline:
|
|||||||
popl %ebx
|
popl %ebx
|
||||||
popl %ebp
|
popl %ebp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.reload_stack:
|
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .done
|
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ read_ip:
|
|||||||
# void start_kernel_thread()
|
# void start_kernel_thread()
|
||||||
.global start_kernel_thread
|
.global start_kernel_thread
|
||||||
start_kernel_thread:
|
start_kernel_thread:
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
|
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
# on_exit arg
|
# on_exit arg
|
||||||
# on_exit func
|
# on_exit func
|
||||||
@@ -34,9 +31,6 @@ start_kernel_thread:
|
|||||||
|
|
||||||
.global start_userspace_thread
|
.global start_userspace_thread
|
||||||
start_userspace_thread:
|
start_userspace_thread:
|
||||||
call get_thread_start_sp
|
|
||||||
movl %eax, %esp
|
|
||||||
|
|
||||||
movw $(0x20 | 3), %bx
|
movw $(0x20 | 3), %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
movw %bx, %es
|
movw %bx, %es
|
||||||
|
|||||||
54
kernel/arch/i686/User.S
Normal file
54
kernel/arch/i686/User.S
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorl %eax, %eax
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep movsb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
incl %eax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_loop:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incl %edi
|
||||||
|
incl %esi
|
||||||
|
decl %ecx
|
||||||
|
jnz .safe_user_strncpy_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorl %eax, %eax
|
||||||
|
jmp .safe_user_strncpy_return
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movl $1, %eax
|
||||||
|
|
||||||
|
.safe_user_strncpy_return:
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
ret
|
||||||
|
|
||||||
|
safe_user_strncpy_end:
|
||||||
@@ -11,13 +11,14 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
# multiboot2 header
|
// video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
.align 8
|
|
||||||
multiboot_start:
|
multiboot_start:
|
||||||
.long 0x1BADB002
|
.long 0x1BADB002
|
||||||
.long (1 << 2) # page align modules
|
.long multiboot_flags
|
||||||
.long -(0x1BADB002 + (1 << 2))
|
.long -(0x1BADB002 + multiboot_flags)
|
||||||
|
|
||||||
.long 0
|
.long 0
|
||||||
.long 0
|
.long 0
|
||||||
@@ -30,7 +31,8 @@ multiboot_start:
|
|||||||
.long FB_HEIGHT
|
.long FB_HEIGHT
|
||||||
.long FB_BPP
|
.long FB_BPP
|
||||||
multiboot_end:
|
multiboot_end:
|
||||||
.align 8
|
|
||||||
|
.section .multiboot2, "aw"
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -66,7 +68,6 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
.macro maybe_load_kernel_segments, n
|
.macro intr_header, n
|
||||||
testb $3, \n(%esp)
|
pushal
|
||||||
jz 1f; jnp 1f
|
testb $3, \n+8*4(%esp)
|
||||||
|
jz 1f
|
||||||
movw $0x10, %ax
|
movw $0x10, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
movw %ax, %fs
|
movw %ax, %fs
|
||||||
movw $0x28, %ax
|
movw $0x28, %ax
|
||||||
movw %ax, %gs
|
movw %ax, %gs
|
||||||
1:
|
1: cld
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro maybe_load_userspace_segments, n
|
.macro intr_footer, n
|
||||||
testb $3, \n(%esp)
|
testb $3, \n+8*4(%esp)
|
||||||
jz 1f; jnp 1f
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
movw $(0x20 | 3), %bx
|
movw $(0x20 | 3), %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
movw %bx, %es
|
movw %bx, %es
|
||||||
@@ -22,14 +22,11 @@
|
|||||||
movw %bx, %fs
|
movw %bx, %fs
|
||||||
movw $(0x38 | 3), %bx
|
movw $(0x38 | 3), %bx
|
||||||
movw %bx, %gs
|
movw %bx, %gs
|
||||||
1:
|
1: popal
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
pushal
|
intr_header 12
|
||||||
maybe_load_kernel_segments 44
|
|
||||||
cld
|
|
||||||
|
|
||||||
movl %cr0, %eax; pushl %eax
|
movl %cr0, %eax; pushl %eax
|
||||||
movl %cr2, %eax; pushl %eax
|
movl %cr2, %eax; pushl %eax
|
||||||
movl %cr3, %eax; pushl %eax
|
movl %cr3, %eax; pushl %eax
|
||||||
@@ -57,15 +54,12 @@ isr_stub:
|
|||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
addl $24, %esp
|
addl $24, %esp
|
||||||
|
|
||||||
maybe_load_userspace_segments 44
|
intr_footer 12
|
||||||
popal
|
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pushal
|
intr_header 12
|
||||||
maybe_load_kernel_segments 44
|
|
||||||
cld
|
|
||||||
|
|
||||||
movl 32(%esp), %edi # interrupt number
|
movl 32(%esp), %edi # interrupt number
|
||||||
|
|
||||||
@@ -78,16 +72,13 @@ irq_stub:
|
|||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
maybe_load_userspace_segments 44
|
intr_footer 12
|
||||||
popal
|
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.global asm_ipi_handler
|
.global asm_ipi_handler
|
||||||
asm_ipi_handler:
|
asm_ipi_handler:
|
||||||
pushal
|
intr_header 4
|
||||||
maybe_load_kernel_segments 36
|
|
||||||
cld
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
andl $-16, %esp
|
||||||
@@ -96,15 +87,12 @@ asm_ipi_handler:
|
|||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
maybe_load_userspace_segments 36
|
intr_footer 4
|
||||||
popal
|
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.global asm_timer_handler
|
.global asm_timer_handler
|
||||||
asm_timer_handler:
|
asm_timer_handler:
|
||||||
pushal
|
intr_header 4
|
||||||
maybe_load_kernel_segments 36
|
|
||||||
cld
|
|
||||||
|
|
||||||
movl %esp, %ebp
|
movl %esp, %ebp
|
||||||
andl $-16, %esp
|
andl $-16, %esp
|
||||||
@@ -113,8 +101,7 @@ asm_timer_handler:
|
|||||||
|
|
||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
maybe_load_userspace_segments 36
|
intr_footer 4
|
||||||
popal
|
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
*(.multiboot2)
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Kernel
|
|||||||
SpinLock PageTable::s_fast_page_lock;
|
SpinLock PageTable::s_fast_page_lock;
|
||||||
|
|
||||||
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
|
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
|
||||||
static bool s_is_hddm_initialized = false;
|
static bool s_is_post_heap_done = false;
|
||||||
|
|
||||||
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
|
||||||
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
|
||||||
@@ -376,7 +376,7 @@ namespace Kernel
|
|||||||
V2P = &FuncsHHDM::V2P;
|
V2P = &FuncsHHDM::V2P;
|
||||||
P2V = &FuncsHHDM::P2V;
|
P2V = &FuncsHHDM::P2V;
|
||||||
|
|
||||||
s_is_hddm_initialized = true;
|
s_is_post_heap_done = true;
|
||||||
|
|
||||||
// This is a hack to unmap fast page. fast page pt is copied
|
// This is a hack to unmap fast page. fast page pt is copied
|
||||||
// while it is mapped, so we need to manually unmap it
|
// while it is mapped, so we need to manually unmap it
|
||||||
@@ -485,6 +485,7 @@ namespace Kernel
|
|||||||
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
|
||||||
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
|
||||||
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
|
||||||
|
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
|
||||||
|
|
||||||
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||||
ASSERT(!(pml4[pml4e] & Flags::Present));
|
ASSERT(!(pml4[pml4e] & Flags::Present));
|
||||||
@@ -497,6 +498,10 @@ namespace Kernel
|
|||||||
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
|
||||||
ASSERT(!(pd[pde] & Flags::Present));
|
ASSERT(!(pd[pde] & Flags::Present));
|
||||||
pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present;
|
pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
ASSERT(pt[pte] == 0);
|
||||||
|
pt[pte] = Flags::Reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_fast_page(paddr_t paddr)
|
void PageTable::map_fast_page(paddr_t paddr)
|
||||||
@@ -542,7 +547,7 @@ namespace Kernel
|
|||||||
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
|
|
||||||
ASSERT(pt[pte] & Flags::Present);
|
ASSERT(pt[pte] & Flags::Present);
|
||||||
pt[pte] = 0;
|
pt[pte] = Flags::Reserved;
|
||||||
|
|
||||||
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
|
||||||
}
|
}
|
||||||
@@ -612,10 +617,39 @@ namespace Kernel
|
|||||||
Processor::set_current_page_table(this);
|
Processor::set_current_page_table(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message)
|
void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
|
|
||||||
|
const bool is_userspace = (vaddr < KERNEL_OFFSET);
|
||||||
|
if (is_userspace && this != &PageTable::current())
|
||||||
|
;
|
||||||
|
else if (pages <= 32 || !s_is_post_heap_done)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
|
||||||
|
asm volatile("invlpg (%0)" :: "r"(vaddr));
|
||||||
|
}
|
||||||
|
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)
|
if (send_smp_message)
|
||||||
{
|
{
|
||||||
@@ -623,14 +657,14 @@ namespace Kernel
|
|||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
.type = Processor::SMPMessage::Type::FlushTLB,
|
||||||
.flush_tlb = {
|
.flush_tlb = {
|
||||||
.vaddr = vaddr,
|
.vaddr = vaddr,
|
||||||
.page_count = 1,
|
.page_count = pages,
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message)
|
void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -663,31 +697,23 @@ namespace Kernel
|
|||||||
|
|
||||||
pt[pte] = 0;
|
pt[pte] = 0;
|
||||||
|
|
||||||
if (old_paddr != 0)
|
if (invalidate && old_paddr != 0)
|
||||||
invalidate(vaddr, send_smp_message);
|
invalidate_page(vaddr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
|
|
||||||
size_t page_count = range_page_count(vaddr, size);
|
const size_t page_count = range_page_count(vaddr, size);
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (vaddr_t page = 0; page < page_count; page++)
|
for (vaddr_t page = 0; page < page_count; page++)
|
||||||
unmap_page(vaddr + page * PAGE_SIZE, false);
|
unmap_page(vaddr + page * PAGE_SIZE, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
Processor::broadcast_smp_message({
|
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = page_count,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
@@ -752,8 +778,8 @@ namespace Kernel
|
|||||||
|
|
||||||
pt[pte] = paddr | uwr_flags | extra_flags;
|
pt[pte] = paddr | uwr_flags | extra_flags;
|
||||||
|
|
||||||
if (old_paddr != 0)
|
if (invalidate && old_paddr != 0)
|
||||||
invalidate(vaddr, send_smp_message);
|
invalidate_page(vaddr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
@@ -769,15 +795,66 @@ namespace Kernel
|
|||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
|
||||||
|
invalidate_range(vaddr, page_count, true);
|
||||||
|
}
|
||||||
|
|
||||||
Processor::broadcast_smp_message({
|
void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
{
|
||||||
.flush_tlb = {
|
ASSERT(vaddr);
|
||||||
.vaddr = vaddr,
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
.page_count = page_count,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
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);
|
||||||
|
|
||||||
|
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||||
|
for (; pml4e <= e_pml4e; pml4e++)
|
||||||
|
{
|
||||||
|
if (!(pml4[pml4e] & Flags::ReadWrite))
|
||||||
|
continue;
|
||||||
|
const 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::ReadWrite))
|
||||||
|
continue;
|
||||||
|
const 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::ReadWrite))
|
||||||
|
continue;
|
||||||
|
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] &= ~static_cast<uint64_t>(Flags::ReadWrite);
|
||||||
|
}
|
||||||
|
pte = 0;
|
||||||
|
}
|
||||||
|
pde = 0;
|
||||||
}
|
}
|
||||||
});
|
pdpte = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate_range(vaddr, size / PAGE_SIZE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
@@ -824,13 +901,13 @@ namespace Kernel
|
|||||||
return page_data & s_page_addr_mask;
|
return page_data & s_page_addr_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
|
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool invalidate)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||||
if (only_free && !is_page_free(vaddr))
|
if (only_free && !is_page_free(vaddr))
|
||||||
return false;
|
return false;
|
||||||
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
|
map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, invalidate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,14 +922,7 @@ namespace Kernel
|
|||||||
return false;
|
return false;
|
||||||
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
|
||||||
reserve_page(vaddr + offset, true, false);
|
reserve_page(vaddr + offset, true, false);
|
||||||
Processor::broadcast_smp_message({
|
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
|
||||||
.type = Processor::SMPMessage::Type::FlushTLB,
|
|
||||||
.flush_tlb = {
|
|
||||||
.vaddr = vaddr,
|
|
||||||
.page_count = bytes / PAGE_SIZE,
|
|
||||||
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,9 +936,9 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address));
|
ASSERT(is_canonical(last_address - 1));
|
||||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
const vaddr_t uc_vaddr_end = uncanonicalize(last_address - 1);
|
||||||
|
|
||||||
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
|
||||||
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
|
||||||
@@ -885,10 +955,8 @@ namespace Kernel
|
|||||||
// Try to find free page that can be mapped without
|
// Try to find free page that can be mapped without
|
||||||
// allocations (page table with unused entries)
|
// allocations (page table with unused entries)
|
||||||
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
const uint64_t* pml4 = P2V(m_highest_paging_struct);
|
||||||
for (; pml4e < 512; pml4e++)
|
for (; pml4e <= e_pml4e; pml4e++)
|
||||||
{
|
{
|
||||||
if (pml4e > e_pml4e)
|
|
||||||
break;
|
|
||||||
if (!(pml4[pml4e] & Flags::Present))
|
if (!(pml4[pml4e] & Flags::Present))
|
||||||
continue;
|
continue;
|
||||||
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
|
||||||
@@ -908,22 +976,24 @@ namespace Kernel
|
|||||||
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
|
||||||
for (; pte < 512; pte++)
|
for (; pte < 512; pte++)
|
||||||
{
|
{
|
||||||
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
|
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
|
||||||
break;
|
break;
|
||||||
if (!(pt[pte] & Flags::Used))
|
if (pt[pte] & Flags::Used)
|
||||||
{
|
continue;
|
||||||
vaddr_t vaddr = 0;
|
vaddr_t vaddr = 0;
|
||||||
vaddr |= static_cast<uint64_t>(pml4e) << 39;
|
vaddr |= static_cast<uint64_t>(pml4e) << 39;
|
||||||
vaddr |= static_cast<uint64_t>(pdpte) << 30;
|
vaddr |= static_cast<uint64_t>(pdpte) << 30;
|
||||||
vaddr |= static_cast<uint64_t>(pde) << 21;
|
vaddr |= static_cast<uint64_t>(pde) << 21;
|
||||||
vaddr |= static_cast<uint64_t>(pte) << 12;
|
vaddr |= static_cast<uint64_t>(pte) << 12;
|
||||||
vaddr = canonicalize(vaddr);
|
vaddr = canonicalize(vaddr);
|
||||||
ASSERT(reserve_page(vaddr));
|
ASSERT(reserve_page(vaddr));
|
||||||
return vaddr;
|
return vaddr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pte = 0;
|
||||||
}
|
}
|
||||||
|
pde = 0;
|
||||||
}
|
}
|
||||||
|
pdpte = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE)
|
for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE)
|
||||||
@@ -935,7 +1005,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
|
||||||
@@ -948,7 +1018,7 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address));
|
ASSERT(is_canonical(last_address - 1));
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
@@ -977,7 +1047,7 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageTable::is_page_free(vaddr_t page) const
|
bool PageTable::is_page_free(vaddr_t page) const
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
.section .userspace, "ax"
|
.section .userspace, "ax"
|
||||||
|
|
||||||
// stack contains
|
// stack contains
|
||||||
// return address
|
// (8 bytes) return address (on return stack)
|
||||||
// return stack
|
// (8 bytes) return stack
|
||||||
// return rflags
|
// (8 bytes) return rflags
|
||||||
// siginfo_t
|
// (8 bytes) restore sigmask
|
||||||
// signal number
|
// (56 bytes) siginfo_t
|
||||||
// signal handler
|
// (8 bytes) signal number
|
||||||
|
// (8 bytes) signal handler
|
||||||
|
|
||||||
.global signal_trampoline
|
.global signal_trampoline
|
||||||
signal_trampoline:
|
signal_trampoline:
|
||||||
@@ -26,6 +27,10 @@ signal_trampoline:
|
|||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rbp
|
pushq %rbp
|
||||||
|
|
||||||
|
movq 208(%rsp), %rax
|
||||||
|
pushq %rax; addq $(128 + 8), (%rsp)
|
||||||
|
pushq (%rax)
|
||||||
|
|
||||||
// FIXME: populate these
|
// FIXME: populate these
|
||||||
xorq %rax, %rax
|
xorq %rax, %rax
|
||||||
pushq %rax // stack
|
pushq %rax // stack
|
||||||
@@ -35,9 +40,9 @@ signal_trampoline:
|
|||||||
pushq %rax // link
|
pushq %rax // link
|
||||||
|
|
||||||
movq %rsp, %rdx // ucontext
|
movq %rsp, %rdx // ucontext
|
||||||
leaq 176(%rsp), %rsi // siginfo
|
leaq 192(%rsp), %rsi // siginfo
|
||||||
movq 168(%rsp), %rdi // signal number
|
movq 184(%rsp), %rdi // signal number
|
||||||
movq 160(%rsp), %rax // handler
|
movq 176(%rsp), %rax // handler
|
||||||
|
|
||||||
// align stack to 16 bytes
|
// align stack to 16 bytes
|
||||||
movq %rsp, %rbp
|
movq %rsp, %rbp
|
||||||
@@ -55,7 +60,15 @@ signal_trampoline:
|
|||||||
movq %rbp, %rsp
|
movq %rbp, %rsp
|
||||||
addq $40, %rsp
|
addq $40, %rsp
|
||||||
|
|
||||||
|
// restore sigmask
|
||||||
|
movq $83, %rdi // SYS_SIGPROCMASK
|
||||||
|
movq $3, %rsi // SIG_SETMASK
|
||||||
|
leaq 192(%rsp), %rdx // set
|
||||||
|
xorq %r10, %r10 // oset
|
||||||
|
syscall
|
||||||
|
|
||||||
// restore registers
|
// restore registers
|
||||||
|
addq $16, %rsp
|
||||||
popq %rbp
|
popq %rbp
|
||||||
popq %rax
|
popq %rax
|
||||||
popq %rbx
|
popq %rbx
|
||||||
@@ -72,13 +85,13 @@ signal_trampoline:
|
|||||||
popq %r14
|
popq %r14
|
||||||
popq %r15
|
popq %r15
|
||||||
|
|
||||||
// skip handler, number, siginfo_t
|
// skip handler, number, siginfo_t, sigmask
|
||||||
addq $72, %rsp
|
addq $80, %rsp
|
||||||
|
|
||||||
// restore flags
|
// restore flags
|
||||||
popfq
|
popfq
|
||||||
|
|
||||||
movq (%rsp), %rsp
|
movq (%rsp), %rsp
|
||||||
|
|
||||||
// return over red-zone and siginfo_t
|
// return over red-zone
|
||||||
ret $128
|
ret $128
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ sys_fork_trampoline:
|
|||||||
|
|
||||||
call read_ip
|
call read_ip
|
||||||
testq %rax, %rax
|
testq %rax, %rax
|
||||||
je .done
|
jz .done
|
||||||
|
|
||||||
movq %rax, %rsi
|
movq %rax, %rsi
|
||||||
movq %rsp, %rdi
|
movq %rsp, %rdi
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ read_ip:
|
|||||||
# void start_kernel_thread()
|
# void start_kernel_thread()
|
||||||
.global start_kernel_thread
|
.global start_kernel_thread
|
||||||
start_kernel_thread:
|
start_kernel_thread:
|
||||||
call get_thread_start_sp
|
|
||||||
movq %rax, %rsp
|
|
||||||
|
|
||||||
# STACK LAYOUT
|
# STACK LAYOUT
|
||||||
# on_exit arg
|
# on_exit arg
|
||||||
# on_exit func
|
# on_exit func
|
||||||
@@ -27,9 +24,5 @@ start_kernel_thread:
|
|||||||
|
|
||||||
.global start_userspace_thread
|
.global start_userspace_thread
|
||||||
start_userspace_thread:
|
start_userspace_thread:
|
||||||
call get_thread_start_sp
|
|
||||||
movq %rax, %rsp
|
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
|
|||||||
87
kernel/arch/x86_64/User.S
Normal file
87
kernel/arch/x86_64/User.S
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorq %rax, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep movsb
|
||||||
|
incq %rax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_loop:
|
||||||
|
testb $0x7, %sil
|
||||||
|
jz .safe_user_strncpy_align_done
|
||||||
|
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_align_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_done:
|
||||||
|
movq $0x0101010101010101, %r8
|
||||||
|
movq $0x8080808080808080, %r9
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_loop:
|
||||||
|
cmpq $8, %rcx
|
||||||
|
jb .safe_user_strncpy_qword_done
|
||||||
|
|
||||||
|
movq (%rsi), %rax
|
||||||
|
movq %rax, %r10
|
||||||
|
movq %rax, %r11
|
||||||
|
|
||||||
|
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
|
||||||
|
subq %r8, %r10
|
||||||
|
notq %r11
|
||||||
|
andq %r11, %r10
|
||||||
|
andq %r9, %r10
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
movq %rax, (%rdi)
|
||||||
|
|
||||||
|
addq $8, %rdi
|
||||||
|
addq $8, %rsi
|
||||||
|
subq $8, %rcx
|
||||||
|
jnz .safe_user_strncpy_qword_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_done:
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_byte_loop:
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movb $1, %al
|
||||||
|
ret
|
||||||
|
safe_user_strncpy_end:
|
||||||
@@ -11,26 +11,28 @@
|
|||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
# multiboot2 header
|
// custom addresses, video mode info, page align modules
|
||||||
|
.set multiboot_flags, (1 << 16) | (1 << 2) | (1 << 0)
|
||||||
|
|
||||||
.section .multiboot, "aw"
|
.section .multiboot, "aw"
|
||||||
.align 8
|
|
||||||
multiboot_start:
|
multiboot_start:
|
||||||
.long 0x1BADB002
|
.long 0x1BADB002
|
||||||
.long (1 << 2) # page align modules
|
.long multiboot_flags
|
||||||
.long -(0x1BADB002 + (1 << 2))
|
.long -(0x1BADB002 + multiboot_flags)
|
||||||
|
|
||||||
.long 0
|
.long V2P(multiboot_start)
|
||||||
.long 0
|
.long V2P(g_kernel_start)
|
||||||
.long 0
|
.long V2P(g_kernel_bss_start)
|
||||||
.long 0
|
.long V2P(g_kernel_end)
|
||||||
.long 0
|
.long V2P(_start)
|
||||||
|
|
||||||
.long 0
|
.long 0
|
||||||
.long FB_WIDTH
|
.long FB_WIDTH
|
||||||
.long FB_HEIGHT
|
.long FB_HEIGHT
|
||||||
.long FB_BPP
|
.long FB_BPP
|
||||||
multiboot_end:
|
multiboot_end:
|
||||||
.align 8
|
|
||||||
|
.section .multiboot2, "aw"
|
||||||
multiboot2_start:
|
multiboot2_start:
|
||||||
.long 0xE85250D6
|
.long 0xE85250D6
|
||||||
.long 0
|
.long 0
|
||||||
@@ -66,7 +68,6 @@ multiboot2_start:
|
|||||||
multiboot2_end:
|
multiboot2_end:
|
||||||
|
|
||||||
.section .bananboot, "aw"
|
.section .bananboot, "aw"
|
||||||
.align 8
|
|
||||||
bananboot_start:
|
bananboot_start:
|
||||||
.long 0xBABAB007
|
.long 0xBABAB007
|
||||||
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
.macro swapgs_if_necessary, n
|
.macro intr_header, n
|
||||||
testb $3, \n(%rsp)
|
|
||||||
jz 1f; jnp 1f
|
|
||||||
swapgs
|
|
||||||
1:
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro pushaq, n
|
|
||||||
swapgs_if_necessary \n
|
|
||||||
pushq %rax
|
pushq %rax
|
||||||
pushq %rcx
|
pushq %rcx
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
@@ -22,10 +14,18 @@
|
|||||||
pushq %r13
|
pushq %r13
|
||||||
pushq %r14
|
pushq %r14
|
||||||
pushq %r15
|
pushq %r15
|
||||||
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
swapgs
|
||||||
|
1: cld
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro popaq, n
|
.macro intr_footer, n
|
||||||
popq %r15
|
testb $3, \n+15*8(%rsp)
|
||||||
|
jz 1f
|
||||||
|
call cpp_check_signal
|
||||||
|
swapgs
|
||||||
|
1: popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
popq %r12
|
popq %r12
|
||||||
@@ -40,12 +40,10 @@
|
|||||||
popq %rdx
|
popq %rdx
|
||||||
popq %rcx
|
popq %rcx
|
||||||
popq %rax
|
popq %rax
|
||||||
swapgs_if_necessary \n
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
isr_stub:
|
isr_stub:
|
||||||
pushaq 24
|
intr_header 24
|
||||||
cld
|
|
||||||
movq %cr0, %rax; pushq %rax
|
movq %cr0, %rax; pushq %rax
|
||||||
movq %cr2, %rax; pushq %rax
|
movq %cr2, %rax; pushq %rax
|
||||||
movq %cr3, %rax; pushq %rax
|
movq %cr3, %rax; pushq %rax
|
||||||
@@ -58,33 +56,33 @@ isr_stub:
|
|||||||
call cpp_isr_handler
|
call cpp_isr_handler
|
||||||
addq $32, %rsp
|
addq $32, %rsp
|
||||||
|
|
||||||
popaq 24
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
irq_stub:
|
irq_stub:
|
||||||
pushaq 24
|
intr_header 24
|
||||||
cld
|
xorq %rbp, %rbp
|
||||||
movq 120(%rsp), %rdi # irq number
|
movq 120(%rsp), %rdi # irq number
|
||||||
call cpp_irq_handler
|
call cpp_irq_handler
|
||||||
popaq 24
|
intr_footer 24
|
||||||
addq $16, %rsp
|
addq $16, %rsp
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
.global asm_ipi_handler
|
.global asm_ipi_handler
|
||||||
asm_ipi_handler:
|
asm_ipi_handler:
|
||||||
pushaq 8
|
intr_header 8
|
||||||
cld
|
xorq %rbp, %rbp
|
||||||
call cpp_ipi_handler
|
call cpp_ipi_handler
|
||||||
popaq 8
|
intr_footer 8
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
.global asm_timer_handler
|
.global asm_timer_handler
|
||||||
asm_timer_handler:
|
asm_timer_handler:
|
||||||
pushaq 8
|
intr_header 8
|
||||||
cld
|
xorq %rbp, %rbp
|
||||||
call cpp_timer_handler
|
call cpp_timer_handler
|
||||||
popaq 8
|
intr_footer 8
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
.macro isr n
|
.macro isr n
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
g_kernel_execute_start = .;
|
g_kernel_execute_start = .;
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
*(.multiboot2)
|
||||||
*(.bananboot)
|
*(.bananboot)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,7 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
|
||||||
{
|
{
|
||||||
|
g_kernel_bss_start = .;
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
g_kernel_writable_end = .;
|
g_kernel_writable_end = .;
|
||||||
|
|||||||
@@ -1,44 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Attributes.h>
|
#include <BAN/MacroUtils.h>
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
#if defined(__x86_64__)
|
||||||
{
|
#define _kas_instruction "syscall"
|
||||||
|
#define _kas_result rax
|
||||||
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
|
#define _kas_arguments rdi, rsi, rdx, r10, r8, r9
|
||||||
{
|
#define _kas_globbers rcx, rdx, rdi, rsi, r8, r9, r10, r11
|
||||||
long ret;
|
#elif defined(__i686__)
|
||||||
#if ARCH(x86_64)
|
#define _kas_instruction "int $0xF0"
|
||||||
register uintptr_t r10 asm("r10") = arg3;
|
#define _kas_result eax
|
||||||
register uintptr_t r8 asm( "r8") = arg4;
|
#define _kas_arguments eax, ebx, ecx, edx, esi, edi
|
||||||
register uintptr_t r9 asm( "r9") = arg5;
|
#define _kas_globbers
|
||||||
asm volatile(
|
|
||||||
"syscall"
|
|
||||||
: "=a"(ret)
|
|
||||||
, "+D"(syscall)
|
|
||||||
, "+S"(arg1)
|
|
||||||
, "+d"(arg2)
|
|
||||||
, "+r"(r10)
|
|
||||||
, "+r"(r8)
|
|
||||||
, "+r"(r9)
|
|
||||||
:: "rcx", "r11", "memory");
|
|
||||||
#elif ARCH(i686)
|
|
||||||
asm volatile(
|
|
||||||
"int %[irq]"
|
|
||||||
: "=a"(ret)
|
|
||||||
: [irq]"i"(static_cast<int>(IRQ_SYSCALL)) // WTF GCC 15
|
|
||||||
, "a"(syscall)
|
|
||||||
, "b"(arg1)
|
|
||||||
, "c"(arg2)
|
|
||||||
, "d"(arg3)
|
|
||||||
, "S"(arg4)
|
|
||||||
, "D"(arg5)
|
|
||||||
: "memory");
|
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
#define _kas_argument_var(index, value) register long _kas_a##index asm(_ban_stringify(_ban_get(index, _kas_arguments))) = (long)value;
|
||||||
|
#define _kas_dummy_var(index, value) register long _kas_d##index asm(#value);
|
||||||
|
#define _kas_input(index, _) "r"(_kas_a##index)
|
||||||
|
#define _kas_output(index, _) , "=r"(_kas_d##index)
|
||||||
|
#define _kas_globber(_, value) #value
|
||||||
|
|
||||||
|
#define _kas_syscall(...) ({ \
|
||||||
|
register long _kas_ret asm(_ban_stringify(_kas_result)); \
|
||||||
|
_ban_for_each(_kas_argument_var, __VA_ARGS__) \
|
||||||
|
_ban_for_each(_kas_dummy_var, _kas_globbers) \
|
||||||
|
asm volatile( \
|
||||||
|
_kas_instruction \
|
||||||
|
: "=r"(_kas_ret) _ban_for_each(_kas_output, _kas_globbers) \
|
||||||
|
: _ban_for_each_comma(_kas_input, __VA_ARGS__) \
|
||||||
|
: "cc", "memory"); \
|
||||||
|
(void)_kas_a0; /* require 1 argument */ \
|
||||||
|
_kas_ret; \
|
||||||
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class AC97AudioController : public AudioController, public Interruptable
|
class AC97AudioController final : public AudioController, public Interruptable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||||
@@ -23,11 +23,15 @@ namespace Kernel
|
|||||||
uint32_t get_current_pin() const override { return 0; }
|
uint32_t get_current_pin() const override { return 0; }
|
||||||
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
|
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AC97AudioController(PCI::Device& pci_device)
|
AC97AudioController(PCI::Device& pci_device)
|
||||||
: m_pci_device(pci_device)
|
: m_pci_device(pci_device)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
uint32_t get_volume_data() const;
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
BAN::ErrorOr<void> initialize_bld();
|
BAN::ErrorOr<void> initialize_bld();
|
||||||
BAN::ErrorOr<void> initialize_interrupts();
|
BAN::ErrorOr<void> initialize_interrupts();
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/Device/Device.h>
|
#include <kernel/Device/Device.h>
|
||||||
|
#include <kernel/Memory/ByteRingBuffer.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -16,6 +19,7 @@ namespace Kernel
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
AudioController();
|
AudioController();
|
||||||
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
virtual void handle_new_data() = 0;
|
virtual void handle_new_data() = 0;
|
||||||
|
|
||||||
@@ -26,8 +30,10 @@ namespace Kernel
|
|||||||
virtual uint32_t get_current_pin() const = 0;
|
virtual uint32_t get_current_pin() const = 0;
|
||||||
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
|
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
|
||||||
|
|
||||||
bool can_read_impl() const override { return false; }
|
bool can_read_impl() const override { return false; }
|
||||||
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return m_sample_data_size < m_sample_data_capacity; }
|
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
|
||||||
bool has_error_impl() const override { return false; }
|
bool has_error_impl() const override { return false; }
|
||||||
bool has_hungup_impl() const override { return false; }
|
bool has_hungup_impl() const override { return false; }
|
||||||
|
|
||||||
@@ -40,9 +46,9 @@ namespace Kernel
|
|||||||
mutable SpinLock m_spinlock;
|
mutable SpinLock m_spinlock;
|
||||||
|
|
||||||
static constexpr size_t m_sample_data_capacity = 1 << 20;
|
static constexpr size_t m_sample_data_capacity = 1 << 20;
|
||||||
uint8_t m_sample_data[m_sample_data_capacity];
|
BAN::UniqPtr<ByteRingBuffer> m_sample_data;
|
||||||
size_t m_sample_data_head { 0 };
|
|
||||||
size_t m_sample_data_size { 0 };
|
snd_volume_info m_volume_info {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const dev_t m_rdev;
|
const dev_t m_rdev;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Kernel
|
|||||||
|
|
||||||
class HDAudioController;
|
class HDAudioController;
|
||||||
|
|
||||||
class HDAudioFunctionGroup : public AudioController
|
class HDAudioFunctionGroup final : public AudioController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
||||||
@@ -24,6 +24,8 @@ namespace Kernel
|
|||||||
uint32_t get_current_pin() const override;
|
uint32_t get_current_pin() const override;
|
||||||
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
|
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||||
|
|
||||||
void handle_new_data() override;
|
void handle_new_data() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -46,15 +48,12 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
||||||
|
|
||||||
uint16_t get_format_data() const;
|
uint16_t get_format_data() const;
|
||||||
uint16_t get_volume_data() const;
|
|
||||||
|
|
||||||
size_t bdl_offset() const;
|
size_t bdl_offset() const;
|
||||||
|
|
||||||
void queue_bdl_data();
|
void queue_bdl_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t m_max_path_length = 16;
|
|
||||||
|
|
||||||
// use 6 512 sample BDL entries
|
// use 6 512 sample BDL entries
|
||||||
// each entry is ~10.7 ms at 48 kHz
|
// each entry is ~10.7 ms at 48 kHz
|
||||||
// -> total buffered audio is 64 ms
|
// -> total buffered audio is 64 ms
|
||||||
@@ -66,6 +65,7 @@ namespace Kernel
|
|||||||
const uint8_t m_cid;
|
const uint8_t m_cid;
|
||||||
|
|
||||||
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
||||||
|
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
|
||||||
size_t m_output_path_index { SIZE_MAX };
|
size_t m_output_path_index { SIZE_MAX };
|
||||||
|
|
||||||
uint8_t m_stream_id { 0xFF };
|
uint8_t m_stream_id { 0xFF };
|
||||||
|
|||||||
@@ -50,9 +50,21 @@ namespace Kernel::HDAudio
|
|||||||
{
|
{
|
||||||
bool input;
|
bool input;
|
||||||
bool output;
|
bool output;
|
||||||
|
bool display; // HDMI or DP
|
||||||
|
uint32_t config;
|
||||||
} pin_complex;
|
} pin_complex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Amplifier
|
||||||
|
{
|
||||||
|
uint8_t offset;
|
||||||
|
uint8_t num_steps;
|
||||||
|
uint8_t step_size;
|
||||||
|
bool mute;
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::Optional<Amplifier> output_amplifier;
|
||||||
|
|
||||||
BAN::Vector<uint16_t> connections;
|
BAN::Vector<uint16_t> connections;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace Kernel::HDAudio
|
|||||||
VMIN = 0x02,
|
VMIN = 0x02,
|
||||||
VMAJ = 0x03,
|
VMAJ = 0x03,
|
||||||
GCTL = 0x08,
|
GCTL = 0x08,
|
||||||
|
STATESTS = 0x0E,
|
||||||
|
|
||||||
INTCTL = 0x20,
|
INTCTL = 0x20,
|
||||||
INTSTS = 0x24,
|
INTSTS = 0x24,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace Kernel
|
|||||||
struct BootModule
|
struct BootModule
|
||||||
{
|
{
|
||||||
paddr_t start;
|
paddr_t start;
|
||||||
size_t size;
|
uint64_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BootInfo
|
struct BootInfo
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace Kernel
|
|||||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
|
||||||
|
|
||||||
virtual bool can_read_impl() const override { return true; }
|
virtual bool can_read_impl() const override { return true; }
|
||||||
virtual bool can_write_impl() const override { return true; }
|
virtual bool can_write_impl() const override { return true; }
|
||||||
virtual bool has_error_impl() const override { return false; }
|
virtual bool has_error_impl() const override { return false; }
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/BootInfo.h>
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/FS/FileSystem.h>
|
#include <kernel/FS/Inode.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
bool is_ustar_boot_module(const BootModule&);
|
BAN::ErrorOr<bool> unpack_boot_module_into_directory(BAN::RefPtr<Inode>, const BootModule&);
|
||||||
BAN::ErrorOr<void> unpack_boot_module_into_filesystem(BAN::RefPtr<FileSystem>, const BootModule&);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Kernel
|
|||||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||||
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
constexpr uint8_t IRQ_MSI_END = 0xF0;
|
||||||
#if ARCH(i686)
|
#if ARCH(i686)
|
||||||
constexpr uint8_t IRQ_SYSCALL = 0xF0;
|
constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
|
||||||
#endif
|
#endif
|
||||||
constexpr uint8_t IRQ_IPI = 0xF1;
|
constexpr uint8_t IRQ_IPI = 0xF1;
|
||||||
constexpr uint8_t IRQ_TIMER = 0xF2;
|
constexpr uint8_t IRQ_TIMER = 0xF2;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ namespace Kernel
|
|||||||
static void initialize();
|
static void initialize();
|
||||||
static Heap& get();
|
static Heap& get();
|
||||||
|
|
||||||
|
void release_boot_modules();
|
||||||
|
|
||||||
paddr_t take_free_page();
|
paddr_t take_free_page();
|
||||||
void release_page(paddr_t);
|
void release_page(paddr_t);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ namespace Kernel
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
|
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PhysicalPage
|
||||||
|
{
|
||||||
|
PhysicalPage(paddr_t paddr)
|
||||||
|
: paddr(paddr)
|
||||||
|
{ }
|
||||||
|
~PhysicalPage();
|
||||||
|
|
||||||
|
BAN::Atomic<uint32_t> ref_count { 1 };
|
||||||
|
const paddr_t paddr;
|
||||||
|
};
|
||||||
|
BAN::Vector<PhysicalPage*> m_physical_pages;
|
||||||
|
Mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,19 +100,21 @@ namespace Kernel
|
|||||||
static BAN::ErrorOr<PageTable*> create_userspace();
|
static BAN::ErrorOr<PageTable*> create_userspace();
|
||||||
~PageTable();
|
~PageTable();
|
||||||
|
|
||||||
void unmap_page(vaddr_t, bool send_smp_message = true);
|
void unmap_page(vaddr_t, bool invalidate = true);
|
||||||
void unmap_range(vaddr_t, size_t bytes);
|
void unmap_range(vaddr_t, size_t bytes);
|
||||||
|
|
||||||
void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool send_smp_message = true);
|
void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool invalidate = true);
|
||||||
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal);
|
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal);
|
||||||
|
|
||||||
|
void remove_writable_from_range(vaddr_t, size_t);
|
||||||
|
|
||||||
paddr_t physical_address_of(vaddr_t) const;
|
paddr_t physical_address_of(vaddr_t) const;
|
||||||
flags_t get_page_flags(vaddr_t) const;
|
flags_t get_page_flags(vaddr_t) const;
|
||||||
|
|
||||||
bool is_page_free(vaddr_t) const;
|
bool is_page_free(vaddr_t) const;
|
||||||
bool is_range_free(vaddr_t, size_t bytes) const;
|
bool is_range_free(vaddr_t, size_t bytes) const;
|
||||||
|
|
||||||
bool reserve_page(vaddr_t, bool only_free = true, bool send_smp_message = true);
|
bool reserve_page(vaddr_t, bool only_free = true, bool invalidate = true);
|
||||||
bool reserve_range(vaddr_t, size_t bytes, bool only_free = true);
|
bool reserve_range(vaddr_t, size_t bytes, bool only_free = true);
|
||||||
|
|
||||||
vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
|
vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
|
||||||
@@ -121,6 +123,9 @@ namespace Kernel
|
|||||||
void load();
|
void load();
|
||||||
void initial_load();
|
void initial_load();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
InterruptState lock() const { return m_lock.lock(); }
|
InterruptState lock() const { return m_lock.lock(); }
|
||||||
void unlock(InterruptState state) const { m_lock.unlock(state); }
|
void unlock(InterruptState state) const { m_lock.unlock(state); }
|
||||||
|
|
||||||
@@ -133,8 +138,6 @@ namespace Kernel
|
|||||||
void map_kernel_memory();
|
void map_kernel_memory();
|
||||||
void prepare_fast_page();
|
void prepare_fast_page();
|
||||||
|
|
||||||
void invalidate(vaddr_t, bool send_smp_message);
|
|
||||||
|
|
||||||
static void map_fast_page(paddr_t);
|
static void map_fast_page(paddr_t);
|
||||||
static void unmap_fast_page();
|
static void unmap_fast_page();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Kernel
|
|||||||
class PhysicalRange
|
class PhysicalRange
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PhysicalRange(paddr_t, size_t);
|
PhysicalRange(paddr_t, uint64_t);
|
||||||
|
|
||||||
paddr_t reserve_page();
|
paddr_t reserve_page();
|
||||||
void release_page(paddr_t);
|
void release_page(paddr_t);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
#define KERNEL_OFFSET 0xFFFFFFFF80000000
|
#define KERNEL_OFFSET 0xFFFFFFFF80000000
|
||||||
#define USERSPACE_END 0xFFFF800000000000
|
#define USERSPACE_END 0x800000000000
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
#define KERNEL_OFFSET 0xC0000000
|
#define KERNEL_OFFSET 0xC0000000
|
||||||
#define USERSPACE_END 0xC0000000
|
#define USERSPACE_END 0xC0000000
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ namespace Kernel
|
|||||||
static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages);
|
static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages);
|
||||||
~VirtualRange();
|
~VirtualRange();
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> clone(PageTable&);
|
|
||||||
|
|
||||||
vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); }
|
vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); }
|
||||||
size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); }
|
size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); }
|
||||||
PageTable::flags_t flags() const { return m_flags; }
|
PageTable::flags_t flags() const { return m_flags; }
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ namespace Kernel
|
|||||||
void close_all();
|
void close_all();
|
||||||
void close_cloexec();
|
void close_cloexec();
|
||||||
|
|
||||||
|
bool is_cloexec(int fd);
|
||||||
|
void add_cloexec(int fd);
|
||||||
|
void remove_cloexec(int fd);
|
||||||
|
|
||||||
BAN::ErrorOr<void> flock(int fd, int op);
|
BAN::ErrorOr<void> flock(int fd, int op);
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
||||||
@@ -84,27 +88,6 @@ namespace Kernel
|
|||||||
friend class BAN::RefPtr<OpenFileDescription>;
|
friend class BAN::RefPtr<OpenFileDescription>;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OpenFile
|
|
||||||
{
|
|
||||||
OpenFile() = default;
|
|
||||||
OpenFile(BAN::RefPtr<OpenFileDescription> description, int descriptor_flags)
|
|
||||||
: description(BAN::move(description))
|
|
||||||
, descriptor_flags(descriptor_flags)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
BAN::RefPtr<Inode> inode() const { ASSERT(description); return description->file.inode; }
|
|
||||||
BAN::StringView path() const { ASSERT(description); return description->file.canonical_path.sv(); }
|
|
||||||
|
|
||||||
int& status_flags() { ASSERT(description); return description->status_flags; }
|
|
||||||
const int& status_flags() const { ASSERT(description); return description->status_flags; }
|
|
||||||
|
|
||||||
off_t& offset() { ASSERT(description); return description->offset; }
|
|
||||||
const off_t& offset() const { ASSERT(description); return description->offset; }
|
|
||||||
|
|
||||||
BAN::RefPtr<OpenFileDescription> description;
|
|
||||||
int descriptor_flags { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> validate_fd(int) const;
|
BAN::ErrorOr<void> validate_fd(int) const;
|
||||||
BAN::ErrorOr<int> get_free_fd() const;
|
BAN::ErrorOr<int> get_free_fd() const;
|
||||||
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
|
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
|
||||||
@@ -139,7 +122,8 @@ namespace Kernel
|
|||||||
const Credentials& m_credentials;
|
const Credentials& m_credentials;
|
||||||
mutable Mutex m_mutex;
|
mutable Mutex m_mutex;
|
||||||
|
|
||||||
BAN::Array<OpenFile, OPEN_MAX> m_open_files;
|
BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> m_open_files;
|
||||||
|
BAN::Array<uint32_t, (OPEN_MAX + 31) / 32> m_cloexec_files {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace Kernel
|
|||||||
InterruptStack* m_interrupt_stack { nullptr };
|
InterruptStack* m_interrupt_stack { nullptr };
|
||||||
InterruptRegisters* m_interrupt_registers { nullptr };
|
InterruptRegisters* m_interrupt_registers { nullptr };
|
||||||
|
|
||||||
uint64_t m_last_reschedule_ns { 0 };
|
uint64_t m_next_reschedule_ns { 0 };
|
||||||
uint64_t m_last_load_balance_ns { 0 };
|
uint64_t m_last_load_balance_ns { 0 };
|
||||||
|
|
||||||
struct ThreadInfo
|
struct ThreadInfo
|
||||||
|
|||||||
@@ -38,8 +38,12 @@ namespace Kernel
|
|||||||
// stack overflows on some machines with 8 page stack
|
// stack overflows on some machines with 8 page stack
|
||||||
static constexpr size_t kernel_stack_size { PAGE_SIZE * 16 };
|
static constexpr size_t kernel_stack_size { PAGE_SIZE * 16 };
|
||||||
|
|
||||||
// TODO: userspace stack is hard limited to 32 MiB, maybe make this dynamic?
|
// TODO: userspace stack size is hard limited, maybe make this dynamic?
|
||||||
|
#if ARCH(x86_64)
|
||||||
static constexpr size_t userspace_stack_size { 32 << 20 };
|
static constexpr size_t userspace_stack_size { 32 << 20 };
|
||||||
|
#elif ARCH(i686)
|
||||||
|
static constexpr size_t userspace_stack_size { 4 << 20 };
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
|
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
|
||||||
@@ -56,12 +60,10 @@ namespace Kernel
|
|||||||
// Returns true, if thread is going to trigger signal
|
// Returns true, if thread is going to trigger signal
|
||||||
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
||||||
|
|
||||||
// Returns true if pending signal can be added to thread
|
|
||||||
bool can_add_signal_to_execute() const;
|
|
||||||
bool will_execute_signal() const;
|
|
||||||
// Returns true if handled signal had SA_RESTART
|
// Returns true if handled signal had SA_RESTART
|
||||||
bool handle_signal(int signal = 0, const siginfo_t& signal_info = {});
|
bool handle_signal_if_interrupted();
|
||||||
void add_signal(int signal, const siginfo_t& info);
|
bool handle_signal(int signal, const siginfo_t&);
|
||||||
|
void add_signal(int signal, const siginfo_t&);
|
||||||
void set_suspend_signal_mask(uint64_t sigmask);
|
void set_suspend_signal_mask(uint64_t sigmask);
|
||||||
|
|
||||||
static bool is_stopping_signal(int signal);
|
static bool is_stopping_signal(int signal);
|
||||||
@@ -153,6 +155,16 @@ namespace Kernel
|
|||||||
|
|
||||||
bool currently_on_alternate_stack() const;
|
bool currently_on_alternate_stack() const;
|
||||||
|
|
||||||
|
struct signal_handle_info_t
|
||||||
|
{
|
||||||
|
vaddr_t handler;
|
||||||
|
vaddr_t stack_top;
|
||||||
|
uint64_t restore_sigmask;
|
||||||
|
bool has_sa_restart;
|
||||||
|
};
|
||||||
|
signal_handle_info_t remove_signal_and_get_info(int signal);
|
||||||
|
void handle_signal_impl(int signal, const siginfo_t&, const signal_handle_info_t&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NOTE: this is the first member to force it being last destructed
|
// NOTE: this is the first member to force it being last destructed
|
||||||
// {kernel,userspace}_stack has to be destroyed before page table
|
// {kernel,userspace}_stack has to be destroyed before page table
|
||||||
@@ -166,7 +178,9 @@ namespace Kernel
|
|||||||
bool m_is_userspace { false };
|
bool m_is_userspace { false };
|
||||||
bool m_delete_process { false };
|
bool m_delete_process { false };
|
||||||
|
|
||||||
|
bool m_has_custom_fsbase { false };
|
||||||
vaddr_t m_fsbase { 0 };
|
vaddr_t m_fsbase { 0 };
|
||||||
|
bool m_has_custom_gsbase { false };
|
||||||
vaddr_t m_gsbase { 0 };
|
vaddr_t m_gsbase { 0 };
|
||||||
|
|
||||||
SchedulerQueue::Node* m_scheduler_node { nullptr };
|
SchedulerQueue::Node* m_scheduler_node { nullptr };
|
||||||
|
|||||||
@@ -531,11 +531,8 @@ acpi_release_global_lock:
|
|||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s5_node.as.package->elements[0].resolved || !s5_node.as.package->elements[1].resolved)
|
TRY(AML::resolve_package_element(s5_node.as.package->elements[0], true));
|
||||||
{
|
TRY(AML::resolve_package_element(s5_node.as.package->elements[1], true));
|
||||||
dwarnln("TODO: lazy evaluate package \\_S5 elements");
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto slp_typa_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[0].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));
|
auto slp_typa_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[0].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));
|
||||||
auto slp_typb_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[1].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));
|
auto slp_typb_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[1].value.node->copy()), AML::ConvInteger, sizeof(uint64_t)));
|
||||||
|
|||||||
@@ -118,6 +118,8 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> AC97AudioController::initialize()
|
BAN::ErrorOr<void> AC97AudioController::initialize()
|
||||||
{
|
{
|
||||||
|
TRY(AudioController::initialize());
|
||||||
|
|
||||||
m_pci_device.enable_bus_mastering();
|
m_pci_device.enable_bus_mastering();
|
||||||
|
|
||||||
m_mixer = TRY(m_pci_device.allocate_bar_region(0));
|
m_mixer = TRY(m_pci_device.allocate_bar_region(0));
|
||||||
@@ -135,8 +137,27 @@ namespace Kernel
|
|||||||
// Reset mixer to default values
|
// Reset mixer to default values
|
||||||
m_mixer->write16(AudioMixerRegister::Reset, 0);
|
m_mixer->write16(AudioMixerRegister::Reset, 0);
|
||||||
|
|
||||||
// Master volume 100%, no mute
|
// Master volumes
|
||||||
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x0000);
|
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x2020);
|
||||||
|
if (m_mixer->read16(AudioMixerRegister::MasterVolume) == 0x2020)
|
||||||
|
{
|
||||||
|
m_volume_info = {
|
||||||
|
.min_mdB = -94500,
|
||||||
|
.max_mdB = 0,
|
||||||
|
.step_mdB = 1500,
|
||||||
|
.mdB = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_volume_info = {
|
||||||
|
.min_mdB = -46500,
|
||||||
|
.max_mdB = 0,
|
||||||
|
.step_mdB = 1500,
|
||||||
|
.mdB = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
|
||||||
|
|
||||||
// PCM output volume left/right +0 db, no mute
|
// PCM output volume left/right +0 db, no mute
|
||||||
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
|
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
|
||||||
@@ -185,6 +206,19 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t AC97AudioController::get_volume_data() const
|
||||||
|
{
|
||||||
|
const uint32_t steps = (-m_volume_info.mdB + m_volume_info.step_mdB / 2) / m_volume_info.step_mdB;
|
||||||
|
return (steps << 8) | steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
|
||||||
|
{
|
||||||
|
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void AC97AudioController::handle_new_data()
|
void AC97AudioController::handle_new_data()
|
||||||
{
|
{
|
||||||
ASSERT(m_spinlock.current_processor_has_lock());
|
ASSERT(m_spinlock.current_processor_has_lock());
|
||||||
@@ -203,23 +237,22 @@ namespace Kernel
|
|||||||
if (next_bld_head == m_bdl_tail)
|
if (next_bld_head == m_bdl_tail)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const size_t sample_data_tail = (m_sample_data_head + m_sample_data_capacity - m_sample_data_size) % m_sample_data_capacity;
|
const size_t sample_frames = BAN::Math::min(m_sample_data->size() / get_channels() / sizeof(uint16_t), m_samples_per_entry / get_channels());
|
||||||
|
if (sample_frames == 0)
|
||||||
const size_t max_memcpy = BAN::Math::min(m_sample_data_size, m_sample_data_capacity - sample_data_tail);
|
|
||||||
const size_t samples = BAN::Math::min(max_memcpy / 2, m_samples_per_entry);
|
|
||||||
if (samples == 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t);
|
||||||
|
|
||||||
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head];
|
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head];
|
||||||
entry.samples = samples;
|
entry.samples = sample_frames * get_channels();
|
||||||
entry.flags = (1 << 15);
|
entry.flags = (1 << 15);
|
||||||
memcpy(
|
memcpy(
|
||||||
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
|
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
|
||||||
&m_sample_data[sample_data_tail],
|
m_sample_data->get_data().data(),
|
||||||
samples * 2
|
copy_total_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
m_sample_data_size -= samples * 2;
|
m_sample_data->pop(copy_total_bytes);
|
||||||
|
|
||||||
lvi = m_bdl_head;
|
lvi = m_bdl_head;
|
||||||
m_bdl_head = next_bld_head;
|
m_bdl_head = next_bld_head;
|
||||||
|
|||||||
@@ -53,34 +53,28 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AudioController::initialize()
|
||||||
|
{
|
||||||
|
m_sample_data = TRY(ByteRingBuffer::create(m_sample_data_capacity));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer)
|
BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer)
|
||||||
{
|
{
|
||||||
SpinLockGuard lock_guard(m_spinlock);
|
SpinLockGuard lock_guard(m_spinlock);
|
||||||
|
|
||||||
while (m_sample_data_size >= m_sample_data_capacity)
|
while (m_sample_data->full())
|
||||||
{
|
{
|
||||||
SpinLockGuardAsMutex smutex(lock_guard);
|
SpinLockGuardAsMutex smutex(lock_guard);
|
||||||
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
|
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nwritten = 0;
|
const size_t to_copy = BAN::Math::min(buffer.size(), m_sample_data->free());
|
||||||
while (nwritten < buffer.size())
|
m_sample_data->push(buffer.slice(0, to_copy));
|
||||||
{
|
|
||||||
if (m_sample_data_size >= m_sample_data_capacity)
|
|
||||||
break;
|
|
||||||
|
|
||||||
const size_t max_memcpy = BAN::Math::min(m_sample_data_capacity - m_sample_data_size, m_sample_data_capacity - m_sample_data_head);
|
|
||||||
const size_t to_copy = BAN::Math::min(buffer.size() - nwritten, max_memcpy);
|
|
||||||
memcpy(m_sample_data + m_sample_data_head, buffer.data() + nwritten, to_copy);
|
|
||||||
|
|
||||||
nwritten += to_copy;
|
|
||||||
m_sample_data_head = (m_sample_data_head + to_copy) % m_sample_data_capacity;
|
|
||||||
m_sample_data_size += to_copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_new_data();
|
handle_new_data();
|
||||||
|
|
||||||
return nwritten;
|
return to_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg)
|
BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg)
|
||||||
@@ -97,9 +91,9 @@ namespace Kernel
|
|||||||
case SND_GET_BUFFERSZ:
|
case SND_GET_BUFFERSZ:
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_spinlock);
|
SpinLockGuard _(m_spinlock);
|
||||||
*static_cast<uint32_t*>(arg) = m_sample_data_size;
|
*static_cast<uint32_t*>(arg) = m_sample_data->size();
|
||||||
if (cmd == SND_RESET_BUFFER)
|
if (cmd == SND_RESET_BUFFER)
|
||||||
m_sample_data_size = 0;
|
m_sample_data->pop(m_sample_data->size());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SND_GET_TOTAL_PINS:
|
case SND_GET_TOTAL_PINS:
|
||||||
@@ -111,6 +105,12 @@ namespace Kernel
|
|||||||
case SND_SET_PIN:
|
case SND_SET_PIN:
|
||||||
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
|
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
|
||||||
return 0;
|
return 0;
|
||||||
|
case SND_GET_VOLUME_INFO:
|
||||||
|
*static_cast<snd_volume_info*>(arg) = m_volume_info;
|
||||||
|
return 0;
|
||||||
|
case SND_SET_VOLUME_MDB:
|
||||||
|
TRY(set_volume_mdB(*static_cast<int32_t*>(arg)));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CharacterDevice::ioctl_impl(cmd, arg);
|
return CharacterDevice::ioctl_impl(cmd, arg);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include <kernel/Audio/HDAudio/Registers.h>
|
#include <kernel/Audio/HDAudio/Registers.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
|
|
||||||
|
#include <BAN/Sort.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -25,6 +27,8 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize()
|
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize()
|
||||||
{
|
{
|
||||||
|
TRY(AudioController::initialize());
|
||||||
|
|
||||||
if constexpr(DEBUG_HDAUDIO)
|
if constexpr(DEBUG_HDAUDIO)
|
||||||
{
|
{
|
||||||
const auto widget_to_string =
|
const auto widget_to_string =
|
||||||
@@ -50,19 +54,13 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (widget.type == HDAudio::AFGWidget::Type::PinComplex)
|
if (widget.type == HDAudio::AFGWidget::Type::PinComplex)
|
||||||
{
|
{
|
||||||
const uint32_t config = TRY(m_controller->send_command({
|
dprintln(" widget {}: {} ({}, {}, {}), {32b}",
|
||||||
.data = 0x00,
|
|
||||||
.command = 0xF1C,
|
|
||||||
.node_index = widget.id,
|
|
||||||
.codec_address = m_cid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
dprintln(" widget {}: {} ({}, {}), {32b}",
|
|
||||||
widget.id,
|
widget.id,
|
||||||
widget_to_string(widget.type),
|
widget_to_string(widget.type),
|
||||||
(int)widget.pin_complex.output,
|
(int)widget.pin_complex.output,
|
||||||
(int)widget.pin_complex.input,
|
(int)widget.pin_complex.input,
|
||||||
config
|
(int)widget.pin_complex.display,
|
||||||
|
widget.pin_complex.config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -79,59 +77,49 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
TRY(initialize_stream());
|
TRY(initialize_stream());
|
||||||
TRY(initialize_output());
|
|
||||||
|
if (auto ret = initialize_output(); ret.is_error())
|
||||||
|
{
|
||||||
|
// No usable pins, not really an error
|
||||||
|
if (ret.error().get_error_code() == ENODEV)
|
||||||
|
return {};
|
||||||
|
return ret.release_error();
|
||||||
|
}
|
||||||
|
|
||||||
DevFileSystem::get().add_device(this);
|
DevFileSystem::get().add_device(this);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HDAudioFunctionGroup::get_total_pins() const
|
uint32_t HDAudioFunctionGroup::get_total_pins() const
|
||||||
{
|
{
|
||||||
uint32_t count = 0;
|
return m_output_pins.size();
|
||||||
for (const auto& widget : m_afg_node.widgets)
|
|
||||||
if (widget.type == HDAudio::AFGWidget::Type::PinComplex && widget.pin_complex.output)
|
|
||||||
count++;
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HDAudioFunctionGroup::get_current_pin() const
|
uint32_t HDAudioFunctionGroup::get_current_pin() const
|
||||||
{
|
{
|
||||||
const auto current_id = m_output_paths[m_output_path_index].front()->id;
|
const auto current_id = m_output_paths[m_output_path_index].front()->id;
|
||||||
|
for (size_t i = 0; i < m_output_pins.size(); i++)
|
||||||
uint32_t pin = 0;
|
if (m_output_pins[i]->id == current_id)
|
||||||
for (const auto& widget : m_afg_node.widgets)
|
return i;
|
||||||
{
|
|
||||||
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
|
|
||||||
continue;
|
|
||||||
if (widget.id == current_id)
|
|
||||||
return pin;
|
|
||||||
pin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::set_current_pin(uint32_t pin)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::set_current_pin(uint32_t pin)
|
||||||
{
|
{
|
||||||
uint32_t pin_id = 0;
|
if (pin >= m_output_pins.size())
|
||||||
for (const auto& widget : m_afg_node.widgets)
|
return BAN::Error::from_errno(EINVAL);
|
||||||
{
|
|
||||||
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
|
|
||||||
continue;
|
|
||||||
if (pin-- > 0)
|
|
||||||
continue;
|
|
||||||
pin_id = widget.id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto ret = disable_output_path(m_output_path_index); ret.is_error())
|
if (auto ret = disable_output_path(m_output_path_index); ret.is_error())
|
||||||
dwarnln("failed to disable old output path {}", ret.error());
|
dwarnln("failed to disable old output path {}", ret.error());
|
||||||
|
|
||||||
|
const uint32_t pin_id = m_output_pins[pin]->id;
|
||||||
for (size_t i = 0; i < m_output_paths.size(); i++)
|
for (size_t i = 0; i < m_output_paths.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_output_paths[i].front()->id != pin_id)
|
if (m_output_paths[i].front()->id != pin_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (auto ret = enable_output_path(i); !ret.is_error())
|
if (auto ret = enable_output_path(i); ret.is_error())
|
||||||
{
|
{
|
||||||
if (ret.error().get_error_code() == ENOTSUP)
|
if (ret.error().get_error_code() == ENOTSUP)
|
||||||
continue;
|
continue;
|
||||||
@@ -139,7 +127,6 @@ namespace Kernel
|
|||||||
return ret.release_error();
|
return ret.release_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintln("set output widget to {}", pin_id);
|
|
||||||
m_output_path_index = i;
|
m_output_path_index = i;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -149,6 +136,37 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
|
||||||
|
{
|
||||||
|
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
|
||||||
|
const auto& path = m_output_paths[m_output_path_index];
|
||||||
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
if (!path[i]->output_amplifier.has_value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int32_t step_round = (mdB >= 0)
|
||||||
|
? +m_volume_info.step_mdB / 2
|
||||||
|
: -m_volume_info.step_mdB / 2;
|
||||||
|
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset;
|
||||||
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
||||||
|
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_volume_info.mdB = mdB;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
size_t HDAudioFunctionGroup::bdl_offset() const
|
size_t HDAudioFunctionGroup::bdl_offset() const
|
||||||
{
|
{
|
||||||
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
|
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
|
||||||
@@ -230,18 +248,39 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize_output()
|
BAN::ErrorOr<void> HDAudioFunctionGroup::initialize_output()
|
||||||
{
|
{
|
||||||
BAN::Vector<const HDAudio::AFGWidget*> path;
|
|
||||||
TRY(path.reserve(m_max_path_length));
|
|
||||||
|
|
||||||
for (const auto& widget : m_afg_node.widgets)
|
for (const auto& widget : m_afg_node.widgets)
|
||||||
{
|
{
|
||||||
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
|
if (widget.type != HDAudio::AFGWidget::Type::PinComplex || !widget.pin_complex.output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// no physical connection
|
||||||
|
if ((widget.pin_complex.config >> 30) == 0b01)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// needs a GPU
|
||||||
|
if (widget.pin_complex.display)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BAN::Vector<const HDAudio::AFGWidget*> path;
|
||||||
TRY(path.push_back(&widget));
|
TRY(path.push_back(&widget));
|
||||||
TRY(recurse_output_paths(widget, path));
|
TRY(recurse_output_paths(widget, path));
|
||||||
path.pop_back();
|
|
||||||
|
if (!m_output_paths.empty() && m_output_paths.back().front()->id == widget.id)
|
||||||
|
TRY(m_output_pins.push_back(&widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_output_pins.empty())
|
||||||
|
return BAN::Error::from_errno(ENODEV);
|
||||||
|
|
||||||
|
// prefer short paths
|
||||||
|
BAN::sort::sort(m_output_paths.begin(), m_output_paths.end(),
|
||||||
|
[](const auto& a, const auto& b) {
|
||||||
|
if (a.front()->id != b.front()->id)
|
||||||
|
return a.front()->id < b.front()->id;
|
||||||
|
return a.size() < b.size();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
dprintln_if(DEBUG_HDAUDIO, "found {} paths from output to DAC", m_output_paths.size());
|
dprintln_if(DEBUG_HDAUDIO, "found {} paths from output to DAC", m_output_paths.size());
|
||||||
|
|
||||||
// select first supported path
|
// select first supported path
|
||||||
@@ -283,13 +322,6 @@ namespace Kernel
|
|||||||
return 0b0'0'000'000'0'001'0001;
|
return 0b0'0'000'000'0'001'0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t HDAudioFunctionGroup::get_volume_data() const
|
|
||||||
{
|
|
||||||
// TODO: don't hardcode this
|
|
||||||
// left and right output, no mute, max gain
|
|
||||||
return 0b1'0'1'1'0000'0'1111111;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
||||||
{
|
{
|
||||||
ASSERT(index < m_output_paths.size());
|
ASSERT(index < m_output_paths.size());
|
||||||
@@ -310,7 +342,6 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto format = get_format_data();
|
const auto format = get_format_data();
|
||||||
const auto volume = get_volume_data();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < path.size(); i++)
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -339,13 +370,17 @@ namespace Kernel
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set volume
|
// set volume to 0 dB, no mute
|
||||||
TRY(m_controller->send_command({
|
if (path[i]->output_amplifier.has_value())
|
||||||
.data = static_cast<uint8_t>(volume & 0xFF),
|
{
|
||||||
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | path[i]->output_amplifier->offset;
|
||||||
.node_index = path[i]->id,
|
TRY(m_controller->send_command({
|
||||||
.codec_address = m_cid,
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
}));
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
switch (path[i]->type)
|
switch (path[i]->type)
|
||||||
{
|
{
|
||||||
@@ -390,6 +425,41 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update volume info to this path
|
||||||
|
m_volume_info.min_mdB = 0;
|
||||||
|
m_volume_info.max_mdB = 0;
|
||||||
|
m_volume_info.step_mdB = 0;
|
||||||
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
if (!path[i]->output_amplifier.has_value())
|
||||||
|
continue;
|
||||||
|
const auto& amp = path[i]->output_amplifier.value();
|
||||||
|
|
||||||
|
const int32_t step_mdB = amp.step_size * 250;
|
||||||
|
m_volume_info.step_mdB = step_mdB;
|
||||||
|
m_volume_info.min_mdB = -amp.offset * step_mdB;
|
||||||
|
m_volume_info.max_mdB = (amp.num_steps - amp.offset) * step_mdB;
|
||||||
|
m_volume_info.mdB = BAN::Math::clamp(m_volume_info.mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
|
||||||
|
const int32_t step_round = (m_volume_info.mdB >= 0)
|
||||||
|
? +step_mdB / 2
|
||||||
|
: -step_mdB / 2;
|
||||||
|
const uint32_t step = (m_volume_info.mdB + step_round) / step_mdB + amp.offset;
|
||||||
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
||||||
|
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
|
||||||
|
m_volume_info.mdB = 0;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,10 +512,6 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path)
|
||||||
{
|
{
|
||||||
// cycle "detection"
|
|
||||||
if (path.size() >= m_max_path_length)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// we've reached a DAC
|
// we've reached a DAC
|
||||||
if (widget.type == HDAudio::AFGWidget::Type::OutputConverter)
|
if (widget.type == HDAudio::AFGWidget::Type::OutputConverter)
|
||||||
{
|
{
|
||||||
@@ -462,9 +528,18 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (!widget.connections.contains(connection.id))
|
if (!widget.connections.contains(connection.id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// cycle detection
|
||||||
|
for (const auto* w : path)
|
||||||
|
if (w == &connection)
|
||||||
|
goto already_visited;
|
||||||
|
|
||||||
TRY(path.push_back(&connection));
|
TRY(path.push_back(&connection));
|
||||||
TRY(recurse_output_paths(connection, path));
|
TRY(recurse_output_paths(connection, path));
|
||||||
path.pop_back();
|
path.pop_back();
|
||||||
|
|
||||||
|
already_visited:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@@ -483,30 +558,18 @@ namespace Kernel
|
|||||||
|
|
||||||
while ((m_bdl_head + 1) % m_bdl_entry_count != m_bdl_tail)
|
while ((m_bdl_head + 1) % m_bdl_entry_count != m_bdl_tail)
|
||||||
{
|
{
|
||||||
const size_t sample_data_tail = (m_sample_data_head + m_sample_data_capacity - m_sample_data_size) % m_sample_data_capacity;
|
const size_t sample_frames = BAN::Math::min(m_sample_data->size() / get_channels() / sizeof(uint16_t), m_bdl_entry_sample_frames);
|
||||||
|
|
||||||
const size_t sample_frames = BAN::Math::min(m_sample_data_size / get_channels() / sizeof(uint16_t), m_bdl_entry_sample_frames);
|
|
||||||
if (sample_frames == 0)
|
if (sample_frames == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t);
|
const size_t copy_total_bytes = sample_frames * get_channels() * sizeof(uint16_t);
|
||||||
const size_t copy_before_wrap = BAN::Math::min(copy_total_bytes, m_sample_data_capacity - sample_data_tail);
|
|
||||||
|
|
||||||
memcpy(
|
memcpy(
|
||||||
reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes),
|
reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes),
|
||||||
&m_sample_data[sample_data_tail],
|
m_sample_data->get_data().data(),
|
||||||
copy_before_wrap
|
copy_total_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
if (copy_before_wrap < copy_total_bytes)
|
|
||||||
{
|
|
||||||
memcpy(
|
|
||||||
reinterpret_cast<void*>(m_bdl_region->vaddr() + m_bdl_head * bdl_entry_bytes + copy_before_wrap),
|
|
||||||
&m_sample_data[0],
|
|
||||||
copy_total_bytes - copy_before_wrap
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_total_bytes < bdl_entry_bytes)
|
if (copy_total_bytes < bdl_entry_bytes)
|
||||||
{
|
{
|
||||||
memset(
|
memset(
|
||||||
@@ -516,8 +579,7 @@ namespace Kernel
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sample_data_size -= copy_total_bytes;
|
m_sample_data->pop(copy_total_bytes);
|
||||||
|
|
||||||
m_bdl_head = (m_bdl_head + 1) % m_bdl_entry_count;
|
m_bdl_head = (m_bdl_head + 1) % m_bdl_entry_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,12 @@ namespace Kernel
|
|||||||
m_pci_device.enable_interrupt(0, *this);
|
m_pci_device.enable_interrupt(0, *this);
|
||||||
m_bar0->write32(Regs::INTCTL, UINT32_MAX);
|
m_bar0->write32(Regs::INTCTL, UINT32_MAX);
|
||||||
|
|
||||||
for (uint8_t codec_id = 0; codec_id < 0x10; codec_id++)
|
const uint16_t state_sts = m_bar0->read16(Regs::STATESTS);
|
||||||
|
for (uint8_t codec_id = 0; codec_id < 15; codec_id++)
|
||||||
{
|
{
|
||||||
|
if (!(state_sts & (1 << codec_id)))
|
||||||
|
continue;
|
||||||
|
|
||||||
auto codec_or_error = initialize_codec(codec_id);
|
auto codec_or_error = initialize_codec(codec_id);
|
||||||
if (codec_or_error.is_error())
|
if (codec_or_error.is_error())
|
||||||
continue;
|
continue;
|
||||||
@@ -307,8 +311,26 @@ namespace Kernel
|
|||||||
if (result.type == AFGWidget::Type::PinComplex)
|
if (result.type == AFGWidget::Type::PinComplex)
|
||||||
{
|
{
|
||||||
const uint32_t cap = send_command_or_zero(0xF00, 0x0C);
|
const uint32_t cap = send_command_or_zero(0xF00, 0x0C);
|
||||||
result.pin_complex.output = !!(cap & (1 << 4));
|
result.pin_complex = {
|
||||||
result.pin_complex.input = !!(cap & (1 << 5));
|
.input = !!(cap & (1 << 5)),
|
||||||
|
.output = !!(cap & (1 << 4)),
|
||||||
|
.display = !!(cap & ((1 << 7) | (1 << 24))),
|
||||||
|
.config = send_command_or_zero(0xF1C, 0x00),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const uint32_t out_amp_cap = send_command_or_zero(0xF00, 0x12))
|
||||||
|
{
|
||||||
|
const uint8_t offset = (out_amp_cap >> 0) & 0x7F;
|
||||||
|
const uint8_t num_steps = (out_amp_cap >> 8) & 0x7F;
|
||||||
|
const uint8_t step_size = (out_amp_cap >> 16) & 0x7F;
|
||||||
|
const bool mute = (out_amp_cap >> 31);
|
||||||
|
result.output_amplifier = HDAudio::AFGWidget::Amplifier {
|
||||||
|
.offset = offset,
|
||||||
|
.num_steps = num_steps,
|
||||||
|
.step_size = step_size,
|
||||||
|
.mute = mute,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||||
|
|
||||||
#include <sys/framebuffer.h>
|
#include <sys/framebuffer.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
|
|
||||||
@@ -133,6 +134,26 @@ namespace Kernel
|
|||||||
return bytes_to_copy;
|
return bytes_to_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> FramebufferDevice::ioctl_impl(int cmd, void* arg)
|
||||||
|
{
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case FB_MSYNC_RECTANGLE:
|
||||||
|
{
|
||||||
|
auto& rectangle = *static_cast<fb_msync_region*>(arg);
|
||||||
|
sync_pixels_rectangle(
|
||||||
|
rectangle.min_x,
|
||||||
|
rectangle.min_y,
|
||||||
|
rectangle.max_x - rectangle.min_x,
|
||||||
|
rectangle.max_y - rectangle.min_y
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharacterDevice::ioctl(cmd, arg);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const
|
uint32_t FramebufferDevice::get_pixel(uint32_t x, uint32_t y) const
|
||||||
{
|
{
|
||||||
ASSERT(x < m_width && y < m_height);
|
ASSERT(x < m_width && y < m_height);
|
||||||
|
|||||||
@@ -1,94 +1,262 @@
|
|||||||
#include <BAN/ScopeGuard.h>
|
#include <BAN/ScopeGuard.h>
|
||||||
#include <kernel/FS/USTARModule.h>
|
#include <kernel/FS/USTARModule.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
#include <LibDEFLATE/Decompressor.h>
|
||||||
|
|
||||||
#include <tar.h>
|
#include <tar.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
bool is_ustar_boot_module(const BootModule& module)
|
class DataSource
|
||||||
{
|
{
|
||||||
if (module.start % PAGE_SIZE)
|
public:
|
||||||
|
DataSource() = default;
|
||||||
|
virtual ~DataSource() = default;
|
||||||
|
|
||||||
|
size_t data_size() const
|
||||||
{
|
{
|
||||||
dprintln("ignoring non-page-aligned module");
|
return m_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ConstByteSpan data()
|
||||||
|
{
|
||||||
|
return { m_data_buffer, m_data_size };
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_data(size_t size)
|
||||||
|
{
|
||||||
|
ASSERT(size <= m_data_size);
|
||||||
|
if (size > 0 && size < m_data_size)
|
||||||
|
memmove(m_data_buffer, m_data_buffer + size, m_data_size - size);
|
||||||
|
m_data_size -= size;
|
||||||
|
m_bytes_produced += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<bool> produce_data() = 0;
|
||||||
|
|
||||||
|
uint64_t bytes_produced() const
|
||||||
|
{
|
||||||
|
return m_bytes_produced;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint64_t bytes_consumed() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t m_data_buffer[4096];
|
||||||
|
size_t m_data_size { 0 };
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t m_bytes_produced { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataSourceRaw final : public DataSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataSourceRaw(const BootModule& module)
|
||||||
|
: m_module(module)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
BAN::ErrorOr<bool> produce_data() override
|
||||||
|
{
|
||||||
|
if (m_offset >= m_module.size || m_data_size >= sizeof(m_data_buffer))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (m_offset < m_module.size && m_data_size < sizeof(m_data_buffer))
|
||||||
|
{
|
||||||
|
const size_t to_copy = BAN::Math::min(
|
||||||
|
sizeof(m_data_buffer) - m_data_size,
|
||||||
|
PAGE_SIZE - (m_offset % PAGE_SIZE)
|
||||||
|
);
|
||||||
|
PageTable::with_fast_page((m_module.start + m_offset) & PAGE_ADDR_MASK, [&] {
|
||||||
|
memcpy(m_data_buffer + m_data_size, PageTable::fast_page_as_ptr(m_offset % PAGE_SIZE), to_copy);
|
||||||
|
});
|
||||||
|
m_data_size += to_copy;
|
||||||
|
m_offset += to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t bytes_consumed() const override
|
||||||
|
{
|
||||||
|
return bytes_produced();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BootModule& m_module;
|
||||||
|
size_t m_offset { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataSourceGZip final : public DataSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataSourceGZip(BAN::UniqPtr<DataSource>&& data_source)
|
||||||
|
: m_data_source(BAN::move(data_source))
|
||||||
|
, m_decompressor(LibDEFLATE::StreamType::GZip)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
BAN::ErrorOr<bool> produce_data() override
|
||||||
|
{
|
||||||
|
if (m_is_done)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool did_produce_data { false };
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
TRY(m_data_source->produce_data());
|
||||||
|
|
||||||
|
size_t input_consumed, output_produced;
|
||||||
|
const auto status = TRY(m_decompressor.decompress(
|
||||||
|
m_data_source->data(),
|
||||||
|
input_consumed,
|
||||||
|
{ m_data_buffer + m_data_size, sizeof(m_data_buffer) - m_data_size },
|
||||||
|
output_produced
|
||||||
|
));
|
||||||
|
|
||||||
|
m_data_source->pop_data(input_consumed);
|
||||||
|
m_data_size += output_produced;
|
||||||
|
|
||||||
|
if (output_produced)
|
||||||
|
did_produce_data = true;
|
||||||
|
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
using DecompStatus = LibDEFLATE::Decompressor::Status;
|
||||||
|
case DecompStatus::Done:
|
||||||
|
m_is_done = true;
|
||||||
|
return did_produce_data;
|
||||||
|
case DecompStatus::NeedMoreInput:
|
||||||
|
break;
|
||||||
|
case DecompStatus::NeedMoreOutput:
|
||||||
|
return did_produce_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t bytes_consumed() const override
|
||||||
|
{
|
||||||
|
return m_data_source->bytes_consumed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::UniqPtr<DataSource> m_data_source;
|
||||||
|
LibDEFLATE::Decompressor m_decompressor;
|
||||||
|
bool m_is_done { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
static BAN::ErrorOr<void> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, DataSource& data_source);
|
||||||
|
|
||||||
|
BAN::ErrorOr<bool> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, const BootModule& module)
|
||||||
|
{
|
||||||
|
ASSERT(root_inode->mode().ifdir());
|
||||||
|
|
||||||
|
BAN::UniqPtr<DataSource> data_source = TRY(BAN::UniqPtr<DataSourceRaw>::create(module));
|
||||||
|
|
||||||
|
bool is_compressed = false;
|
||||||
|
|
||||||
|
TRY(data_source->produce_data());
|
||||||
|
if (data_source->data_size() >= 2 && memcmp(&data_source->data()[0], "\x1F\x8B", 2) == 0)
|
||||||
|
{
|
||||||
|
data_source = TRY(BAN::UniqPtr<DataSourceGZip>::create(BAN::move(data_source)));
|
||||||
|
is_compressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY(data_source->produce_data());
|
||||||
|
if (data_source->data_size() < 512 || memcmp(&data_source->data()[257], "ustar", 5) != 0)
|
||||||
|
{
|
||||||
|
dwarnln("Unrecognized initrd format");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.size < 512)
|
const auto module_size_kib = module.size / 1024;
|
||||||
return false;
|
dprintln("unpacking {}.{3} MiB{} initrd",
|
||||||
|
module_size_kib / 1024, (module_size_kib % 1024) * 1000 / 1024,
|
||||||
|
is_compressed ? " compressed" : ""
|
||||||
|
);
|
||||||
|
|
||||||
bool has_ustar_signature;
|
const auto unpack_ms1 = SystemTimer::get().ms_since_boot();
|
||||||
PageTable::with_fast_page(module.start, [&] {
|
TRY(unpack_boot_module_into_directory(root_inode, *data_source));
|
||||||
has_ustar_signature = memcmp(PageTable::fast_page_as_ptr(257), "ustar", 5) == 0;
|
const auto unpack_ms2 = SystemTimer::get().ms_since_boot();
|
||||||
});
|
|
||||||
|
|
||||||
return has_ustar_signature;
|
const auto duration_ms = unpack_ms2 - unpack_ms1;
|
||||||
|
dprintln("unpacking {}.{3} MiB{} initrd took {}.{3} s",
|
||||||
|
module_size_kib / 1024, (module_size_kib % 1024) * 1000 / 1024,
|
||||||
|
is_compressed ? " compressed" : "",
|
||||||
|
duration_ms / 1000, duration_ms % 1000
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_compressed)
|
||||||
|
{
|
||||||
|
const auto uncompressed_kib = data_source->bytes_produced() / 1024;
|
||||||
|
dprintln("uncompressed size {}.{3} MiB",
|
||||||
|
uncompressed_kib / 1024, (uncompressed_kib % 1024) * 1000 / 1024
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> unpack_boot_module_into_filesystem(BAN::RefPtr<FileSystem> filesystem, const BootModule& module)
|
BAN::ErrorOr<void> unpack_boot_module_into_directory(BAN::RefPtr<Inode> root_inode, DataSource& data_source)
|
||||||
{
|
{
|
||||||
ASSERT(is_ustar_boot_module(module));
|
|
||||||
|
|
||||||
auto root_inode = filesystem->root_inode();
|
|
||||||
|
|
||||||
uint8_t* temp_page = static_cast<uint8_t*>(kmalloc(PAGE_SIZE));
|
|
||||||
if (temp_page == nullptr)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
BAN::ScopeGuard _([temp_page] { kfree(temp_page); });
|
|
||||||
|
|
||||||
BAN::String next_file_name;
|
BAN::String next_file_name;
|
||||||
BAN::String next_link_name;
|
BAN::String next_link_name;
|
||||||
|
|
||||||
size_t offset = 0;
|
constexpr uint32_t print_interval_ms = 1000;
|
||||||
while (offset + 512 <= module.size)
|
auto next_print_ms = SystemTimer::get().ms_since_boot() + print_interval_ms;
|
||||||
|
|
||||||
|
while (TRY(data_source.produce_data()), data_source.data_size() >= 512)
|
||||||
{
|
{
|
||||||
size_t file_size = 0;
|
if (SystemTimer::get().ms_since_boot() >= next_print_ms)
|
||||||
mode_t file_mode = 0;
|
{
|
||||||
uid_t file_uid = 0;
|
const auto kib_consumed = data_source.bytes_consumed() / 1024;
|
||||||
gid_t file_gid = 0;
|
const auto kib_produced = data_source.bytes_produced() / 1024;
|
||||||
uint8_t file_type = 0;
|
if (kib_consumed == kib_produced)
|
||||||
char file_path[100 + 1 + 155 + 1] {};
|
{
|
||||||
|
dprintln(" ... {}.{3} MiB",
|
||||||
PageTable::with_fast_page((module.start + offset) & PAGE_ADDR_MASK, [&] {
|
kib_consumed / 1024, (kib_consumed % 1024) * 1000 / 1024
|
||||||
const size_t page_off = offset % PAGE_SIZE;
|
);
|
||||||
|
|
||||||
const auto parse_octal =
|
|
||||||
[page_off](size_t offset, size_t length) -> size_t
|
|
||||||
{
|
|
||||||
size_t result = 0;
|
|
||||||
for (size_t i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
const char ch = PageTable::fast_page_as<char>(page_off + offset + i);
|
|
||||||
if (ch == '\0')
|
|
||||||
break;
|
|
||||||
result = (result * 8) + (ch - '0');
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (memcmp(PageTable::fast_page_as_ptr(page_off + 257), "ustar", 5)) {
|
|
||||||
file_size = SIZE_MAX;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dprintln(" ... {}.{3} MiB ({}.{3} MiB)",
|
||||||
|
kib_consumed / 1024, (kib_consumed % 1024) * 1000 / 1024,
|
||||||
|
kib_produced / 1024, (kib_produced % 1024) * 1000 / 1024
|
||||||
|
);
|
||||||
|
}
|
||||||
|
next_print_ms = SystemTimer::get().ms_since_boot() + print_interval_ms;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(file_path, PageTable::fast_page_as_ptr(page_off + 345), 155);
|
const auto parse_octal =
|
||||||
const size_t prefix_len = strlen(file_path);
|
[&data_source](size_t offset, size_t length) -> size_t
|
||||||
file_path[prefix_len] = '/';
|
{
|
||||||
memcpy(file_path + prefix_len + 1, PageTable::fast_page_as_ptr(page_off), 100);
|
size_t result = 0;
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
const char ch = data_source.data()[offset + i];
|
||||||
|
if (ch == '\0')
|
||||||
|
break;
|
||||||
|
result = (result * 8) + (ch - '0');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
file_mode = parse_octal(100, 8);
|
if (memcmp(&data_source.data()[257], "ustar", 5) != 0)
|
||||||
file_uid = parse_octal(108, 8);
|
|
||||||
file_gid = parse_octal(116, 8);
|
|
||||||
file_size = parse_octal(124, 12);
|
|
||||||
file_type = PageTable::fast_page_as<char>(page_off + 156);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (file_size == SIZE_MAX)
|
|
||||||
break;
|
|
||||||
if (offset + 512 + file_size > module.size)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto parent_inode = filesystem->root_inode();
|
char file_path[100 + 1 + 155 + 1];
|
||||||
|
memcpy(file_path, &data_source.data()[345], 155);
|
||||||
|
const size_t prefix_len = strlen(file_path);
|
||||||
|
file_path[prefix_len] = '/';
|
||||||
|
memcpy(file_path + prefix_len + 1, &data_source.data()[0], 100);
|
||||||
|
|
||||||
|
mode_t file_mode = parse_octal(100, 8);
|
||||||
|
const uid_t file_uid = parse_octal(108, 8);
|
||||||
|
const gid_t file_gid = parse_octal(116, 8);
|
||||||
|
const size_t file_size = parse_octal(124, 12);
|
||||||
|
const uint8_t file_type = data_source.data()[156];
|
||||||
|
|
||||||
|
auto parent_inode = root_inode;
|
||||||
|
|
||||||
auto file_path_parts = TRY(BAN::StringView(next_file_name.empty() ? file_path : next_file_name.sv()).split('/'));
|
auto file_path_parts = TRY(BAN::StringView(next_file_name.empty() ? file_path : next_file_name.sv()).split('/'));
|
||||||
for (size_t i = 0; i < file_path_parts.size() - 1; i++)
|
for (size_t i = 0; i < file_path_parts.size() - 1; i++)
|
||||||
@@ -111,27 +279,33 @@ namespace Kernel
|
|||||||
|
|
||||||
auto file_name_sv = file_path_parts.back();
|
auto file_name_sv = file_path_parts.back();
|
||||||
|
|
||||||
|
bool did_consume_data = false;
|
||||||
|
|
||||||
if (file_type == 'L' || file_type == 'K')
|
if (file_type == 'L' || file_type == 'K')
|
||||||
{
|
{
|
||||||
auto& target = (file_type == 'L') ? next_file_name : next_link_name;
|
auto& target_str = (file_type == 'L') ? next_file_name : next_link_name;
|
||||||
TRY(target.resize(file_size));
|
TRY(target_str.resize(file_size));
|
||||||
|
|
||||||
|
data_source.pop_data(512);
|
||||||
|
|
||||||
size_t nwritten = 0;
|
size_t nwritten = 0;
|
||||||
while (nwritten < file_size)
|
while (nwritten < file_size)
|
||||||
{
|
{
|
||||||
const paddr_t paddr = module.start + offset + 512 + nwritten;
|
TRY(data_source.produce_data());
|
||||||
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
|
if (data_source.data_size() == 0)
|
||||||
memcpy(temp_page, PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
return {};
|
||||||
});
|
|
||||||
|
|
||||||
const size_t page_off = paddr % PAGE_SIZE;
|
const size_t to_copy = BAN::Math::min(data_source.data_size(), file_size - nwritten);
|
||||||
const size_t to_write = BAN::Math::min(file_size - nwritten, PAGE_SIZE - page_off);
|
memcpy(target_str.data() + nwritten, data_source.data().data(), to_copy);
|
||||||
memcpy(target.data() + nwritten, temp_page + page_off, to_write);
|
nwritten += to_copy;
|
||||||
nwritten += to_write;
|
|
||||||
|
data_source.pop_data(to_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!target.empty() && target.back() == '\0')
|
did_consume_data = true;
|
||||||
target.pop_back();
|
|
||||||
|
while (!target_str.empty() && target_str.back() == '\0')
|
||||||
|
target_str.pop_back();
|
||||||
}
|
}
|
||||||
else if (file_type == DIRTYPE)
|
else if (file_type == DIRTYPE)
|
||||||
{
|
{
|
||||||
@@ -149,14 +323,11 @@ namespace Kernel
|
|||||||
link_name = next_link_name.sv();
|
link_name = next_link_name.sv();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const paddr_t paddr = module.start + offset;
|
memcpy(link_buffer, &data_source.data()[157], 100);
|
||||||
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
|
|
||||||
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
|
|
||||||
});
|
|
||||||
link_name = link_buffer;
|
link_name = link_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto target_inode = filesystem->root_inode();
|
auto target_inode = root_inode;
|
||||||
|
|
||||||
auto link_path_parts = TRY(link_name.split('/'));
|
auto link_path_parts = TRY(link_name.split('/'));
|
||||||
for (const auto part : link_path_parts)
|
for (const auto part : link_path_parts)
|
||||||
@@ -188,10 +359,7 @@ namespace Kernel
|
|||||||
link_name = next_link_name.sv();
|
link_name = next_link_name.sv();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const paddr_t paddr = module.start + offset;
|
memcpy(link_buffer, &data_source.data()[157], 100);
|
||||||
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
|
|
||||||
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
|
|
||||||
});
|
|
||||||
link_name = link_buffer;
|
link_name = link_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,26 +371,26 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
if (auto ret = parent_inode->create_file(file_name_sv, file_mode, file_uid, file_gid); ret.is_error())
|
if (auto ret = parent_inode->create_file(file_name_sv, file_mode, file_uid, file_gid); ret.is_error())
|
||||||
dwarnln("failed to create file '{}': {}", file_name_sv, ret.error());
|
dwarnln("failed to create file '{}': {}", file_name_sv, ret.error());
|
||||||
else
|
else if (file_size)
|
||||||
{
|
{
|
||||||
if (file_size)
|
auto inode = TRY(parent_inode->find_inode(file_name_sv));
|
||||||
|
|
||||||
|
data_source.pop_data(512);
|
||||||
|
|
||||||
|
size_t nwritten = 0;
|
||||||
|
while (nwritten < file_size)
|
||||||
{
|
{
|
||||||
auto inode = TRY(parent_inode->find_inode(file_name_sv));
|
TRY(data_source.produce_data());
|
||||||
|
ASSERT(data_source.data_size() > 0); // what to do?
|
||||||
|
|
||||||
size_t nwritten = 0;
|
const size_t to_write = BAN::Math::min(file_size - nwritten, data_source.data_size());
|
||||||
while (nwritten < file_size)
|
TRY(inode->write(nwritten, data_source.data().slice(0, to_write)));
|
||||||
{
|
nwritten += to_write;
|
||||||
const paddr_t paddr = module.start + offset + 512 + nwritten;
|
|
||||||
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
|
|
||||||
memcpy(temp_page, PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
|
||||||
});
|
|
||||||
|
|
||||||
const size_t page_off = paddr % PAGE_SIZE;
|
data_source.pop_data(to_write);
|
||||||
const size_t to_write = BAN::Math::min(file_size - nwritten, PAGE_SIZE - page_off);
|
|
||||||
TRY(inode->write(nwritten, { temp_page + page_off, to_write }));
|
|
||||||
nwritten += to_write;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
did_consume_data = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +400,27 @@ namespace Kernel
|
|||||||
next_link_name.clear();
|
next_link_name.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 512 + file_size;
|
if (!did_consume_data)
|
||||||
if (auto rem = offset % 512)
|
{
|
||||||
offset += 512 - rem;
|
data_source.pop_data(512);
|
||||||
|
|
||||||
|
size_t consumed = 0;
|
||||||
|
while (consumed < file_size)
|
||||||
|
{
|
||||||
|
TRY(data_source.produce_data());
|
||||||
|
if (data_source.data_size() == 0)
|
||||||
|
return {};
|
||||||
|
data_source.pop_data(BAN::Math::min(file_size - consumed, data_source.data_size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto rem = file_size % 512)
|
||||||
|
{
|
||||||
|
TRY(data_source.produce_data());
|
||||||
|
if (data_source.data_size() < rem)
|
||||||
|
return {};
|
||||||
|
data_source.pop_data(512 - rem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -61,18 +61,22 @@ namespace Kernel
|
|||||||
if (filesystem_or_error.is_error())
|
if (filesystem_or_error.is_error())
|
||||||
panic("Failed to create fallback filesystem: {}", filesystem_or_error.error());
|
panic("Failed to create fallback filesystem: {}", filesystem_or_error.error());
|
||||||
|
|
||||||
dprintln("Loading fallback filesystem from {} modules", g_boot_info.modules.size());
|
dprintln("Trying to load fallback filesystem from {} modules", g_boot_info.modules.size());
|
||||||
|
|
||||||
auto filesystem = BAN::RefPtr<FileSystem>::adopt(filesystem_or_error.release_value());
|
auto filesystem = BAN::RefPtr<FileSystem>::adopt(filesystem_or_error.release_value());
|
||||||
|
|
||||||
|
bool loaded_initrd = false;
|
||||||
for (const auto& module : g_boot_info.modules)
|
for (const auto& module : g_boot_info.modules)
|
||||||
{
|
{
|
||||||
if (!is_ustar_boot_module(module))
|
if (auto ret = unpack_boot_module_into_directory(filesystem->root_inode(), module); ret.is_error())
|
||||||
continue;
|
|
||||||
if (auto ret = unpack_boot_module_into_filesystem(filesystem, module); ret.is_error())
|
|
||||||
dwarnln("Failed to unpack boot module: {}", ret.error());
|
dwarnln("Failed to unpack boot module: {}", ret.error());
|
||||||
|
else
|
||||||
|
loaded_initrd |= ret.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!loaded_initrd)
|
||||||
|
panic("Could not load initrd from any boot module :(");
|
||||||
|
|
||||||
return filesystem;
|
return filesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,6 +164,33 @@ namespace Kernel
|
|||||||
"Unkown Exception 0x1F",
|
"Unkown Exception 0x1F",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" uint8_t safe_user_memcpy[];
|
||||||
|
extern "C" uint8_t safe_user_memcpy_end[];
|
||||||
|
extern "C" uint8_t safe_user_memcpy_fault[];
|
||||||
|
|
||||||
|
extern "C" uint8_t safe_user_strncpy[];
|
||||||
|
extern "C" uint8_t safe_user_strncpy_end[];
|
||||||
|
extern "C" uint8_t safe_user_strncpy_fault[];
|
||||||
|
|
||||||
|
struct safe_user_page_fault
|
||||||
|
{
|
||||||
|
const uint8_t* ip_start;
|
||||||
|
const uint8_t* ip_end;
|
||||||
|
const uint8_t* ip_fault;
|
||||||
|
};
|
||||||
|
static constexpr safe_user_page_fault s_safe_user_page_faults[] {
|
||||||
|
{
|
||||||
|
.ip_start = safe_user_memcpy,
|
||||||
|
.ip_end = safe_user_memcpy_end,
|
||||||
|
.ip_fault = safe_user_memcpy_fault,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ip_start = safe_user_strncpy,
|
||||||
|
.ip_end = safe_user_strncpy_end,
|
||||||
|
.ip_fault = safe_user_strncpy_fault,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
|
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
|
||||||
{
|
{
|
||||||
if (g_paniced)
|
if (g_paniced)
|
||||||
@@ -194,13 +221,28 @@ namespace Kernel
|
|||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("Demand paging: {}", result.error());
|
dwarnln("Demand paging: {}", result.error());
|
||||||
|
|
||||||
|
// TODO: this is too strict, we should maybe do SIGBUS and
|
||||||
|
// SIGKILL only on recursive exceptions
|
||||||
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
Thread::current().handle_signal(SIGKILL, {});
|
Thread::current().handle_signal(SIGKILL, {});
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.value())
|
if (result.value())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const uint8_t* ip = reinterpret_cast<const uint8_t*>(interrupt_stack->ip);
|
||||||
|
for (const auto& safe_user : s_safe_user_page_faults)
|
||||||
|
{
|
||||||
|
if (ip < safe_user.ip_start || ip >= safe_user.ip_end)
|
||||||
|
continue;
|
||||||
|
interrupt_stack->ip = reinterpret_cast<vaddr_t>(safe_user.ip_fault);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ISR::DeviceNotAvailable:
|
case ISR::DeviceNotAvailable:
|
||||||
@@ -285,7 +327,7 @@ namespace Kernel
|
|||||||
|
|
||||||
Debug::s_debug_lock.unlock(InterruptState::Disabled);
|
Debug::s_debug_lock.unlock(InterruptState::Disabled);
|
||||||
|
|
||||||
if (tid && Thread::current().is_userspace())
|
if (tid && GDT::is_user_segment(interrupt_stack->cs))
|
||||||
{
|
{
|
||||||
// TODO: Confirm and fix the exception to signal mappings
|
// TODO: Confirm and fix the exception to signal mappings
|
||||||
|
|
||||||
@@ -316,6 +358,7 @@ namespace Kernel
|
|||||||
case ISR::InvalidOpcode:
|
case ISR::InvalidOpcode:
|
||||||
signal_info.si_signo = SIGILL;
|
signal_info.si_signo = SIGILL;
|
||||||
signal_info.si_code = ILL_ILLOPC;
|
signal_info.si_code = ILL_ILLOPC;
|
||||||
|
signal_info.si_addr = reinterpret_cast<void*>(interrupt_stack->ip);
|
||||||
break;
|
break;
|
||||||
case ISR::PageFault:
|
case ISR::PageFault:
|
||||||
signal_info.si_signo = SIGSEGV;
|
signal_info.si_signo = SIGSEGV;
|
||||||
@@ -323,6 +366,7 @@ namespace Kernel
|
|||||||
signal_info.si_code = SEGV_ACCERR;
|
signal_info.si_code = SEGV_ACCERR;
|
||||||
else
|
else
|
||||||
signal_info.si_code = SEGV_MAPERR;
|
signal_info.si_code = SEGV_MAPERR;
|
||||||
|
signal_info.si_addr = reinterpret_cast<void*>(regs->cr2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dwarnln("Unhandled exception");
|
dwarnln("Unhandled exception");
|
||||||
@@ -330,7 +374,9 @@ namespace Kernel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
Thread::current().handle_signal(signal_info.si_signo, signal_info);
|
Thread::current().handle_signal(signal_info.si_signo, signal_info);
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -365,10 +411,6 @@ namespace Kernel
|
|||||||
Process::update_alarm_queue();
|
Process::update_alarm_queue();
|
||||||
|
|
||||||
Processor::scheduler().timer_interrupt();
|
Processor::scheduler().timer_interrupt();
|
||||||
|
|
||||||
auto& current_thread = Thread::current();
|
|
||||||
if (current_thread.can_add_signal_to_execute())
|
|
||||||
current_thread.handle_signal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void cpp_irq_handler(uint32_t irq)
|
extern "C" void cpp_irq_handler(uint32_t irq)
|
||||||
@@ -392,15 +434,18 @@ namespace Kernel
|
|||||||
else
|
else
|
||||||
dprintln("no handler for irq 0x{2H}", irq);
|
dprintln("no handler for irq 0x{2H}", irq);
|
||||||
|
|
||||||
auto& current_thread = Thread::current();
|
|
||||||
if (current_thread.can_add_signal_to_execute())
|
|
||||||
current_thread.handle_signal();
|
|
||||||
|
|
||||||
Processor::scheduler().reschedule_if_idle();
|
Processor::scheduler().reschedule_if_idle();
|
||||||
|
|
||||||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void cpp_check_signal()
|
||||||
|
{
|
||||||
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
|
Thread::current().handle_signal_if_interrupted();
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
void IDT::register_interrupt_handler(uint8_t index, void (*handler)(), uint8_t ist)
|
void IDT::register_interrupt_handler(uint8_t index, void (*handler)(), uint8_t ist)
|
||||||
{
|
{
|
||||||
auto& desc = m_idt[index];
|
auto& desc = m_idt[index];
|
||||||
@@ -440,7 +485,6 @@ namespace Kernel
|
|||||||
IRQ_LIST_X
|
IRQ_LIST_X
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
extern "C" void asm_yield_handler();
|
|
||||||
extern "C" void asm_ipi_handler();
|
extern "C" void asm_ipi_handler();
|
||||||
extern "C" void asm_timer_handler();
|
extern "C" void asm_timer_handler();
|
||||||
#if ARCH(i686)
|
#if ARCH(i686)
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_extended[0x49] = keycode_function(18);
|
m_scancode_to_keycode_extended[0x49] = keycode_function(18);
|
||||||
m_scancode_to_keycode_extended[0x51] = keycode_function(19);
|
m_scancode_to_keycode_extended[0x51] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x46] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x46] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_extended[0x20] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_extended[0x2E] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_extended[0x30] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
|
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
|
||||||
@@ -246,6 +249,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
|
m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
|
||||||
m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
|
m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_extended[0x23] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_extended[0x21] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_extended[0x32] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
|
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
|
||||||
@@ -356,6 +362,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
|
m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
|
||||||
m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
|
m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_normal[0x9C] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_normal[0x9D] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_normal[0x95] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);
|
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);
|
||||||
|
|||||||
@@ -2,11 +2,62 @@
|
|||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
|
#include <BAN/Sort.h>
|
||||||
|
|
||||||
extern uint8_t g_kernel_end[];
|
extern uint8_t g_kernel_end[];
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ReservedRegion
|
||||||
|
{
|
||||||
|
paddr_t paddr;
|
||||||
|
uint64_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static BAN::Vector<ReservedRegion> get_reserved_regions()
|
||||||
|
{
|
||||||
|
BAN::Vector<ReservedRegion> reserved_regions;
|
||||||
|
MUST(reserved_regions.reserve(2 + g_boot_info.modules.size()));
|
||||||
|
MUST(reserved_regions.emplace_back(0, 0x100000));
|
||||||
|
MUST(reserved_regions.emplace_back(g_boot_info.kernel_paddr, reinterpret_cast<size_t>(g_kernel_end - KERNEL_OFFSET)));
|
||||||
|
for (const auto& module : g_boot_info.modules)
|
||||||
|
MUST(reserved_regions.emplace_back(module.start, module.size));
|
||||||
|
|
||||||
|
// page align regions
|
||||||
|
for (auto& region : reserved_regions)
|
||||||
|
{
|
||||||
|
const auto rem = region.paddr % PAGE_SIZE;
|
||||||
|
region.paddr -= rem;
|
||||||
|
region.size += rem;
|
||||||
|
|
||||||
|
if (const auto rem = region.size % PAGE_SIZE)
|
||||||
|
region.size += PAGE_SIZE - rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort regions
|
||||||
|
BAN::sort::sort(reserved_regions.begin(), reserved_regions.end(),
|
||||||
|
[](const auto& lhs, const auto& rhs) -> bool {
|
||||||
|
if (lhs.paddr == rhs.paddr)
|
||||||
|
return lhs.size < rhs.size;
|
||||||
|
return lhs.paddr < rhs.paddr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// combine overlapping regions
|
||||||
|
for (size_t i = 1; i < reserved_regions.size(); i++)
|
||||||
|
{
|
||||||
|
auto& prev = reserved_regions[i - 1];
|
||||||
|
auto& curr = reserved_regions[i - 0];
|
||||||
|
if (prev.paddr > curr.paddr + curr.size || curr.paddr > prev.paddr + prev.size)
|
||||||
|
continue;
|
||||||
|
prev.size = BAN::Math::max(prev.size, curr.paddr + curr.size - prev.paddr);
|
||||||
|
reserved_regions.remove(i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reserved_regions;
|
||||||
|
}
|
||||||
|
|
||||||
static Heap* s_instance = nullptr;
|
static Heap* s_instance = nullptr;
|
||||||
|
|
||||||
void Heap::initialize()
|
void Heap::initialize()
|
||||||
@@ -28,6 +79,7 @@ namespace Kernel
|
|||||||
if (g_boot_info.memory_map_entries.empty())
|
if (g_boot_info.memory_map_entries.empty())
|
||||||
panic("Bootloader did not provide a memory map");
|
panic("Bootloader did not provide a memory map");
|
||||||
|
|
||||||
|
auto reserved_regions = get_reserved_regions();
|
||||||
for (const auto& entry : g_boot_info.memory_map_entries)
|
for (const auto& entry : g_boot_info.memory_map_entries)
|
||||||
{
|
{
|
||||||
const char* entry_type_string = nullptr;
|
const char* entry_type_string = nullptr;
|
||||||
@@ -58,33 +110,71 @@ namespace Kernel
|
|||||||
if (entry.type != MemoryMapEntry::Type::Available)
|
if (entry.type != MemoryMapEntry::Type::Available)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// FIXME: only reserve kernel area and modules, not everything from 0 -> kernel end
|
paddr_t e_start = entry.address;
|
||||||
paddr_t start = entry.address;
|
if (auto rem = e_start % PAGE_SIZE)
|
||||||
if (start < (vaddr_t)g_kernel_end - KERNEL_OFFSET + g_boot_info.kernel_paddr)
|
e_start = PAGE_SIZE - rem;
|
||||||
start = (vaddr_t)g_kernel_end - KERNEL_OFFSET + g_boot_info.kernel_paddr;
|
|
||||||
for (const auto& module : g_boot_info.modules)
|
paddr_t e_end = entry.address + entry.length;
|
||||||
if (start < module.start + module.size)
|
if (auto rem = e_end % PAGE_SIZE)
|
||||||
start = module.start + module.size;
|
e_end -= rem;
|
||||||
|
|
||||||
|
for (const auto& reserved_region : reserved_regions)
|
||||||
|
{
|
||||||
|
const paddr_t r_start = reserved_region.paddr;
|
||||||
|
const paddr_t r_end = reserved_region.paddr + reserved_region.size;
|
||||||
|
if (r_end < e_start)
|
||||||
|
continue;
|
||||||
|
if (r_start > e_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const paddr_t end = BAN::Math::max(e_start, r_start);
|
||||||
|
if (e_start + 2 * PAGE_SIZE <= end)
|
||||||
|
MUST(m_physical_ranges.emplace_back(e_start, end - e_start));
|
||||||
|
|
||||||
|
e_start = BAN::Math::max(e_start, BAN::Math::min(e_end, r_end));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e_start + 2 * PAGE_SIZE <= e_end)
|
||||||
|
MUST(m_physical_ranges.emplace_back(e_start, e_end - e_start));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t total_kibi_bytes = 0;
|
||||||
|
for (auto& range : m_physical_ranges)
|
||||||
|
{
|
||||||
|
const uint64_t kibi_bytes = range.usable_memory() / 1024;
|
||||||
|
dprintln("RAM {8H}->{8H} ({}.{3} MiB)", range.start(), range.end(), kibi_bytes / 1024, kibi_bytes % 1024);
|
||||||
|
total_kibi_bytes += kibi_bytes;
|
||||||
|
}
|
||||||
|
dprintln("Total RAM {}.{3} MiB", total_kibi_bytes / 1024, total_kibi_bytes % 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Heap::release_boot_modules()
|
||||||
|
{
|
||||||
|
const auto modules = BAN::move(g_boot_info.modules);
|
||||||
|
|
||||||
|
uint64_t kibi_bytes = 0;
|
||||||
|
for (const auto& module : modules)
|
||||||
|
{
|
||||||
|
vaddr_t start = module.start;
|
||||||
if (auto rem = start % PAGE_SIZE)
|
if (auto rem = start % PAGE_SIZE)
|
||||||
start += PAGE_SIZE - rem;
|
start += PAGE_SIZE - rem;
|
||||||
|
|
||||||
paddr_t end = entry.address + entry.length;
|
vaddr_t end = module.start + module.size;
|
||||||
if (auto rem = end % PAGE_SIZE)
|
if (auto rem = end % PAGE_SIZE)
|
||||||
end -= rem;
|
end -= rem;
|
||||||
|
|
||||||
// Physical pages needs atleast 2 pages
|
const size_t size = end - start;
|
||||||
if (end > start + PAGE_SIZE)
|
if (size < 2 * PAGE_SIZE)
|
||||||
MUST(m_physical_ranges.emplace_back(start, end - start));
|
continue;
|
||||||
|
|
||||||
|
SpinLockGuard _(m_lock);
|
||||||
|
MUST(m_physical_ranges.emplace_back(start, size));
|
||||||
|
|
||||||
|
kibi_bytes += m_physical_ranges.back().usable_memory() / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t total = 0;
|
if (kibi_bytes)
|
||||||
for (auto& range : m_physical_ranges)
|
dprintln("Released {}.{3} MiB of RAM from boot modules", kibi_bytes / 1024, kibi_bytes % 1024);
|
||||||
{
|
|
||||||
size_t bytes = range.usable_memory();
|
|
||||||
dprintln("RAM {8H}->{8H} ({}.{} MB)", range.start(), range.end(), bytes / (1 << 20), bytes % (1 << 20) * 1000 / (1 << 20));
|
|
||||||
total += bytes;
|
|
||||||
}
|
|
||||||
dprintln("Total RAM {}.{} MB", total / (1 << 20), total % (1 << 20) * 1000 / (1 << 20));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
paddr_t Heap::take_free_page()
|
paddr_t Heap::take_free_page()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/MemoryBackedRegion.h>
|
#include <kernel/Memory/MemoryBackedRegion.h>
|
||||||
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
@@ -14,6 +15,9 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
|
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
|
||||||
|
|
||||||
|
const size_t page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
TRY(region->m_physical_pages.resize(page_count, nullptr));
|
||||||
|
|
||||||
TRY(region->initialize(address_range));
|
TRY(region->initialize(address_range));
|
||||||
|
|
||||||
return region;
|
return region;
|
||||||
@@ -28,38 +32,75 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
ASSERT(m_type == Type::PRIVATE);
|
ASSERT(m_type == Type::PRIVATE);
|
||||||
|
|
||||||
size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
for (auto* page : m_physical_pages)
|
||||||
for (size_t i = 0; i < needed_pages; i++)
|
if (page && --page->ref_count == 0)
|
||||||
{
|
delete page;
|
||||||
paddr_t paddr = m_page_table.physical_address_of(m_vaddr + i * PAGE_SIZE);
|
}
|
||||||
if (paddr != 0)
|
|
||||||
Heap::get().release_page(paddr);
|
MemoryBackedRegion::PhysicalPage::~PhysicalPage()
|
||||||
}
|
{
|
||||||
|
Heap::get().release_page(paddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<bool> MemoryBackedRegion::allocate_page_containing_impl(vaddr_t address, bool wants_write)
|
BAN::ErrorOr<bool> MemoryBackedRegion::allocate_page_containing_impl(vaddr_t address, bool wants_write)
|
||||||
{
|
{
|
||||||
ASSERT(m_type == Type::PRIVATE);
|
ASSERT(m_type == Type::PRIVATE);
|
||||||
|
|
||||||
ASSERT(contains(address));
|
ASSERT(contains(address));
|
||||||
(void)wants_write;
|
|
||||||
|
|
||||||
// Check if address is already mapped
|
const vaddr_t vaddr = address & PAGE_ADDR_MASK;
|
||||||
vaddr_t vaddr = address & PAGE_ADDR_MASK;
|
|
||||||
if (m_page_table.physical_address_of(vaddr) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Map new physcial page to address
|
LockGuard _(m_mutex);
|
||||||
paddr_t paddr = Heap::get().take_free_page();
|
|
||||||
|
auto& physical_page = m_physical_pages[(vaddr - m_vaddr) / PAGE_SIZE];
|
||||||
|
|
||||||
|
if (physical_page == nullptr)
|
||||||
|
{
|
||||||
|
const paddr_t paddr = Heap::get().take_free_page();
|
||||||
|
if (paddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
physical_page = new PhysicalPage(paddr);
|
||||||
|
if (physical_page == nullptr)
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto is_only_ref = (physical_page->ref_count == 1); is_only_ref || !wants_write)
|
||||||
|
{
|
||||||
|
auto flags = m_flags;
|
||||||
|
if (!is_only_ref)
|
||||||
|
flags &= ~PageTable::ReadWrite;
|
||||||
|
|
||||||
|
m_page_table.map_page_at(physical_page->paddr, vaddr, flags);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const paddr_t paddr = Heap::get().take_free_page();
|
||||||
if (paddr == 0)
|
if (paddr == 0)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
|
auto* new_physical_page = new PhysicalPage(paddr);
|
||||||
|
if (new_physical_page == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
m_page_table.map_page_at(paddr, vaddr, m_flags);
|
m_page_table.map_page_at(paddr, vaddr, m_flags);
|
||||||
|
|
||||||
// Zero out the new page
|
ASSERT(&m_page_table == &PageTable::current());
|
||||||
PageTable::with_fast_page(paddr, [&] {
|
PageTable::with_fast_page(physical_page->paddr, [vaddr] {
|
||||||
memset(PageTable::fast_page_as_ptr(), 0x00, PAGE_SIZE);
|
memcpy(reinterpret_cast<void*>(vaddr), PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (--physical_page->ref_count == 0)
|
||||||
|
delete physical_page;
|
||||||
|
physical_page = new_physical_page;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,16 +108,20 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
ASSERT(&PageTable::current() == &m_page_table);
|
ASSERT(&PageTable::current() == &m_page_table);
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
||||||
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
|
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
|
||||||
|
|
||||||
for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE)
|
if (writable())
|
||||||
|
m_page_table.remove_writable_from_range(m_vaddr, m_size);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_physical_pages.size(); i++)
|
||||||
{
|
{
|
||||||
paddr_t paddr = m_page_table.physical_address_of(m_vaddr + offset);
|
if (m_physical_pages[i] == nullptr)
|
||||||
if (paddr == 0)
|
|
||||||
continue;
|
continue;
|
||||||
const size_t to_copy = BAN::Math::min<size_t>(PAGE_SIZE, m_size - offset);
|
result->m_physical_pages[i] = m_physical_pages[i];
|
||||||
TRY(result->copy_data_to_region(offset, (const uint8_t*)(m_vaddr + offset), to_copy));
|
result->m_physical_pages[i]->ref_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
|
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
|
||||||
@@ -87,20 +132,35 @@ namespace Kernel
|
|||||||
ASSERT(offset && offset < m_size);
|
ASSERT(offset && offset < m_size);
|
||||||
ASSERT(offset % PAGE_SIZE == 0);
|
ASSERT(offset % PAGE_SIZE == 0);
|
||||||
|
|
||||||
auto* new_region = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
|
LockGuard _(m_mutex);
|
||||||
if (new_region == nullptr)
|
|
||||||
|
auto* new_region_ptr = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
|
||||||
|
if (new_region_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto new_region = BAN::UniqPtr<MemoryBackedRegion>::adopt(new_region_ptr);
|
||||||
|
|
||||||
new_region->m_vaddr = m_vaddr + offset;
|
new_region->m_vaddr = m_vaddr + offset;
|
||||||
|
|
||||||
|
const size_t moved_pages = (m_size - offset + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
TRY(new_region->m_physical_pages.resize(moved_pages));
|
||||||
|
|
||||||
|
const size_t remaining_pages = m_physical_pages.size() - moved_pages;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < moved_pages; i++)
|
||||||
|
new_region->m_physical_pages[i] = m_physical_pages[remaining_pages + i];
|
||||||
|
MUST(m_physical_pages.resize(remaining_pages));
|
||||||
|
|
||||||
m_size = offset;
|
m_size = offset;
|
||||||
|
|
||||||
return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
|
return BAN::UniqPtr<MemoryRegion>(BAN::move(new_region));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
|
BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
ASSERT(offset_into_region + buffer_size <= m_size);
|
ASSERT(offset_into_region + buffer_size <= m_size);
|
||||||
|
|
||||||
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
while (written < buffer_size)
|
while (written < buffer_size)
|
||||||
{
|
{
|
||||||
@@ -108,18 +168,18 @@ namespace Kernel
|
|||||||
vaddr_t page_offset = write_vaddr % PAGE_SIZE;
|
vaddr_t page_offset = write_vaddr % PAGE_SIZE;
|
||||||
size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
|
size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
|
||||||
|
|
||||||
paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
|
if (!(m_page_table.get_page_flags(write_vaddr & PAGE_ADDR_MASK) & PageTable::ReadWrite))
|
||||||
if (paddr == 0)
|
|
||||||
{
|
{
|
||||||
if (!TRY(allocate_page_containing(write_vaddr, false)))
|
if (!TRY(allocate_page_containing(write_vaddr, true)))
|
||||||
{
|
{
|
||||||
dwarnln("Could not allocate page for data copying");
|
dwarnln("Could not allocate page for data copying");
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
|
|
||||||
ASSERT(paddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
|
||||||
|
ASSERT(paddr);
|
||||||
|
|
||||||
PageTable::with_fast_page(paddr, [&] {
|
PageTable::with_fast_page(paddr, [&] {
|
||||||
memcpy(PageTable::fast_page_as_ptr(page_offset), (void*)(buffer + written), bytes);
|
memcpy(PageTable::fast_page_as_ptr(page_offset), (void*)(buffer + written), bytes);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range)
|
BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range)
|
||||||
{
|
{
|
||||||
size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
if (auto rem = address_range.end % PAGE_SIZE)
|
||||||
m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start);
|
address_range.end += PAGE_SIZE - rem;
|
||||||
|
const size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
||||||
|
m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start, address_range.end);
|
||||||
if (m_vaddr == 0)
|
if (m_vaddr == 0)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
if (m_vaddr + m_size > address_range.end)
|
if (m_vaddr + m_size > address_range.end)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Kernel
|
|||||||
|
|
||||||
static constexpr size_t bits_per_page = PAGE_SIZE * 8;
|
static constexpr size_t bits_per_page = PAGE_SIZE * 8;
|
||||||
|
|
||||||
PhysicalRange::PhysicalRange(paddr_t paddr, size_t size)
|
PhysicalRange::PhysicalRange(paddr_t paddr, uint64_t size)
|
||||||
: m_paddr(paddr)
|
: m_paddr(paddr)
|
||||||
, m_page_count(size / PAGE_SIZE)
|
, m_page_count(size / PAGE_SIZE)
|
||||||
, m_free_pages(m_page_count)
|
, m_free_pages(m_page_count)
|
||||||
|
|||||||
@@ -110,36 +110,6 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> VirtualRange::clone(PageTable& page_table)
|
|
||||||
{
|
|
||||||
ASSERT(&PageTable::current() == &m_page_table);
|
|
||||||
ASSERT(&m_page_table != &page_table);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
|
||||||
|
|
||||||
auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages));
|
|
||||||
|
|
||||||
const size_t page_count = size() / PAGE_SIZE;
|
|
||||||
for (size_t i = 0; i < page_count; i++)
|
|
||||||
{
|
|
||||||
if (m_paddrs[i] == 0)
|
|
||||||
continue;
|
|
||||||
if (!result->m_preallocated)
|
|
||||||
{
|
|
||||||
result->m_paddrs[i] = Heap::get().take_free_page();
|
|
||||||
if (result->m_paddrs[i] == 0)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
result->m_page_table.map_page_at(result->m_paddrs[i], vaddr() + i * PAGE_SIZE, m_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
PageTable::with_fast_page(result->m_paddrs[i], [&] {
|
|
||||||
memcpy(PageTable::fast_page_as_ptr(), reinterpret_cast<void*>(vaddr() + i * PAGE_SIZE), PAGE_SIZE);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
|
BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
|
||||||
{
|
{
|
||||||
ASSERT(contains(vaddr));
|
ASSERT(contains(vaddr));
|
||||||
|
|||||||
@@ -51,17 +51,19 @@ namespace Kernel
|
|||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
|
|
||||||
for (int fd = 0; fd < (int)other.m_open_files.size(); fd++)
|
for (int fd = 0; fd < static_cast<int>(other.m_open_files.size()); fd++)
|
||||||
{
|
{
|
||||||
if (other.validate_fd(fd).is_error())
|
if (other.validate_fd(fd).is_error())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
open_file.description = other.m_open_files[fd].description;
|
open_file = other.m_open_files[fd];
|
||||||
open_file.descriptor_flags = other.m_open_files[fd].descriptor_flags;
|
open_file->file.inode->on_clone(open_file->status_flags);
|
||||||
open_file.inode()->on_clone(open_file.status_flags());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_cloexec_files.size(); i++)
|
||||||
|
m_cloexec_files[i] = other.m_cloexec_files[i];
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,11 +83,15 @@ namespace Kernel
|
|||||||
if ((flags & O_TRUNC) && (flags & O_WRONLY) && file.inode->mode().ifreg())
|
if ((flags & O_TRUNC) && (flags & O_WRONLY) && file.inode->mode().ifreg())
|
||||||
TRY(file.inode->truncate(0));
|
TRY(file.inode->truncate(0));
|
||||||
|
|
||||||
LockGuard _(m_mutex);
|
|
||||||
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
|
constexpr int status_mask = O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC | O_ACCMODE;
|
||||||
int fd = TRY(get_free_fd());
|
|
||||||
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(BAN::move(file), 0, flags & status_mask));
|
LockGuard _(m_mutex);
|
||||||
m_open_files[fd].descriptor_flags = flags & O_CLOEXEC;
|
|
||||||
|
const int fd = TRY(get_free_fd());
|
||||||
|
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(BAN::move(file), 0, flags & status_mask));
|
||||||
|
if (flags & O_CLOEXEC)
|
||||||
|
add_cloexec(fd);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +105,7 @@ namespace Kernel
|
|||||||
Socket::Domain domain;
|
Socket::Domain domain;
|
||||||
Socket::Type type;
|
Socket::Type type;
|
||||||
int status_flags;
|
int status_flags;
|
||||||
int descriptor_flags;
|
bool cloexec;
|
||||||
};
|
};
|
||||||
|
|
||||||
static BAN::ErrorOr<SocketInfo> parse_socket_info(int domain, int type, int protocol)
|
static BAN::ErrorOr<SocketInfo> parse_socket_info(int domain, int type, int protocol)
|
||||||
@@ -124,11 +130,11 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
info.status_flags = 0;
|
info.status_flags = 0;
|
||||||
info.descriptor_flags = 0;
|
info.cloexec = false;
|
||||||
if (type & SOCK_NONBLOCK)
|
if (type & SOCK_NONBLOCK)
|
||||||
info.status_flags |= O_NONBLOCK;
|
info.status_flags |= O_NONBLOCK;
|
||||||
if (type & SOCK_CLOEXEC)
|
if (type & SOCK_CLOEXEC)
|
||||||
info.descriptor_flags |= O_CLOEXEC;
|
info.cloexec = true;
|
||||||
type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
|
type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
@@ -171,9 +177,12 @@ namespace Kernel
|
|||||||
socket_sv = "<udp socket>";
|
socket_sv = "<udp socket>";
|
||||||
|
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
int fd = TRY(get_free_fd());
|
|
||||||
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, socket_sv), 0, O_RDWR | sock_info.status_flags));
|
const int fd = TRY(get_free_fd());
|
||||||
m_open_files[fd].descriptor_flags = sock_info.descriptor_flags;
|
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, socket_sv), 0, O_RDWR | sock_info.status_flags));
|
||||||
|
if (sock_info.cloexec)
|
||||||
|
add_cloexec(fd);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,10 +197,14 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
TRY(get_free_fd_pair(socket_vector));
|
TRY(get_free_fd_pair(socket_vector));
|
||||||
m_open_files[socket_vector[0]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket1, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
m_open_files[socket_vector[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket1, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
||||||
m_open_files[socket_vector[0]].descriptor_flags = sock_info.descriptor_flags;
|
m_open_files[socket_vector[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket2, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
||||||
m_open_files[socket_vector[1]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket2, "<socketpair>"_sv), 0, O_RDWR | sock_info.status_flags));
|
if (sock_info.cloexec)
|
||||||
m_open_files[socket_vector[1]].descriptor_flags = sock_info.descriptor_flags;
|
{
|
||||||
|
add_cloexec(socket_vector[0]);
|
||||||
|
add_cloexec(socket_vector[1]);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,10 +215,11 @@ namespace Kernel
|
|||||||
TRY(get_free_fd_pair(fds));
|
TRY(get_free_fd_pair(fds));
|
||||||
|
|
||||||
auto pipe = TRY(Pipe::create(m_credentials));
|
auto pipe = TRY(Pipe::create(m_credentials));
|
||||||
m_open_files[fds[0]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe rd>"_sv), 0, O_RDONLY));
|
m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe rd>"_sv), 0, O_RDONLY));
|
||||||
m_open_files[fds[0]].descriptor_flags = 0;
|
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe wr>"_sv), 0, O_WRONLY));
|
||||||
m_open_files[fds[1]].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(pipe, "<pipe wr>"_sv), 0, O_WRONLY));
|
|
||||||
m_open_files[fds[1]].descriptor_flags = 0;
|
ASSERT(!is_cloexec(fds[0]));
|
||||||
|
ASSERT(!is_cloexec(fds[1]));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -224,9 +238,10 @@ namespace Kernel
|
|||||||
(void)close(fildes2);
|
(void)close(fildes2);
|
||||||
|
|
||||||
auto& open_file = m_open_files[fildes2];
|
auto& open_file = m_open_files[fildes2];
|
||||||
open_file.description = m_open_files[fildes].description;
|
open_file = m_open_files[fildes];
|
||||||
open_file.descriptor_flags = 0;
|
open_file->file.inode->on_clone(open_file->status_flags);
|
||||||
open_file.inode()->on_clone(open_file.status_flags());
|
|
||||||
|
ASSERT(!is_cloexec(fildes2));
|
||||||
|
|
||||||
return fildes2;
|
return fildes2;
|
||||||
}
|
}
|
||||||
@@ -246,18 +261,16 @@ namespace Kernel
|
|||||||
|
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
const auto& open_file = m_open_files[fd];
|
inode = m_open_files[fd]->file.inode;
|
||||||
|
|
||||||
inode = open_file.inode();
|
|
||||||
|
|
||||||
switch (flock.l_whence)
|
switch (flock.l_whence)
|
||||||
{
|
{
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
break;
|
break;
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
if (BAN::Math::will_addition_overflow(flock.l_start, open_file.offset()))
|
if (BAN::Math::will_addition_overflow(flock.l_start, m_open_files[fd]->offset))
|
||||||
return BAN::Error::from_errno(EOVERFLOW);
|
return BAN::Error::from_errno(EOVERFLOW);
|
||||||
flock.l_start += m_open_files[fd].offset();
|
flock.l_start += m_open_files[fd]->offset;
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
if (BAN::Math::will_addition_overflow(flock.l_start, inode->size()))
|
if (BAN::Math::will_addition_overflow(flock.l_start, inode->size()))
|
||||||
@@ -307,26 +320,27 @@ namespace Kernel
|
|||||||
const int new_fd = TRY(get_free_fd());
|
const int new_fd = TRY(get_free_fd());
|
||||||
|
|
||||||
auto& open_file = m_open_files[new_fd];
|
auto& open_file = m_open_files[new_fd];
|
||||||
open_file.description = m_open_files[fd].description;
|
open_file = m_open_files[fd];
|
||||||
open_file.descriptor_flags = (cmd == F_DUPFD_CLOEXEC) ? O_CLOEXEC : 0;
|
open_file->file.inode->on_clone(open_file->status_flags);
|
||||||
open_file.inode()->on_clone(open_file.status_flags());
|
if (cmd == F_DUPFD_CLOEXEC)
|
||||||
|
add_cloexec(new_fd);
|
||||||
|
|
||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
case F_GETFD:
|
case F_GETFD:
|
||||||
return m_open_files[fd].descriptor_flags;
|
return is_cloexec(fd) ? O_CLOEXEC : 0;
|
||||||
case F_SETFD:
|
case F_SETFD:
|
||||||
if (extra & FD_CLOEXEC)
|
if (extra & FD_CLOEXEC)
|
||||||
m_open_files[fd].descriptor_flags |= O_CLOEXEC;
|
add_cloexec(fd);
|
||||||
else
|
else
|
||||||
m_open_files[fd].descriptor_flags &= ~O_CLOEXEC;
|
remove_cloexec(fd);
|
||||||
return 0;
|
return 0;
|
||||||
case F_GETFL:
|
case F_GETFL:
|
||||||
return m_open_files[fd].status_flags();
|
return m_open_files[fd]->status_flags;
|
||||||
case F_SETFL:
|
case F_SETFL:
|
||||||
extra &= O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC;
|
extra &= O_APPEND | O_DSYNC | O_NONBLOCK | O_RSYNC | O_SYNC;
|
||||||
m_open_files[fd].status_flags() &= O_ACCMODE;
|
m_open_files[fd]->status_flags &= O_ACCMODE;
|
||||||
m_open_files[fd].status_flags() |= extra;
|
m_open_files[fd]->status_flags |= extra;
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -349,10 +363,10 @@ namespace Kernel
|
|||||||
base_offset = 0;
|
base_offset = 0;
|
||||||
break;
|
break;
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
base_offset = m_open_files[fd].offset();
|
base_offset = m_open_files[fd]->offset;
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
base_offset = m_open_files[fd].inode()->size();
|
base_offset = m_open_files[fd]->file.inode->size();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
@@ -362,7 +376,7 @@ namespace Kernel
|
|||||||
if (new_offset < 0)
|
if (new_offset < 0)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
m_open_files[fd].offset() = new_offset;
|
m_open_files[fd]->offset = new_offset;
|
||||||
|
|
||||||
return new_offset;
|
return new_offset;
|
||||||
}
|
}
|
||||||
@@ -371,14 +385,14 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].offset();
|
return m_open_files[fd]->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
|
BAN::ErrorOr<void> OpenFileDescriptorSet::truncate(int fd, off_t length)
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].inode()->truncate(length);
|
return m_open_files[fd]->file.inode->truncate(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
|
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
|
||||||
@@ -389,7 +403,7 @@ namespace Kernel
|
|||||||
|
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
|
|
||||||
if (auto& flock = open_file.description->flock; Thread::current().has_process() && flock.lockers.contains(Process::current().pid()))
|
if (auto& flock = open_file->flock; Thread::current().has_process() && flock.lockers.contains(Process::current().pid()))
|
||||||
{
|
{
|
||||||
flock.lockers.remove(Process::current().pid());
|
flock.lockers.remove(Process::current().pid());
|
||||||
if (flock.lockers.empty())
|
if (flock.lockers.empty())
|
||||||
@@ -401,7 +415,7 @@ namespace Kernel
|
|||||||
|
|
||||||
{
|
{
|
||||||
LockGuard _(s_fcntl_lock_mutex);
|
LockGuard _(s_fcntl_lock_mutex);
|
||||||
if (auto it = s_fcntl_locks.find(open_file.inode()); it != s_fcntl_locks.end())
|
if (auto it = s_fcntl_locks.find(open_file->file.inode); it != s_fcntl_locks.end())
|
||||||
{
|
{
|
||||||
auto& flocks = it->value;
|
auto& flocks = it->value;
|
||||||
for (size_t i = 0; i < flocks.size(); i++)
|
for (size_t i = 0; i < flocks.size(); i++)
|
||||||
@@ -411,9 +425,9 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open_file.inode()->on_close(open_file.status_flags());
|
open_file->file.inode->on_close(open_file->status_flags);
|
||||||
open_file.description.clear();
|
open_file = {};
|
||||||
open_file.descriptor_flags = 0;
|
remove_cloexec(fd);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -421,20 +435,31 @@ namespace Kernel
|
|||||||
void OpenFileDescriptorSet::close_all()
|
void OpenFileDescriptorSet::close_all()
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < static_cast<int>(m_open_files.size()); fd++)
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenFileDescriptorSet::close_cloexec()
|
void OpenFileDescriptorSet::close_cloexec()
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < static_cast<int>(m_open_files.size()); fd++)
|
||||||
{
|
if (is_cloexec(fd))
|
||||||
if (validate_fd(fd).is_error())
|
|
||||||
continue;
|
|
||||||
if (m_open_files[fd].descriptor_flags & O_CLOEXEC)
|
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenFileDescriptorSet::is_cloexec(int fd)
|
||||||
|
{
|
||||||
|
return m_cloexec_files[fd / 32] & (1u << (fd % 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenFileDescriptorSet::add_cloexec(int fd)
|
||||||
|
{
|
||||||
|
m_cloexec_files[fd / 32] |= 1u << (fd % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenFileDescriptorSet::remove_cloexec(int fd)
|
||||||
|
{
|
||||||
|
m_cloexec_files[fd / 32] &= ~(1u << (fd % 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
static BAN::ErrorOr<void> fcntl_lock(BAN::RefPtr<Inode> inode, int cmd, struct flock& flock)
|
static BAN::ErrorOr<void> fcntl_lock(BAN::RefPtr<Inode> inode, int cmd, struct flock& flock)
|
||||||
@@ -588,7 +613,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
|
|
||||||
auto& flock = m_open_files[fd].description->flock;
|
auto& flock = m_open_files[fd]->flock;
|
||||||
switch (op & ~LOCK_NB)
|
switch (op & ~LOCK_NB)
|
||||||
{
|
{
|
||||||
case LOCK_UN:
|
case LOCK_UN:
|
||||||
@@ -645,11 +670,11 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!(open_file.status_flags() & O_RDONLY))
|
if (!(open_file->status_flags & O_RDONLY))
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
inode = open_file.inode();
|
inode = open_file->file.inode;
|
||||||
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
|
||||||
offset = open_file.offset();
|
offset = open_file->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode->mode().ifsock())
|
if (inode->mode().ifsock())
|
||||||
@@ -685,7 +710,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
// NOTE: race condition with offset, its UB per POSIX
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
if (!validate_fd(fd).is_error())
|
if (!validate_fd(fd).is_error())
|
||||||
m_open_files[fd].offset() = offset + nread;
|
m_open_files[fd]->offset = offset + nread;
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,11 +724,11 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!(open_file.status_flags() & O_WRONLY))
|
if (!(open_file->status_flags & O_WRONLY))
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
inode = open_file.inode();
|
inode = open_file->file.inode;
|
||||||
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
|
||||||
offset = (open_file.status_flags() & O_APPEND) ? inode->size() : open_file.offset();
|
offset = (open_file->status_flags & O_APPEND) ? inode->size() : open_file->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode->mode().ifsock())
|
if (inode->mode().ifsock())
|
||||||
@@ -742,7 +767,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
// NOTE: race condition with offset, its UB per POSIX
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
if (!validate_fd(fd).is_error())
|
if (!validate_fd(fd).is_error())
|
||||||
m_open_files[fd].offset() = offset + nwrite;
|
m_open_files[fd]->offset = offset + nwrite;
|
||||||
return nwrite;
|
return nwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,10 +780,10 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!(open_file.status_flags() & O_RDONLY))
|
if (!(open_file->status_flags & O_RDONLY))
|
||||||
return BAN::Error::from_errno(EACCES);
|
return BAN::Error::from_errno(EACCES);
|
||||||
inode = open_file.inode();
|
inode = open_file->file.inode;
|
||||||
offset = open_file.offset();
|
offset = open_file->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@@ -773,7 +798,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
// NOTE: race condition with offset, its UB per POSIX
|
// NOTE: race condition with offset, its UB per POSIX
|
||||||
if (!validate_fd(fd).is_error())
|
if (!validate_fd(fd).is_error())
|
||||||
m_open_files[fd].offset() = offset;
|
m_open_files[fd]->offset = offset;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -787,10 +812,10 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!open_file.inode()->mode().ifsock())
|
if (!open_file->file.inode->mode().ifsock())
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
inode = open_file.inode();
|
inode = open_file->file.inode;
|
||||||
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
LockGuard _(inode->m_mutex);
|
LockGuard _(inode->m_mutex);
|
||||||
@@ -808,10 +833,10 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
auto& open_file = m_open_files[fd];
|
auto& open_file = m_open_files[fd];
|
||||||
if (!open_file.inode()->mode().ifsock())
|
if (!open_file->file.inode->mode().ifsock())
|
||||||
return BAN::Error::from_errno(ENOTSOCK);
|
return BAN::Error::from_errno(ENOTSOCK);
|
||||||
inode = open_file.inode();
|
inode = open_file->file.inode;
|
||||||
is_nonblock = !!(open_file.status_flags() & O_NONBLOCK);
|
is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
LockGuard _(inode->m_mutex);
|
LockGuard _(inode->m_mutex);
|
||||||
@@ -830,7 +855,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return TRY(m_open_files[fd].description->file.clone());
|
return TRY(m_open_files[fd]->file.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::String> OpenFileDescriptorSet::path_of(int fd) const
|
BAN::ErrorOr<BAN::String> OpenFileDescriptorSet::path_of(int fd) const
|
||||||
@@ -838,7 +863,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
BAN::String path;
|
BAN::String path;
|
||||||
TRY(path.append(m_open_files[fd].path()));
|
TRY(path.append(m_open_files[fd]->file.canonical_path));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,14 +871,14 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].inode();
|
return m_open_files[fd]->file.inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<int> OpenFileDescriptorSet::status_flags_of(int fd) const
|
BAN::ErrorOr<int> OpenFileDescriptorSet::status_flags_of(int fd) const
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return m_open_files[fd].status_flags();
|
return m_open_files[fd]->status_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
|
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
|
||||||
@@ -861,7 +886,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
if (fd < 0 || fd >= (int)m_open_files.size())
|
if (fd < 0 || fd >= (int)m_open_files.size())
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
if (!m_open_files[fd].description)
|
if (!m_open_files[fd])
|
||||||
return BAN::Error::from_errno(EBADF);
|
return BAN::Error::from_errno(EBADF);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -870,7 +895,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
if (!m_open_files[fd].description)
|
if (!m_open_files[fd])
|
||||||
return fd;
|
return fd;
|
||||||
return BAN::Error::from_errno(EMFILE);
|
return BAN::Error::from_errno(EMFILE);
|
||||||
}
|
}
|
||||||
@@ -881,7 +906,7 @@ namespace Kernel
|
|||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||||
{
|
{
|
||||||
if (!m_open_files[fd].description)
|
if (!m_open_files[fd])
|
||||||
fds[found++] = fd;
|
fds[found++] = fd;
|
||||||
if (found == 2)
|
if (found == 2)
|
||||||
return {};
|
return {};
|
||||||
@@ -929,7 +954,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(validate_fd(fd));
|
TRY(validate_fd(fd));
|
||||||
return FDWrapper { m_open_files[fd].description };
|
return FDWrapper { m_open_files[fd] };
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OpenFileDescriptorSet::open_all_fd_wrappers(BAN::Span<FDWrapper> fd_wrappers)
|
size_t OpenFileDescriptorSet::open_all_fd_wrappers(BAN::Span<FDWrapper> fd_wrappers)
|
||||||
@@ -943,8 +968,7 @@ namespace Kernel
|
|||||||
return i;
|
return i;
|
||||||
|
|
||||||
const int fd = fd_or_error.release_value();
|
const int fd = fd_or_error.release_value();
|
||||||
m_open_files[fd].description = BAN::move(fd_wrappers[i].m_description);
|
m_open_files[fd] = BAN::move(fd_wrappers[i].m_description);
|
||||||
m_open_files[fd].descriptor_flags = 0;
|
|
||||||
fd_wrappers[i].m_fd = fd;
|
fd_wrappers[i].m_fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -303,6 +303,8 @@ namespace Kernel
|
|||||||
|
|
||||||
void Process::exit(int status, int signal)
|
void Process::exit(int status, int signal)
|
||||||
{
|
{
|
||||||
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
|
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
if (!m_is_exiting.compare_exchange(expected, true))
|
if (!m_is_exiting.compare_exchange(expected, true))
|
||||||
{
|
{
|
||||||
@@ -310,9 +312,6 @@ namespace Kernel
|
|||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto state = Processor::get_interrupt_state();
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
|
||||||
|
|
||||||
if (m_parent)
|
if (m_parent)
|
||||||
{
|
{
|
||||||
Process* parent_process = nullptr;
|
Process* parent_process = nullptr;
|
||||||
@@ -369,8 +368,6 @@ namespace Kernel
|
|||||||
while (m_threads.size() > 1)
|
while (m_threads.size() > 1)
|
||||||
Processor::yield();
|
Processor::yield();
|
||||||
|
|
||||||
Processor::set_interrupt_state(state);
|
|
||||||
|
|
||||||
Thread::current().on_exit();
|
Thread::current().on_exit();
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
@@ -2951,7 +2948,7 @@ namespace Kernel
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
while (Thread::current().will_exit_because_of_signal())
|
while (Thread::current().will_exit_because_of_signal())
|
||||||
Thread::current().handle_signal();
|
Thread::current().handle_signal_if_interrupted();
|
||||||
|
|
||||||
SpinLockGuard guard(m_signal_lock);
|
SpinLockGuard guard(m_signal_lock);
|
||||||
if (!m_stopped)
|
if (!m_stopped)
|
||||||
@@ -3050,7 +3047,7 @@ namespace Kernel
|
|||||||
TRY(read_from_user(user_act, &new_act, sizeof(struct sigaction)));
|
TRY(read_from_user(user_act, &new_act, sizeof(struct sigaction)));
|
||||||
|
|
||||||
{
|
{
|
||||||
SpinLockGuard signal_lock_guard(m_signal_lock);
|
SpinLockGuard _(m_signal_lock);
|
||||||
old_act = m_signal_handlers[signal];
|
old_act = m_signal_handlers[signal];
|
||||||
if (user_act != nullptr)
|
if (user_act != nullptr)
|
||||||
m_signal_handlers[signal] = new_act;
|
m_signal_handlers[signal] = new_act;
|
||||||
@@ -3064,7 +3061,14 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_sigpending(sigset_t* user_sigset)
|
BAN::ErrorOr<long> Process::sys_sigpending(sigset_t* user_sigset)
|
||||||
{
|
{
|
||||||
const sigset_t sigset = (signal_pending_mask() | Thread::current().m_signal_pending_mask) & Thread::current().m_signal_block_mask;
|
sigset_t sigset;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& thread = Thread::current();
|
||||||
|
SpinLockGuard _(thread.m_signal_lock);
|
||||||
|
sigset = (signal_pending_mask() | thread.m_signal_pending_mask) & thread.m_signal_block_mask;
|
||||||
|
}
|
||||||
|
|
||||||
TRY(write_to_user(user_sigset, &sigset, sizeof(sigset_t)));
|
TRY(write_to_user(user_sigset, &sigset, sizeof(sigset_t)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3073,34 +3077,36 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
if (user_oset != nullptr)
|
auto& thread = Thread::current();
|
||||||
{
|
|
||||||
const sigset_t current = Thread::current().m_signal_block_mask;
|
const sigset_t old_sigset = thread.m_signal_block_mask;
|
||||||
TRY(write_to_user(user_oset, ¤t, sizeof(sigset_t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user_set != nullptr)
|
if (user_set != nullptr)
|
||||||
{
|
{
|
||||||
sigset_t set;
|
sigset_t mask;
|
||||||
TRY(read_from_user(user_set, &set, sizeof(sigset_t)));
|
TRY(read_from_user(user_set, &mask, sizeof(sigset_t)));
|
||||||
|
mask &= ~((1ull << SIGKILL) | (1ull << SIGSTOP));
|
||||||
|
|
||||||
const sigset_t mask = set & ~(SIGKILL | SIGSTOP);
|
SpinLockGuard _(thread.m_signal_lock);
|
||||||
switch (how)
|
switch (how)
|
||||||
{
|
{
|
||||||
case SIG_BLOCK:
|
case SIG_BLOCK:
|
||||||
Thread::current().m_signal_block_mask |= mask;
|
thread.m_signal_block_mask |= mask;
|
||||||
break;
|
|
||||||
case SIG_SETMASK:
|
|
||||||
Thread::current().m_signal_block_mask = mask;
|
|
||||||
break;
|
break;
|
||||||
case SIG_UNBLOCK:
|
case SIG_UNBLOCK:
|
||||||
Thread::current().m_signal_block_mask &= ~mask;
|
thread.m_signal_block_mask &= ~mask;
|
||||||
|
break;
|
||||||
|
case SIG_SETMASK:
|
||||||
|
thread.m_signal_block_mask = mask;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user_oset != nullptr)
|
||||||
|
TRY(write_to_user(user_oset, &old_sigset, sizeof(sigset_t)));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3112,7 +3118,7 @@ namespace Kernel
|
|||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
auto& thread = Thread::current();
|
auto& thread = Thread::current();
|
||||||
thread.set_suspend_signal_mask(set & ~(SIGKILL | SIGSTOP));
|
thread.set_suspend_signal_mask(set & ~((1ull << SIGKILL) | (1ull << SIGSTOP)));
|
||||||
|
|
||||||
// FIXME: i *think* here is a race condition as kill doesnt hold process lock
|
// FIXME: i *think* here is a race condition as kill doesnt hold process lock
|
||||||
while (!thread.is_interrupted_by_signal())
|
while (!thread.is_interrupted_by_signal())
|
||||||
@@ -3305,7 +3311,9 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_set_fsbase(void* addr)
|
BAN::ErrorOr<long> Process::sys_set_fsbase(void* addr)
|
||||||
{
|
{
|
||||||
Thread::current().set_fsbase(reinterpret_cast<vaddr_t>(addr));
|
auto& thread = Thread::current();
|
||||||
|
thread.m_has_custom_fsbase = true;
|
||||||
|
thread.set_fsbase(reinterpret_cast<vaddr_t>(addr));
|
||||||
Processor::load_fsbase();
|
Processor::load_fsbase();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3317,7 +3325,9 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_set_gsbase(void* addr)
|
BAN::ErrorOr<long> Process::sys_set_gsbase(void* addr)
|
||||||
{
|
{
|
||||||
Thread::current().set_gsbase(reinterpret_cast<vaddr_t>(addr));
|
auto& thread = Thread::current();
|
||||||
|
thread.m_has_custom_gsbase = true;
|
||||||
|
thread.set_gsbase(reinterpret_cast<vaddr_t>(addr));
|
||||||
Processor::load_gsbase();
|
Processor::load_gsbase();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3887,237 +3897,45 @@ namespace Kernel
|
|||||||
return region->allocate_page_containing(address, wants_write);
|
return region->allocate_page_containing(address, wants_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The following 3 functions could be simplified into one generic helper function
|
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)
|
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
if (!is_valid_user_address(user_addr, size))
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
auto* out_u8 = static_cast<uint8_t*>(out);
|
if (!safe_user_memcpy(out, user_addr, size))
|
||||||
size_t ncopied = 0;
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
return {};
|
||||||
{
|
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) != flags)
|
|
||||||
goto read_from_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
read_from_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
|
|
||||||
continue;
|
|
||||||
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, false)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
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))
|
||||||
size_t ncopied = 0;
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
if (!safe_user_strncpy(out, user_addr, max_size))
|
||||||
{
|
return BAN::Error::from_errno(EFAULT);
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
return {};
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
vaddr_t last_page = 0;
|
|
||||||
|
|
||||||
for (; ncopied < max_size; ncopied++)
|
|
||||||
{
|
|
||||||
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
if (curr_page != last_page)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(curr_page) & flags) != flags)
|
|
||||||
goto read_string_from_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
out[ncopied] = user_addr[ncopied];
|
|
||||||
if (out[ncopied] == '\0')
|
|
||||||
return {};
|
|
||||||
|
|
||||||
last_page = curr_page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= max_size)
|
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
read_string_from_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
vaddr_t last_page = 0;
|
|
||||||
|
|
||||||
for (; ncopied < max_size; ncopied++)
|
|
||||||
{
|
|
||||||
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
if (curr_page != last_page)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(curr_page) & flags) == flags)
|
|
||||||
;
|
|
||||||
else if (!TRY(region->allocate_page_containing(curr_page, false)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
out[ncopied] = user_addr[ncopied];
|
|
||||||
if (out[ncopied] == '\0')
|
|
||||||
return {};
|
|
||||||
|
|
||||||
last_page = curr_page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= max_size)
|
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
|
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
if (!is_valid_user_address(user_addr, size))
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
const auto* in_u8 = static_cast<const uint8_t*>(in);
|
if (!safe_user_memcpy(user_addr, in, size))
|
||||||
size_t ncopied = 0;
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
return {};
|
||||||
{
|
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t i = 0; i < page_count; i++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + i * PAGE_SIZE) & flags) != flags)
|
|
||||||
goto write_to_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
write_to_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
|
|
||||||
continue;
|
|
||||||
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, true)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
||||||
|
|||||||
@@ -377,8 +377,7 @@ namespace Kernel
|
|||||||
case SMPMessage::Type::FlushTLB:
|
case SMPMessage::Type::FlushTLB:
|
||||||
if (message->flush_tlb.page_table && message->flush_tlb.page_table != processor.m_current_page_table)
|
if (message->flush_tlb.page_table && message->flush_tlb.page_table != processor.m_current_page_table)
|
||||||
break;
|
break;
|
||||||
for (size_t i = 0; i < message->flush_tlb.page_count; i++)
|
PageTable::current().invalidate_range(message->flush_tlb.vaddr, message->flush_tlb.page_count, false);
|
||||||
asm volatile("invlpg (%0)" :: "r"(message->flush_tlb.vaddr + i * PAGE_SIZE) : "memory");
|
|
||||||
break;
|
break;
|
||||||
case SMPMessage::Type::NewThread:
|
case SMPMessage::Type::NewThread:
|
||||||
processor.m_scheduler->add_thread(message->new_thread);
|
processor.m_scheduler->add_thread(message->new_thread);
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ namespace Kernel
|
|||||||
if (Processor::count() > 1)
|
if (Processor::count() > 1)
|
||||||
Processor::set_smp_enabled();
|
Processor::set_smp_enabled();
|
||||||
|
|
||||||
|
m_next_reschedule_ns = SystemTimer::get().ns_since_boot();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,13 +350,10 @@ namespace Kernel
|
|||||||
|
|
||||||
wake_up_sleeping_threads();
|
wake_up_sleeping_threads();
|
||||||
|
|
||||||
|
if (SystemTimer::get().ns_since_boot() >= m_next_reschedule_ns)
|
||||||
{
|
{
|
||||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
m_next_reschedule_ns += s_reschedule_interval_ns;
|
||||||
if (current_ns >= m_last_reschedule_ns + s_reschedule_interval_ns)
|
Processor::yield();
|
||||||
{
|
|
||||||
m_last_reschedule_ns = current_ns;
|
|
||||||
Processor::yield();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
#define DUMP_ALL_SYSCALLS 0
|
#define DUMP_ALL_SYSCALLS 0
|
||||||
#define DUMP_LONG_SYSCALLS 0
|
#define DUMP_LONG_SYSCALLS 0
|
||||||
@@ -94,13 +95,11 @@ namespace Kernel
|
|||||||
|
|
||||||
Process::current().wait_while_stopped();
|
Process::current().wait_while_stopped();
|
||||||
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
if (Thread::current().handle_signal_if_interrupted())
|
||||||
|
if (ret.is_error() && ret.error().get_error_code() == EINTR && is_restartable_syscall(syscall))
|
||||||
|
ret = BAN::Error::from_errno(ERESTART);
|
||||||
|
|
||||||
auto& current_thread = Thread::current();
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
if (current_thread.can_add_signal_to_execute())
|
|
||||||
if (current_thread.handle_signal())
|
|
||||||
if (ret.is_error() && ret.error().get_error_code() == EINTR && is_restartable_syscall(syscall))
|
|
||||||
ret = BAN::Error::from_errno(ERESTART);
|
|
||||||
|
|
||||||
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
|
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
static constexpr vaddr_t s_user_stack_addr_start = 0x0000700000000000;
|
||||||
|
#elif ARCH(i686)
|
||||||
|
static constexpr vaddr_t s_user_stack_addr_start = 0xB0000000;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" [[noreturn]] void start_kernel_thread();
|
extern "C" [[noreturn]] void start_kernel_thread();
|
||||||
extern "C" [[noreturn]] void start_userspace_thread();
|
extern "C" [[noreturn]] void start_userspace_thread();
|
||||||
|
|
||||||
@@ -25,11 +31,6 @@ namespace Kernel
|
|||||||
*(uintptr_t*)rsp = (uintptr_t)value;
|
*(uintptr_t*)rsp = (uintptr_t)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" uintptr_t get_thread_start_sp()
|
|
||||||
{
|
|
||||||
return Thread::current().yield_registers().sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pid_t s_next_tid = 1;
|
static pid_t s_next_tid = 1;
|
||||||
|
|
||||||
alignas(16) static uint8_t s_default_sse_storage[512];
|
alignas(16) static uint8_t s_default_sse_storage[512];
|
||||||
@@ -205,15 +206,9 @@ namespace Kernel
|
|||||||
|
|
||||||
thread->m_is_userspace = true;
|
thread->m_is_userspace = true;
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
|
||||||
static constexpr vaddr_t stack_addr_start = 0x0000700000000000;
|
|
||||||
#elif ARCH(i686)
|
|
||||||
static constexpr vaddr_t stack_addr_start = 0xB0000000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
page_table,
|
page_table,
|
||||||
stack_addr_start, USERSPACE_END,
|
s_user_stack_addr_start, USERSPACE_END,
|
||||||
kernel_stack_size,
|
kernel_stack_size,
|
||||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
true, true
|
true, true
|
||||||
@@ -222,7 +217,7 @@ namespace Kernel
|
|||||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||||
page_table,
|
page_table,
|
||||||
userspace_stack_size,
|
userspace_stack_size,
|
||||||
{ stack_addr_start, USERSPACE_END },
|
{ s_user_stack_addr_start, USERSPACE_END },
|
||||||
MemoryRegion::Type::PRIVATE,
|
MemoryRegion::Type::PRIVATE,
|
||||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
O_RDWR
|
O_RDWR
|
||||||
@@ -310,6 +305,14 @@ namespace Kernel
|
|||||||
if (!is_userspace() || !has_process())
|
if (!is_userspace() || !has_process())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
if (m_has_custom_gsbase)
|
||||||
|
return;
|
||||||
|
#elif ARCH(i686)
|
||||||
|
if (m_has_custom_fsbase)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
const vaddr_t vaddr = process().shared_page_vaddr() + Processor::current_index();
|
const vaddr_t vaddr = process().shared_page_vaddr() + Processor::current_index();
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
@@ -351,7 +354,24 @@ namespace Kernel
|
|||||||
|
|
||||||
thread->m_is_userspace = true;
|
thread->m_is_userspace = true;
|
||||||
|
|
||||||
thread->m_kernel_stack = TRY(m_kernel_stack->clone(new_process->page_table()));
|
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
|
new_process->page_table(),
|
||||||
|
s_user_stack_addr_start, USERSPACE_END,
|
||||||
|
kernel_stack_size,
|
||||||
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
|
true, true
|
||||||
|
));
|
||||||
|
|
||||||
|
// NOTE: copy [sp, stack_end] so fork return works
|
||||||
|
PageTable::with_fast_page(thread->m_kernel_stack->paddr_of(thread->kernel_stack_top() - PAGE_SIZE), [&] {
|
||||||
|
const size_t ncopy = kernel_stack_top() - sp;
|
||||||
|
ASSERT(ncopy <= PAGE_SIZE);
|
||||||
|
memcpy(
|
||||||
|
PageTable::fast_page_as_ptr(PAGE_SIZE - ncopy),
|
||||||
|
reinterpret_cast<void*>(sp),
|
||||||
|
ncopy
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
|
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
|
||||||
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
|
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
|
||||||
@@ -572,19 +592,6 @@ namespace Kernel
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::can_add_signal_to_execute() const
|
|
||||||
{
|
|
||||||
return is_interrupted_by_signal() && m_mutex_count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Thread::will_execute_signal() const
|
|
||||||
{
|
|
||||||
if (!is_userspace() || m_state != State::Executing)
|
|
||||||
return false;
|
|
||||||
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
|
||||||
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Thread::will_exit_because_of_signal() const
|
bool Thread::will_exit_because_of_signal() const
|
||||||
{
|
{
|
||||||
const uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();
|
const uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();
|
||||||
@@ -596,21 +603,17 @@ namespace Kernel
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::handle_signal(int signal, const siginfo_t& _signal_info)
|
bool Thread::handle_signal_if_interrupted()
|
||||||
{
|
{
|
||||||
ASSERT(&Thread::current() == this);
|
int signal;
|
||||||
ASSERT(is_userspace());
|
siginfo_t signal_info;
|
||||||
|
signal_handle_info_t handle_info;
|
||||||
|
|
||||||
auto state = m_signal_lock.lock();
|
|
||||||
|
|
||||||
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
|
||||||
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
|
|
||||||
|
|
||||||
auto signal_info = _signal_info;
|
|
||||||
|
|
||||||
if (signal == 0)
|
|
||||||
{
|
{
|
||||||
const uint64_t process_signal_pending_mask = process().signal_pending_mask();
|
SpinLockGuard _1(m_signal_lock);
|
||||||
|
SpinLockGuard _2(m_process->m_signal_lock);
|
||||||
|
|
||||||
|
const uint64_t process_signal_pending_mask = m_process->m_signal_pending_mask;
|
||||||
const uint64_t full_pending_mask = m_signal_pending_mask | process_signal_pending_mask;
|
const uint64_t full_pending_mask = m_signal_pending_mask | process_signal_pending_mask;
|
||||||
for (signal = _SIGMIN; signal <= _SIGMAX; signal++)
|
for (signal = _SIGMIN; signal <= _SIGMAX; signal++)
|
||||||
{
|
{
|
||||||
@@ -618,42 +621,90 @@ namespace Kernel
|
|||||||
if ((full_pending_mask & mask) && !(m_signal_block_mask & mask))
|
if ((full_pending_mask & mask) && !(m_signal_block_mask & mask))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ASSERT(signal <= _SIGMAX);
|
if (signal > _SIGMAX)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (process_signal_pending_mask & (1ull << signal))
|
if (process_signal_pending_mask & (1ull << signal))
|
||||||
signal_info = process().m_signal_infos[signal];
|
signal_info = m_process->m_signal_infos[signal];
|
||||||
else
|
else
|
||||||
signal_info = m_signal_infos[signal];
|
signal_info = m_signal_infos[signal];
|
||||||
}
|
signal_info.si_signo = signal;
|
||||||
else
|
|
||||||
{
|
handle_info = remove_signal_and_get_info(signal);
|
||||||
ASSERT(signal >= _SIGMIN);
|
|
||||||
ASSERT(signal <= _SIGMAX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr_t signal_handler;
|
handle_signal_impl(signal, signal_info, handle_info);
|
||||||
bool has_sa_restart;
|
|
||||||
|
return handle_info.has_sa_restart;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::handle_signal(int signal, const siginfo_t& signal_info)
|
||||||
|
{
|
||||||
|
ASSERT(&Thread::current() == this);
|
||||||
|
ASSERT(is_userspace());
|
||||||
|
|
||||||
|
ASSERT(signal >= _SIGMIN);
|
||||||
|
ASSERT(signal <= _SIGMAX);
|
||||||
|
|
||||||
|
signal_handle_info_t handle_info;
|
||||||
|
|
||||||
|
// If this signal is blocked or ignored, terminate the process
|
||||||
|
bool terminate_process = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
SpinLockGuard _1(m_signal_lock);
|
||||||
|
SpinLockGuard _2(m_process->m_signal_lock);
|
||||||
|
|
||||||
|
if (m_signal_block_mask & (1ull << signal))
|
||||||
|
terminate_process = true;
|
||||||
|
|
||||||
|
handle_info = remove_signal_and_get_info(signal);
|
||||||
|
|
||||||
|
if (handle_info.handler == reinterpret_cast<vaddr_t>(SIG_IGN))
|
||||||
|
terminate_process = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terminate_process)
|
||||||
|
{
|
||||||
|
process().exit(128 + signal, signal | 0x80);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_signal_impl(signal, signal_info, handle_info);
|
||||||
|
|
||||||
|
return handle_info.has_sa_restart;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::signal_handle_info_t Thread::remove_signal_and_get_info(int signal)
|
||||||
|
{
|
||||||
|
ASSERT(m_signal_lock.current_processor_has_lock());
|
||||||
|
ASSERT(m_process->m_signal_lock.current_processor_has_lock());
|
||||||
|
|
||||||
|
ASSERT(signal >= _SIGMIN);
|
||||||
|
ASSERT(signal <= _SIGMAX);
|
||||||
|
|
||||||
|
const uint64_t restore_sigmask = m_signal_block_mask;
|
||||||
|
|
||||||
|
auto& handler = m_process->m_signal_handlers[signal];
|
||||||
|
|
||||||
|
const vaddr_t signal_handler = (handler.sa_flags & SA_SIGINFO)
|
||||||
|
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
|
||||||
|
: reinterpret_cast<vaddr_t>(handler.sa_handler);
|
||||||
|
const bool has_sa_restart = !!(handler.sa_flags & SA_RESTART);
|
||||||
|
|
||||||
vaddr_t signal_stack_top = 0;
|
vaddr_t signal_stack_top = 0;
|
||||||
|
if (m_signal_alt_stack.ss_flags != SS_DISABLE && (handler.sa_flags & SA_ONSTACK) && !currently_on_alternate_stack())
|
||||||
|
signal_stack_top = reinterpret_cast<vaddr_t>(m_signal_alt_stack.ss_sp) + m_signal_alt_stack.ss_size;
|
||||||
|
|
||||||
{
|
m_signal_block_mask |= handler.sa_mask;
|
||||||
SpinLockGuard _(m_process->m_signal_lock);
|
if (!(handler.sa_flags & SA_NODEFER))
|
||||||
|
m_signal_block_mask |= 1ull << signal;
|
||||||
|
|
||||||
auto& handler = m_process->m_signal_handlers[signal];
|
if (handler.sa_flags & SA_RESETHAND)
|
||||||
|
handler = { .sa_handler = SIG_DFL, .sa_mask = 0, .sa_flags = 0 };
|
||||||
signal_handler = (handler.sa_flags & SA_SIGINFO)
|
|
||||||
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
|
|
||||||
: reinterpret_cast<vaddr_t>(handler.sa_handler);
|
|
||||||
has_sa_restart = !!(handler.sa_flags & SA_RESTART);
|
|
||||||
|
|
||||||
const auto& alt_stack = m_signal_alt_stack;
|
|
||||||
if (alt_stack.ss_flags != SS_DISABLE && (handler.sa_flags & SA_ONSTACK) && !currently_on_alternate_stack())
|
|
||||||
signal_stack_top = reinterpret_cast<vaddr_t>(alt_stack.ss_sp) + alt_stack.ss_size;
|
|
||||||
|
|
||||||
if (handler.sa_flags & SA_RESETHAND)
|
|
||||||
handler = { .sa_handler = SIG_DFL, .sa_mask = 0, .sa_flags = 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
m_signal_pending_mask &= ~(1ull << signal);
|
m_signal_pending_mask &= ~(1ull << signal);
|
||||||
process().remove_pending_signal(signal);
|
m_process->m_signal_pending_mask &= ~(1ull << signal);
|
||||||
|
|
||||||
if (m_signal_suspend_mask.has_value())
|
if (m_signal_suspend_mask.has_value())
|
||||||
{
|
{
|
||||||
@@ -661,66 +712,54 @@ namespace Kernel
|
|||||||
m_signal_suspend_mask.clear();
|
m_signal_suspend_mask.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_signal_lock.unlock(state);
|
return {
|
||||||
|
.handler = signal_handler,
|
||||||
|
.stack_top = signal_stack_top,
|
||||||
|
.restore_sigmask = restore_sigmask,
|
||||||
|
.has_sa_restart = has_sa_restart,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (signal_handler == (vaddr_t)SIG_IGN)
|
void Thread::handle_signal_impl(int signal, const siginfo_t& signal_info, const signal_handle_info_t& handle_info)
|
||||||
|
{
|
||||||
|
ASSERT(this == &Thread::current());
|
||||||
|
ASSERT(is_userspace());
|
||||||
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
|
|
||||||
|
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
||||||
|
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
|
||||||
|
|
||||||
|
if (handle_info.handler == reinterpret_cast<vaddr_t>(SIG_IGN))
|
||||||
;
|
;
|
||||||
else if (signal_handler != (vaddr_t)SIG_DFL)
|
else if (handle_info.handler != reinterpret_cast<vaddr_t>(SIG_DFL))
|
||||||
{
|
{
|
||||||
// call userspace signal handlers
|
// call userspace signal handlers
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
interrupt_stack.sp -= 128; // skip possible red-zone
|
interrupt_stack.sp -= 128; // skip possible red-zone
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
const auto write_to_stack =
|
||||||
// Make sure stack is allocated
|
[&]<typename T>(uintptr_t& sp, const T& value)
|
||||||
|
|
||||||
vaddr_t pages[3] {};
|
|
||||||
size_t page_count { 0 };
|
|
||||||
|
|
||||||
if (signal_stack_top == 0)
|
|
||||||
{
|
{
|
||||||
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
|
static_assert(sizeof(T) >= sizeof(uintptr_t));
|
||||||
pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK;
|
sp -= sizeof(T);
|
||||||
page_count = 2;
|
if (m_process->write_to_user(reinterpret_cast<void*>(sp), &value, sizeof(T)).is_error())
|
||||||
}
|
m_process->exit(128 + SIGSEGV, SIGSEGV | 0x80);
|
||||||
else
|
};
|
||||||
{
|
|
||||||
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
|
|
||||||
pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK;
|
|
||||||
pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK;
|
|
||||||
page_count = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < page_count; i++)
|
|
||||||
{
|
|
||||||
if (m_process->page_table().get_page_flags(pages[i]) & PageTable::Flags::Present)
|
|
||||||
continue;
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
|
||||||
if (auto ret = m_process->allocate_page_for_demand_paging(pages[i], true, false); ret.is_error() || !ret.value())
|
|
||||||
m_process->exit(128 + SIGSEGV, SIGSEGV);
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write_to_stack(interrupt_stack.sp, interrupt_stack.ip);
|
write_to_stack(interrupt_stack.sp, interrupt_stack.ip);
|
||||||
const vaddr_t old_stack = interrupt_stack.sp;
|
const vaddr_t old_stack = interrupt_stack.sp;
|
||||||
if (signal_stack_top)
|
if (handle_info.stack_top)
|
||||||
interrupt_stack.sp = signal_stack_top;
|
interrupt_stack.sp = handle_info.stack_top;
|
||||||
write_to_stack(interrupt_stack.sp, old_stack);
|
write_to_stack(interrupt_stack.sp, old_stack);
|
||||||
write_to_stack(interrupt_stack.sp, interrupt_stack.flags);
|
write_to_stack(interrupt_stack.sp, interrupt_stack.flags);
|
||||||
|
write_to_stack(interrupt_stack.sp, handle_info.restore_sigmask);
|
||||||
|
|
||||||
{
|
ASSERT(signal_info.si_signo == signal);
|
||||||
signal_info.si_signo = signal;
|
write_to_stack(interrupt_stack.sp, signal_info);
|
||||||
signal_info.si_addr = reinterpret_cast<void*>(interrupt_stack.ip);
|
|
||||||
|
|
||||||
interrupt_stack.sp -= sizeof(siginfo_t);
|
write_to_stack(interrupt_stack.sp, static_cast<uintptr_t>(signal));
|
||||||
*reinterpret_cast<siginfo_t*>(interrupt_stack.sp) = signal_info;
|
write_to_stack(interrupt_stack.sp, handle_info.handler);
|
||||||
static_assert(sizeof(siginfo_t) % sizeof(uintptr_t) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
write_to_stack(interrupt_stack.sp, signal);
|
|
||||||
write_to_stack(interrupt_stack.sp, signal_handler);
|
|
||||||
interrupt_stack.ip = (uintptr_t)signal_trampoline;
|
interrupt_stack.ip = (uintptr_t)signal_trampoline;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -752,8 +791,6 @@ namespace Kernel
|
|||||||
panic("Executing unhandled signal {}", signal);
|
panic("Executing unhandled signal {}", signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return has_sa_restart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::add_signal(int signal, const siginfo_t& info)
|
void Thread::add_signal(int signal, const siginfo_t& info)
|
||||||
|
|||||||
@@ -342,6 +342,9 @@ namespace Kernel
|
|||||||
s_scancode_to_keycode[0x4B] = keycode_function(18);
|
s_scancode_to_keycode[0x4B] = keycode_function(18);
|
||||||
s_scancode_to_keycode[0x4E] = keycode_function(19);
|
s_scancode_to_keycode[0x4E] = keycode_function(19);
|
||||||
s_scancode_to_keycode[0x47] = keycode_function(20);
|
s_scancode_to_keycode[0x47] = keycode_function(20);
|
||||||
|
s_scancode_to_keycode[0x7F] = keycode_function(21);
|
||||||
|
s_scancode_to_keycode[0x81] = keycode_function(22);
|
||||||
|
s_scancode_to_keycode[0x80] = keycode_function(23);
|
||||||
|
|
||||||
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
|
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
|
||||||
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);
|
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);
|
||||||
|
|||||||
@@ -255,8 +255,8 @@ static void init2(void*)
|
|||||||
VirtualFileSystem::initialize(cmdline.root);
|
VirtualFileSystem::initialize(cmdline.root);
|
||||||
dprintln("VFS initialized");
|
dprintln("VFS initialized");
|
||||||
|
|
||||||
// FIXME: release memory used by modules. If modules are used
|
// NOTE: All modules should be loaded
|
||||||
// they are already loaded in here
|
Heap::get().release_boot_modules();
|
||||||
|
|
||||||
TTY::initialize_devices();
|
TTY::initialize_devices();
|
||||||
|
|
||||||
|
|||||||
47
kernel/klibc/arch/i686/string.S
Normal file
47
kernel/klibc/arch/i686/string.S
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
.align 16
|
||||||
|
.global memcpy
|
||||||
|
memcpy:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep movsb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
movl %edx, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memmove
|
||||||
|
memmove:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
cmpl %edi, %esi
|
||||||
|
jb .memmove_slow
|
||||||
|
rep movsb
|
||||||
|
.memmove_done:
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
movl %edx, %eax
|
||||||
|
ret
|
||||||
|
.memmove_slow:
|
||||||
|
leal -1(%edi, %ecx), %edi
|
||||||
|
leal -1(%esi, %ecx), %esi
|
||||||
|
std
|
||||||
|
rep movsb
|
||||||
|
cld
|
||||||
|
jmp .memmove_done
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memset
|
||||||
|
memset:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %eax
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep stosb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl %edx, %eax
|
||||||
|
ret
|
||||||
31
kernel/klibc/arch/x86_64/string.S
Normal file
31
kernel/klibc/arch/x86_64/string.S
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.align 16
|
||||||
|
.global memcpy
|
||||||
|
memcpy:
|
||||||
|
movq %rdi, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep movsb
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memmove
|
||||||
|
memmove:
|
||||||
|
cmpq %rdi, %rsi
|
||||||
|
jae memcpy
|
||||||
|
movq %rdi, %rax
|
||||||
|
leaq -1(%rdi, %rdx), %rdi
|
||||||
|
leaq -1(%rsi, %rdx), %rsi
|
||||||
|
movq %rdx, %rcx
|
||||||
|
std
|
||||||
|
rep movsb
|
||||||
|
cld
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memset
|
||||||
|
memset:
|
||||||
|
movq %rdi, %r8
|
||||||
|
movb %sil, %al
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep stosb
|
||||||
|
movq %r8, %rax
|
||||||
|
ret
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
diff -ruN SDL2-2.32.8/cmake/sdlplatform.cmake SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake
|
diff -ruN SDL2-2.32.8/cmake/sdlplatform.cmake SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake
|
||||||
--- SDL2-2.32.8/cmake/sdlplatform.cmake 2024-08-14 13:35:43.000000000 +0300
|
--- SDL2-2.32.8/cmake/sdlplatform.cmake 2024-08-14 13:35:43.000000000 +0300
|
||||||
+++ SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake 2026-01-07 19:04:34.332166371 +0200
|
+++ SDL2-2.32.8-banan_os/cmake/sdlplatform.cmake 2026-04-03 04:34:27.256800208 +0300
|
||||||
@@ -28,6 +28,8 @@
|
@@ -28,6 +28,8 @@
|
||||||
set(SDL_CMAKE_PLATFORM AIX)
|
set(SDL_CMAKE_PLATFORM AIX)
|
||||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Minix.*")
|
elseif(CMAKE_SYSTEM_NAME MATCHES "Minix.*")
|
||||||
@@ -12,7 +12,7 @@ diff -ruN SDL2-2.32.8/cmake/sdlplatform.cmake SDL2-2.32.8-banan_os/cmake/sdlplat
|
|||||||
endif()
|
endif()
|
||||||
diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
|
diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
|
||||||
--- SDL2-2.32.8/CMakeLists.txt 2025-06-03 02:00:39.000000000 +0300
|
--- SDL2-2.32.8/CMakeLists.txt 2025-06-03 02:00:39.000000000 +0300
|
||||||
+++ SDL2-2.32.8-banan_os/CMakeLists.txt 2026-01-07 19:04:34.343116295 +0200
|
+++ SDL2-2.32.8-banan_os/CMakeLists.txt 2026-04-03 04:34:27.257159543 +0300
|
||||||
@@ -14,7 +14,7 @@
|
@@ -14,7 +14,7 @@
|
||||||
set(SDL2_SUBPROJECT ON)
|
set(SDL2_SUBPROJECT ON)
|
||||||
endif()
|
endif()
|
||||||
@@ -98,7 +98,7 @@ diff -ruN SDL2-2.32.8/CMakeLists.txt SDL2-2.32.8-banan_os/CMakeLists.txt
|
|||||||
file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/riscos/*.c)
|
file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/riscos/*.c)
|
||||||
diff -ruN SDL2-2.32.8/include/SDL_config.h.cmake SDL2-2.32.8-banan_os/include/SDL_config.h.cmake
|
diff -ruN SDL2-2.32.8/include/SDL_config.h.cmake SDL2-2.32.8-banan_os/include/SDL_config.h.cmake
|
||||||
--- SDL2-2.32.8/include/SDL_config.h.cmake 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/include/SDL_config.h.cmake 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/include/SDL_config.h.cmake 2026-01-07 19:04:34.358682129 +0200
|
+++ SDL2-2.32.8-banan_os/include/SDL_config.h.cmake 2026-04-03 04:34:27.257563019 +0300
|
||||||
@@ -307,6 +307,7 @@
|
@@ -307,6 +307,7 @@
|
||||||
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
|
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
|
||||||
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
|
#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
|
||||||
@@ -125,7 +125,7 @@ diff -ruN SDL2-2.32.8/include/SDL_config.h.cmake SDL2-2.32.8-banan_os/include/SD
|
|||||||
#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
|
#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
|
||||||
diff -ruN SDL2-2.32.8/include/SDL_platform.h SDL2-2.32.8-banan_os/include/SDL_platform.h
|
diff -ruN SDL2-2.32.8/include/SDL_platform.h SDL2-2.32.8-banan_os/include/SDL_platform.h
|
||||||
--- SDL2-2.32.8/include/SDL_platform.h 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/include/SDL_platform.h 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/include/SDL_platform.h 2026-01-07 19:04:34.370086235 +0200
|
+++ SDL2-2.32.8-banan_os/include/SDL_platform.h 2026-04-03 04:34:27.257711782 +0300
|
||||||
@@ -36,6 +36,10 @@
|
@@ -36,6 +36,10 @@
|
||||||
#undef __HAIKU__
|
#undef __HAIKU__
|
||||||
#define __HAIKU__ 1
|
#define __HAIKU__ 1
|
||||||
@@ -139,8 +139,8 @@ diff -ruN SDL2-2.32.8/include/SDL_platform.h SDL2-2.32.8-banan_os/include/SDL_pl
|
|||||||
#define __BSDI__ 1
|
#define __BSDI__ 1
|
||||||
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp
|
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp
|
||||||
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp 2026-01-07 19:04:34.370691623 +0200
|
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.cpp 2026-04-03 16:06:27.541819001 +0300
|
||||||
@@ -0,0 +1,150 @@
|
@@ -0,0 +1,134 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||||
@@ -154,11 +154,11 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-bana
|
|||||||
+ freely, subject to the following restrictions:
|
+ freely, subject to the following restrictions:
|
||||||
+
|
+
|
||||||
+ 1. The origin of this software must not be misrepresented; you must not
|
+ 1. The origin of this software must not be misrepresented; you must not
|
||||||
+ claim that you wrote the original software. If you use this software
|
+ claim that you wrote the original software. If you use this software
|
||||||
+ in a product, an acknowledgment in the product documentation would be
|
+ in a product, an acknowledgment in the product documentation would be
|
||||||
+ appreciated but is not required.
|
+ appreciated but is not required.
|
||||||
+ 2. Altered source versions must be plainly marked as such, and must not be
|
+ 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
+ misrepresented as being the original software.
|
+ misrepresented as being the original software.
|
||||||
+ 3. This notice may not be removed or altered from any source distribution.
|
+ 3. This notice may not be removed or altered from any source distribution.
|
||||||
+*/
|
+*/
|
||||||
+#include "../../SDL_internal.h"
|
+#include "../../SDL_internal.h"
|
||||||
@@ -201,8 +201,8 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-bana
|
|||||||
+ DUMP_FUNCTION();
|
+ DUMP_FUNCTION();
|
||||||
+
|
+
|
||||||
+ // TODO: try to accept already existing spec
|
+ // TODO: try to accept already existing spec
|
||||||
+ _this->spec.freq = 44100;
|
+ _this->spec.freq = 48000;
|
||||||
+ _this->spec.format = AUDIO_S16LSB;
|
+ _this->spec.format = AUDIO_F32LSB;
|
||||||
+ _this->spec.channels = 2;
|
+ _this->spec.channels = 2;
|
||||||
+ _this->spec.samples = 2048;
|
+ _this->spec.samples = 2048;
|
||||||
+ SDL_CalculateAudioSpec(&_this->spec);
|
+ SDL_CalculateAudioSpec(&_this->spec);
|
||||||
@@ -229,38 +229,22 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-bana
|
|||||||
+
|
+
|
||||||
+ const bool should_play = SDL_AtomicGet(&_this->enabled) && !SDL_AtomicGet(&_this->paused);
|
+ const bool should_play = SDL_AtomicGet(&_this->enabled) && !SDL_AtomicGet(&_this->paused);
|
||||||
+ _this->hidden->audio.set_paused(!should_play);
|
+ _this->hidden->audio.set_paused(!should_play);
|
||||||
+ if (!should_play)
|
+ if (!should_play)
|
||||||
+ {
|
+ {
|
||||||
+ usleep(100);
|
+ usleep(100);
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ static_assert(BAN::is_same_v<LibAudio::AudioBuffer::sample_t, double>);
|
+ auto sample_span = BAN::Span(
|
||||||
+
|
+ static_cast<const float*>(_this->hidden->mixbuf),
|
||||||
+ const auto convert_sample = [](int16_t input) {
|
+ _this->spec.size / sizeof(float)
|
||||||
+ return (static_cast<double>(input) - BAN::numeric_limits<int16_t>::min()) / BAN::numeric_limits<int16_t>::max() * 2.0 - 1.0;
|
+ );
|
||||||
+ };
|
+ while (!sample_span.empty())
|
||||||
+
|
|
||||||
+ const size_t input_samples = _this->spec.size / sizeof(int16_t);
|
|
||||||
+ size_t samples_queued = 0;
|
|
||||||
+
|
|
||||||
+ const int16_t* mixbuf = static_cast<const int16_t*>(_this->hidden->mixbuf);
|
|
||||||
+ while (samples_queued < input_samples)
|
|
||||||
+ {
|
+ {
|
||||||
+ const size_t to_convert = BAN::Math::min(_this->hidden->conversion.size(), input_samples - samples_queued);
|
+ const size_t queued = _this->hidden->audio.queue_samples(sample_span);
|
||||||
+ for (size_t i = 0; i < to_convert; i++)
|
+ if (queued == 0)
|
||||||
+ _this->hidden->conversion[i] = convert_sample(mixbuf[samples_queued + i]);
|
+ usleep(100);
|
||||||
+
|
+ sample_span = sample_span.slice(queued);
|
||||||
+ auto sample_span = _this->hidden->conversion.span();
|
|
||||||
+ while (!sample_span.empty())
|
|
||||||
+ {
|
|
||||||
+ const size_t queued = _this->hidden->audio.queue_samples(sample_span);
|
|
||||||
+ if (queued == 0)
|
|
||||||
+ usleep(100);
|
|
||||||
+ sample_span = sample_span.slice(queued);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ samples_queued += to_convert;
|
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
@@ -268,33 +252,33 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.cpp SDL2-2.32.8-bana
|
|||||||
+{
|
+{
|
||||||
+ DUMP_FUNCTION();
|
+ DUMP_FUNCTION();
|
||||||
+
|
+
|
||||||
+ return static_cast<Uint8*>(_this->hidden->mixbuf);
|
+ return static_cast<Uint8*>(_this->hidden->mixbuf);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static SDL_bool BANANOS_Init(SDL_AudioDriverImpl* impl)
|
+static SDL_bool BANANOS_Init(SDL_AudioDriverImpl* impl)
|
||||||
+{
|
+{
|
||||||
+ impl->OpenDevice = BANANOS_OpenDevice;
|
+ impl->OpenDevice = BANANOS_OpenDevice;
|
||||||
+ impl->CloseDevice = BANANOS_CloseDevice;
|
+ impl->CloseDevice = BANANOS_CloseDevice;
|
||||||
+ impl->PlayDevice = BANANOS_PlayDevice;
|
+ impl->PlayDevice = BANANOS_PlayDevice;
|
||||||
+ impl->GetDeviceBuf = BANANOS_GetDeviceBuf;
|
+ impl->GetDeviceBuf = BANANOS_GetDeviceBuf;
|
||||||
+
|
+
|
||||||
+ impl->ProvidesOwnCallbackThread = SDL_FALSE;
|
+ impl->ProvidesOwnCallbackThread = SDL_FALSE;
|
||||||
+ impl->HasCaptureSupport = SDL_FALSE;
|
+ impl->HasCaptureSupport = SDL_FALSE;
|
||||||
+ impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
+ impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||||
+ impl->SupportsNonPow2Samples = SDL_TRUE;
|
+ impl->SupportsNonPow2Samples = SDL_TRUE;
|
||||||
+
|
+
|
||||||
+ return SDL_TRUE;
|
+ return SDL_TRUE;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+AudioBootStrap BANANOSAUDIO_bootstrap = {
|
+AudioBootStrap BANANOSAUDIO_bootstrap = {
|
||||||
+ "banan-os", "banan-os AudioServer", BANANOS_Init, SDL_FALSE
|
+ "banan-os", "banan-os AudioServer", BANANOS_Init, SDL_FALSE
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+#endif
|
+#endif
|
||||||
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h
|
diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h
|
||||||
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h 2026-01-07 19:04:34.370883199 +0200
|
+++ SDL2-2.32.8-banan_os/src/audio/banan_os/SDL_banan_os_audio.h 2026-04-03 15:56:58.603415021 +0300
|
||||||
@@ -0,0 +1,34 @@
|
@@ -0,0 +1,33 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||||
@@ -327,11 +311,10 @@ diff -ruN SDL2-2.32.8/src/audio/banan_os/SDL_banan_os_audio.h SDL2-2.32.8-banan_
|
|||||||
+struct SDL_PrivateAudioData {
|
+struct SDL_PrivateAudioData {
|
||||||
+ LibAudio::Audio audio;
|
+ LibAudio::Audio audio;
|
||||||
+ void* mixbuf { nullptr };
|
+ void* mixbuf { nullptr };
|
||||||
+ BAN::Array<LibAudio::AudioBuffer::sample_t, 4096> conversion;
|
|
||||||
+};
|
+};
|
||||||
diff -ruN SDL2-2.32.8/src/audio/SDL_audio.c SDL2-2.32.8-banan_os/src/audio/SDL_audio.c
|
diff -ruN SDL2-2.32.8/src/audio/SDL_audio.c SDL2-2.32.8-banan_os/src/audio/SDL_audio.c
|
||||||
--- SDL2-2.32.8/src/audio/SDL_audio.c 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/src/audio/SDL_audio.c 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/audio/SDL_audio.c 2026-01-07 19:04:34.371410923 +0200
|
+++ SDL2-2.32.8-banan_os/src/audio/SDL_audio.c 2026-04-03 04:34:27.258080476 +0300
|
||||||
@@ -87,6 +87,9 @@
|
@@ -87,6 +87,9 @@
|
||||||
#ifdef SDL_AUDIO_DRIVER_HAIKU
|
#ifdef SDL_AUDIO_DRIVER_HAIKU
|
||||||
&HAIKUAUDIO_bootstrap,
|
&HAIKUAUDIO_bootstrap,
|
||||||
@@ -344,7 +327,7 @@ diff -ruN SDL2-2.32.8/src/audio/SDL_audio.c SDL2-2.32.8-banan_os/src/audio/SDL_a
|
|||||||
#endif
|
#endif
|
||||||
diff -ruN SDL2-2.32.8/src/audio/SDL_sysaudio.h SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h
|
diff -ruN SDL2-2.32.8/src/audio/SDL_sysaudio.h SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h
|
||||||
--- SDL2-2.32.8/src/audio/SDL_sysaudio.h 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/src/audio/SDL_sysaudio.h 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h 2026-01-07 19:04:34.372150756 +0200
|
+++ SDL2-2.32.8-banan_os/src/audio/SDL_sysaudio.h 2026-04-03 04:34:27.258278128 +0300
|
||||||
@@ -196,6 +196,7 @@
|
@@ -196,6 +196,7 @@
|
||||||
extern AudioBootStrap WINMM_bootstrap;
|
extern AudioBootStrap WINMM_bootstrap;
|
||||||
extern AudioBootStrap PAUDIO_bootstrap;
|
extern AudioBootStrap PAUDIO_bootstrap;
|
||||||
@@ -355,7 +338,7 @@ diff -ruN SDL2-2.32.8/src/audio/SDL_sysaudio.h SDL2-2.32.8-banan_os/src/audio/SD
|
|||||||
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
||||||
diff -ruN SDL2-2.32.8/src/joystick/banan_os/SDL_banan_os_joystick.cpp SDL2-2.32.8-banan_os/src/joystick/banan_os/SDL_banan_os_joystick.cpp
|
diff -ruN SDL2-2.32.8/src/joystick/banan_os/SDL_banan_os_joystick.cpp SDL2-2.32.8-banan_os/src/joystick/banan_os/SDL_banan_os_joystick.cpp
|
||||||
--- SDL2-2.32.8/src/joystick/banan_os/SDL_banan_os_joystick.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/joystick/banan_os/SDL_banan_os_joystick.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/joystick/banan_os/SDL_banan_os_joystick.cpp 2026-01-07 19:07:12.677617077 +0200
|
+++ SDL2-2.32.8-banan_os/src/joystick/banan_os/SDL_banan_os_joystick.cpp 2026-04-03 04:34:27.258447075 +0300
|
||||||
@@ -0,0 +1,296 @@
|
@@ -0,0 +1,296 @@
|
||||||
+/*
|
+/*
|
||||||
+Simple DirectMedia Layer
|
+Simple DirectMedia Layer
|
||||||
@@ -655,7 +638,7 @@ diff -ruN SDL2-2.32.8/src/joystick/banan_os/SDL_banan_os_joystick.cpp SDL2-2.32.
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/joystick/SDL_joystick.c SDL2-2.32.8-banan_os/src/joystick/SDL_joystick.c
|
diff -ruN SDL2-2.32.8/src/joystick/SDL_joystick.c SDL2-2.32.8-banan_os/src/joystick/SDL_joystick.c
|
||||||
--- SDL2-2.32.8/src/joystick/SDL_joystick.c 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/src/joystick/SDL_joystick.c 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/joystick/SDL_joystick.c 2026-01-07 19:04:34.373890653 +0200
|
+++ SDL2-2.32.8-banan_os/src/joystick/SDL_joystick.c 2026-04-03 04:34:27.258656321 +0300
|
||||||
@@ -85,6 +85,9 @@
|
@@ -85,6 +85,9 @@
|
||||||
#ifdef SDL_JOYSTICK_HAIKU
|
#ifdef SDL_JOYSTICK_HAIKU
|
||||||
&SDL_HAIKU_JoystickDriver,
|
&SDL_HAIKU_JoystickDriver,
|
||||||
@@ -668,7 +651,7 @@ diff -ruN SDL2-2.32.8/src/joystick/SDL_joystick.c SDL2-2.32.8-banan_os/src/joyst
|
|||||||
#endif
|
#endif
|
||||||
diff -ruN SDL2-2.32.8/src/joystick/SDL_sysjoystick.h SDL2-2.32.8-banan_os/src/joystick/SDL_sysjoystick.h
|
diff -ruN SDL2-2.32.8/src/joystick/SDL_sysjoystick.h SDL2-2.32.8-banan_os/src/joystick/SDL_sysjoystick.h
|
||||||
--- SDL2-2.32.8/src/joystick/SDL_sysjoystick.h 2025-01-01 17:47:53.000000000 +0200
|
--- SDL2-2.32.8/src/joystick/SDL_sysjoystick.h 2025-01-01 17:47:53.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/joystick/SDL_sysjoystick.h 2026-01-07 19:04:34.374337431 +0200
|
+++ SDL2-2.32.8-banan_os/src/joystick/SDL_sysjoystick.h 2026-04-03 04:34:27.259001479 +0300
|
||||||
@@ -235,6 +235,7 @@
|
@@ -235,6 +235,7 @@
|
||||||
|
|
||||||
/* The available joystick drivers */
|
/* The available joystick drivers */
|
||||||
@@ -679,7 +662,7 @@ diff -ruN SDL2-2.32.8/src/joystick/SDL_sysjoystick.h SDL2-2.32.8-banan_os/src/jo
|
|||||||
extern SDL_JoystickDriver SDL_DUMMY_JoystickDriver;
|
extern SDL_JoystickDriver SDL_DUMMY_JoystickDriver;
|
||||||
diff -ruN SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp
|
diff -ruN SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp
|
||||||
--- SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp 2026-01-07 19:04:34.379748697 +0200
|
+++ SDL2-2.32.8-banan_os/src/misc/banan_os/SDL_sysurl.cpp 2026-04-03 04:34:27.259173778 +0300
|
||||||
@@ -0,0 +1,30 @@
|
@@ -0,0 +1,30 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -713,7 +696,7 @@ diff -ruN SDL2-2.32.8/src/misc/banan_os/SDL_sysurl.cpp SDL2-2.32.8-banan_os/src/
|
|||||||
+
|
+
|
||||||
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp
|
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp
|
||||||
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp 2026-01-07 19:04:34.379995308 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.cpp 2026-04-03 04:34:27.259271557 +0300
|
||||||
@@ -0,0 +1,51 @@
|
@@ -0,0 +1,51 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -768,7 +751,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.cpp SDL2-2.32.8-
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h
|
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h
|
||||||
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h 2026-01-07 19:04:34.380137576 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_clipboard.h 2026-04-03 04:34:27.259318700 +0300
|
||||||
@@ -0,0 +1,43 @@
|
@@ -0,0 +1,43 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -815,7 +798,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_clipboard.h SDL2-2.32.8-ba
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp
|
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp
|
||||||
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp 2026-01-07 19:04:34.380308339 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.cpp 2026-04-03 04:34:27.259375481 +0300
|
||||||
@@ -0,0 +1,60 @@
|
@@ -0,0 +1,60 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -879,7 +862,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.cpp SDL2-2.32.
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h
|
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h
|
||||||
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h 2026-01-07 19:04:34.380550899 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_message_box.h 2026-04-03 04:34:27.259437082 +0300
|
||||||
@@ -0,0 +1,45 @@
|
@@ -0,0 +1,45 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -928,7 +911,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_message_box.h SDL2-2.32.8-
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp
|
diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp
|
||||||
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp 1970-01-01 02:00:00.000000000 +0200
|
--- SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp 1970-01-01 02:00:00.000000000 +0200
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp 2026-01-07 19:04:34.380720824 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/banan_os/SDL_banan_os_video.cpp 2026-04-03 04:34:27.259503082 +0300
|
||||||
@@ -0,0 +1,729 @@
|
@@ -0,0 +1,729 @@
|
||||||
+/*
|
+/*
|
||||||
+ Simple DirectMedia Layer
|
+ Simple DirectMedia Layer
|
||||||
@@ -1661,7 +1644,7 @@ diff -ruN SDL2-2.32.8/src/video/banan_os/SDL_banan_os_video.cpp SDL2-2.32.8-bana
|
|||||||
+/* vi: set ts=4 sw=4 expandtab: */
|
+/* vi: set ts=4 sw=4 expandtab: */
|
||||||
diff -ruN SDL2-2.32.8/src/video/SDL_sysvideo.h SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h
|
diff -ruN SDL2-2.32.8/src/video/SDL_sysvideo.h SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h
|
||||||
--- SDL2-2.32.8/src/video/SDL_sysvideo.h 2025-05-20 00:24:41.000000000 +0300
|
--- SDL2-2.32.8/src/video/SDL_sysvideo.h 2025-05-20 00:24:41.000000000 +0300
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h 2026-01-07 19:04:34.381316574 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/SDL_sysvideo.h 2026-04-03 04:34:27.259743826 +0300
|
||||||
@@ -462,6 +462,7 @@
|
@@ -462,6 +462,7 @@
|
||||||
extern VideoBootStrap WINDOWS_bootstrap;
|
extern VideoBootStrap WINDOWS_bootstrap;
|
||||||
extern VideoBootStrap WINRT_bootstrap;
|
extern VideoBootStrap WINRT_bootstrap;
|
||||||
@@ -1672,7 +1655,7 @@ diff -ruN SDL2-2.32.8/src/video/SDL_sysvideo.h SDL2-2.32.8-banan_os/src/video/SD
|
|||||||
extern VideoBootStrap Android_bootstrap;
|
extern VideoBootStrap Android_bootstrap;
|
||||||
diff -ruN SDL2-2.32.8/src/video/SDL_video.c SDL2-2.32.8-banan_os/src/video/SDL_video.c
|
diff -ruN SDL2-2.32.8/src/video/SDL_video.c SDL2-2.32.8-banan_os/src/video/SDL_video.c
|
||||||
--- SDL2-2.32.8/src/video/SDL_video.c 2025-05-20 00:24:41.000000000 +0300
|
--- SDL2-2.32.8/src/video/SDL_video.c 2025-05-20 00:24:41.000000000 +0300
|
||||||
+++ SDL2-2.32.8-banan_os/src/video/SDL_video.c 2026-01-07 19:04:34.398132645 +0200
|
+++ SDL2-2.32.8-banan_os/src/video/SDL_video.c 2026-04-03 04:34:27.260110007 +0300
|
||||||
@@ -96,6 +96,9 @@
|
@@ -96,6 +96,9 @@
|
||||||
#ifdef SDL_VIDEO_DRIVER_HAIKU
|
#ifdef SDL_VIDEO_DRIVER_HAIKU
|
||||||
&HAIKU_bootstrap,
|
&HAIKU_bootstrap,
|
||||||
|
|||||||
36
ports/bzip2/build.sh
Executable file
36
ports/bzip2/build.sh
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
|
NAME='bzip2'
|
||||||
|
VERSION='1.0.8'
|
||||||
|
DOWNLOAD_URL="https://sourceware.org/pub/bzip2/bzip2-$VERSION.tar.gz#ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269"
|
||||||
|
|
||||||
|
configure() {
|
||||||
|
:
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
make -j$(nproc) -f Makefile-libbz2_so CC="$CC" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
cp -v libbz2.so.$VERSION $BANAN_SYSROOT/usr/lib/ || exit 1
|
||||||
|
ln -svf libbz2.so.$VERSION $BANAN_SYSROOT/usr/lib/libbz2.so || exit 1
|
||||||
|
ln -svf libbz2.so.$VERSION $BANAN_SYSROOT/usr/lib/libbz2.so.1 || exit 1
|
||||||
|
ln -svf libbz2.so.$VERSION $BANAN_SYSROOT/usr/lib/libbz2.so.1.0 || exit 1
|
||||||
|
|
||||||
|
cp -v bzlib.h $BANAN_SYSROOT/usr/include/ || exit 1
|
||||||
|
|
||||||
|
cat > $BANAN_SYSROOT/usr/lib/pkgconfig/bzip2.pc << EOF
|
||||||
|
prefix=/usr
|
||||||
|
exec_prefix=\${prefix}
|
||||||
|
bindir=\${exec_prefix}/bin
|
||||||
|
libdir=\${exec_prefix}/lib
|
||||||
|
includedir=\${prefix}/include
|
||||||
|
|
||||||
|
Name: bzip2
|
||||||
|
Description: A file compression library
|
||||||
|
Version: $VERSION
|
||||||
|
Libs: -L\${libdir} -lbz2
|
||||||
|
Cflags: -I\${includedir}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
23
ports/libarchive/build.sh
Executable file
23
ports/libarchive/build.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
|
NAME='libarchive'
|
||||||
|
VERSION='3.8.6'
|
||||||
|
DOWNLOAD_URL="https://github.com/libarchive/libarchive/releases/download/v$VERSION/libarchive-$VERSION.tar.xz#8ac57c1f5e99550948d1fe755c806d26026e71827da228f36bef24527e372e6f"
|
||||||
|
DEPENDENCIES=('zlib' 'zstd' 'bzip2' 'xz')
|
||||||
|
|
||||||
|
configure() {
|
||||||
|
cmake --fresh -B build -S . -G Ninja \
|
||||||
|
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DENABLE_TEST=OFF \
|
||||||
|
|| exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cmake --build build || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
cmake --install build || exit 1
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ CONFIGURE_OPTIONS=(
|
|||||||
)
|
)
|
||||||
|
|
||||||
configure() {
|
configure() {
|
||||||
|
CFLAGS='-shared-libgcc' \
|
||||||
meson setup \
|
meson setup \
|
||||||
--reconfigure \
|
--reconfigure \
|
||||||
--cross-file "$MESON_CROSS_FILE" \
|
--cross-file "$MESON_CROSS_FILE" \
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
NAME='xbanan'
|
NAME='xbanan'
|
||||||
VERSION='git'
|
VERSION='git'
|
||||||
DOWNLOAD_URL="https://git.bananymous.com/Bananymous/xbanan.git#b228ef13c41adff2738acaeda5db804ebf493bfd"
|
DOWNLOAD_URL="https://git.bananymous.com/Bananymous/xbanan.git#b2c642f03d2e498e9d6acd55cc89a5e76c220811"
|
||||||
DEPENDENCIES=('mesa' 'libX11' 'xorgproto')
|
DEPENDENCIES=('xorgproto')
|
||||||
|
|
||||||
configure() {
|
configure() {
|
||||||
cmake --fresh -B build -S . -G Ninja \
|
cmake --fresh -B build -S . -G Ninja \
|
||||||
|
|||||||
24
ports/xz/build.sh
Executable file
24
ports/xz/build.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
|
NAME='xz'
|
||||||
|
VERSION='5.8.2'
|
||||||
|
DOWNLOAD_URL="https://github.com/tukaani-project/xz/releases/download/v5.8.2/xz-$VERSION.tar.xz#890966ec3f5d5cc151077879e157c0593500a522f413ac50ba26d22a9a145214"
|
||||||
|
|
||||||
|
configure() {
|
||||||
|
cmake --fresh -B build -S . -G Ninja \
|
||||||
|
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
|
-DXZ_NLS=OFF \
|
||||||
|
-DXZ_DOC=OFF \
|
||||||
|
|| exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cmake --build build ||exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
cmake --install build ||exit 1
|
||||||
|
}
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
#!/bin/bash ../install.sh
|
#!/bin/bash ../install.sh
|
||||||
|
|
||||||
NAME='zlib'
|
NAME='zlib'
|
||||||
VERSION='1.3.1'
|
VERSION='1.3.2'
|
||||||
DOWNLOAD_URL="https://www.zlib.net/zlib-$VERSION.tar.gz#9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23"
|
DOWNLOAD_URL="https://www.zlib.net/zlib-$VERSION.tar.gz#bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16"
|
||||||
|
|
||||||
configure() {
|
configure() {
|
||||||
./configure --prefix=/usr --uname=banan_os
|
cmake --fresh -B build -S . -G Ninja \
|
||||||
|
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
|| exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cmake --build build || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
cmake --install build || exit 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
diff -ruN zlib-1.3.1/configure zlib-1.3.1-banan_os/configure
|
|
||||||
--- zlib-1.3.1/configure 2024-01-21 04:29:31.000000000 +0200
|
|
||||||
+++ zlib-1.3.1-banan_os/configure 2025-06-27 23:48:53.039461360 +0300
|
|
||||||
@@ -236,6 +236,8 @@
|
|
||||||
*BSD | *bsd* | DragonFly)
|
|
||||||
LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"}
|
|
||||||
LDCONFIG="ldconfig -m" ;;
|
|
||||||
+ *banan_os)
|
|
||||||
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"} ;;
|
|
||||||
CYGWIN* | Cygwin* | cygwin* | *-cygwin* | OS/2*)
|
|
||||||
EXE='.exe' ;;
|
|
||||||
MINGW* | mingw* | *-mingw*)
|
|
||||||
@@ -14,5 +14,8 @@ strip = 'ARCH-pc-banan_os-strip'
|
|||||||
pkg-config = 'pkg-config'
|
pkg-config = 'pkg-config'
|
||||||
cmake = 'CMAKE'
|
cmake = 'CMAKE'
|
||||||
|
|
||||||
|
glib-compile-schemas = '/usr/bin/glib-compile-schemas'
|
||||||
|
glib-compile-resources = '/usr/bin/glib-compile-resources'
|
||||||
|
|
||||||
[properties]
|
[properties]
|
||||||
sys_root='SYSROOT'
|
sys_root='SYSROOT'
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ namespace LibAudio
|
|||||||
|
|
||||||
LibAudio::Packet packet {
|
LibAudio::Packet packet {
|
||||||
.type = LibAudio::Packet::Notify,
|
.type = LibAudio::Packet::Notify,
|
||||||
.parameter = 0,
|
.parameter = {},
|
||||||
};
|
};
|
||||||
|
|
||||||
send(m_server_fd, &packet, sizeof(packet), 0);
|
send(m_server_fd, &packet, sizeof(packet), 0);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace LibAudio
|
|||||||
|
|
||||||
struct AudioBuffer
|
struct AudioBuffer
|
||||||
{
|
{
|
||||||
using sample_t = double;
|
using sample_t = float;
|
||||||
|
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
uint32_t channels;
|
uint32_t channels;
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ namespace LibAudio
|
|||||||
SetPin, // parameter: pin number
|
SetPin, // parameter: pin number
|
||||||
// response: nothing
|
// response: nothing
|
||||||
// set the active pin of the current device
|
// set the active pin of the current device
|
||||||
|
|
||||||
|
GetVolume, // parameter: ignored
|
||||||
|
// response: 10 * volume percentage (uint32_t)
|
||||||
|
// get the volume of the current device
|
||||||
|
|
||||||
|
SetVolume, // parameter: 10 * volume percentage (uint32_t)
|
||||||
|
// response: nothing
|
||||||
|
// set the volume of the current device
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
uint64_t parameter;
|
uint64_t parameter;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ set(LIBC_SOURCES
|
|||||||
dlfcn.cpp
|
dlfcn.cpp
|
||||||
endian.cpp
|
endian.cpp
|
||||||
environ.cpp
|
environ.cpp
|
||||||
errno.cpp
|
|
||||||
fcntl.cpp
|
fcntl.cpp
|
||||||
fenv.cpp
|
fenv.cpp
|
||||||
fnmatch.cpp
|
fnmatch.cpp
|
||||||
@@ -43,6 +42,7 @@ set(LIBC_SOURCES
|
|||||||
strings.cpp
|
strings.cpp
|
||||||
sys/banan-os.cpp
|
sys/banan-os.cpp
|
||||||
sys/epoll.cpp
|
sys/epoll.cpp
|
||||||
|
sys/eventfd.cpp
|
||||||
sys/file.cpp
|
sys/file.cpp
|
||||||
sys/futex.cpp
|
sys/futex.cpp
|
||||||
sys/ioctl.cpp
|
sys/ioctl.cpp
|
||||||
@@ -74,7 +74,7 @@ set(LIBC_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_library(objlibc OBJECT ${LIBC_SOURCES})
|
add_library(objlibc OBJECT ${LIBC_SOURCES})
|
||||||
target_compile_definitions(objlibc PRIVATE __arch=${BANAN_ARCH})
|
target_compile_definitions(objlibc PRIVATE __arch=${BANAN_ARCH} __is_libc)
|
||||||
|
|
||||||
target_compile_options(objlibc PRIVATE -O2 -g -Wstack-usage=512 -fno-exceptions -fno-rtti -fpic)
|
target_compile_options(objlibc PRIVATE -O2 -g -Wstack-usage=512 -fno-exceptions -fno-rtti -fpic)
|
||||||
target_compile_options(objlibc PUBLIC -Wall -Wextra -Werror -Wno-error=stack-usage=)
|
target_compile_options(objlibc PUBLIC -Wall -Wextra -Werror -Wno-error=stack-usage=)
|
||||||
@@ -99,8 +99,8 @@ banan_install_headers(objlibc)
|
|||||||
add_library(libc-static STATIC $<TARGET_OBJECTS:objlibc>)
|
add_library(libc-static STATIC $<TARGET_OBJECTS:objlibc>)
|
||||||
add_library(libc-shared SHARED $<TARGET_OBJECTS:objlibc>)
|
add_library(libc-shared SHARED $<TARGET_OBJECTS:objlibc>)
|
||||||
|
|
||||||
target_link_options(libc-static PRIVATE -nolibc)
|
target_link_options(libc-static PRIVATE -nolibc -nostdlib++)
|
||||||
target_link_options(libc-shared PRIVATE -nolibc)
|
target_link_options(libc-shared PRIVATE -nolibc -nostdlib++)
|
||||||
|
|
||||||
install(TARGETS libc-static OPTIONAL)
|
install(TARGETS libc-static OPTIONAL)
|
||||||
install(TARGETS libc-shared OPTIONAL)
|
install(TARGETS libc-shared OPTIONAL)
|
||||||
|
|||||||
@@ -1,35 +1,4 @@
|
|||||||
.global memchr
|
.align 16
|
||||||
memchr:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %eax
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
movl $1, %edx
|
|
||||||
cmpl $1, %ecx # clear ZF if count is zero
|
|
||||||
repne scasb
|
|
||||||
cmovel %edi, %edx
|
|
||||||
leal -1(%edx), %eax
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcmp
|
|
||||||
memcmp:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xchgl 8(%esp), %esi
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
testl %ecx, %ecx # set ZF if count is zero
|
|
||||||
repe cmpsb
|
|
||||||
jne .memcmp_not_equal
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .memcmp_done
|
|
||||||
.memcmp_not_equal:
|
|
||||||
movzbl -1(%edi), %eax
|
|
||||||
movzbl -1(%esi), %ecx
|
|
||||||
subl %ecx, %eax
|
|
||||||
.memcmp_done:
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %esi
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcpy
|
.global memcpy
|
||||||
memcpy:
|
memcpy:
|
||||||
xchgl 4(%esp), %edi
|
xchgl 4(%esp), %edi
|
||||||
@@ -42,6 +11,7 @@ memcpy:
|
|||||||
movl %edx, %eax
|
movl %edx, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global memmove
|
.global memmove
|
||||||
memmove:
|
memmove:
|
||||||
xchgl 4(%esp), %edi
|
xchgl 4(%esp), %edi
|
||||||
@@ -64,6 +34,7 @@ memmove:
|
|||||||
cld
|
cld
|
||||||
jmp .memmove_done
|
jmp .memmove_done
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global memset
|
.global memset
|
||||||
memset:
|
memset:
|
||||||
xchgl 4(%esp), %edi
|
xchgl 4(%esp), %edi
|
||||||
@@ -74,14 +45,3 @@ memset:
|
|||||||
movl 4(%esp), %edi
|
movl 4(%esp), %edi
|
||||||
movl %edx, %eax
|
movl %edx, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global strlen
|
|
||||||
strlen:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xorb %al, %al
|
|
||||||
movl $-1, %ecx
|
|
||||||
repne scasb
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl $-2, %eax
|
|
||||||
subl %ecx, %eax
|
|
||||||
ret
|
|
||||||
|
|||||||
@@ -1,62 +1,312 @@
|
|||||||
.global memchr
|
.set nt_threshold, 32 * 1024
|
||||||
memchr:
|
|
||||||
movb %sil, %al
|
|
||||||
movq %rdx, %rcx
|
|
||||||
movq $1, %rdx
|
|
||||||
cmpq $1, %rcx # clear ZF if count is zero
|
|
||||||
repne scasb
|
|
||||||
cmoveq %rdi, %rdx
|
|
||||||
leaq -1(%rdx), %rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcmp
|
|
||||||
memcmp:
|
|
||||||
movq %rdx, %rcx
|
|
||||||
testq %rcx, %rcx # set ZF if count is zero
|
|
||||||
repe cmpsb
|
|
||||||
jne .memcmp_not_equal
|
|
||||||
xorq %rax, %rax
|
|
||||||
ret
|
|
||||||
.memcmp_not_equal:
|
|
||||||
movzbl -1(%rdi), %eax
|
|
||||||
movzbl -1(%rsi), %ecx
|
|
||||||
subq %rcx, %rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global memcpy
|
.global memcpy
|
||||||
memcpy:
|
memcpy:
|
||||||
|
cmpq $nt_threshold, %rdx
|
||||||
|
jae .Lmemcpy_nt
|
||||||
movq %rdi, %rax
|
movq %rdi, %rax
|
||||||
movq %rdx, %rcx
|
movq %rdx, %rcx
|
||||||
rep movsb
|
rep movsb
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.Lmemcpy_nt:
|
||||||
|
movq %rdi, %rax
|
||||||
|
|
||||||
|
testq $63, %rdi
|
||||||
|
jz .Lmemcpy_nt_aligned
|
||||||
|
|
||||||
|
# NOTE: this unconditionally copies 64 bytes to align to 64 byte boundary
|
||||||
|
# but as nt branch is only taken for huge buffers, it doesnt add much overhead
|
||||||
|
|
||||||
|
movdqu 0(%rsi), %xmm0
|
||||||
|
movdqu 16(%rsi), %xmm1
|
||||||
|
movdqu 32(%rsi), %xmm2
|
||||||
|
movdqu 48(%rsi), %xmm3
|
||||||
|
|
||||||
|
movdqu %xmm0, 0(%rdi)
|
||||||
|
movdqu %xmm1, 16(%rdi)
|
||||||
|
movdqu %xmm2, 32(%rdi)
|
||||||
|
movdqu %xmm3, 48(%rdi)
|
||||||
|
|
||||||
|
movq %rdi, %rcx
|
||||||
|
andq $63, %rcx
|
||||||
|
leaq -64(%rdx, %rcx), %rdx
|
||||||
|
|
||||||
|
negq %rcx
|
||||||
|
leaq 64(%rdi, %rcx), %rdi
|
||||||
|
leaq 64(%rsi, %rcx), %rsi
|
||||||
|
|
||||||
|
.Lmemcpy_nt_aligned:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
shrq $6, %rdx
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.Lmemcpy_nt_loop:
|
||||||
|
prefetchnta 256(%rsi)
|
||||||
|
prefetchnta 32+256(%rsi)
|
||||||
|
|
||||||
|
movdqu 0(%rsi), %xmm0
|
||||||
|
movdqu 16(%rsi), %xmm1
|
||||||
|
movdqu 32(%rsi), %xmm2
|
||||||
|
movdqu 48(%rsi), %xmm3
|
||||||
|
|
||||||
|
movntdq %xmm0, 0(%rdi)
|
||||||
|
movntdq %xmm1, 16(%rdi)
|
||||||
|
movntdq %xmm2, 32(%rdi)
|
||||||
|
movntdq %xmm3, 48(%rdi)
|
||||||
|
|
||||||
|
addq $64, %rdi
|
||||||
|
addq $64, %rsi
|
||||||
|
subq $1, %rdx
|
||||||
|
jnz .Lmemcpy_nt_loop
|
||||||
|
|
||||||
|
andq $63, %rcx
|
||||||
|
rep movsb
|
||||||
|
sfence
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global memmove
|
.global memmove
|
||||||
memmove:
|
memmove:
|
||||||
cmpq %rdi, %rsi
|
cmpq $nt_threshold, %rdx
|
||||||
jae memcpy
|
jb .Lmemmove_small
|
||||||
|
leaq (%rdi, %rdx), %rax
|
||||||
|
cmpq %rax, %rsi
|
||||||
|
jae .Lmemcpy_nt
|
||||||
|
leaq (%rsi, %rdx), %rax
|
||||||
|
cmpq %rax, %rdi
|
||||||
|
jae .Lmemcpy_nt
|
||||||
|
.Lmemmove_small:
|
||||||
movq %rdi, %rax
|
movq %rdi, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
cmpq %rdi, %rsi
|
||||||
|
jb .Lmemmove_backwards
|
||||||
|
rep movsb
|
||||||
|
ret
|
||||||
|
.Lmemmove_backwards:
|
||||||
leaq -1(%rdi, %rdx), %rdi
|
leaq -1(%rdi, %rdx), %rdi
|
||||||
leaq -1(%rsi, %rdx), %rsi
|
leaq -1(%rsi, %rdx), %rsi
|
||||||
movq %rdx, %rcx
|
|
||||||
std
|
std
|
||||||
rep movsb
|
rep movsb
|
||||||
cld
|
cld
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global memset
|
.global memset
|
||||||
memset:
|
memset:
|
||||||
|
cmpq $nt_threshold, %rdx
|
||||||
|
jae .Lmemset_nt
|
||||||
movq %rdi, %r8
|
movq %rdi, %r8
|
||||||
movb %sil, %al
|
|
||||||
movq %rdx, %rcx
|
movq %rdx, %rcx
|
||||||
|
movzbl %sil, %eax
|
||||||
rep stosb
|
rep stosb
|
||||||
movq %r8, %rax
|
movq %r8, %rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.Lmemset_nt:
|
||||||
|
movq %rdi, %rax
|
||||||
|
|
||||||
|
movzbl %sil, %esi
|
||||||
|
imul $0x01010101, %esi
|
||||||
|
movd %esi, %xmm0
|
||||||
|
pshufd $0, %xmm0, %xmm0
|
||||||
|
|
||||||
|
testq $63, %rdi
|
||||||
|
jz .Lmemset_nt_aligned
|
||||||
|
|
||||||
|
# NOTE: this unconditionally writes 64 bytes to align to 64 byte boundary
|
||||||
|
# but as nt branch is only taken for huge buffers, it doesnt add much overhead
|
||||||
|
|
||||||
|
movdqu %xmm0, 0(%rdi)
|
||||||
|
movdqu %xmm0, 16(%rdi)
|
||||||
|
movdqu %xmm0, 32(%rdi)
|
||||||
|
movdqu %xmm0, 48(%rdi)
|
||||||
|
|
||||||
|
movq %rdi, %rcx
|
||||||
|
andq $63, %rcx
|
||||||
|
leaq -64(%rdx, %rcx), %rdx
|
||||||
|
|
||||||
|
negq %rcx
|
||||||
|
leaq 64(%rdi, %rcx), %rdi
|
||||||
|
|
||||||
|
.Lmemset_nt_aligned:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
shrq $6, %rdx
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.Lmemset_nt_loop:
|
||||||
|
movntdq %xmm0, 0(%rdi)
|
||||||
|
movntdq %xmm0, 16(%rdi)
|
||||||
|
movntdq %xmm0, 32(%rdi)
|
||||||
|
movntdq %xmm0, 48(%rdi)
|
||||||
|
|
||||||
|
addq $64, %rdi
|
||||||
|
subq $1, %rdx
|
||||||
|
jnz .Lmemset_nt_loop
|
||||||
|
|
||||||
|
andq $63, %rcx
|
||||||
|
jnz .Lmemset_nt_bytes
|
||||||
|
sfence
|
||||||
|
ret
|
||||||
|
|
||||||
|
.Lmemset_nt_bytes:
|
||||||
|
movq %rax, %rdx
|
||||||
|
movzbl %sil, %eax
|
||||||
|
rep stosb
|
||||||
|
movq %rdx, %rax
|
||||||
|
sfence
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memchr
|
||||||
|
memchr:
|
||||||
|
testq %rdx, %rdx
|
||||||
|
jz .Lmemchr_no_match
|
||||||
|
|
||||||
|
movzbl %sil, %esi
|
||||||
|
imul $0x01010101, %esi
|
||||||
|
movd %esi, %xmm0
|
||||||
|
pshufd $0, %xmm0, %xmm0
|
||||||
|
|
||||||
|
movq %rdi, %rcx
|
||||||
|
andq $15, %rcx
|
||||||
|
jz .Lmemchr_loop
|
||||||
|
|
||||||
|
movq %rdi, %rsi
|
||||||
|
subq %rcx, %rsi
|
||||||
|
movdqa (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
shrl %cl, %eax
|
||||||
|
jnz .Lmemchr_match
|
||||||
|
|
||||||
|
leaq 16(%rsi), %rdi
|
||||||
|
|
||||||
|
addq %rcx, %rdx
|
||||||
|
subq $16, %rdx
|
||||||
|
jbe .Lmemchr_no_match
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.Lmemchr_loop:
|
||||||
|
movdqa (%rdi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
testl %eax, %eax
|
||||||
|
jnz .Lmemchr_match
|
||||||
|
|
||||||
|
addq $16, %rdi
|
||||||
|
subq $16, %rdx
|
||||||
|
ja .Lmemchr_loop
|
||||||
|
|
||||||
|
.Lmemchr_no_match:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.Lmemchr_match:
|
||||||
|
bsfl %eax, %eax
|
||||||
|
cmpq %rdx, %rax
|
||||||
|
jae .Lmemchr_no_match
|
||||||
|
addq %rdi, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.global memcmp
|
||||||
|
memcmp:
|
||||||
|
testq %rdx, %rdx
|
||||||
|
jz .Lmemcmp_equal
|
||||||
|
|
||||||
|
movq %rdi, %rax
|
||||||
|
movq %rsi, %rcx
|
||||||
|
andq $15, %rax
|
||||||
|
andq $15, %rcx
|
||||||
|
cmpq %rax, %rcx
|
||||||
|
cmovaq %rcx, %rax
|
||||||
|
|
||||||
|
testq %rax, %rax
|
||||||
|
jz .Lmemcmp_loop
|
||||||
|
|
||||||
|
movq $16, %rcx
|
||||||
|
subq %rax, %rcx
|
||||||
|
|
||||||
|
cmpq %rcx, %rdx
|
||||||
|
cmovbq %rdx, %rcx
|
||||||
|
|
||||||
|
subq %rcx, %rdx
|
||||||
|
|
||||||
|
.Lmemcmp_align_loop:
|
||||||
|
movzbl (%rdi), %eax
|
||||||
|
movzbl (%rsi), %r8d
|
||||||
|
subl %r8d, %eax
|
||||||
|
jnz .Lmemcmp_return
|
||||||
|
|
||||||
|
addq $1, %rdi
|
||||||
|
addq $1, %rsi
|
||||||
|
subq $1, %rcx
|
||||||
|
jnz .Lmemcmp_align_loop
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.Lmemcmp_loop:
|
||||||
|
movdqu (%rdi), %xmm0
|
||||||
|
movdqu (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
xorl $0xFFFF, %eax
|
||||||
|
jnz .Lmemcmp_differ
|
||||||
|
|
||||||
|
addq $16, %rdi
|
||||||
|
addq $16, %rsi
|
||||||
|
subq $16, %rdx
|
||||||
|
ja .Lmemcmp_loop
|
||||||
|
|
||||||
|
.Lmemcmp_equal:
|
||||||
|
xorl %eax, %eax
|
||||||
|
.Lmemcmp_return:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.Lmemcmp_differ:
|
||||||
|
bsfl %eax, %ecx
|
||||||
|
cmpq %rdx, %rcx
|
||||||
|
jae .Lmemcmp_equal
|
||||||
|
movzbl (%rdi, %rcx), %eax
|
||||||
|
movzbl (%rsi, %rcx), %edx
|
||||||
|
subl %edx, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 16
|
||||||
.global strlen
|
.global strlen
|
||||||
strlen:
|
strlen:
|
||||||
xorb %al, %al
|
movq %rdi, %rsi
|
||||||
movq $-1, %rcx
|
|
||||||
repne scasb
|
pxor %xmm0, %xmm0
|
||||||
movq $-2, %rax
|
|
||||||
subq %rcx, %rax
|
movq %rsi, %rcx
|
||||||
|
andq $15, %rcx
|
||||||
|
jz .Lstrlen_loop
|
||||||
|
|
||||||
|
movq %rsi, %rdx
|
||||||
|
subq %rcx, %rdx
|
||||||
|
movdqa (%rdx), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
shrl %cl, %eax
|
||||||
|
jnz .Lstrlen_null_found
|
||||||
|
|
||||||
|
leaq 16(%rdx), %rsi
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
.Lstrlen_loop:
|
||||||
|
movdqa (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
testl %eax, %eax
|
||||||
|
jnz .Lstrlen_null_found
|
||||||
|
|
||||||
|
addq $16, %rsi
|
||||||
|
jmp .Lstrlen_loop
|
||||||
|
|
||||||
|
.Lstrlen_null_found:
|
||||||
|
bsfl %eax, %eax
|
||||||
|
addq %rsi, %rax
|
||||||
|
subq %rdi, %rax
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -14,6 +14,19 @@ static bool s_environ_malloced = false;
|
|||||||
static size_t s_environ_count = 0; // only valid when s_environ_malloced == true
|
static size_t s_environ_count = 0; // only valid when s_environ_malloced == true
|
||||||
static uint8_t* s_environ_bitmap = nullptr; // if bit i is set, environ[i] has to be freed
|
static uint8_t* s_environ_bitmap = nullptr; // if bit i is set, environ[i] has to be freed
|
||||||
|
|
||||||
|
static bool is_bitmap_bit_set(size_t index)
|
||||||
|
{
|
||||||
|
return !!(s_environ_bitmap[index / 8] & (1 << (index % 8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_bitmap_bit(size_t index, bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
s_environ_bitmap[index / 8] |= 1 << (index % 8);
|
||||||
|
else
|
||||||
|
s_environ_bitmap[index / 8] &= ~(1 << (index % 8));
|
||||||
|
}
|
||||||
|
|
||||||
static int malloc_environ()
|
static int malloc_environ()
|
||||||
{
|
{
|
||||||
ASSERT(!s_environ_malloced);
|
ASSERT(!s_environ_malloced);
|
||||||
@@ -28,7 +41,7 @@ static int malloc_environ()
|
|||||||
return -1;
|
return -1;
|
||||||
memset(new_bitmap, 0, bitmap_size);
|
memset(new_bitmap, 0, bitmap_size);
|
||||||
|
|
||||||
char** new_environ = static_cast<char**>(malloc((environ_count + 1) * sizeof(char*)));
|
auto** new_environ = static_cast<char**>(malloc((environ_count + 1) * sizeof(char*)));
|
||||||
if (new_environ == nullptr)
|
if (new_environ == nullptr)
|
||||||
{
|
{
|
||||||
free(new_bitmap);
|
free(new_bitmap);
|
||||||
@@ -60,53 +73,42 @@ static int putenv_impl(char* string, bool malloced)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const size_t namelen = eq_addr - string;
|
const size_t namelen = eq_addr - string;
|
||||||
for (int i = 0; environ[i]; i++)
|
for (size_t i = 0; environ[i]; i++)
|
||||||
{
|
{
|
||||||
if (strncmp(environ[i], string, namelen + 1) == 0)
|
if (strncmp(environ[i], string, namelen + 1) != 0)
|
||||||
{
|
continue;
|
||||||
const size_t byte = i / 8;
|
|
||||||
const uint8_t mask = 1 << (i % 8);
|
|
||||||
|
|
||||||
if (s_environ_bitmap[byte] & mask)
|
if (is_bitmap_bit_set(i))
|
||||||
free(environ[i]);
|
free(environ[i]);
|
||||||
|
set_bitmap_bit(i, malloced);
|
||||||
|
|
||||||
if (malloced)
|
environ[i] = string;
|
||||||
s_environ_bitmap[byte] |= mask;
|
return 0;
|
||||||
else
|
|
||||||
s_environ_bitmap[byte] &= ~mask;
|
|
||||||
|
|
||||||
environ[i] = string;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_environ_count % 8 == 0)
|
if (s_environ_count % 8 == 0)
|
||||||
{
|
{
|
||||||
const size_t bytes = s_environ_count / 8 + 1;
|
const size_t bytes = s_environ_count / 8 + 1;
|
||||||
|
|
||||||
void* new_bitmap = realloc(s_environ_bitmap, bytes);
|
auto* new_bitmap = static_cast<uint8_t*>(realloc(s_environ_bitmap, bytes));
|
||||||
if (new_bitmap == nullptr)
|
if (new_bitmap == nullptr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s_environ_bitmap = static_cast<uint8_t*>(new_bitmap);
|
s_environ_bitmap = new_bitmap;
|
||||||
s_environ_bitmap[bytes - 1] = 0;
|
s_environ_bitmap[bytes - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_environ = realloc(environ, sizeof(char*) * (s_environ_count + 2));
|
auto** new_environ = static_cast<char**>(realloc(environ, (s_environ_count + 2) * sizeof(char*)));
|
||||||
if (new_environ == nullptr)
|
if (new_environ == nullptr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
environ = static_cast<char**>(new_environ);
|
environ = new_environ;
|
||||||
environ[s_environ_count] = string;
|
environ[s_environ_count] = string;
|
||||||
environ[s_environ_count + 1] = nullptr;
|
environ[s_environ_count + 1] = nullptr;
|
||||||
s_environ_count++;
|
|
||||||
|
|
||||||
if (malloced)
|
set_bitmap_bit(s_environ_count, malloced);
|
||||||
{
|
|
||||||
const size_t byte = s_environ_count / 8;
|
s_environ_count++;
|
||||||
const size_t mask = 1 << (s_environ_count % 8);
|
|
||||||
s_environ_bitmap[byte] |= mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -116,15 +118,9 @@ int clearenv(void)
|
|||||||
if (s_environ_malloced)
|
if (s_environ_malloced)
|
||||||
{
|
{
|
||||||
ASSERT(environ);
|
ASSERT(environ);
|
||||||
|
|
||||||
for (size_t i = 0; environ[i]; i++)
|
for (size_t i = 0; environ[i]; i++)
|
||||||
{
|
if (is_bitmap_bit_set(i))
|
||||||
const size_t byte = i / 8;
|
|
||||||
const size_t mask = 1 << (i % 8);
|
|
||||||
if (s_environ_bitmap[byte] & mask)
|
|
||||||
free(environ[i]);
|
free(environ[i]);
|
||||||
}
|
|
||||||
|
|
||||||
free(s_environ_bitmap);
|
free(s_environ_bitmap);
|
||||||
free(environ);
|
free(environ);
|
||||||
}
|
}
|
||||||
@@ -142,9 +138,8 @@ char* getenv(const char* name)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
const size_t namelen = strlen(name);
|
const size_t namelen = strlen(name);
|
||||||
for (size_t i = 0; environ[i]; i++)
|
for (size_t i = 0; environ[i]; i++)
|
||||||
if (strncmp(name, environ[i], namelen) == 0)
|
if (strncmp(name, environ[i], namelen) == 0 && environ[i][namelen] == '=')
|
||||||
if (environ[i][namelen] == '=')
|
return environ[i] + namelen + 1;
|
||||||
return environ[i] + namelen + 1;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +157,7 @@ int setenv(const char* name, const char* val, int overwrite)
|
|||||||
const size_t namelen = strlen(name);
|
const size_t namelen = strlen(name);
|
||||||
const size_t vallen = strlen(val);
|
const size_t vallen = strlen(val);
|
||||||
|
|
||||||
char* string = (char*)malloc(namelen + vallen + 2);
|
auto* string = static_cast<char*>(malloc(namelen + vallen + 2));
|
||||||
memcpy(string, name, namelen);
|
memcpy(string, name, namelen);
|
||||||
string[namelen] = '=';
|
string[namelen] = '=';
|
||||||
memcpy(string + namelen + 1, val, vallen);
|
memcpy(string + namelen + 1, val, vallen);
|
||||||
@@ -189,13 +184,8 @@ int unsetenv(const char* name)
|
|||||||
{
|
{
|
||||||
if (strncmp(environ[i], name, namelen) || environ[i][namelen] != '=')
|
if (strncmp(environ[i], name, namelen) || environ[i][namelen] != '=')
|
||||||
continue;
|
continue;
|
||||||
if (!s_environ_malloced)
|
if (s_environ_malloced && is_bitmap_bit_set(i))
|
||||||
break;
|
|
||||||
const size_t byte = i / 8;
|
|
||||||
const size_t mask = 1 << (i % 8);
|
|
||||||
if (s_environ_bitmap[byte] & mask)
|
|
||||||
free(environ[i]);
|
free(environ[i]);
|
||||||
s_environ_count--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,17 +194,7 @@ int unsetenv(const char* name)
|
|||||||
environ[i] = environ[i + 1];
|
environ[i] = environ[i + 1];
|
||||||
if (!s_environ_malloced)
|
if (!s_environ_malloced)
|
||||||
continue;
|
continue;
|
||||||
|
set_bitmap_bit(i, is_bitmap_bit_set(i + 1));
|
||||||
const size_t cbyte = i / 8;
|
|
||||||
const size_t cmask = 1 << (i % 8);
|
|
||||||
|
|
||||||
const size_t nbyte = (i + 1) / 8;
|
|
||||||
const size_t nmask = 1 << ((i + 1) % 8);
|
|
||||||
|
|
||||||
if (s_environ_bitmap[nbyte] & nmask)
|
|
||||||
s_environ_bitmap[cbyte] |= cmask;
|
|
||||||
else
|
|
||||||
s_environ_bitmap[cbyte] &= ~cmask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (environ[i])
|
if (environ[i])
|
||||||
@@ -223,9 +203,8 @@ int unsetenv(const char* name)
|
|||||||
|
|
||||||
if (s_environ_malloced)
|
if (s_environ_malloced)
|
||||||
{
|
{
|
||||||
const size_t byte = i / 8;
|
set_bitmap_bit(i, false);
|
||||||
const size_t mask = 1 << (i % 8);
|
s_environ_count--;
|
||||||
s_environ_bitmap[byte] &= ~mask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#include <errno.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
int* __errno_location()
|
|
||||||
{
|
|
||||||
return &_get_uthread()->errno_;
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <ctype.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -5,6 +6,8 @@
|
|||||||
|
|
||||||
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
|
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
|
||||||
{
|
{
|
||||||
|
const bool ignore_case = !!(flags & FNM_IGNORECASE);
|
||||||
|
|
||||||
while (*pattern)
|
while (*pattern)
|
||||||
{
|
{
|
||||||
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
|
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
|
||||||
@@ -34,9 +37,13 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
|
|||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
uint32_t bitmap[0x100 / 8] {};
|
uint32_t bitmap[0x100 / 8] {};
|
||||||
while ((ch = *pattern++) != ']')
|
while ((ch = *pattern++) != ']')
|
||||||
|
{
|
||||||
|
if (ignore_case)
|
||||||
|
ch = tolower(ch);
|
||||||
bitmap[ch / 32] |= 1 << (ch % 32);
|
bitmap[ch / 32] |= 1 << (ch % 32);
|
||||||
|
}
|
||||||
|
|
||||||
ch = *string++;
|
ch = ignore_case ? tolower(*string++) : *string++;
|
||||||
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
|
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
|
||||||
return FNM_NOMATCH;
|
return FNM_NOMATCH;
|
||||||
|
|
||||||
@@ -63,7 +70,10 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
|
|||||||
if (*pattern == '\0')
|
if (*pattern == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (*pattern != *string)
|
const char lhs = ignore_case ? tolower(*pattern) : *pattern;
|
||||||
|
const char rhs = ignore_case ? tolower(*string) : *string;
|
||||||
|
|
||||||
|
if (lhs != rhs)
|
||||||
return FNM_NOMATCH;
|
return FNM_NOMATCH;
|
||||||
if ((flags & FNM_PATHNAME) && *string == '/')
|
if ((flags & FNM_PATHNAME) && *string == '/')
|
||||||
leading = true;
|
leading = true;
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
#ifndef assert
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert(ignore) ((void)0)
|
||||||
|
#else
|
||||||
|
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _ASSERT_H
|
#ifndef _ASSERT_H
|
||||||
#define _ASSERT_H 1
|
#define _ASSERT_H 1
|
||||||
|
|
||||||
@@ -5,12 +13,6 @@
|
|||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define assert(ignore) ((void)0)
|
|
||||||
#else
|
|
||||||
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
|
#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
|
||||||
#define static_assert _Static_assert
|
#define static_assert _Static_assert
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ typedef struct
|
|||||||
} pthread_barrierattr_t;
|
} pthread_barrierattr_t;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
pthread_barrierattr_t attr;
|
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_cond_t cond;
|
pthread_cond_t cond;
|
||||||
unsigned target;
|
unsigned target;
|
||||||
@@ -68,9 +67,11 @@ typedef struct
|
|||||||
} pthread_rwlockattr_t;
|
} pthread_rwlockattr_t;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
pthread_rwlockattr_t attr;
|
pthread_mutex_t lock;
|
||||||
unsigned lockers;
|
pthread_cond_t cond;
|
||||||
unsigned writers;
|
unsigned writers_waiting;
|
||||||
|
unsigned writer_active;
|
||||||
|
unsigned readers_active;
|
||||||
} pthread_rwlock_t;
|
} pthread_rwlock_t;
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|||||||
55
userspace/libraries/LibC/include/bits/types/uthread.h
Normal file
55
userspace/libraries/LibC/include/bits/types/uthread.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef _BITS_TYPES_UTHREAD_H
|
||||||
|
#define _BITS_TYPES_UTHREAD_H 1
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#define __need_size_t
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <bits/types/pthread_t.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct _pthread_cleanup_t
|
||||||
|
{
|
||||||
|
void (*routine)(void*);
|
||||||
|
void* arg;
|
||||||
|
struct _pthread_cleanup_t* next;
|
||||||
|
} _pthread_cleanup_t;
|
||||||
|
|
||||||
|
typedef struct _dynamic_tls_entry_t
|
||||||
|
{
|
||||||
|
void* master_addr;
|
||||||
|
size_t master_size;
|
||||||
|
} _dynamic_tls_entry_t;
|
||||||
|
|
||||||
|
typedef struct _dynamic_tls_t
|
||||||
|
{
|
||||||
|
int lock;
|
||||||
|
size_t entry_count;
|
||||||
|
_dynamic_tls_entry_t* entries;
|
||||||
|
} _dynamic_tls_t;
|
||||||
|
|
||||||
|
struct uthread
|
||||||
|
{
|
||||||
|
struct uthread* self;
|
||||||
|
void* master_tls_addr;
|
||||||
|
size_t master_tls_size;
|
||||||
|
size_t master_tls_module_count;
|
||||||
|
_dynamic_tls_t* dynamic_tls;
|
||||||
|
_pthread_cleanup_t* cleanup_stack;
|
||||||
|
pthread_t id;
|
||||||
|
int errno_;
|
||||||
|
int cancel_type;
|
||||||
|
int cancel_state;
|
||||||
|
volatile int canceled;
|
||||||
|
// FIXME: make this dynamic
|
||||||
|
uintptr_t dtv[1 + 256];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define _get_uthread() ((struct uthread*)__builtin_thread_pointer())
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <bits/types/uthread.h>
|
||||||
|
|
||||||
|
#define errno (_get_uthread()->errno_)
|
||||||
|
|
||||||
#define E2BIG 1
|
#define E2BIG 1
|
||||||
#define EACCES 2
|
#define EACCES 2
|
||||||
#define EADDRINUSE 3
|
#define EADDRINUSE 3
|
||||||
@@ -94,10 +98,6 @@ __BEGIN_DECLS
|
|||||||
#define ERESTART 0xFE /* internal errno for SA_RESTART */
|
#define ERESTART 0xFE /* internal errno for SA_RESTART */
|
||||||
#define EUNKNOWN 0xFF
|
#define EUNKNOWN 0xFF
|
||||||
|
|
||||||
#define errno (*__errno_location())
|
|
||||||
|
|
||||||
int* __errno_location(void);
|
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ __BEGIN_DECLS
|
|||||||
#define FNM_PATHNAME 0x01
|
#define FNM_PATHNAME 0x01
|
||||||
#define FNM_PERIOD 0x02
|
#define FNM_PERIOD 0x02
|
||||||
#define FNM_NOESCAPE 0x04
|
#define FNM_NOESCAPE 0x04
|
||||||
|
#define FNM_CASEFOLD 0x08
|
||||||
|
#define FNM_IGNORECASE FNM_CASEFOLD
|
||||||
|
|
||||||
int fnmatch(const char* pattern, const char* string, int flags);
|
int fnmatch(const char* pattern, const char* string, int flags);
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,13 @@ struct ifreq
|
|||||||
#define SIOCGIFFLAGS 9
|
#define SIOCGIFFLAGS 9
|
||||||
#define SIOCGIFMTU 10
|
#define SIOCGIFMTU 10
|
||||||
|
|
||||||
|
#define IFF_UP 0x01
|
||||||
|
#define IFF_BROADCAST 0x02
|
||||||
|
#define IFF_LOOPBACK 0x04
|
||||||
|
#define IFF_POINTOPOINT 0x08
|
||||||
|
#define IFF_RUNNING 0x10
|
||||||
|
#define IFF_MULTICAST 0x20
|
||||||
|
|
||||||
void if_freenameindex(struct if_nameindex* ptr);
|
void if_freenameindex(struct if_nameindex* ptr);
|
||||||
char* if_indextoname(unsigned ifindex, char* ifname);
|
char* if_indextoname(unsigned ifindex, char* ifname);
|
||||||
struct if_nameindex* if_nameindex(void);
|
struct if_nameindex* if_nameindex(void);
|
||||||
|
|||||||
@@ -18,49 +18,26 @@ __BEGIN_DECLS
|
|||||||
#define IPPROTO_TCP 6
|
#define IPPROTO_TCP 6
|
||||||
#define IPPROTO_UDP 7
|
#define IPPROTO_UDP 7
|
||||||
|
|
||||||
enum
|
#define IP_ADD_MEMBERSHIP 0
|
||||||
{
|
#define IP_ADD_SOURCE_MEMBERSHIP 1
|
||||||
IP_ADD_MEMBERSHIP,
|
#define IP_DROP_MEMBERSHIP 2
|
||||||
#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
|
#define IP_DROP_SOURCE_MEMBERSHIP 3
|
||||||
IP_ADD_SOURCE_MEMBERSHIP,
|
#define IP_MULTICAST_IF 4
|
||||||
#define IP_ADD_SOURCE_MEMBERSHIP IP_ADD_SOURCE_MEMBERSHIP
|
#define IP_MULTICAST_LOOP 5
|
||||||
IP_DROP_MEMBERSHIP,
|
#define IP_MULTICAST_TTL 6
|
||||||
#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
|
#define IP_TTL 7
|
||||||
IP_DROP_SOURCE_MEMBERSHIP,
|
#define IP_TOS 8
|
||||||
#define IP_DROP_SOURCE_MEMBERSHIP IP_DROP_SOURCE_MEMBERSHIP
|
|
||||||
IP_MULTICAST_IF,
|
|
||||||
#define IP_MULTICAST_IF IP_MULTICAST_IF
|
|
||||||
IP_MULTICAST_LOOP,
|
|
||||||
#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP
|
|
||||||
IP_MULTICAST_TTL,
|
|
||||||
#define IP_MULTICAST_TTL IP_MULTICAST_TTL
|
|
||||||
IP_TTL,
|
|
||||||
#define IP_TTL IP_TTL
|
|
||||||
IP_TOS,
|
|
||||||
#define IP_TOS IP_TOS
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
#define IPV6_ADD_MEMBERSHIP 0
|
||||||
{
|
#define IPV6_DROP_MEMBERSHIP 1
|
||||||
IPV6_ADD_MEMBERSHIP,
|
#define IPV6_JOIN_GROUP 2
|
||||||
#define IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
|
#define IPV6_LEAVE_GROUP 3
|
||||||
IPV6_DROP_MEMBERSHIP,
|
#define IPV6_MULTICAST_HOPS 4
|
||||||
#define IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
|
#define IPV6_MULTICAST_IF 5
|
||||||
IPV6_JOIN_GROUP,
|
#define IPV6_MULTICAST_LOOP 6
|
||||||
#define IPV6_JOIN_GROUP IPV6_JOIN_GROUP
|
#define IPV6_UNICAST_HOPS 7
|
||||||
IPV6_LEAVE_GROUP,
|
#define IPV6_V6ONLY 8
|
||||||
#define IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
|
#define IPV6_TCLASS 9
|
||||||
IPV6_MULTICAST_HOPS,
|
|
||||||
#define IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
|
|
||||||
IPV6_MULTICAST_IF,
|
|
||||||
#define IPV6_MULTICAST_IF IPV6_MULTICAST_IF
|
|
||||||
IPV6_MULTICAST_LOOP,
|
|
||||||
#define IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
|
|
||||||
IPV6_UNICAST_HOPS,
|
|
||||||
#define IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
|
|
||||||
IPV6_V6ONLY,
|
|
||||||
#define IPV6_V6ONLY IPV6_V6ONLY
|
|
||||||
};
|
|
||||||
|
|
||||||
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
|
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
|
||||||
#define IN_CLASSA_NET 0xFF000000
|
#define IN_CLASSA_NET 0xFF000000
|
||||||
|
|||||||
@@ -16,43 +16,7 @@ __BEGIN_DECLS
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <bits/types/pthread_types.h>
|
#include <bits/types/pthread_types.h>
|
||||||
|
#include <bits/types/uthread.h>
|
||||||
typedef struct _pthread_cleanup_t
|
|
||||||
{
|
|
||||||
void (*routine)(void*);
|
|
||||||
void* arg;
|
|
||||||
struct _pthread_cleanup_t* next;
|
|
||||||
} _pthread_cleanup_t;
|
|
||||||
|
|
||||||
typedef struct _dynamic_tls_entry_t
|
|
||||||
{
|
|
||||||
void* master_addr;
|
|
||||||
size_t master_size;
|
|
||||||
} _dynamic_tls_entry_t;
|
|
||||||
|
|
||||||
typedef struct _dynamic_tls_t
|
|
||||||
{
|
|
||||||
int lock;
|
|
||||||
size_t entry_count;
|
|
||||||
_dynamic_tls_entry_t* entries;
|
|
||||||
} _dynamic_tls_t;
|
|
||||||
|
|
||||||
struct uthread
|
|
||||||
{
|
|
||||||
struct uthread* self;
|
|
||||||
void* master_tls_addr;
|
|
||||||
size_t master_tls_size;
|
|
||||||
size_t master_tls_module_count;
|
|
||||||
_dynamic_tls_t* dynamic_tls;
|
|
||||||
_pthread_cleanup_t* cleanup_stack;
|
|
||||||
pthread_t id;
|
|
||||||
int errno_;
|
|
||||||
int cancel_type;
|
|
||||||
int cancel_state;
|
|
||||||
int canceled;
|
|
||||||
// FIXME: make this dynamic
|
|
||||||
uintptr_t dtv[1 + 128];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PTHREAD_CANCELED (void*)1
|
#define PTHREAD_CANCELED (void*)1
|
||||||
|
|
||||||
@@ -103,20 +67,6 @@ struct uthread
|
|||||||
#define _PTHREAD_ATFORK_CHILD 2
|
#define _PTHREAD_ATFORK_CHILD 2
|
||||||
void _pthread_call_atfork(int state);
|
void _pthread_call_atfork(int state);
|
||||||
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
#define _get_uthread() ({ \
|
|
||||||
struct uthread* __tmp; \
|
|
||||||
asm volatile("movq %%fs:0, %0" : "=r"(__tmp)); \
|
|
||||||
__tmp; \
|
|
||||||
})
|
|
||||||
#elif defined(__i686__)
|
|
||||||
#define _get_uthread() ({ \
|
|
||||||
struct uthread* __tmp; \
|
|
||||||
asm volatile("movl %%gs:0, %0" : "=r"(__tmp)); \
|
|
||||||
__tmp; \
|
|
||||||
})
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
|
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
|
||||||
int pthread_attr_destroy(pthread_attr_t* attr);
|
int pthread_attr_destroy(pthread_attr_t* attr);
|
||||||
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate);
|
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate);
|
||||||
@@ -159,7 +109,7 @@ int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared);
|
|||||||
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void *(*start_routine)(void*), void* __restrict arg);
|
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void *(*start_routine)(void*), void* __restrict arg);
|
||||||
int pthread_detach(pthread_t thread);
|
int pthread_detach(pthread_t thread);
|
||||||
int pthread_equal(pthread_t t1, pthread_t t2);
|
int pthread_equal(pthread_t t1, pthread_t t2);
|
||||||
void pthread_exit(void* value_ptr);
|
void pthread_exit(void* value_ptr) __attribute__((__noreturn__));
|
||||||
int pthread_getconcurrency(void);
|
int pthread_getconcurrency(void);
|
||||||
int pthread_getcpuclockid(pthread_t thread_id, clockid_t* clock_id);
|
int pthread_getcpuclockid(pthread_t thread_id, clockid_t* clock_id);
|
||||||
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param);
|
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param);
|
||||||
@@ -219,6 +169,14 @@ void pthread_testcancel(void);
|
|||||||
void pthread_cleanup_pop(int execute);
|
void pthread_cleanup_pop(int execute);
|
||||||
void pthread_cleanup_push(void (*routine)(void*), void* arg);
|
void pthread_cleanup_push(void (*routine)(void*), void* arg);
|
||||||
|
|
||||||
|
#define _pthread_testcancel() do { \
|
||||||
|
struct uthread* uthread = _get_uthread(); \
|
||||||
|
if (__builtin_expect(uthread->cancel_state == PTHREAD_CANCEL_ENABLE, 1)) \
|
||||||
|
if (__builtin_expect(uthread->canceled, 0)) \
|
||||||
|
pthread_exit(PTHREAD_CANCELED); \
|
||||||
|
} while (0)
|
||||||
|
#define pthread_testcancel() _pthread_testcancel()
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ int sched_setparam(pid_t pid, const struct sched_param* param);
|
|||||||
int sched_setscheduler(pid_t pid, int, const struct sched_param* param);
|
int sched_setscheduler(pid_t pid, int, const struct sched_param* param);
|
||||||
int sched_yield(void);
|
int sched_yield(void);
|
||||||
|
|
||||||
|
int sched_getcpu(void);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ char* strndup(const char* s, size_t n);
|
|||||||
size_t strnlen(const char* s, size_t maxlen);
|
size_t strnlen(const char* s, size_t maxlen);
|
||||||
char* strpbrk(const char* s1, const char* s2);
|
char* strpbrk(const char* s1, const char* s2);
|
||||||
char* strrchr(const char* s, int c);
|
char* strrchr(const char* s, int c);
|
||||||
|
char* strsep(char** __restrict stringp, const char* __restrict delim);
|
||||||
char* strsignal(int signum);
|
char* strsignal(int signum);
|
||||||
size_t strspn(const char* s1, const char* s2);
|
size_t strspn(const char* s1, const char* s2);
|
||||||
char* strstr(const char* s1, const char* s2);
|
char* strstr(const char* s1, const char* s2);
|
||||||
|
char* strcasestr(const char* haystack, const char* needle);
|
||||||
char* strtok(char* __restrict s, const char* __restrict sep);
|
char* strtok(char* __restrict s, const char* __restrict sep);
|
||||||
char* strtok_r(char* __restrict s, const char* __restrict sep, char** __restrict state);
|
char* strtok_r(char* __restrict s, const char* __restrict sep, char** __restrict state);
|
||||||
size_t strxfrm(char* __restrict s1, const char* __restrict s2, size_t n);
|
size_t strxfrm(char* __restrict s1, const char* __restrict s2, size_t n);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define I_ATMARK 1
|
#define I_ATMARK 1
|
||||||
#define I_CANPUT 2
|
#define I_CANPUT 2
|
||||||
#define I_CKBAND 3
|
#define I_CKBAND 3
|
||||||
@@ -50,6 +52,13 @@ struct winsize
|
|||||||
#define TIOCGWINSZ 50
|
#define TIOCGWINSZ 50
|
||||||
#define TIOCSWINSZ 51
|
#define TIOCSWINSZ 51
|
||||||
|
|
||||||
|
struct snd_volume_info
|
||||||
|
{
|
||||||
|
int32_t min_mdB;
|
||||||
|
int32_t max_mdB;
|
||||||
|
int32_t step_mdB;
|
||||||
|
int32_t mdB;
|
||||||
|
};
|
||||||
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
|
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
|
||||||
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
|
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
|
||||||
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
|
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
|
||||||
@@ -57,12 +66,23 @@ struct winsize
|
|||||||
#define SND_GET_TOTAL_PINS 64 /* gets the number of pins on the current device as uint32_t */
|
#define SND_GET_TOTAL_PINS 64 /* gets the number of pins on the current device as uint32_t */
|
||||||
#define SND_GET_PIN 65 /* gets the currently active pin as uint32_t */
|
#define SND_GET_PIN 65 /* gets the currently active pin as uint32_t */
|
||||||
#define SND_SET_PIN 66 /* sets the currently active pin to uint32_t */
|
#define SND_SET_PIN 66 /* sets the currently active pin to uint32_t */
|
||||||
|
#define SND_GET_VOLUME_INFO 67 /* gets the current volume as snd_volume_info */
|
||||||
|
#define SND_SET_VOLUME_MDB 68 /* sets the current volume to int32_t dB */
|
||||||
|
|
||||||
#define JOYSTICK_GET_LEDS 80 /* get controller led bitmap to uint8_t argument */
|
#define JOYSTICK_GET_LEDS 80 /* get controller led bitmap to uint8_t argument */
|
||||||
#define JOYSTICK_SET_LEDS 81 /* set controller leds to uint8_t bitmap */
|
#define JOYSTICK_SET_LEDS 81 /* set controller leds to uint8_t bitmap */
|
||||||
#define JOYSTICK_GET_RUMBLE 82 /* get controller rumble strength to uint8_t argument */
|
#define JOYSTICK_GET_RUMBLE 82 /* get controller rumble strength to uint8_t argument */
|
||||||
#define JOYSTICK_SET_RUMBLE 83 /* set controller rumble strength to uint8_t argument */
|
#define JOYSTICK_SET_RUMBLE 83 /* set controller rumble strength to uint8_t argument */
|
||||||
|
|
||||||
|
struct fb_msync_region
|
||||||
|
{
|
||||||
|
uint32_t min_x;
|
||||||
|
uint32_t min_y;
|
||||||
|
uint32_t max_x;
|
||||||
|
uint32_t max_y;
|
||||||
|
};
|
||||||
|
#define FB_MSYNC_RECTANGLE 90 /* msync a rectangular area in mmap'd framebuffer device */
|
||||||
|
|
||||||
int ioctl(int, int, ...);
|
int ioctl(int, int, ...);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
#define LOG_PID 0x01
|
#define LOG_PID 0x01
|
||||||
@@ -47,6 +49,7 @@ void closelog(void);
|
|||||||
void openlog(const char* ident, int logopt, int facility);
|
void openlog(const char* ident, int logopt, int facility);
|
||||||
int setlogmask(int maskpri);
|
int setlogmask(int maskpri);
|
||||||
void syslog(int priority, const char* message, ...);
|
void syslog(int priority, const char* message, ...);
|
||||||
|
void vsyslog(int priority, const char* format, va_list ap);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,10 @@ enum
|
|||||||
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
|
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
|
||||||
_SC_XOPEN_VERSION,
|
_SC_XOPEN_VERSION,
|
||||||
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
|
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
|
||||||
|
_SC_PHYS_PAGES,
|
||||||
|
#define _SC_PHYS_PAGES _SC_PHYS_PAGES
|
||||||
|
_SC_AVPHYS_PAGES,
|
||||||
|
#define _SC_AVPHYS_PAGES _SC_AVPHYS_PAGES
|
||||||
};
|
};
|
||||||
|
|
||||||
#define F_OK 0x01
|
#define F_OK 0x01
|
||||||
@@ -604,6 +608,22 @@ char* getpass(const char* prompt);
|
|||||||
|
|
||||||
long syscall(long syscall, ...);
|
long syscall(long syscall, ...);
|
||||||
|
|
||||||
|
#ifdef __is_libc
|
||||||
|
#include <kernel/API/Syscall.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#define _syscall(...) ({ \
|
||||||
|
long _ret = -ERESTART; \
|
||||||
|
while (_ret == -ERESTART) \
|
||||||
|
_ret = _kas_syscall(__VA_ARGS__); \
|
||||||
|
if (_ret < 0) { \
|
||||||
|
errno = -_ret; \
|
||||||
|
_ret = -1; \
|
||||||
|
} \
|
||||||
|
_ret; \
|
||||||
|
})
|
||||||
|
#define syscall _syscall
|
||||||
|
#endif
|
||||||
|
|
||||||
extern char** environ;
|
extern char** environ;
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ FUNC_EXPR1(nearbyint, BAN::Math::rint(a))
|
|||||||
FUNC_EXPR2(nextafter, nextafter_impl(a, b))
|
FUNC_EXPR2(nextafter, nextafter_impl(a, b))
|
||||||
FUNC_EXPR2_TYPE(nexttoward, long double, nextafter_impl(a, b))
|
FUNC_EXPR2_TYPE(nexttoward, long double, nextafter_impl(a, b))
|
||||||
FUNC_EXPR2(pow, ({ if (isnan(a)) return a; if (isnan(b)) return b; BAN::Math::pow(a, b); }))
|
FUNC_EXPR2(pow, ({ if (isnan(a)) return a; if (isnan(b)) return b; BAN::Math::pow(a, b); }))
|
||||||
// remainder
|
BAN_FUNC2(remainder)
|
||||||
// remquo
|
// remquo
|
||||||
BAN_FUNC1(rint)
|
BAN_FUNC1(rint)
|
||||||
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))
|
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))
|
||||||
|
|||||||
@@ -22,7 +22,21 @@ struct pthread_trampoline_info_t
|
|||||||
void* arg;
|
void* arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr unsigned rwlock_writer_locked = -1;
|
static void _pthread_cancel_handler(int)
|
||||||
|
{
|
||||||
|
uthread* uthread = _get_uthread();
|
||||||
|
uthread->canceled = true;
|
||||||
|
if (uthread->cancel_state == PTHREAD_CANCEL_DISABLE)
|
||||||
|
return;
|
||||||
|
if (uthread->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||||
|
pthread_exit(PTHREAD_CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void _install_main_thread_cancel_handler()
|
||||||
|
{
|
||||||
|
signal(SIGCANCEL, &_pthread_cancel_handler);
|
||||||
|
}
|
||||||
|
|
||||||
// stack is 16 byte aligned on entry, this `call` is used to align it
|
// stack is 16 byte aligned on entry, this `call` is used to align it
|
||||||
extern "C" void _pthread_trampoline(void*);
|
extern "C" void _pthread_trampoline(void*);
|
||||||
@@ -35,7 +49,6 @@ asm(
|
|||||||
"call _pthread_trampoline_cpp"
|
"call _pthread_trampoline_cpp"
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
"_pthread_trampoline:"
|
"_pthread_trampoline:"
|
||||||
"ud2;"
|
|
||||||
"popl %edi;"
|
"popl %edi;"
|
||||||
"andl $-16, %esp;"
|
"andl $-16, %esp;"
|
||||||
"xorl %ebp, %ebp;"
|
"xorl %ebp, %ebp;"
|
||||||
@@ -57,6 +70,7 @@ extern "C" void _pthread_trampoline_cpp(void* arg)
|
|||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
free(arg);
|
free(arg);
|
||||||
|
signal(SIGCANCEL, &_pthread_cancel_handler);
|
||||||
pthread_exit(info.start_routine(info.arg));
|
pthread_exit(info.start_routine(info.arg));
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
@@ -613,25 +627,8 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(voi
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pthread_cancel_handler(int)
|
|
||||||
{
|
|
||||||
uthread* uthread = _get_uthread();
|
|
||||||
BAN::atomic_store(uthread->canceled, true);
|
|
||||||
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
|
|
||||||
return;
|
|
||||||
switch (BAN::atomic_load(uthread->cancel_type))
|
|
||||||
{
|
|
||||||
case PTHREAD_CANCEL_ASYNCHRONOUS:
|
|
||||||
pthread_exit(PTHREAD_CANCELED);
|
|
||||||
case PTHREAD_CANCEL_DEFERRED:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_cancel(pthread_t thread)
|
int pthread_cancel(pthread_t thread)
|
||||||
{
|
{
|
||||||
signal(SIGCANCEL, &pthread_cancel_handler);
|
|
||||||
return pthread_kill(thread, SIGCANCEL);
|
return pthread_kill(thread, SIGCANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,14 +666,10 @@ int pthread_setcanceltype(int type, int* oldtype)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef pthread_testcancel
|
||||||
void pthread_testcancel(void)
|
void pthread_testcancel(void)
|
||||||
{
|
{
|
||||||
uthread* uthread = _get_uthread();
|
_pthread_testcancel();
|
||||||
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
|
|
||||||
return;
|
|
||||||
if (!BAN::atomic_load(uthread->canceled))
|
|
||||||
return;
|
|
||||||
pthread_exit(PTHREAD_CANCELED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param)
|
int pthread_getschedparam(pthread_t thread, int* __restrict policy, struct sched_param* __restrict param)
|
||||||
@@ -943,102 +936,100 @@ int pthread_rwlock_init(pthread_rwlock_t* __restrict rwlock, const pthread_rwloc
|
|||||||
if (attr == nullptr)
|
if (attr == nullptr)
|
||||||
attr = &default_attr;
|
attr = &default_attr;
|
||||||
*rwlock = {
|
*rwlock = {
|
||||||
.attr = *attr,
|
.lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.lockers = 0,
|
.cond = PTHREAD_COND_INITIALIZER,
|
||||||
.writers = 0,
|
.writers_waiting = 0,
|
||||||
|
.writer_active = 0,
|
||||||
|
.readers_active = 0,
|
||||||
};
|
};
|
||||||
|
const pthread_mutexattr_t mattr {
|
||||||
|
.type = PTHREAD_MUTEX_DEFAULT,
|
||||||
|
.shared = attr->shared,
|
||||||
|
};
|
||||||
|
pthread_mutex_init(&rwlock->lock, &mattr);
|
||||||
|
const pthread_condattr_t cattr {
|
||||||
|
.clock = CLOCK_REALTIME,
|
||||||
|
.shared = attr->shared,
|
||||||
|
};
|
||||||
|
pthread_cond_init(&rwlock->cond, &cattr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rewrite rwlock with futexes
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static int pthread_rwlock_timedlock(T* __restrict lock, const struct timespec* __restrict abstime, int (*trylock)(T*))
|
|
||||||
{
|
|
||||||
if (trylock(lock) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
constexpr auto has_timed_out =
|
|
||||||
[](const struct timespec* abstime) -> bool
|
|
||||||
{
|
|
||||||
struct timespec curtime;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &curtime);
|
|
||||||
if (curtime.tv_sec < abstime->tv_sec)
|
|
||||||
return false;
|
|
||||||
if (curtime.tv_sec > abstime->tv_sec)
|
|
||||||
return true;
|
|
||||||
return curtime.tv_nsec >= abstime->tv_nsec;
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!has_timed_out(abstime))
|
|
||||||
{
|
|
||||||
if (trylock(lock) == 0)
|
|
||||||
return 0;
|
|
||||||
sched_yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock)
|
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock)
|
||||||
{
|
{
|
||||||
unsigned expected = BAN::atomic_load(rwlock->lockers);
|
return pthread_rwlock_timedrdlock(rwlock, nullptr);
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (expected == rwlock_writer_locked || BAN::atomic_load(rwlock->writers))
|
|
||||||
sched_yield();
|
|
||||||
else if (BAN::atomic_compare_exchange(rwlock->lockers, expected, expected + 1))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock)
|
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock)
|
||||||
{
|
{
|
||||||
unsigned expected = BAN::atomic_load(rwlock->lockers);
|
int ret = 0;
|
||||||
while (expected != rwlock_writer_locked && BAN::atomic_load(rwlock->writers) == 0)
|
pthread_mutex_lock(&rwlock->lock);
|
||||||
if (BAN::atomic_compare_exchange(rwlock->lockers, expected, expected + 1))
|
if (!rwlock->writers_waiting && !rwlock->writer_active)
|
||||||
return 0;
|
rwlock->readers_active++;
|
||||||
return EBUSY;
|
else
|
||||||
|
ret = EBUSY;
|
||||||
|
pthread_mutex_unlock(&rwlock->lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_timedrdlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
|
int pthread_rwlock_timedrdlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
|
||||||
{
|
{
|
||||||
return pthread_rwlock_timedlock(rwlock, abstime, &pthread_rwlock_tryrdlock);
|
int ret = 0;
|
||||||
|
pthread_mutex_lock(&rwlock->lock);
|
||||||
|
while (ret == 0 && (rwlock->writers_waiting || rwlock->writer_active))
|
||||||
|
ret = pthread_cond_timedwait(&rwlock->cond, &rwlock->lock, abstime);
|
||||||
|
if (ret == 0)
|
||||||
|
rwlock->readers_active++;
|
||||||
|
pthread_mutex_unlock(&rwlock->lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock)
|
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock)
|
||||||
{
|
{
|
||||||
BAN::atomic_add_fetch(rwlock->writers, 1);
|
return pthread_rwlock_timedwrlock(rwlock, nullptr);
|
||||||
unsigned expected = 0;
|
|
||||||
while (!BAN::atomic_compare_exchange(rwlock->lockers, expected, rwlock_writer_locked))
|
|
||||||
{
|
|
||||||
sched_yield();
|
|
||||||
expected = 0;
|
|
||||||
}
|
|
||||||
BAN::atomic_sub_fetch(rwlock->writers, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock)
|
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock)
|
||||||
{
|
{
|
||||||
unsigned expected = 0;
|
int ret = 0;
|
||||||
if (!BAN::atomic_compare_exchange(rwlock->lockers, expected, rwlock_writer_locked))
|
pthread_mutex_lock(&rwlock->lock);
|
||||||
return EBUSY;
|
if (!rwlock->readers_active && !rwlock->writer_active)
|
||||||
return 0;
|
rwlock->writer_active = 1;
|
||||||
|
else
|
||||||
|
ret = EBUSY;
|
||||||
|
pthread_mutex_unlock(&rwlock->lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_timedwrlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
|
int pthread_rwlock_timedwrlock(pthread_rwlock_t* __restrict rwlock, const struct timespec* __restrict abstime)
|
||||||
{
|
{
|
||||||
return pthread_rwlock_timedlock(rwlock, abstime, &pthread_rwlock_trywrlock);
|
int ret = 0;
|
||||||
|
pthread_mutex_lock(&rwlock->lock);
|
||||||
|
rwlock->writers_waiting++;
|
||||||
|
while (ret == 0 && (rwlock->readers_active || rwlock->writer_active))
|
||||||
|
ret = pthread_cond_timedwait(&rwlock->cond, &rwlock->lock, abstime);
|
||||||
|
rwlock->writers_waiting--;
|
||||||
|
if (ret == 0)
|
||||||
|
rwlock->writer_active = 1;
|
||||||
|
pthread_mutex_unlock(&rwlock->lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock)
|
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock)
|
||||||
{
|
{
|
||||||
if (BAN::atomic_load(rwlock->lockers) == rwlock_writer_locked)
|
pthread_mutex_lock(&rwlock->lock);
|
||||||
BAN::atomic_store(rwlock->lockers, 0);
|
if (rwlock->writer_active)
|
||||||
|
{
|
||||||
|
rwlock->writer_active = 0;
|
||||||
|
pthread_cond_broadcast(&rwlock->cond);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
BAN::atomic_sub_fetch(rwlock->lockers, 1);
|
{
|
||||||
|
rwlock->readers_active--;
|
||||||
|
if (rwlock->readers_active == 0)
|
||||||
|
pthread_cond_broadcast(&rwlock->cond);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rwlock->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1167,16 +1158,14 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
|
|||||||
|
|
||||||
pthread_mutex_unlock(mutex);
|
pthread_mutex_unlock(mutex);
|
||||||
|
|
||||||
while (BAN::atomic_load(block.futex) == 0)
|
int ret = 0;
|
||||||
|
while (ret == 0 && BAN::atomic_load(block.futex) == 0)
|
||||||
{
|
{
|
||||||
const int op = FUTEX_WAIT
|
const int op = FUTEX_WAIT
|
||||||
| (cond->attr.shared ? 0 : FUTEX_PRIVATE)
|
| (cond->attr.shared ? 0 : FUTEX_PRIVATE)
|
||||||
| (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0);
|
| (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0);
|
||||||
if (futex(op, &block.futex, 0, abstime) == -1 && errno == ETIMEDOUT)
|
if (futex(op, &block.futex, 0, abstime) == -1 && errno == ETIMEDOUT)
|
||||||
{
|
ret = ETIMEDOUT;
|
||||||
pthread_mutex_lock(mutex);
|
|
||||||
return ETIMEDOUT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_spin_lock(&cond->lock);
|
pthread_spin_lock(&cond->lock);
|
||||||
@@ -1192,7 +1181,7 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
|
|||||||
pthread_spin_unlock(&cond->lock);
|
pthread_spin_unlock(&cond->lock);
|
||||||
|
|
||||||
pthread_mutex_lock(mutex);
|
pthread_mutex_lock(mutex);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_barrierattr_destroy(pthread_barrierattr_t* attr)
|
int pthread_barrierattr_destroy(pthread_barrierattr_t* attr)
|
||||||
@@ -1245,13 +1234,22 @@ int pthread_barrier_init(pthread_barrier_t* __restrict barrier, const pthread_ba
|
|||||||
if (attr == nullptr)
|
if (attr == nullptr)
|
||||||
attr = &default_attr;
|
attr = &default_attr;
|
||||||
*barrier = {
|
*barrier = {
|
||||||
.attr = *attr,
|
|
||||||
.lock = PTHREAD_MUTEX_INITIALIZER,
|
.lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
.cond = PTHREAD_COND_INITIALIZER,
|
.cond = PTHREAD_COND_INITIALIZER,
|
||||||
.target = count,
|
.target = count,
|
||||||
.waiting = 0,
|
.waiting = 0,
|
||||||
.generation = 0,
|
.generation = 0,
|
||||||
};
|
};
|
||||||
|
const pthread_mutexattr_t mattr {
|
||||||
|
.type = PTHREAD_MUTEX_DEFAULT,
|
||||||
|
.shared = attr->shared,
|
||||||
|
};
|
||||||
|
pthread_mutex_init(&barrier->lock, &mattr);
|
||||||
|
const pthread_condattr_t cattr {
|
||||||
|
.clock = CLOCK_REALTIME,
|
||||||
|
.shared = attr->shared,
|
||||||
|
};
|
||||||
|
pthread_cond_init(&barrier->cond, &cattr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <kernel/API/SharedPage.h>
|
||||||
|
|
||||||
|
extern volatile Kernel::API::SharedPage* g_shared_page;
|
||||||
|
|
||||||
int sched_get_priority_max(int policy)
|
int sched_get_priority_max(int policy)
|
||||||
{
|
{
|
||||||
(void)policy;
|
(void)policy;
|
||||||
@@ -18,3 +22,17 @@ int sched_yield(void)
|
|||||||
{
|
{
|
||||||
return syscall(SYS_YIELD);
|
return syscall(SYS_YIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sched_getcpu(void)
|
||||||
|
{
|
||||||
|
if (g_shared_page == nullptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint8_t cpu;
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asm volatile("movb %%gs:0, %0" : "=r"(cpu));
|
||||||
|
#elif defined(__i686__)
|
||||||
|
asm volatile("movb %%fs:0, %0" : "=q"(cpu));
|
||||||
|
#endif
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,8 +49,12 @@ int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict absti
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
uint32_t expected = BAN::atomic_load(sem->value);
|
uint32_t expected = BAN::atomic_load(sem->value);
|
||||||
if (expected > 0 && BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
if (expected > 0)
|
||||||
|
{
|
||||||
|
if (!BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
||||||
|
continue;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
|
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
|
||||||
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))
|
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ static mode_t parse_mode_string(const char* mode_str)
|
|||||||
return 0;
|
return 0;
|
||||||
if (len == 3 && mode_str[1] == mode_str[2])
|
if (len == 3 && mode_str[1] == mode_str[2])
|
||||||
return 0;
|
return 0;
|
||||||
if (strspn(mode_str + 1, "b+") != len - 1)
|
if (strspn(mode_str + 1, "tb+") != len - 1)
|
||||||
return 0;
|
return 0;
|
||||||
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
|
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
|
||||||
switch (mode_str[0])
|
switch (mode_str[0])
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user