News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Where is BIOS?

Started by dncprogrammer, February 25, 2006, 03:16:15 PM

Previous topic - Next topic

MichaelW

Jon,

I read it, but I didn't comment because it looked reasonable to me, at least for a start. You put the stack where I would have put it, and the size is reasonable for an OS that fits in 64KB. I do think that you will probably run out of space when (or if?) you try to implement any sort of efficient disk/file management, and you will definitely run out when you add the GUI :lol


eschew obfuscation

dncprogrammer

Actually, the disk and hardware management are next in line after I start experimenting with writing my own ISR's. I appreciate you looking at what I have so far. Remember, this is a just an experimental project, and a very interesting one. On the subject of ISRs, where would I put mine? I have no desire to take out any BIOS code, so where do you put it?
jon

MichaelW

If by ISR's you mean your interrupt handlers, you should be able to put them anywhere in memory, but since you will have to code them and load them they should probably be part of your executable image. I definitely do not understand what you mean my "take out any BIOS code".

eschew obfuscation

dncprogrammer

Hi Michael,
I didn't mean BIOS code although that is what I wrote. Im not sure what had crossed my mind at that point. I was trying to say that I didn't have any weird ideas about bumping anything existing out of memory in order to seat my handler code. Yes, ISR (Interrupt Service Routine) I read too many books. :)
On the subject of the actual ISR code, I was planning on extending my boot process to 3 stages
accomodating for initialization & placement of interrupt routines without trying my hand at magic with the (512B) boot image.
Here is the sequence: Boot image does it's thing, then loads an executable with the interrupt routines package from disk, jump to it. Routines package loads routines to (wherever memory USA) , modifies the vector table accordingly, then loads the "kernel" image from disk to my low memory spot. After a little verification here and there everything should be solid. Kernel takes over and thats that. The kernel, or "loader", program will not do any start-up specific tasks
With that all in mind where would you suggest putting my interrupt routines? And, of course, if you see any underlying crack-pot aspect to my idea here. Im convinced of the potential size of my interrupt code so Im a little lost on where to put it. This is, afterall, an experimental system but it matters to me that its reasonable well done. Thank you for your insight.
jon


keep it real simple.



MichaelW

It seems that your "loader" is evolving into an OS, so I'll call it that. I think for a small test OS I would keep the load/initialization process as simple as possible:

1. Boot sector loads at normal location.
2. Boot sector moves itself to some out of the way location.
3. Boot sector loads the OS image at its final location.
4. Boot sector jumps to the entry point of the OS image.
5. The OS image initializes itself and starts the command processor.

The OS image would be an exact memory image, with the interrupt handlers, static data, stack, and any necessary buffers included. Assuming you were running in real mode, on recent hardware, booting from a diskette and not using any other drives, at least initially you would have no hardware variations to deal with. With only a few exceptions you could use the BIOS to interface with the hardware. With the aid of a jump table at a fixed memory location your API could be accessed by far call, instead of the clumsy software interrupt mechanism that DOS used. If you were using MASM, this could be done very cleanly with macros.


eschew obfuscation

Tedd

Simple as possible? - Is there any real need for step 2?
It does chop up your memory space a little, but with a bit of arrangement, you can easily overwrite it once the os image has been loaded.
No snowflake in an avalanche feels responsible.

dncprogrammer

I suppose it all depends on where the "kernel" image is going to reside, as not to overrun the boot image before it gets control, right?
jon

Tedd

Yup.
But if you're using seg7000 for data space, you just have to make sure the boot-sector doesn't overwrite itself before it finishes - which shouldn't be too difficult.
No snowflake in an avalanche feels responsible.

MichaelW

If the kernel image will not overlap the boot sector then there is no reason to move it. But if the kernel image will overlap the boot sector, which seems to be the case here, then it would probably be easier to move the boot sector than to rearrange the kernel image to avoid it. Moving the boot sector after it is loaded is the established norm. Even using straightforward, easy to understand code no more than 9 instructions and two words of data would be required.


eschew obfuscation

dncprogrammer

Michael,
You made mention of not using clumsy interrupt routines and it has stuck with me but I guess I don't understand what you meant. I mean, it occurs to me that since the interrupt mechanism is built into the IA-32 machine they would be considered a fairly bullet-proof system for making far calls to resident procedures to be called from any application, and API system if you will. I would really like, for perspective, if you would elaborate on your feelings towards the software interrupt system.
jon

dncprogrammer

Hello? Does anyone have any insight on the post just above?
thanks,
jon

MichaelW

Hi Jon, I've been busy recently solving other people's self-inflicted computer problems.

AFAIK the interrupt mechanism was designed primarily as an efficient method of handling hardware interrupts and exceptions. I think the software interrupt mechanism was just a convenient adaptation that provided additional functionality without requiring any significant increase in processor complexity or transistor count. IMO the decision to base the BIOS and PC-DOS APIs on software interrupts was just another one of the mistakes made by IBM on the PC. The convention of passing parameters in the processor registers limits the number of parameters, and because of the small size of the register set, it substantially increases the complexity of the code on both ends of the call. Preserving the flags around an interrupt call makes sense for a hardware interrupt or exception, but it increases the complexity of the code in functions that return error/status information in the flags. Given the fixed size of the interrupt vector table, APIs with more than roughly 224 functions must hang multiple functions off of at least some of the interrupts, using at least one additional register for these interrupts, and increasing the complexity of the handler.

Contrast these things with a far call interface the passes the parameters on the stack and use a jump table at a fixed memory location. The number of parameters that could be passed would be limited only by available stack space. Because the registers would not be used to pass parameters, and because at least some operations could be performed on the parameters without using registers, the pressure on the register set would be greatly reduced. The flags would not be automatically preserved, so a function could return error/status information in the flags directly, instead of having to modify the preserved flags on the stack. The size of the jump table would be limited only by the available memory, so in most cases each function could have its own table address and code.

You would still need to support hardware interrupts and exceptions, so you would still need an interrupt vector table, and because the BIOS is coded to use software interrupts, you would still need to use software interrupts. But for an OS API, I think a far call interface would be a better choice.

eschew obfuscation

dncprogrammer

Hi Michael,
Excellent. I am very happy to finally hear back from you. Inisght like yours and from the others in this forum makes the impossible possible. I am assuming that the jump table would be at a set-in-stone location that the programmer would use by calculating the start point of the table + some sort of index value (probably double word*routine#) to hook the correct routine. In that, the "routine" at the end of the line would know how many of the stack layers to pop in order to satisfy it's parameter requirements. Finally, on return, the "routine" would push in the same number of arguments to satisfy the expectations of the caller. Am I in the ballpark here? If so, it reminds me of when I used some assembly with quickbasic years ago.
jon


MichaelW

In the most common situation where you were chaining to the previous "handler" at the end of your handler you could do it with a far jump. You would need to chain with a far call only when your handler needed to do further processing after the call returned. Unlike a far jump a far call would disturb the stack, so to pass the original parameters in the call you would need to push copies of the parameters onto the stack at the correct locations, easily done with an invoke statement. In either case, the called handler would be completely unaware of the handler chain, and it would access the parameters in the normal manner.


eschew obfuscation

dncprogrammer

Why is it that a regular jmp is limited to only 128 bytes, or whatever, forward or backward from current IP?
jon