aboutsummaryrefslogtreecommitdiff
path: root/lib/mlibc/sysdeps/managarm/generic/entry.cpp
blob: 3ff28d2cb3d85bb9e796f68c152899b961f3ebe4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <pthread.h>
#include <stdlib.h>
#include <sys/auxv.h>

#include <frg/eternal.hpp>

#include <bits/ensure.h>
#include <mlibc/allocator.hpp>
#include <mlibc/debug.hpp>
#include <mlibc/posix-pipe.hpp>
#include <mlibc/all-sysdeps.hpp>
#include <mlibc/elf/startup.h>

#include <protocols/posix/data.hpp>
#include <protocols/posix/supercalls.hpp>

// defined by the POSIX library
void __mlibc_initLocale();

extern "C" uintptr_t *__dlapi_entrystack();
extern "C" void __dlapi_enter(uintptr_t *);

// declared in posix-pipe.hpp
thread_local Queue globalQueue;

// TODO: clock tracker page and file table don't need to be thread-local!
thread_local HelHandle __mlibc_posix_lane;
thread_local void *__mlibc_clk_tracker_page;

namespace {
	thread_local unsigned __mlibc_gsf_nesting;
	thread_local void *__mlibc_cached_thread_page;
	thread_local HelHandle *cachedFileTable;

	// This construction is a bit weird: Even though the variables above
	// are thread_local we still protect their initialization with a pthread_once_t
	// (instead of using a C++ constructor).
	// We do this in order to able to clear the pthread_once_t after a fork.
	thread_local pthread_once_t has_cached_infos = PTHREAD_ONCE_INIT;

	void actuallyCacheInfos() {
		posix::ManagarmProcessData data;
		HEL_CHECK(helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast<HelWord>(&data)));

		__mlibc_posix_lane = data.posixLane;
		__mlibc_cached_thread_page = data.threadPage;
		cachedFileTable = data.fileTable;
		__mlibc_clk_tracker_page = data.clockTrackerPage;
	}
}

SignalGuard::SignalGuard() {
	pthread_once(&has_cached_infos, &actuallyCacheInfos);
	if(!__mlibc_cached_thread_page)
		return;
	auto p = reinterpret_cast<unsigned int *>(__mlibc_cached_thread_page);
	if(!__mlibc_gsf_nesting)
		__atomic_store_n(p, 1, __ATOMIC_RELAXED);
	__mlibc_gsf_nesting++;
}

SignalGuard::~SignalGuard() {
	pthread_once(&has_cached_infos, &actuallyCacheInfos);
	if(!__mlibc_cached_thread_page)
		return;
	auto p = reinterpret_cast<unsigned int *>(__mlibc_cached_thread_page);
	__ensure(__mlibc_gsf_nesting > 0);
	__mlibc_gsf_nesting--;
	if(!__mlibc_gsf_nesting) {
		unsigned int result = __atomic_exchange_n(p, 0, __ATOMIC_RELAXED);
		if(result == 2) {
			HEL_CHECK(helSyscall0(kHelCallSuper + posix::superSigRaise));
		}else{
			__ensure(result == 1);
		}
	}
}

MemoryAllocator &getSysdepsAllocator() {
	// use frg::eternal to prevent a call to __cxa_atexit().
	// this is necessary because __cxa_atexit() call this function.
	static frg::eternal<VirtualAllocator> virtualAllocator;
	static frg::eternal<MemoryPool> heap{virtualAllocator.get()};
	static frg::eternal<MemoryAllocator> singleton{&heap.get()};
	return singleton.get();
}

HelHandle getPosixLane() {
	cacheFileTable();
	return __mlibc_posix_lane;
}

HelHandle *cacheFileTable() {
	// TODO: Make sure that this is signal-safe (it is called e.g. by sys_clock_get()).
	pthread_once(&has_cached_infos, &actuallyCacheInfos);
	return cachedFileTable;
}

HelHandle getHandleForFd(int fd) {
	if (fd >= 512)
		return 0;

	return cacheFileTable()[fd];
}

void clearCachedInfos() {
	has_cached_infos = PTHREAD_ONCE_INIT;
}

struct LibraryGuard {
	LibraryGuard();
};

static LibraryGuard guard;

extern char **environ;
static mlibc::exec_stack_data __mlibc_stack_data;

LibraryGuard::LibraryGuard() {
	__mlibc_initLocale();

	// Parse the exec() stack.
	mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data);
	mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv,
			__mlibc_stack_data.envp);
}

extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) {
	__dlapi_enter(entry_stack);
	auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ);
	exit(result);
}