Skip to content

Commit bc2dbf9

Browse files
author
zhiayang
committed
fix syscalls and signals properly.
1. syscalls can now be preempted properly, and signals work with that as well without problems. 2. syscalls now happen on their own stack. we support 'nesting' them, only in the sense that you can get preempted while inside a syscall, then get signalled; to return from the signal requires doing a sigreturn syscall; in theory you can get preempted from that and get signalled again -- this should work now, barring any stack overflow. 3. don't map the kernel and syscall stacks as user-accessible. 4. add a syscall to get the nanosecond timestamp 5. check that gsbase != 0 before attempting to access the CPULocalState to prevent cascading faults in the unlikely event of swapgs failure 6. handle the 128-byte red zone (by subtracting 128 bytes from the user %rsp when calling the signal handler)
1 parent 3c91a06 commit bc2dbf9

File tree

29 files changed

+436
-149
lines changed

29 files changed

+436
-149
lines changed

Diff for: .gdbinit

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ file build/sysroot/boot/nxkernel64
22
target remote :1234
33
set pagination off
44
set confirm off
5+
display/i $pc

Diff for: drivers/placebo/source/placebo.cpp

+22-44
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@
1313

1414
void sig_handler(uint64_t sender, uint64_t type, uint64_t a, uint64_t b, uint64_t c)
1515
{
16-
printf("received signal!!!! (%lu, %lu, %lu, %lu, %lu)\n", sender, type, a, b, c);
16+
syscall::kernel_log(0, "lmao", 4, "OMG", 3); // (%lu, %lu, %lu, %lu, %lu)\n", sender, type, a, b, c);
17+
18+
uint32_t* fb = (uint32_t*) 0xFF'0000'0000;
19+
for(int y = 20; y < 40; y++)
20+
{
21+
for(int x = 1420; x < 1440; x++)
22+
{
23+
*(fb + y * 1440 + x) = 0xff'ffffff;
24+
}
25+
}
1726
}
1827

1928

@@ -32,61 +41,30 @@ extern "C" int main()
3241
0xff'0ab04a,
3342
};
3443

44+
int ctr2 = 0;
3545
constexpr size_t numColours = sizeof(colours) / sizeof(uint32_t);
3646

37-
int ctr2 = 0;
47+
// these are in nanoseconds.
48+
uint64_t last_update = 0;
49+
constexpr uint64_t update_time = 250'000'000;
50+
51+
3852
while(true)
3953
{
40-
if(ctr++ % 20000000 == 0)
54+
if(auto ts = syscall::nanosecond_timestamp(); last_update + update_time < ts)
4155
{
56+
last_update = ts;
57+
4258
ctr2++;
4359
uint32_t* fb = (uint32_t*) 0xFF'0000'0000;
44-
for(int y = 0; y < 300; y++)
60+
for(int y = 0; y < 20; y++)
4561
{
46-
for(int x = 0; x < 800; x++)
62+
for(int x = 1420; x < 1440; x++)
4763
{
48-
*(fb + y * 800 + x) = colours[ctr2 % 4];
49-
}
50-
}
51-
52-
{
53-
using namespace nx::ipc;
54-
{
55-
auto str = ".";
56-
57-
size_t len = sizeof(ttysvr::payload_t) + strlen(str) + 1;
58-
char buf[len];
59-
memset(buf, 0, len);
60-
61-
62-
auto ttypl = (ttysvr::payload_t*) buf;
63-
64-
ttypl->magic = ttysvr::MAGIC;
65-
ttypl->tty = 0;
66-
67-
ttypl->dataSize = strlen(str) + 1;
68-
memcpy(ttypl->data, str, strlen(str));
69-
70-
// send(1, buf, len);
64+
*(fb + y * 1440 + x) = colours[ctr2 % numColours];
7165
}
7266
}
7367
}
74-
75-
// if(ctr2 == 12)
76-
// {
77-
// uint32_t* fb = (uint32_t*) 0xFFFF'FFFF'0000'0000;
78-
// for(int y = 0; y < 300; y++)
79-
// {
80-
// for(int x = 0; x < 800; x++)
81-
// {
82-
// *(fb + y * 800 + x) = 0;
83-
// }
84-
// }
85-
86-
// // int ret;
87-
// // __nx_syscall_1(nx::SYSCALL_EXIT, ret, 103);
88-
// }
89-
9068
}
9169
}
9270

Diff for: kernel/include/cpu/scheduler.h

+38-13
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,32 @@ namespace nx
5555
uint64_t tssSelector = 0; // ofs: 0x18
5656

5757
addr_t cr3 = 0; // ofs: 0x20
58-
addr_t unused = 0; // ofs: 0x28
58+
addr_t syscallStack = 0; // ofs: 0x28
5959
CPU* cpu = 0; // ofs: 0x30
60+
addr_t tmpUserRsp = 0; // ofs: 0x38
61+
Thread* currentThread = 0; // ofs: 0x40
6062
};
6163

64+
// these need to be used from ASM, so we must make sure they never change!
65+
static_assert(offsetof(CPULocalState, self) == 0x00);
66+
static_assert(offsetof(CPULocalState, id) == 0x08);
67+
static_assert(offsetof(CPULocalState, lApicId) == 0x0C);
68+
static_assert(offsetof(CPULocalState, TSSBase) == 0x10);
69+
static_assert(offsetof(CPULocalState, tssSelector) == 0x18);
70+
static_assert(offsetof(CPULocalState, cr3) == 0x20);
71+
static_assert(offsetof(CPULocalState, syscallStack) == 0x28);
72+
static_assert(offsetof(CPULocalState, cpu) == 0x30);
73+
static_assert(offsetof(CPULocalState, tmpUserRsp) == 0x38);
74+
static_assert(offsetof(CPULocalState, currentThread)== 0x40);
75+
76+
6277
struct CPU
6378
{
64-
int id;
65-
int lApicId;
79+
int id = 0;
80+
int lApicId = 0;
6681

67-
bool isBootstrap;
68-
addr_t localApicAddr;
82+
bool isBootstrap = 0;
83+
addr_t localApicAddr = 0;
6984

7085
Process* currentProcess = 0;
7186

@@ -77,15 +92,15 @@ namespace nx
7792

7893
struct Process
7994
{
80-
pid_t processId;
95+
pid_t processId = 0;
8196
nx::string processName;
8297

83-
addr_t cr3;
98+
addr_t cr3 = 0;
8499
nx::array<Thread> threads;
85100

86-
int flags;
101+
int flags = 0;
87102

88-
addr_t tlsMasterCopy;
103+
addr_t tlsMasterCopy = 0;
89104
size_t tlsAlign = 0;
90105
size_t tlsSize = 0;
91106

@@ -126,12 +141,16 @@ namespace nx
126141

127142
struct Thread
128143
{
129-
pid_t threadId;
144+
pid_t threadId = 0; // ofs: 0x0
145+
addr_t syscallSavedUserStack = 0; // ofs: 0x8
130146

131-
addr_t userStackBottom;
147+
addr_t userStackBottom = 0;
132148

133-
addr_t kernelStackTop;
134-
addr_t kernelStackBottom;
149+
addr_t syscallStackTop = 0;
150+
addr_t syscallStackBottom = 0;
151+
152+
addr_t kernelStackTop = 0;
153+
addr_t kernelStackBottom = 0;
135154

136155
Process* parent = 0;
137156

@@ -151,6 +170,10 @@ namespace nx
151170
bool pendingSignalRestore = false;
152171
};
153172

173+
// these need to be used from ASM, so we must make sure they never change!
174+
static_assert(offsetof(Thread, threadId) == 0x00);
175+
static_assert(offsetof(Thread, syscallSavedUserStack) == 0x08);
176+
154177

155178
void setupKernelProcess(addr_t cr3);
156179

@@ -221,6 +244,8 @@ namespace nx
221244

222245
// returns t.
223246
Thread* addThread(Thread* t);
247+
Thread* pauseThread(Thread* t);
248+
Thread* resumeThread(Thread* t);
224249

225250
void destroyThread(Thread* t);
226251
void destroyProcess(Process* p);

Diff for: kernel/include/export/syscall_funcs.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace nx
2626
constexpr uint64_t SYSCALL_VFS_WRITE = 21;
2727

2828

29+
constexpr uint64_t SYSCALL_GET_NANOSECOND_TS = 97;
2930
constexpr uint64_t SYSCALL_USER_SIGNAL_LEAVE = 98;
3031
constexpr uint64_t SYSCALL_LOG = 99;
3132

Diff for: kernel/include/misc/syscall.h

+2
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@ namespace nx
3838
void sc_user_signal_leave();
3939

4040
void sc_log(int level, char* sys, size_t syslen, char* buf, size_t buflen);
41+
42+
uint64_t sc_nanosecond_timestamp();
4143
}
4244
}

Diff for: kernel/makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ CXXOBJ = $(CXXSRC:.cpp=.cpp.o)
2727
CXXDEPS = $(CXXOBJ:.o=.d)
2828
CDEPS = $(COBJ:.o=.d)
2929

30-
DEBUG_FLAG := -O0 -g
30+
DEBUG_FLAG := -O3
3131
LDFLAGS := -z max-page-size=0x1000 -L$(SYSROOT)/usr/lib -nostdlib
3232

3333
DEFINES = -DORION_KERNEL=1 -D__ARCH_x64__=1

Diff for: kernel/source/arch/x86_64/descriptors/gdt.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ namespace gdt
122122
addDescriptor(makeGDTEntry(0, 0, 0, 0)); // 0x18: stupid null descriptor
123123

124124
addDescriptor(makeGDTEntry(0, 0xFFFFFFFF, false, 3)); // 0x20: ring 3 data segment
125-
addDescriptor(makeGDTEntry(0, 0xFFFFFFFF, true, 3)); // 0x18: ring 3 code segment
125+
addDescriptor(makeGDTEntry(0, 0xFFFFFFFF, true, 3)); // 0x28: ring 3 code segment
126126
}
127127

128128

Diff for: kernel/source/arch/x86_64/descriptors/tss.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ namespace tss
122122

123123
uint8_t* iopb = (uint8_t*) (tssBase + sizeof(tss_t));
124124
for(auto it = ports.begin(); it != ports.end(); it++)
125-
iopb[it->key] = it->value;
125+
{
126+
// below, we reversed the convention -- bit set=allowed, bit clear=not allowed
127+
// so when setting the actual iopb for the CPU, just NOT it.
128+
iopb[it->key] = ~it->value;
129+
}
126130
}
127131
}
128132

@@ -132,8 +136,10 @@ namespace tss
132136
size_t ofs = port % 8;
133137
uint8_t bit = (1UL << ofs);
134138

135-
if(allowed) (*iopb)[byte] &= ~bit;
136-
else (*iopb)[byte] |= bit;
139+
// ok, here's the thing: the default values of these idiots are 0, ie. all allowed!!
140+
// so, in OUR TREEMAP, a set bit means allowed, and a clear bit means NOT ALLOWED.
141+
if(allowed) (*iopb)[byte] |= bit;
142+
else (*iopb)[byte] &= ~bit;
137143
}
138144

139145

Diff for: kernel/source/arch/x86_64/exceptions/exceptions.cpp

+11-5
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ namespace exceptions
161161
while(1);
162162
}
163163

164-
uint64_t cr2;
165-
uint64_t cr3;
164+
uint64_t cr2 = 0;
165+
uint64_t cr3 = 0;
166+
auto gsbase = cpu::readMSR(cpu::MSR_GS_BASE);
166167

167168
asm volatile("mov %%cr2, %0" : "=r" (cr2));
168169
asm volatile("mov %%cr3, %0" : "=r" (cr3));
@@ -174,11 +175,16 @@ namespace exceptions
174175
debugprintf("cpu exception %d: %s\n", regs->InterruptID, ExceptionMessages[regs->InterruptID]);
175176
debugprintf("error code: %d\n", regs->ErrorCode);
176177

177-
if(__likely(scheduler::getInitPhase() >= scheduler::SchedulerInitPhase::SchedulerStarted))
178+
// note: we must check gs, in case it was some kind of swapgs failure -- we don't want to end up triple-faulting.
179+
if(gsbase != 0 && scheduler::getInitPhase() >= scheduler::SchedulerInitPhase::SchedulerStarted)
178180
{
179181
debugprintf("pid: %lu / tid: %lu\n", scheduler::getCurrentProcess()->processId,
180182
scheduler::getCurrentThread()->threadId);
181183
}
184+
else
185+
{
186+
debugprintf("pre-scheduler");
187+
}
182188

183189
if(regs->InterruptID == 13 && regs->ErrorCode != 0)
184190
{
@@ -226,7 +232,7 @@ namespace exceptions
226232

227233

228234
// if this was a user program, then fuck that guy.
229-
if(scheduler::getCurrentProcess() != scheduler::getKernelProcess())
235+
if(gsbase != 0 && scheduler::getCurrentProcess() != scheduler::getKernelProcess())
230236
{
231237
auto thr = scheduler::getCurrentThread();
232238
warn("kernel", "killing thread %lu (from process %lu) due to exception", thr->threadId, thr->parent->processId);
@@ -241,7 +247,7 @@ namespace exceptions
241247
if(faultCount == 1)
242248
util::printStackTrace(regs->rbp);
243249

244-
debugprintf("\n!! error: unrecoverable cpu exception !!");
250+
debugprintf("\n!! error: unrecoverable cpu exception !!\n");
245251
}
246252

247253
while(1);

Diff for: kernel/source/arch/x86_64/include/macros.s

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525

2626

27-
2827
.macro push_all_regs
2928
push %r15
3029
push %r14

0 commit comments

Comments
 (0)