@Solidus: if you aren't going to use paging then there is no problem with your theory. If you are going to use paging then the virtual address of your struct e.g. 0x12345678 will mean different physical addresses to your application and to the kernel. That means that the kernel has to
* determine the pages your struct lays on. It's a computation based on the page directory/tables of your application.
* map these pages in its page table in the appropriate order. From this the kernel gets a new virtual address of your struct which can this way already be used by it.
* unmap the newly mapped pages when returning.
It's not a big problem but note that in your example system calls are software interrupts. That means that each system call implicitly conveys two context-switches (task change to the kernel and back to the app.) plus the above described address maneuvers. I don't need to say that OS working this way will never be a real-time OS.
I know there have already been discussions about necessity of paging on the old forum, but believe me you will need it to speed up your OS or to be able to use shared libraries or to create a correct well functioning memory management etc.
T.
Brendan- 03-14-2006
Hi,
It's not a big problem but note that in your example system calls are software interrupts. That means that each system call implicitly conveys two context-switches (task change to the kernel and back to the app.) plus the above described address maneuvers. I don't need to say that OS working this way will never be a real-time OS.
Just to put things into perspective, a CPL=3 to CPL=0 context switch, followed by a CPL=0 to CPL=3 context switch (i.e. the system call and it's return) works out to about 180 cycles for a software interrupt and/or about 150 cycles for a call gate on an Intel Pentium 4. Of course this depends a lot on which CPU it is (for e.g. on an 80386 it costs less). SYSENTER and SYSCALL are both faster.
A cache miss on a Pentium 4 can be just as expensive.
As for "realtime" please look it up. For a realtime OS you want to minimize the maximum time any operation could take. For a "non-realtime" OS you'd minimize the average time operations take.
Consider an operation that normally takes 50 cycles, but on rare occasions could take 10000 cycles. The average time this operation takes might be 52 cycles (which is great for a non-realtime OS) but the maximum time it takes is 10000 cycles (which isn't good for a real time OS).
Imagine you might find another way to do the same operation that always takes 5000 cycles. For a non-realtime OS the average time would go from 52 cycles to 5000 cycles, and the new method would be considered about 92 times slower. For a realtime OS, the maximum time would go from 10000 cycles down to 5000 cycles, and the new method would be considered twice as fast.
In general, a non-realtime OS will perform better, but a realtime OS will give guaranteed maximum times.
Real time OSs are good for some critical embedded systems, where "guaranteed" times are required. For example, imagine you've got a nuclear reactor with a temperature sensor. If the temperature sensor says "too hot!" then you need to turn on the cooling fans within 5 mS or it'll blow up. For a real-time OS you'd be able to calculate that it'd never take more than 3 mS (but don't really care how long it usually takes). For a non-realtime OS you could work out that it normally takes 1 mS (but that there's a very small chance it could take 10 mS and blow up).
For Menuet, users do not want a realtime OS - they want something that performs as fast as possible.
Cheers,
Brendan
Theorizer- 03-14-2006
According to the Pentium Processor Family Developer's Manual:
Call gate:
------------
clocks = 45 + 2x (x parameters)
clocks = 44 (no parameters)
RET: clocks = 23 (stack switch)
Sum = 45 + 23 + 2x = 68 + 2x clocks
===========================
According to AMD's SYSCALL and SYSRET specification the syscall and sysret instructions consume less then one-fourth of the above calculated amount of clocks. Let's assume a K6 processor. When an application uses call gates with syscall/sysret for OS services then this operation dual needs about 20 clocks.
Now make a rough calculation for
software interrupt:
-----------------------
INT (via task gate): clocks = 23 + TS (=85 assuming task switch to 32 bit tss)
IRET clocks = 10 + TS (=85)
Sum = 23 + 10 + 2 * 85 = 203 clocks
===========================
So on a K6 the ratio would be about 10!
I see you know what a real time OS is, but not that was the stake.
I would not claim so easily that MenuetOS users do not want real time OS. I didn't see vote about that. Not speaking about the fact that originally Ville had declared MenuetOS to be a real time system. Which it is not. But you certainly know about x86 based processors for embedded systems from intel. I've just thought that also MenuetOS could run on such hardwares. So I just want to say that with a more flexible design you might not have to be stuck at one or another design principle.
T.
Dex- 03-14-2006
@Theorizer, What if you use paging, but mapped 1-1.
To me the problem is speed verse's compatibility, i think the best way round this is to make Menuet very module, so anything can be replaced or tested and improved on.
So for now that is what we need to work on.
Brendan- 03-14-2006
Hi,
According to the Pentium Processor Family Developer's Manual:
My cycle timings were measured on a Pentium 4 (Williamette), which was one of the first (worst) Pentium 4's - I had a 1.6 GHz Pentium 4 that ran about as fast as a 1 GHz Pentium III for basic integer operations.
While the timings do vary, it's never really much to worry about...
Now make a rough calculation for
software interrupt:
-----------------------
INT (via task gate): clocks = 23 + TS (=85 assuming task switch to 32 bit tss)
Woah!
The last thing you ever want is to have a task switch every time the kernel API is used. This would be completely broken (although to my horror, it is what the original 32 bit version of Menuet did AFAIK, which is one of the reasons it was so slow, and probably one of the first things the russians fixed).
In general, only some specific kernel API functions might cause a task switch. For example "sleep(time)" would as long as "time" isn't zero, the kernel code to send and recieve events (or messages or "IPC") would but only in some situations, the code to spawn a new thread/task/process might depending on how it was written and the priorities of the threads/tasks/processes involved, and the code to terminate the current thread/task/process would always involve a task switch. For everything else there should be no task switch (the timer IRQ handler would do task switches too, but it's not a kernel API function).
So on a K6 the ratio would be about 10!
That's because you compared a call gate without a task switch to an interrupt with a task switch....:)
For an 80386 you'd have:
CALL ptr16:32 = 86 cycles (call gate, more privilege, no parameters)
RETF = 68 (lesser privilege, switch stacks)
INT n = 99 cycles (protected mode to higher privilege)
IRETD = 60 cycles (protected mode return to lesser privilege)
By my calculation this makes call gates 154 cycles and software interrupts 159 cycles on an 80386.
BTW, if you're curious, for the 80386 a "Jump via. 32 bit task state segment" where virtual 8086 isn't involved costs 303 cycles.
Anyway, the cycle timings don't tell the whole truth. For example, if you're optimizing for size then you'd want to use a software interrupt (2 bytes) instead of a 32 bit far call (7 bytes).
It is possible to write a kernel that supports both software interrupts and call gates (and SYSCALL/SYSENTER if you like). This is what I prefer - it allows applications developers to choose for themselves. For example, I tend to use software interrupts for code that isn't run often and call gates for code that is run often.
Not speaking about the fact that originally Ville had declared MenuetOS to be a real time system. Which it is not. But you certainly know about x86 based processors for embedded systems from intel. I've just thought that also MenuetOS could run on such hardwares. So I just want to say that with a more flexible design you might not have to be stuck at one or another design principle.T.
AFAIK Menuet was originally intended as a multi-tasking OS with a GUI in 100% assembly for 80x86 computers, and was never intended for embedded systems - hardcoding the GUI into the kernel seems to confirm this.
Of course what "Menuet32" (or "Menuet4U"?) becomes is open to interpretation - no-one knows for sure yet, but I'd guess that most people would want a general purpose desktop OS (rather than something to run in an embedded device, like a router or broadband modem).
As for Ville, I'm not convinced he knew what he was saying - I wouldn't be surprised if he said "Real Time OS" because it sounded good at the time. It's false advertising, nothing more (unless the 64 bit version is incredibly different to his 32 bit version, but I find that extremely unlikely - writing a true real time OS is much harder and people don't learn that much in such a small amount of time).
Cheers,
Brendan
Dex- 03-14-2006
Yes RealTime OS is a miss used word, most of the time RealTime OS are slower than nonRealTime OS, but can guaranteed to do something, in a given time. Like for ABS breaks etc.
I think that we need to take 80% of the function calls from the kernel and develop OS independent libs, this is the only way for a ASM OS to survive. Take FASM as a example, it only tuck me 2 hour to get it working on Dex4u, this is because it was designed to be easy portable. With the miniman OS dependent code.
Michael H- 03-14-2006
Hi Brendan, thanks for your input.
The last thing you ever want is to have a task switch every time the kernel API is used.
Ok, but you still have to guard against the timer IRQ being processed and doing a task switch before the app int40 IRQ is processed. How would you do it?
Anyway a task switch isn't done every time the kernel API is used, for instance about line 2300 in sys32.inc Menuet m079p1 version in
sys_resize_app_memory:
; wait for process table to be free
rsm0:
cli ; Disable Interrupt Flag
cmp [application_table_status],0 ; can we get a lock
je rsm1 ; yes
sti ; no lock, set interrupts again
call change_task ; change task so lock in other thread is processed
jmp rsm0
rsm1:
call set_application_table_status ; this thread sets it's id in application_table_status to obtain a lock
sti ; Now this process has the lock set interrupt flag again so other interupts can be processes
Brendan- 03-14-2006
Hi,
Ok, but you still have to guard against the timer IRQ being processed and doing a task switch before the app int40 IRQ is processed. How would you do it?
In general, there's parts of the kernel that need to be protected from being run by several tasks at the same time. The parts that need to be protected are called "critical sections", and are normally protected by some form of "re-entrancy locking".
The simplest way to implement re-entrancy locking is to disable interrupts around the critical section. This can work if it's done right, but if used badly it can seriously mess up IRQ latency (and in the worst case can cause IRQs to be missed entirely).
Disabling IRQs doesn't work for multi-CPU computers (disabling IRQs on one CPU won't prevent another CPU from accessing the data). In this case you need full re-entrancy locking, with spinlocks, semaphores, mutexes, etc. This is far more complex, as there's things like lock contention, livelock, deadlock, priority inversion, cache thrashing, scalability, etc.
For performance (better IRQ latency and/or lock contention), the idea is to minimize the amount of CPU time spent inside any one critical section. This means doing as much as possible outside of the critical section, and can sometimes mean splitting a larger critical section into several smaller critical sections.
How I do it is to use spinlocks around critical sections, where the "acquire_lock" code looks something like:
;Input
; edi = address of lock
acquire_lock:
pushfd
cli
lock bts [edi],1
jnc .acquired
.retry:
popfd
pause
pushfd
cli
lock bts [edi],1
jc .retry
.acquired:
lock inc dword [scheduler_lock_count]
popfd
ret
The code to release a lock goes something like this:
;Input
; edi = address of lock
release_lock:
pushfd
cli
lock btr [edi],1
sub dword [scheduler_lock_count],1
jne .noSwitch
cmp byte [thread_switch_missed_flag],0
je .noSwitch
call scheduler_do_switch
.noSwitch:
popfd
ret
And lastly, the timer IRQ code:
timer_IRQ:
cmp dword [scheduler_lock_count],0
jne .threadSwitchDisabled
call scheduler_do_switch
iret
.threadSwitchDisabled:
mov byte [thread_switch_missed_flag],1
iret
Normally I'd add some extra code to detect deadlocks (when the same task tries to lock a lock twice) and to detect when a lock is released when it's not acquired. In these cases I'd jump to a critical error handler ("Kernel Panic: Someone stuffed things up badly!" :)).
The code above is fine for normal spinlocks, but won't work if things need to be protected from code run by IRQ handlers. I normally have a "missed IRQ queue" and special "IRQ safe" spinlocks for this, with more complex acquire and release code (and some extra code at the start of each IRQ handler).
Of course spinlocks like this should only be used to protect small critical sections (anything that will always be faster than a task switch). For a micro-kernel IMHO that's all the kernel needs (because everything in the kernel should be faster than a task switch), but for a monolithic kernel you'd need semaphores too - for example, you don't want to spin for a few seconds while the hard disk driver waits to acquire a "disk controller in use" lock.
Anyway a task switch isn't done every time the kernel API is used, for instance about line 2300 in sys32.inc Menuet m079p1 version in
sys_resize_app_memory:
I was refering to the mess starting at line 551 in "SYS32.INC" from the kernel source package "k078.zip" (it's the only Menuet32 kernel source I've been able to find). It begins like this:
i40:
cli
mov edi,[0x3000]
imul edi,8
mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b
mov eax,[schd]
mov [usedi40+eax],byte 1
push eax
mov edi,[0x3000]
imul edi,256
mov [edi+0x80000+0xB0],eax
Then around line 630 (after around 80 lines of scheduler code) there's this:
sti
push eax
and edi,0xff
call dword [servetable+edi*4]
pop eax
cli
This followed by another 50 lines of scheduler code.
I'd expect to see something more like:
i40:
movzx eax,al
call [servetable+eax*4]
iret
Or (as I suggested elsewhere):
i40:
cmp eax,MAX_API_FUNCTION
jae .undefined
call [servetable+eax*4]
iret
.undefined:
mov eax,ERR_FUNCTION_NOT_DEFINED
iret
Cheers,
Brendan
Michael H- 03-14-2006
Yes but that's the rub, most 32 bit computers are single processor and do not have an APIC for advanced things like spin locks etc so they are not options available. However I think you've mentioned a good reason with the coming of multicore processors to actually go back to the beginning and redesign things from scratch ;)
As for the code -
i40:
movzx eax,al
call [servetable+eax*4]
iret
That's what I'm saying, because you can't count on the order of interrupts being processed, you can't just do that...... maybe :)
As for the i40: code in sys32.inc, yes maybe it can be massaged ;)
cmp eax,MAX_API_FUNCTION
So simple yet so effective :)
Thanks for the thoughts Brendan, hope this ignites some debate about different ways of doing things and maybe more support for a redesign? I mainly want to see drawing code and buttons stripped out of the kernel in favour of driver modules.
Brendan- 03-14-2006
Hi,
Yes but that's the rub, most 32 bit computers are single processor and do not have an APIC for advanced things like spin locks etc so they are not options available. However I think you've mentioned a good reason with the coming of multicore processors to actually go back to the beginning and redesign things from scratch ;)
The spinlock code above will work for single CPU, even for an old 80386. It is a bit of overkill for a "single CPU only" OS though...
For "multi-CPU" support, it's a sliding scale. At one end is simple single-CPU, but at the other end is large servers with NUMA, lots of multi-core CPUs and maybe hyper-threading. Beyond that there's clusters (perhaps starting at a pair of identical computers used for redundancy, but going up to parallel processing and grid computing).
If you're curious, take a look at this thing:
http://www.tyan.com/products/html/clusterservers.html
http://www.tyan.com/products/html/typhoon_b2881_spec.html
As for the code -
i40:
movzx eax,al
call [servetable+eax*4]
iret
That's what I'm saying, because you can't count on the order of interrupts being processed, you can't just do that...... maybe :)
Why not! :)
It's just a matter of perspective. If you think of an IRQ handler as a "mini-task" with it's own context, then anything any task does and anything any IRQ handler does happens sequentially from that task or IRQ handler's perspective (even for multi-CPU).
The only problem is for some parts of the kernel, where code can be being run by several tasks and/or several IRQ handlers at the same time. For any kernel code that can't handle this you use re-entrancy locks to ensure that only one task or IRQ handler can be running in that code at a time.
The basic idea is only a little trickier than that, as the re-entrancy locks actually protect data from being used by several tasks and/or several IRQ handlers at the same time. For example, you could have 5 different routines that access the memory manager's data that all share the same re-entrancy lock.
Thanks for the thoughts Brendan, hope this ignites some debate about different ways of doing things and maybe more support for a redesign? I mainly want to see drawing code and buttons stripped out of the kernel in favour of driver modules.
I've always favoured the micro-kernel approach myself - strip out everything except memory management, the scheduler, IPC/messaging, excpetion and critical error handling, and some IRQ and I/O port handling code. Make everything else run as normal processes at CPL=3 (including the GUI, drivers and applications).
I doubt anyone here would agree to that idea though - it's not so good for performance.... :)
Cheers,
Brendan
Theorizer- 03-15-2006
Hi,
I thought you'd ment interrupt through task-gate when you'd spoken about context-switch. Sorry. In case of trap and interrupt gates the ratio I calculated is significantly smaller: AMD claims four-time speed-up if you use syscall/sysret instructions instead of usual call/ret. That means that on every AMD processor (above K5) system calls will run faster, but on intel processors they won't be slower either than sw-interrupts.
If you consider that intel has taken over sysxxx instructions into its newest processors then it seems to be worth to use call-gates where you can.
There are however other issues regarding call-gates:
* as you've mentioned they make the code bigger.
* maintenance of them may be more difficult than that of the one sw-interrupt (int 40h) (calculating with hundreds of system calls, lots of LDT entries).
* they work like normal functions - passing parameters in the stack(s) (this might mean that debugging will be easier - stack dump).
* it's easy to directly call to services with CPL 2, 1, 0 (not only 0) from CPL 3. (better safety, security?)
* etc.
There are some types of microkernels. Qnx, the most successful one, and amoeba use synchronous message passing which I don't like. Mach based OSs (e.g. Hurd), L4, etc. use asynchronous message passing which is really sympathetic, but programming them on user level can be a nightmare.
How (with what technic) would you pass a message between two processes? And if you had to broadcast a message to more processes?
T.
Brendan- 03-15-2006
Hi,
I thought you'd ment interrupt through task-gate when you'd spoken about context-switch. Sorry. In case of trap and interrupt gates the ratio I calculated is significantly smaller: AMD claims four-time speed-up if you use syscall/sysret instructions instead of usual call/ret. That means that on every AMD processor (above K5) system calls will run faster, but on intel processors they won't be slower either than sw-interrupts.
If you consider that intel has taken over sysxxx instructions into its newest processors then it seems to be worth to use call-gates where you can.
Intel supports SYSCALL/SYSRET on newer CPUs, but only for 64 bit code.
Long mode itself is split into 2 "sub-modes", the 64 bit sub-mode (for 64 bit code) and legacy sub-mode (for 32 bit or 16 bit code originally written for 32 bit or 16 bit protected mode). In long mode, all code at CPL=0 must be 64 bit.
In the 64 bit sub-mode of long mode, all CPUs support SYSCALL/SYSRET, Intel CPUs support SYSENTER/SYSEXIT and all CPUs support software interrupts.
In the legacy sub-mode of long mode, Intel CPUs have SYSENTER/SYSEXIT but not SYSCALL/SYSRET, AMD CPUs have SYSCALL/SYSRET but not SYSENTER/SYSEXIT, and all CPUs have software interrupts and call gates.
In protected mode, newer Intel CPUs have SYSENTER/SYSEXIT but not SYSCALL/SYSRET, newer AMD CPUs have SYSCALL/SYSRET but not SYSENTER/SYSEXIT, older CPUs don't support SYSENTER/SYSEXIT or SYSCALL/SYSRET, and all CPUs have software interrupts and call gates.
This means that 64 bit code should just use SYSCALL/SYSRET and everything will be fine on all CPUs that support long mode. In all other cases (protected mode or the legacy sub-mode of long mode), what the CPU supports depends on who made it and how old it is (use CPUID to find out).
There are however other issues regarding call-gates:
* as you've mentioned they make the code bigger.
* maintenance of them may be more difficult than that of the one sw-interrupt (int 40h) (calculating with hundreds of system calls, lots of LDT entries).
* they work like normal functions - passing parameters in the stack(s) (this might mean that debugging will be easier - stack dump).
* it's easy to directly call to services with CPL 2, 1, 0 (not only 0) from CPL 3. (better safety, security?)
* etc
For call gates, they can be used to pass parameters on the stack, but you can still pass no parameters like a software interrupt.
Consider something like this:
i40:
cmp eax,MAX_API_FUNCTION
jae .undefined
call [servetable+eax*4]
iret
.undefined:
mov eax,ERR_FUNCTION_NOT_DEFINED
iret
system_call_gate_handler:
cmp eax,MAX_API_FUNCTION
jae .undefined
call [servetable+eax*4]
retf
.undefined:
mov eax,ERR_FUNCTION_NOT_DEFINED
retf
Notice how easy it is to support both software interrupts and call gates? Both can be used in an identical way with parameters passed in registers (and returned in registers).
In a similar way it's possible to support SYSCALL and SYSENTER too - you'd just have similar looking handlers for them. The problem here is that for SYSENTER, the CPU doesn't store any return information anywhere. For SYSEXIT, ECX must contain the CPL=3 code's ESP and EDX must contain the CPL=3 code's EIP before SYSEXIT it executed. A simple way of handling this is for CPL=3 code to to do something like:
mov eax,function_number
mov ecx,esp
mov edx,.here
sysenter
.here:
Also, it's possible to emulate SYSENTER and/or SYSCALL in the invalid opcode execption handler so that they work on CPUs that don't support them. The invalid opcode handler would do something like this:
exception_06:
push edx
mov edx,[esp+4] ;edx = return EIP
cmp [edx],SYSCALL_OPCODE ;Was it SYSCALL?
je .fakeSYSCALL ; yes
cmp [edx],SYSENTER_OPCODE ;Was it SYSENTER?
je .fakeSYSENTER ; yes
pop edx
push dword 0 ;Set fake error code
push dword 6 ;Push exception number
jmp critical_error_handler ;Jump to the generic error handler
.fakeSYSCALL:
pop edx
cmp eax,MAX_API_FUNCTION
jae .undefined1
call [servetable+eax*4]
iretd
.fakeSYSENTER:
pop edx
mov [esp],edx ;Set new return EIP
mov [esp+12],ecx ;Set new return ESP
cmp eax,MAX_API_FUNCTION
jae .undefined
call [servetable+eax*4]
iretd
.undefined:
mov eax,ERR_FUNCTION_NOT_DEFINED
iretd
That way you can say that every method always works (but SYSCALL and SYSENTER may be slow if the CPU doesn't "hardware accelerate" them)... :)
There are some types of microkernels. Qnx, the most successful one, and amoeba use synchronous message passing which I don't like. Mach based OSs (e.g. Hurd), L4, etc. use asynchronous message passing which is really sympathetic, but programming them on user level can be a nightmare.
How (with what technic) would you pass a message between two processes? And if you had to broadcast a message to more processes?
This depends on the overall design of the OS, what it's goals are and what other features it supports. For example, for a "single-CPU only" OS I'd probably use synchronous message passing, and for an OS that supports shared memory buffers (or single address space OS's) I'd only support small messages (several dwords or qwords of message data passed in registers). For a single-user OS designed for "many-CPU" I'd use asynchonous message passing, but for a multi-user OS designed for "many-CPU" I can't be sure what I'd do.
I guess this is where things get tricky for this forum - too much about the OS is undecided...
For example, I'm not sure if people here want something that is similar to Menuet (single-user, multi-tasking, single-CPU, monolithic with a focus on 100% assembly) or if they want something different.
Cheers,
Brendan
Dex- 03-15-2006
I guess this is where things get tricky for this forum - too much about the OS is undecided...
For example, I'm not sure if people here want something that is similar to Menuet (single-user, multi-tasking, single-CPU, monolithic with a focus on 100% assembly) or if they want something different.
What i would like to see, is a number of designs, but with a common program interface, so that even though underneather is differant, the programs will still run on the same.
One design may work much better than the others and this is the one that we can take forward, even a C ver would be good if you could still run the same programs as a ASM + this would be a great test bed for C v ASM.
As for ASM i think the BIG mistake, is not using it advantages, over other languages.
This is not speed that most people think :shock: .
It's SIZE no other language come close, we as ASM programmers are still programming as if we are using C.
We do thinks like embed function in the kernel ( i counted 11 different call for a simple text box ) My whole OS is about 43K with everything from Hdd, floppy, atapi, vesa, ac97, keyboard, fonts, fat12/16/32 50 built in functions + more.
Even by add all this to a program it would still be a small program (i am not saying we add all this to each program).
This is a example of why we may need to re-thing the best way to program a ASM OS like MenuetOS.
Solidus117- 03-15-2006
I guess this is where things get tricky for this forum - too much about the OS is undecided...
For example, I'm not sure if people here want something that is similar to Menuet (single-user, multi-tasking, single-CPU, monolithic with a focus on 100% assembly) or if they want something different.
What do the public want? As part of the public, I want an easy programming interface for application writing using assembly and secondly a persistant desktop that I can modify to my own desires. But mainly the assembly programming, it doesn't get much easier than MenuetOS (maybe DOS, but has no GUI). Keep the focus on the assembly, I say.
That's my 2c.
Brendan- 03-15-2006
Hi,
What i would like to see, is a number of designs, but with a common program interface, so that even though underneather is differant, the programs will still run on the same.
One design may work much better than the others and this is the one that we can take forward, even a C ver would be good if you could still run the same programs as a ASM + this would be a great test bed for C v ASM.
This is a good idea, but I don't think "a number of designs" is possible.
Basically, every interface between all components must be fixed (i.e. the way thing things are used and how they behave must be identical, regardless of which version of what code is being used). As long as this is the case, then you can have "mix and match" components without major compatibility problems.
This means a single fixed design, with "mix and match" components. It also means that solid interface specifications would be required (otherwise you end up with disagreements with no way to resolve them).
Then you'd need to decide the granularity of those components - should users have a choice of kernels, or should they be able to grab a scheduler from one place, a memory manager from another and IPC code from a third place and combine them? What about device drivers?
Next is the "when" - should users be able to choose which components to use when they re-compile, or when they install the OS, each time it boots, or perhaps at run time? For example, being able to change the memory manager or scheduler while the OS is running would be a powerful feature, but actually implementing it wouldn't be easy...
Each of these decisions leads to a different architecture, a different number of interfaces that need to be specified and a different development model. For example, if components are chosen at compile time then you could use a monolithic kernel, but all developers would need access to a shared source repository. If components are chosen during OS installation a monolithic kernel probably won't work well but all developers can maintain their own source code repositories and distribute their own binaries.
As for ASM i think the BIG mistake, is not using it advantages, over other languages.
This is not speed that most people think :shock: .
It's SIZE no other language come close, we as ASM programmers are still programming as if we are using C.
We do thinks like embed function in the kernel ( i counted 11 different call for a simple text box ) My whole OS is about 43K with everything from Hdd, floppy, atapi, vesa, ac97, keyboard, fonts, fat12/16/32 50 built in functions + more.
Even by add all this to a program it would still be a small program (i am not saying we add all this to each program).
This is a example of why we may need to re-thing the best way to program a ASM OS like MenuetOS.
IMHO one of the main advantages to assembly is being able to port or write native tools to the OS. For an example, someone ported FASM to their OS in 2 hours, but I'll bet they couldn't port GCC in that amount of time. ;)
Cheers,
Brendan
Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.