2024-06-21 03:46:42 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
│ Copyright 2024 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
|
|
│ │
|
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
#include "libc/intrin/maps.h"
|
|
|
|
#include "ape/sections.internal.h"
|
2024-07-26 07:44:45 +00:00
|
|
|
#include "libc/calls/state.internal.h"
|
2024-12-17 04:51:27 +00:00
|
|
|
#include "libc/cosmo.h"
|
2024-06-21 03:46:42 +00:00
|
|
|
#include "libc/dce.h"
|
2024-07-26 07:44:45 +00:00
|
|
|
#include "libc/intrin/describebacktrace.h"
|
2024-06-21 03:46:42 +00:00
|
|
|
#include "libc/intrin/dll.h"
|
2024-07-26 07:44:45 +00:00
|
|
|
#include "libc/intrin/kprintf.h"
|
2024-07-06 06:13:20 +00:00
|
|
|
#include "libc/intrin/maps.h"
|
2024-12-17 04:51:27 +00:00
|
|
|
#include "libc/nexgen32e/rdtsc.h"
|
2024-06-21 03:46:42 +00:00
|
|
|
#include "libc/runtime/runtime.h"
|
|
|
|
#include "libc/runtime/stack.h"
|
|
|
|
#include "libc/sysv/consts/prot.h"
|
2024-07-26 07:44:45 +00:00
|
|
|
#include "libc/thread/lock.h"
|
2024-06-21 03:46:42 +00:00
|
|
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
__static_yoink("_init_maps");
|
|
|
|
#endif
|
|
|
|
|
2024-12-17 04:51:27 +00:00
|
|
|
#define ABI privileged optimizespeed
|
|
|
|
|
|
|
|
// take great care if you enable this
|
|
|
|
// especially if you're using --ftrace too
|
|
|
|
#define DEBUG_MAPS_LOCK 0
|
|
|
|
|
2024-06-21 03:46:42 +00:00
|
|
|
struct Maps __maps;
|
|
|
|
|
2024-07-04 09:50:20 +00:00
|
|
|
void __maps_add(struct Map *map) {
|
2024-07-06 06:13:20 +00:00
|
|
|
tree_insert(&__maps.maps, &map->tree, __maps_compare);
|
2024-07-04 09:50:20 +00:00
|
|
|
++__maps.count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __maps_adder(struct Map *map, int pagesz) {
|
|
|
|
__maps.pages += ((map->size + pagesz - 1) & -pagesz) / pagesz;
|
|
|
|
__maps_add(map);
|
|
|
|
}
|
|
|
|
|
2024-07-04 17:52:16 +00:00
|
|
|
void __maps_stack(char *stackaddr, int pagesz, int guardsize, size_t stacksize,
|
|
|
|
int stackprot, intptr_t stackhand) {
|
|
|
|
__maps.stack.addr = stackaddr + guardsize;
|
|
|
|
__maps.stack.size = stacksize - guardsize;
|
2024-07-04 09:50:20 +00:00
|
|
|
__maps.stack.prot = stackprot;
|
2024-07-04 17:52:16 +00:00
|
|
|
__maps.stack.hand = -1;
|
2024-07-04 09:50:20 +00:00
|
|
|
__maps_adder(&__maps.stack, pagesz);
|
2024-07-04 17:52:16 +00:00
|
|
|
if (guardsize) {
|
|
|
|
__maps.guard.addr = stackaddr;
|
|
|
|
__maps.guard.size = guardsize;
|
|
|
|
__maps.guard.prot = PROT_NONE;
|
|
|
|
__maps.guard.hand = stackhand;
|
|
|
|
__maps_adder(&__maps.guard, pagesz);
|
|
|
|
}
|
2024-07-04 09:50:20 +00:00
|
|
|
}
|
|
|
|
|
2024-06-21 03:46:42 +00:00
|
|
|
void __maps_init(void) {
|
2024-07-19 04:02:59 +00:00
|
|
|
int pagesz = __pagesize;
|
2024-06-21 03:46:42 +00:00
|
|
|
|
2024-12-17 04:51:27 +00:00
|
|
|
// initialize lemur64 rng
|
|
|
|
__maps.rand = 2131259787901769494;
|
|
|
|
__maps.rand ^= rdtsc();
|
|
|
|
|
2024-06-21 03:46:42 +00:00
|
|
|
// record _start() stack mapping
|
|
|
|
if (!IsWindows()) {
|
|
|
|
struct AddrSize stack;
|
|
|
|
stack = __get_main_stack();
|
2024-07-04 17:52:16 +00:00
|
|
|
__maps_stack(stack.addr, pagesz, 0, stack.size, (uintptr_t)ape_stack_prot,
|
|
|
|
0);
|
2024-06-21 03:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// record .text and .data mappings
|
|
|
|
static struct Map text, data;
|
|
|
|
text.addr = (char *)__executable_start;
|
|
|
|
text.size = _etext - __executable_start;
|
|
|
|
text.prot = PROT_READ | PROT_EXEC;
|
|
|
|
uintptr_t ds = ((uintptr_t)_etext + pagesz - 1) & -pagesz;
|
|
|
|
if (ds < (uintptr_t)_end) {
|
|
|
|
data.addr = (char *)ds;
|
|
|
|
data.size = (uintptr_t)_end - ds;
|
|
|
|
data.prot = PROT_READ | PROT_WRITE;
|
2024-07-04 09:50:20 +00:00
|
|
|
__maps_adder(&data, pagesz);
|
2024-06-21 03:46:42 +00:00
|
|
|
}
|
2024-07-04 09:50:20 +00:00
|
|
|
__maps_adder(&text, pagesz);
|
2024-06-21 03:46:42 +00:00
|
|
|
}
|
|
|
|
|
2024-12-17 04:51:27 +00:00
|
|
|
#if DEBUG_MAPS_LOCK
|
|
|
|
privileged static void __maps_panic(const char *msg) {
|
|
|
|
// it's only safe to pass a format string. if we use directives such
|
|
|
|
// as %s, %t etc. then kprintf() will recursively call __maps_lock()
|
|
|
|
kprintf(msg);
|
|
|
|
DebugBreak();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ABI bool __maps_lock(void) {
|
2024-07-26 07:44:45 +00:00
|
|
|
int me;
|
|
|
|
uint64_t word, lock;
|
2024-06-21 03:46:42 +00:00
|
|
|
struct CosmoTib *tib;
|
2024-07-26 05:12:08 +00:00
|
|
|
if (!__tls_enabled)
|
2024-07-04 17:52:16 +00:00
|
|
|
return false;
|
2024-07-26 07:44:45 +00:00
|
|
|
if (!(tib = __get_tls_privileged()))
|
|
|
|
return false;
|
|
|
|
if (tib->tib_flags & TIB_FLAG_VFORKED)
|
|
|
|
return false;
|
|
|
|
me = atomic_load_explicit(&tib->tib_tid, memory_order_acquire);
|
|
|
|
if (me <= 0)
|
|
|
|
return false;
|
2024-12-17 04:51:27 +00:00
|
|
|
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
|
2024-07-26 07:44:45 +00:00
|
|
|
for (;;) {
|
|
|
|
if (MUTEX_OWNER(word) == me) {
|
|
|
|
if (atomic_compare_exchange_weak_explicit(
|
2024-12-17 04:51:27 +00:00
|
|
|
&__maps.lock.word, &word, MUTEX_INC_DEPTH(word),
|
|
|
|
memory_order_relaxed, memory_order_relaxed))
|
2024-07-26 07:44:45 +00:00
|
|
|
return true;
|
|
|
|
continue;
|
|
|
|
}
|
2024-12-17 04:51:27 +00:00
|
|
|
#if DEBUG_MAPS_LOCK
|
|
|
|
if (__deadlock_tracked(&__maps.lock) == 1)
|
|
|
|
__maps_panic("error: maps lock already held\n");
|
|
|
|
if (__deadlock_check(&__maps.lock, 1))
|
|
|
|
__maps_panic("error: maps lock is cyclic\n");
|
|
|
|
#endif
|
2024-07-26 07:44:45 +00:00
|
|
|
word = 0;
|
|
|
|
lock = MUTEX_LOCK(word);
|
|
|
|
lock = MUTEX_SET_OWNER(lock, me);
|
2024-12-17 04:51:27 +00:00
|
|
|
if (atomic_compare_exchange_weak_explicit(&__maps.lock.word, &word, lock,
|
2024-07-26 07:44:45 +00:00
|
|
|
memory_order_acquire,
|
2024-12-17 04:51:27 +00:00
|
|
|
memory_order_relaxed)) {
|
|
|
|
#if DEBUG_MAPS_LOCK
|
|
|
|
__deadlock_track(&__maps.lock, 0);
|
|
|
|
__deadlock_record(&__maps.lock, 0);
|
|
|
|
#endif
|
2024-07-26 07:44:45 +00:00
|
|
|
return false;
|
2024-12-17 04:51:27 +00:00
|
|
|
}
|
2024-07-26 07:44:45 +00:00
|
|
|
for (;;) {
|
2024-12-17 04:51:27 +00:00
|
|
|
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
|
2024-07-26 07:44:45 +00:00
|
|
|
if (MUTEX_OWNER(word) == me)
|
|
|
|
break;
|
|
|
|
if (!word)
|
|
|
|
break;
|
2024-07-26 05:24:32 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-21 03:46:42 +00:00
|
|
|
}
|
|
|
|
|
2024-12-17 04:51:27 +00:00
|
|
|
ABI void __maps_unlock(void) {
|
2024-07-26 07:44:45 +00:00
|
|
|
int me;
|
|
|
|
uint64_t word;
|
2024-06-21 03:46:42 +00:00
|
|
|
struct CosmoTib *tib;
|
2024-06-29 12:10:15 +00:00
|
|
|
if (!__tls_enabled)
|
|
|
|
return;
|
2024-07-26 07:44:45 +00:00
|
|
|
if (!(tib = __get_tls_privileged()))
|
|
|
|
return;
|
|
|
|
if (tib->tib_flags & TIB_FLAG_VFORKED)
|
|
|
|
return;
|
|
|
|
me = atomic_load_explicit(&tib->tib_tid, memory_order_acquire);
|
|
|
|
if (me <= 0)
|
|
|
|
return;
|
2024-12-17 04:51:27 +00:00
|
|
|
word = atomic_load_explicit(&__maps.lock.word, memory_order_relaxed);
|
|
|
|
#if DEBUG_MAPS_LOCK
|
|
|
|
if (__deadlock_tracked(&__maps.lock) == 0)
|
|
|
|
__maps_panic("error: maps lock not owned by caller\n");
|
|
|
|
#endif
|
2024-07-26 07:44:45 +00:00
|
|
|
for (;;) {
|
|
|
|
if (MUTEX_DEPTH(word)) {
|
|
|
|
if (atomic_compare_exchange_weak_explicit(
|
2024-12-17 04:51:27 +00:00
|
|
|
&__maps.lock.word, &word, MUTEX_DEC_DEPTH(word),
|
|
|
|
memory_order_relaxed, memory_order_relaxed))
|
2024-07-26 07:44:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2024-12-17 04:51:27 +00:00
|
|
|
if (atomic_compare_exchange_weak_explicit(&__maps.lock.word, &word, 0,
|
|
|
|
memory_order_release,
|
|
|
|
memory_order_relaxed)) {
|
|
|
|
#if DEBUG_MAPS_LOCK
|
|
|
|
__deadlock_untrack(&__maps.lock);
|
|
|
|
#endif
|
2024-07-26 07:44:45 +00:00
|
|
|
break;
|
2024-12-17 04:51:27 +00:00
|
|
|
}
|
2024-07-26 07:44:45 +00:00
|
|
|
}
|
2024-06-21 03:46:42 +00:00
|
|
|
}
|