Skip to content

Commit

Permalink
#27 process manager switches to user mode and directly into code on u…
Browse files Browse the repository at this point in the history
…ser heap/stack as preparation to hide kernel space memory in user mode
  • Loading branch information
mwoerlein committed Nov 8, 2023
1 parent 9bfd4ba commit e08aca1
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 92 deletions.
27 changes: 0 additions & 27 deletions src/gridos/i386/GlobalDescriptorTable.pool
Original file line number Diff line number Diff line change
Expand Up @@ -137,31 +137,4 @@ class GlobalDescriptorTable extends sys::core::Object {
entry.esp0 = topOfStack;
return this;
}

[] toUserMode() {
__pasm__(<"
cli
// ensure user segment in all segment registers
movw 0x23, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
// %cs and %ss are set by iret

// setup iret stack frame
movl %esp, %eax
pushl 0x23 // data selector (with bottom 2 bits set for ring 3)
pushl %eax // current esp
pushfl // eflags
orl 0x200, (%esp) // set FI-Flag to enable interrupts with iret
pushl 0x1B // code selector (with bottom 2 bits set for ring 3)
movl 8(%ebp), %eax
addl (_gdt_to_user_mode - _gridos_i386_GlobalDescriptorTable), %eax
pushl %eax // instruction address to return to
iret

_gdt_to_user_mode:
">, {}, {"%eax": null});
}
}
15 changes: 2 additions & 13 deletions src/gridos/i386/Startup.pool
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class Startup extends Runtime, RuntimeBuilder {
Scheduler scheduler = this.createInstance(Scheduler:CLASSNAME);
this.setScheduler(scheduler.setMMU(mmu));
ProcessManager pm = this.createInstance(ProcessManager:CLASSNAME);
this.setProcessManager(pm.init(scheduler, mmu, gdt));
this.setProcessManager(pm.init(scheduler, mmu));

/* activate keyboard and interrupts */
PIC pic = this.createInstance(PIC:CLASSNAME);
Expand All @@ -246,17 +246,6 @@ class Startup extends Runtime, RuntimeBuilder {
gdt.activate().activateTSS(0);
ivt.activate();

/*
{
sys::memory::MemoryInfo ks = getAllocator().allocate(0x1000);
out.printChar('?').printNewline();
gdt.setKernelStack(0, ks.buf+0xF00);
gdt.toUserMode();
out.printChar('!').printNewline();
while (1) { __pasm__("hlt"); } // sollte in einen GP(0) laufen
}
//*/

/* activate runtime clock */
TickClock clock := this.createInstance(TickClock:CLASSNAME);
pit.registerHandler(clock.handler());
Expand Down Expand Up @@ -298,7 +287,7 @@ class Startup extends Runtime, RuntimeBuilder {
sys::core::String taskClassname = modules.getCModule("startup").getCStringProperty("meta.runTask");
if (taskClassname) {
pm.createProcess(
taskClassname.toCString(),
taskClassname,
vs2.createOStream(FOStream:BLACK, FOStream:WHITE),
vs2.createOStream(FOStream:BRIGHT_RED, FOStream:WHITE)
);
Expand Down
20 changes: 16 additions & 4 deletions src/gridos/i386/memory/MMU.pool
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,6 @@ class MMU extends Object {
return Bitset:and(ptEntry, 0xfffff000);
}

[int] allocateStackPagesAt(int virtualAddress, int count) {
return this.allocatePagesAt(virtualAddress - count * PageAllocator:PAGESIZE, count);
}

[int] allocatePagesAt(int virtualAddress, int count) {
int pages = count;
int allocated = 0;
Expand All @@ -167,6 +163,22 @@ class MMU extends Object {
// TODO: handle page info list
}

[int] allocateStackPagesAt(int virtualAddress, int count) {
return this.allocatePagesAt(virtualAddress - count * PageAllocator:PAGESIZE, count);
}

[StackBuilder] allocateStackBuilderAt(int virtualAddress, int count) {
int vAddr = virtualAddress - count * PageAllocator:PAGESIZE;
int allocated = this.allocatePagesAt(vAddr, count);
if (allocated != count) {
if (allocated > 0) { this.freePagesAt(vAddr, allocated); }
return null;
}
StackBuilder sb = this.rt().createInstance(StackBuilder:CLASSNAME);
sb.init(vAddr, count, 0);
return sb;
}

[] freePagesAt(int virtualAddress, int count) {
// TODO: mark pages as free and merge into free page info list
int pages = count;
Expand Down
106 changes: 61 additions & 45 deletions src/gridos/i386/process/ProcessManager.pool
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ version = 0.1.0
*/
namespace gridos::i386::process;

use gridos::i386::GlobalDescriptorTable;

use gridos::i386::memory::MMU;
use gridos::i386::memory::MMUPageAllocator;
use gridos::i386::memory::StackBuilder;
Expand All @@ -15,9 +13,11 @@ use gridos::i386::sys::OutStream;
use gridos::i386::sys::ErrStream;
use gridos::i386::sys::Clock;
use gridos::i386::sys::PageAllocator;
use gridos::i386::sys::Thread as UserThread;

use gridos::module::Module;

use sys::core::String;
use sys::memory::PagedMemoryManager;
use sys::runtime::ClassStorage;
use sys::runtime::DynamicClassStorage;
Expand All @@ -28,14 +28,12 @@ class ProcessManager extends sys::core::Object {

MMU mmu;
Scheduler scheduler;
GlobalDescriptorTable gdt;

Process first;
Process last;
int pidCounter;

[ProcessManager] init(Scheduler scheduler, MMU mmu, GlobalDescriptorTable gdt) {
this.gdt = gdt;
[ProcessManager] init(Scheduler scheduler, MMU mmu) {
this.scheduler = scheduler;
this.mmu = mmu;
// setup initial kernel process/thread
Expand All @@ -44,16 +42,16 @@ class ProcessManager extends sys::core::Object {
Thread thread = process.createOwn(Thread:CLASSNAME);
thread._initStart(process);
process._initFinish(rt, rt, null);
thread._initFinish();
thread._initFinish("ignore");
scheduler.setInitialThread(thread);
return this;
}

[Process] createProcess(cstring taskClassname, OStream out, OStream err) {
[Process] createProcess(String taskClassname, OStream out, OStream err) {
[int pageDirectoryPAddr, StackBuilder sb] = mmu.newThreadPageDirectoryAndKernelStack(MMU:AFTER_KERNEL_LOCAL_STACKS);

Process process := this._newProcess(pageDirectoryPAddr);
Thread thread := this.setupNewProcess(process, sb, null, out, err, taskClassname);
Thread thread := this.setupNewProcess(process, sb, null, out, err, taskClassname.toCString());

scheduler.addReadyThread(thread);
sb.unmap(mmu);
Expand All @@ -62,7 +60,7 @@ class ProcessManager extends sys::core::Object {
}

[Process] createProcessFromModule(Module module, OStream out, OStream err) {
sys::core::String taskClassname = module.getCStringProperty("meta.runTask");
String taskClassname = module.getCStringProperty("meta.runTask");
if (!taskClassname) { return null; }

[int pageDirectoryPAddr, StackBuilder sb] = mmu.newThreadPageDirectoryAndKernelStack(MMU:AFTER_KERNEL_LOCAL_STACKS);
Expand All @@ -88,18 +86,18 @@ class ProcessManager extends sys::core::Object {
return p._initStart(++pidCounter, pageDirectoryPAddr);
}

[Thread] setupNewProcess(Process process, StackBuilder sb, Module module, OStream out, OStream err, cstring taskClassname) {
[Thread] setupNewProcess(Process process, StackBuilder sb, Module module, OStream out, OStream err, cstring tcn) {
Thread thread = process.createOwn(Thread:CLASSNAME);
thread._initStart(process);

{ // fake stack frame for __setupProcess
int basePtr = sb.getTopOfStack();
sb.pushString(taskClassname); // task name
sb.pushPtr(thread); // thread
sb.pushPtr(err); // err
sb.pushPtr(out); // out
sb.pushPtr(module); // module
sb.pushPtr(process); // process
sb.pushString(tcn); // task classname
sb.pushPtr(thread); // thread
sb.pushPtr(err); // err
sb.pushPtr(out); // out
sb.pushPtr(module); // module
sb.pushPtr(process); // process
sb.buildMethodCallEntry(this, this.getClass(), 0, basePtr);
}
scheduler.setupStackFrameForSwitchTo(sb, this.__getSetupProcessEntry(), thread);
Expand All @@ -108,11 +106,11 @@ class ProcessManager extends sys::core::Object {
return thread;
}

[Thread] setupNewThread(Thread thread, StackBuilder sb, cstring taskClassname) {
[Thread] setupNewThread(Thread thread, StackBuilder sb, cstring tcn) {
{ // fake stack frame for __setupThread
int basePtr = sb.getTopOfStack();
sb.pushString(taskClassname); // second argument
sb.pushPtr(thread); // first argument
sb.pushString(tcn); // task classname
sb.pushPtr(thread); // thread
sb.buildMethodCallEntry(this, this.getClass(), 0, basePtr);
}
scheduler.setupStackFrameForSwitchTo(sb, this.__getSetupThreadEntry(), thread);
Expand All @@ -127,10 +125,10 @@ class ProcessManager extends sys::core::Object {
return entry;
}

[] __setupProcess(Process process, Module module, OStream out, OStream err, Thread thread, cstring taskClassname) {
[] __setupProcess(Process process, Module module, OStream out, OStream err, Thread thread, cstring tcn) {
__pasm__("_cr_mo_setup_process_entry := (_setup_process_entry - _gridos_i386_process_ProcessManager); _setup_process_entry:");
this._setupProcess(process, module, out, err);
this._setupThread(thread, taskClassname);
this._setupThread(thread, tcn);
}

[int] __getSetupThreadEntry() {
Expand All @@ -139,12 +137,12 @@ class ProcessManager extends sys::core::Object {
return entry;
}

[] __setupThread(Thread thread, cstring taskClassname) {
[] __setupThread(Thread thread, cstring tcn) {
__pasm__(<"
_cr_mo_setup_thread_entry := (_setup_thread_entry - _gridos_i386_process_ProcessManager)
_setup_thread_entry:
">);
this._setupThread(thread, taskClassname);
this._setupThread(thread, tcn);
}

[] _setupProcess(Process process, Module module, OStream out, OStream err) {
Expand Down Expand Up @@ -246,37 +244,55 @@ class ProcessManager extends sys::core::Object {
process._initFinish(kernelRt, userRt, userMPA.pageAllocator());
}

[] _setupThread(Thread thread, cstring taskClassname) {
[] _setupThread(Thread thread, cstring tcn) {
this.rt().err()
.printCString("setup new thread in process ").printInt(thread.getPid())
.printCString(" for class '").printCString(taskClassname).printChar('\'')
//.printCString(" via ").print(this)
.printCString(" for task '").printCString(tcn).printChar('\'')
.printNewline();

thread._initFinish();
thread._initFinish(tcn);

UserThread userThread = thread.getUserThread();
int topOfUserStack = 0;
{
// prepare user thread stack
int userTopOfStack = MMU:AFTER_USER_STACKS; // TODO #30: determine correct stack
mmu.allocateStackPagesAt(userTopOfStack, 1);
// switch to user thread stack and store kernel thread stack for syscall entries
__pasm__("movl %eax, %esp", {"%eax": userTopOfStack});
// switch to user mode
gdt.toUserMode();
}
{
// create and run task in userland
Runtime userRt := thread.getKernelProcess().getUserRuntime();
userRt.createAndRunTask(taskClassname);
StackBuilder sb = mmu.allocateStackBuilderAt(MMU:AFTER_USER_STACKS, 1); // TODO #30: determine correct stack

// there is no way back to kernel mode => never return!
// TODO: cleanup/exit process/thread if task returns
//scheduler.terminateThread(thread);
while (1) {
userRt.yield();
userRt.sleep(5,0); // wait some time
}
// fake stack frame for __setupThread
int basePtr = sb.getTopOfStack();

sb.buildMethodCallEntry(userThread, userThread.getClass(), 0, basePtr);
topOfUserStack = sb.getTopOfStack();
sb.destroy();
}

// switch to user mode and jump to user entry method and user stack
__pasm__(
<"
cli
// ensure user segment in all segment registers
movw 0x23, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
// %cs and %ss are set by iret

// setup iret stack frame
pushl 0x23 // data selector (with bottom 2 bits set for ring 3)
pushl %ecx // current esp
pushfl // eflags
orl 0x200, (%esp) // set FI-Flag to re-enable interrupts with iret
pushl 0x1B // code selector (with bottom 2 bits set for ring 3)
pushl %ebx // instruction address to return to

// setup base pointer
movl %ecx, %ebp
iret
">,
{"%ebx": userThread._getUserEntry(), "%ecx": topOfUserStack },
{"%eax": null }
);
}

}
4 changes: 2 additions & 2 deletions src/gridos/i386/process/Thread.pool
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ class Thread extends sys::core::Object {
return this;
}

[Thread] _initFinish() {
[Thread] _initFinish(cstring taskClassname) {
sys::runtime::Runtime urt = this.process.getUserRuntime();
this.cpuTS = this.own(urt.createInstance(Timestamp:CLASSNAME));
this.cpuTS.setTime(0, 0);
this.userThread = this.own(urt.createInstance(UserThread:CLASSNAME));
this.userThread._initThread(this.process.getUserProcess(), this.cpuTS);
this.userThread._initThread(this.process.getUserProcess(), this.cpuTS, taskClassname);
return this;
}

Expand Down
32 changes: 31 additions & 1 deletion src/gridos/i386/sys/Thread.pool
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ version = 0.1.0
*/
namespace gridos::i386::sys;

use sys::core::String;
use sys::runtime::Process as SysProcess;
use sys::runtime::Thread as SysThread;
use sys::time::Timestamp;
Expand All @@ -13,10 +14,14 @@ class Thread extends SysThread {

Process process;
Timestamp cpuTS;
String taskClassname;

[Thread] _initThread(Process process, Timestamp cpuTS) {
[Thread] _initThread(Process process, Timestamp cpuTS, cstring tcn) {
this.process = process;
this.cpuTS = cpuTS;
// copy class name into user heap
this.taskClassname = this.createOwn(String:CLASSNAME);
this.taskClassname.printCString(tcn);
return this;
}

Expand All @@ -31,4 +36,29 @@ class Thread extends SysThread {
[] awaitTermination() {
// TODO #24
}

[int] _getUserEntry() {
int entry = 0;
__pasm__("movl 8(%ebp), %eax; addl _cr_mo_thread_user_entry, %eax", {}, {"%eax": entry});
return entry;
}

[] _userEntry() {
__pasm__("_cr_mo_thread_user_entry := (_thread_user_entry - _gridos_i386_sys_Thread); _thread_user_entry:");
// only a simple method call, to create fully functional stackframe with temporal variables, if required
this._createAndRunTask();
}

[] _createAndRunTask() {
sys::runtime::Runtime userRt := this.rt();
userRt.createAndRunTask(taskClassname.toCString());

// there is no way back to kernel mode => never return!
// TODO: cleanup/exit process/thread if task returns
while (1) {
userRt.yield();
userRt.sleep(5,0); // wait some time
}
}

}

0 comments on commit e08aca1

Please sign in to comment.