Page 1 of 1
virtual abstraction layer
Posted: Thu Dec 15, 2016 3:02 am
by iliak
Hello
My goal is to make some kind of a "virtual abstraction layer" to make my os and to avoid very low level details (bootloader, hardware memory managemnt... ) : focusing on the kernel implementation details and not on managing the hardware. For the record, the idea is to mimic the [http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node0000.html Amiga Kernel], but I don't want to bother with all the 680x0 and hardware parts. So, I plan to go with some kind of a virtual abstraction layer that will simulate (not emulate) the hardware (I don't want to go the virtualization way). I would like to keep it simple (as possible...).
The idea I have in mind is to make a native program (in the linux way) that will be the virtual environment (let's call it 'venv'). During the initialization, the kernel will loads all the needed routines.
The first question that arise, is how to handle the scheduling ? The question is not how my kernel should do this, but how Linux allows me to manage process outside of its own scheduler ? How can I start / stop process like a scheduler can do ?
Hope to be enough clear...
Iliak
Re: virtual abstraction layer
Posted: Thu Dec 15, 2016 5:24 am
by Kevin
Maybe ucontext.h is what you're looking for.
Re: virtual abstraction layer
Posted: Thu Dec 15, 2016 3:42 pm
by iliak
Hi Kevin,
Thank you for the tip !
Here is given a nice example of what my virtual scheduler could be :
Code: Select all
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <sys/time.h>
/* Set by the signal handler. */
static volatile int expired;
/* The contexts. */
static ucontext_t uc[3];
/* We do only a certain number of switches. */
static int switches;
/* This is the function doing the work. It is just a
skeleton, real code has to be filled in. */
static void
f (int n)
{
int m = 0;
while (1)
{
/* This is where the work would be done. */
if (++m % 100 == 0)
{
putchar ('.');
fflush (stdout);
}
/* Regularly the expire variable must be checked. */
if (expired)
{
/* We do not want the program to run forever. */
if (++switches == 20)
return;
printf ("\nswitching from %d to %d\n", n, 3 - n);
expired = 0;
/* Switch to the other context, saving the current one. */
swapcontext (&uc[n], &uc[3 - n]);
}
}
}
/* This is the signal handler which simply set the variable. */
void
handler (int signal)
{
expired = 1;
}
int
main (void)
{
struct sigaction sa;
struct itimerval it;
char st1[8192];
char st2[8192];
/* Initialize the data structures for the interval timer. */
sa.sa_flags = SA_RESTART;
sigfillset (&sa.sa_mask);
sa.sa_handler = handler;
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 1;
it.it_value = it.it_interval;
/* Install the timer and get the context we can manipulate. */
if (sigaction (SIGPROF, &sa, NULL) < 0
|| setitimer (ITIMER_PROF, &it, NULL) < 0
|| getcontext (&uc[1]) == -1
|| getcontext (&uc[2]) == -1)
abort ();
/* Create a context with a separate stack which causes the
function f to be call with the parameter 1.
Note that the uc_link points to the main context
which will cause the program to terminate once the function
return. */
uc[1].uc_link = &uc[0];
uc[1].uc_stack.ss_sp = st1;
uc[1].uc_stack.ss_size = sizeof st1;
makecontext (&uc[1], (void (*) (void)) f, 1, 1);
/* Similarly, but 2 is passed as the parameter to f. */
uc[2].uc_link = &uc[0];
uc[2].uc_stack.ss_sp = st2;
uc[2].uc_stack.ss_size = sizeof st2;
makecontext (&uc[2], (void (*) (void)) f, 1, 2);
/* Start running. */
swapcontext (&uc[0], &uc[1]);
putchar ('\n');
return 0;
}
But... :
This an example how the context functions can be used to implement co-routines or cooperative multi-threading. All that has to be done is to call every once in a while swapcontext to continue running a different context. It is not recommended to do the context switching from the signal handler directly since leaving the signal handler via setcontext if the signal was delivered during code that was not asynchronous signal safe could lead to problems. Setting a variable in the signal handler and checking it in the body of the functions which are executed is a safer approach. Since swapcontext is saving the current context it is possible to have multiple different scheduling points in the code. Execution will always resume where it was left.
This is not good for a preemptiv kernel but rather a cooperative one...
Re: virtual abstraction layer
Posted: Thu Dec 15, 2016 4:20 pm
by Kevin
This doesn't say that you can't do that, just that they don't recommend it. For normal applications this is probably good advice, because it's much easier to handle a context switch at defined points rather than whereever the instruction pointer happens to be when the timer is triggered. But if you do swap the context from a signal handler, I think the effect that you get won't be much different from what happens with real threads. Yes, synchronisation becomes harder than with the solution they suggest, but it's harder with real threads, too.
You're doing something exotic here, and sometimes the right thing to do when doing something exotic is ignoring friendly advice that is based on different assumptions.
Re: virtual abstraction layer
Posted: Fri Dec 16, 2016 3:37 am
by iliak
Ok.
The other problem is memory location. I think about allocating a big chunk of memory (ie: 10Mo) for the whole virtual environment and distribute pieces on demand. My concern is how to make process see those memory location ranging from 0x00000000 to 0x00A00000 and not the real location on my Linux ?
Re: virtual abstraction layer
Posted: Fri Dec 16, 2016 5:00 am
by alexfru
iliak wrote:The other problem is memory location. I think about allocating a big chunk of memory (ie: 10Mo) for the whole virtual environment and distribute pieces on demand. My concern is how to make process see those memory location ranging from 0x00000000 to 0x00A00000 and not the real location on my Linux ?
There are some memory APIs where you can specify the desired location, not just the size. Also, in 32-bit mode there was a system call to allocate segment descriptors in an LDT, so you could compensate the offset in the segment base.
However, you could just pass and use a pointer to your 10MB area. Once you get things to work with the pointer, you can always change it to a constant.
Re: virtual abstraction layer
Posted: Sun Dec 18, 2016 2:21 am
by iliak
Could you point me to thoses memory API please ?
I need (at least would like) to mimic as close as possible the AmigaOS. There is only one constant memory location (0x00000004) which point to the exec.library.
Re: virtual abstraction layer
Posted: Thu Dec 22, 2016 1:54 am
by Boris
Im not sure you can map something below 4kb, so you will end up with an offset anyway.
If you insist on having a by-address allocator, you should write your own, and use mmap/sbrk . But then, you won't be able to use malloc anymore in your code, because the two allocators would overlap