I started out by creating a dll file with all the system calls implemented. Later I learned how a kernel actually works. So I rewrote it, emulating an interrupt to run in a separate kernel space. Could you name some of the details you want described?
skybrian|10 months ago
Maybe start with an explanation of what it does without referring to Cygwin? That would be for people unfamiliar with Cygwin. Edit: actually you already did that, but starting off with “not Cygwin” is confusing.
You could also explain how your approach differs from Cygwin, for people who do know it.
cryptonector|10 months ago
So what happens when you "boot" MinC? It sounds like it runs all the usual OpenBSD services and what not. But are all of those new Windows processes, or just new threads in the one MinC process?
Also, do processes inside MinC get to interact with the Windows host filesystem and networking in any way?
BTW, this is very cool!
nialv7|10 months ago
[0]: https://en.wikipedia.org/wiki/Operating_system#Library
potus_kushner|10 months ago
quietbritishjim|10 months ago
"to run in a separate kernel space" You emulated those interrupts, and they really run in a separate kernel space [1]? Or you mean it's emulated as if it runs in a separate kernel space?
If it's really running in kernel mode, as you are literally saying, how is it doing that? Is it running in some virtual machine manager like Hyper-V or as something like a driver in the Windows kernel? How does it interact with the hardware e.g. does it access the same file systems that Windows does, and how does it coordinate that?
Looking at the source code I don't see any references to the Windows WDK / DDK (driver development kit) but a lot of references to user-space Windows API functions. I also don't see most of the actual BSD kernel [2]. For example, could you point me at the process/thread scheduling code (like sched_bsd.c [3])? Are you sure it's a kernel? Are you sure it runs kernel space, not user space after all? It seems like it might actually be an abstraction layer that emulates the user-space BSD system calls but runs in user-mode and make use of (only) the Windows kernel. If so, what do you mean by "emulating an interrupt" - how are you intercepting them? If you're just providing the C API functions to link into the application, and that don't actually trigger those interrupts at all, that is something a lot less ambitious. Still something impressive and worthwhile but you're setting readers up for disappointment if you describe it as something that it isn't.
That is what Cygwin does by the way. It implements POSIX APIs in user space. It does not claim to be a kernel (because it's not) or to run in kernel mode (because it doesn't). The thing is, I can understand you may have chosen the name "MinC is not Cygwin" because it works in roughly the same sort of way as Cygwin but is a different implementation. But the name, along with the description as being "a tiny kernel", suggests that it's not Cygwin because it works in a fundamentally different way, i.e., running the actual BSD kernel in actual kernel mode.
[1] https://en.wikipedia.org/wiki/User_space_and_kernel_space
[2] Mirror is available at: https://github.com/openbsd/src/tree/master/sys/kern
[3] https://github.com/openbsd/src/blob/master/sys/kern/sched_bs...
thingfish|10 months ago
For starters, I needed to put the code of my kernel emulation (libposix-6.1.0.dll) at a specific memory address in order to get that snappy feeling when you start an OpenBSD program. Normally, 32bit DLLs in Windows are loaded at 0x10000000 (called the "ImageBase"). This causes the Windows kernel reposition the DLL because in most cases, other DLLs are already loaded there. In my case these are netapi32.dll, ws2_32.dll, iphlpapi.dll and shell32.dll among others. Making my DLLs load at an address just below the 0x10000000 boundary makes MinC programs load faster, in effect creating a space for my kernel, e.g. "kernel space".
Secondly, I needed some mechanism to reset the contents of the CPU's registers after calling into the various Windows DLLs which are not part of the Windows NT kernel. For instance, the WriteFile() function changes the %edx register, which is used by the GCC compiler to contain the high part of 64bit variables. Turns out I needed what is called a "context switch", saving the contents of all registers onto the stack, calling my kernel emulation and then restoring the registers from the stack. In Linux, this mechanism is triggered by a special interrupt (int 0x80). I decided to name the function that does this in my kernel emulation "__kernel", so in assembly I can write "call ___kernel" [0].
There is more, but I won't go into that right now. I plan to do a write-up on the topic. By the way, Microsoft also has a user space implementation of their kernel, called kernel32.dll, implementing Win32 APIs in user space.
[0] https://github.com/dboland/minc/blob/master/libposix/arch/x8...