20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/compiler.h"
22#include "pedigree/kernel/core/SlamAllocator.h"
23#include "pedigree/kernel/core/cppsupport.h"
24#include "pedigree/kernel/machine/Trace.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/processor/Processor.h"
27#include "pedigree/kernel/processor/VirtualAddressSpace.h"
28#include "pedigree/kernel/processor/types.h"
29#include "pedigree/kernel/utilities/MemoryTracing.h"
30#include "pedigree/kernel/utilities/utility.h"
32#if PEDIGREE_HOSTED_DARWIN
33#include <mach-o/getsect.h>
34#include <mach-o/ldsyms.h>
39#define DEBUG_ALLOCATOR_CHECK_UNDERFLOWS 1
42#if __GNUC__ && !defined(__clang__)
43#pragma GCC diagnostic ignored "-Wframe-address"
48extern "C" void* __dso_handle;
51#if !PEDIGREE_HOSTED_DARWIN
53extern uintptr_t start_kernel_ctors;
54extern uintptr_t end_kernel_ctors;
55extern uintptr_t start_kernel_dtors;
56extern uintptr_t end_kernel_dtors;
59#if PEDIGREE_HOSTED_DARWIN
60static void runKernelConstructorSection(
const char* section) {
61 unsigned long size = 0;
62 uint8_t* contents = getsectiondata(&_mh_execute_header,
"__DATA", section, &size);
63 auto functions =
reinterpret_cast<void (**)()
>(contents);
64 const size_t count = size /
sizeof(*functions);
65 for (
size_t i = 0; i < count; ++i) {
73void initialiseConstructors() {
74#if PEDIGREE_HOSTED_DARWIN
75 runKernelConstructorSection(
"__pedigree_init");
80 uintptr_t* iterator = &start_kernel_ctors;
81 while (iterator < &end_kernel_ctors) {
82 void (*fp)(void) =
reinterpret_cast<void (*)(
void)
>(*iterator);
89void runKernelDestructors() {
90#if PEDIGREE_HOSTED_DARWIN
91 runKernelConstructorSection(
"__pedigree_term");
93 uintptr_t* iterator = &start_kernel_dtors;
94 while (iterator < &end_kernel_dtors) {
95 void (*fp)(void) =
reinterpret_cast<void (*)(
void)
>(*iterator);
103static bool traceAllocations = MEMORY_TRACING;
105void startTracingAllocations() {
106 if constexpr (MEMORY_TRACING) {
107 traceAllocations =
true;
111void stopTracingAllocations() {
112 if constexpr (MEMORY_TRACING) {
113 traceAllocations =
false;
117void toggleTracingAllocations() {
118 if constexpr (MEMORY_TRACING) {
119 traceAllocations = !traceAllocations;
123void traceAllocation(
void* ptr, MemoryTracing::AllocationTrace type,
size_t size) {
125 if constexpr (!MEMORY_TRACING) {
130 if (!traceAllocations)
135 case MemoryTracing::Allocation:
136 case MemoryTracing::Free:
137 case MemoryTracing::Metadata:
146 entry.data.type = type;
147 entry.data.sz = size & 0xFFFFFFFFU;
148 entry.data.ptr =
reinterpret_cast<uintptr_t
>(ptr);
149 for (
size_t i = 0; i < MemoryTracing::num_backtrace_entries; ++i) {
150 entry.data.bt[i] = 0;
153#define BT_FRAME(M, N) \
155 if (M && !entry.data.bt[M - 1]) \
157 void* frame_addr = __builtin_frame_address(N); \
158 if (!(frame_addr && va.isMapped(frame_addr))) { \
159 entry.data.bt[M] = 0; \
162 entry.data.bt[M] = reinterpret_cast<uintptr_t>(__builtin_return_address(N)) & 0xFFFFFFFFU; \
167 if (MemoryTracing::num_backtrace_entries >= 1)
169 if (MemoryTracing::num_backtrace_entries >= 2)
171 if (MemoryTracing::num_backtrace_entries >= 3)
173 if (MemoryTracing::num_backtrace_entries >= 4)
175 if (MemoryTracing::num_backtrace_entries >= 5)
178 __asm__ __volatile__(
"pushfq; cli" :::
"memory");
180 for (
size_t i = 0; i <
sizeof entry.buf; ++i) {
181 __asm__ __volatile__(
"outb %%al, %%dx" ::
"Nd"(0x2E8),
"a"(entry.buf[i]));
184 __asm__ __volatile__(
"popf" :::
"memory");
198extern "C" EXPORTED_PUBLIC
void atexit(
void (*f)(
void*),
void* p,
void* d);
199void atexit(
void (*f)(
void*),
void* p,
void* d) {}
203extern "C" EXPORTED_PUBLIC
void __cxa_pure_virtual()
NORETURN;
204void __cxa_pure_virtual() {
206 TRACE(
"Pure virtual function call made");
209 asm volatile(
"int $3");
212 FATAL_NOLOCK(
"Pure virtual function call made");
216#if !HAS_THREAD_SANITIZER
217extern "C" EXPORTED_PUBLIC
int __cxa_guard_acquire(uint64_t* guard);
218extern "C" EXPORTED_PUBLIC
void __cxa_guard_release(uint64_t* guard);
219extern "C" EXPORTED_PUBLIC
void __cxa_guard_abort(uint64_t* guard);
221int __cxa_guard_acquire(uint64_t* guard) {
222 auto* bytes =
reinterpret_cast<uint8_t*
>(guard);
224 if (__atomic_load_n(bytes, __ATOMIC_ACQUIRE))
227 uint8_t expected = 0;
228 if (__atomic_compare_exchange_n(bytes + 1, &expected, uint8_t{1},
false, __ATOMIC_ACQUIRE,
232 if (__atomic_load_n(bytes, __ATOMIC_ACQUIRE)) {
233 __atomic_store_n(bytes + 1, uint8_t{0}, __ATOMIC_RELEASE);
253void __cxa_guard_release(uint64_t* guard) {
254 auto* bytes =
reinterpret_cast<uint8_t*
>(guard);
255 __atomic_store_n(bytes, uint8_t{1}, __ATOMIC_RELEASE);
256 __atomic_store_n(bytes + 1, uint8_t{0}, __ATOMIC_RELEASE);
259void __cxa_guard_abort(uint64_t* guard) {
260 auto* bytes =
reinterpret_cast<uint8_t*
>(guard);
261 __atomic_store_n(bytes + 1, uint8_t{0}, __ATOMIC_RELEASE);
265#ifndef HOSTED_SYSTEM_MALLOC
266#define HOSTED_SYSTEM_MALLOC 0
271#if HOSTED_SYSTEM_MALLOC
273#define INDIR_MALLOC hosted_malloc
274#define INDIR_CALLOC hosted_calloc
275#define INDIR_FREE hosted_free
276#define INDIR_REALLOC hosted_realloc
278#define INDIR_MALLOC _malloc
279#define INDIR_CALLOC _calloc
280#define INDIR_FREE _free
281#define INDIR_REALLOC _realloc
285#define INDIR_MALLOC malloc
286#define INDIR_CALLOC calloc
287#define INDIR_FREE free
288#define INDIR_REALLOC realloc
292#define PEDIGREE_ALLOCATOR_NOTHROW
294#define PEDIGREE_ALLOCATOR_NOTHROW C_NOTHROW
297extern "C" PEDIGREE_ALLOCATOR_NOTHROW
void* INDIR_MALLOC(
size_t sz) {
298 return reinterpret_cast<void*
>(
new uint8_t[sz]);
301extern "C" PEDIGREE_ALLOCATOR_NOTHROW
void* INDIR_CALLOC(
size_t num,
size_t sz) {
302 void* result =
reinterpret_cast<void*
>(
new uint8_t[num * sz]);
303 ByteSet(result, 0, num * sz);
307extern "C" PEDIGREE_ALLOCATOR_NOTHROW
void INDIR_FREE(
void* p) {
311 delete[]
reinterpret_cast<uint8_t*
>(p);
314extern "C" PEDIGREE_ALLOCATOR_NOTHROW
void* INDIR_REALLOC(
void* p,
size_t sz) {
316 return INDIR_MALLOC(sz);
323 size_t copySz = SlamAllocator::instance().allocSize(
reinterpret_cast<uintptr_t
>(p));
328 void* tmp = INDIR_MALLOC(sz);
329 MemoryCopy(tmp, p, copySz);
335#undef PEDIGREE_ALLOCATOR_NOTHROW
337EXPORTED_PUBLIC
void*
operator new(size_t,
void* memory)
noexcept {
340EXPORTED_PUBLIC
void*
operator new[](size_t,
void* memory)
noexcept {
343EXPORTED_PUBLIC
void operator delete(
void*,
void*)
noexcept {}
344EXPORTED_PUBLIC
void operator delete[](
void*,
void*)
noexcept {}
346#if !HOSTED_SYSTEM_MALLOC
348enum class align_val_t :
size_t {};
351void*
operator new(
size_t size) {
352 void* ret =
reinterpret_cast<void*
>(SlamAllocator::instance().
allocate(size));
355void*
operator new[](
size_t size) {
356 void* ret =
reinterpret_cast<void*
>(SlamAllocator::instance().
allocate(size));
359void*
operator new(
size_t size, std::align_val_t align) {
361 void* ret =
reinterpret_cast<void*
>(SlamAllocator::instance().
allocate(size));
364static void delete_shared(
void* p)
noexcept {
367 uintptr_t
mem =
reinterpret_cast<uintptr_t
>(p);
371 if (traceAllocations || SlamAllocator::instance().isPointerValid(
mem)) {
372 SlamAllocator::instance().free(
mem);
374 if (SlamAllocator::instance().isWithinHeap(
mem)) {
375 FATAL(
"delete_shared failed as pointer was invalid: " << p);
378 PEDANTRY(
"delete_shared failed as pointer was not in the kernel heap: " << p);
382void operator delete(
void* p)
noexcept {
385void operator delete[](
void* p)
noexcept {
388void operator delete(
void* p,
size_t sz)
noexcept {
391void operator delete(
void* p, std::align_val_t align)
noexcept {
394void operator delete(
void* p,
size_t sz, std::align_val_t align)
noexcept {
397void operator delete[](
void* p,
size_t sz)
noexcept {
402#if HOSTED && !HOSTED_SYSTEM_MALLOC
404void* __wrap_malloc(
size_t sz) {
405 return INDIR_MALLOC(sz);
408void* __wrap_realloc(
void* p,
size_t sz) {
409 return INDIR_REALLOC(p, sz);
412void __wrap_free(
void* p) {
413 return INDIR_FREE(p);
static ExecutionContext executionContext()
static size_t isInitialised()
static Scheduler & instance()
uintptr_t allocate(size_t nBytes)
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()