Running .com files / API implementation

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Running .com files / API implementation

Post by Fergo »

Hello all.
I'm working on a 16 real mode os with FAT12 filesystem and now I need to make my OS execute (and return from) .com files. At the moment I can read the .com file from floppy and copy it to memory, but I don't know exactly how to run it (which registers I should change, pass the execution and return to the OS when the execution is done). Which steps should I take? (event the simplest method is welcome)

Thanks in advance,
Fergo
Last edited by Fergo on Wed Feb 13, 2008 11:51 am, edited 1 time in total.
User avatar
Zenith
Member
Member
Posts: 224
Joined: Tue Apr 10, 2007 4:42 pm

Post by Zenith »

I would think that you just have to jump to the application in memory at offset 0x100 (if this is a standard DOS .com file). And also, standard .com files call int 13h, ah=0 to terminate execution, so you have make an interrupt handler for that too.

See
http://en.wikipedia.org/wiki/COM_file

and
http://www.uv.tietgen.dk/Staff/Mlha/PC/ ... /index.htm

Some .com files will expect these DOS services to be available
"Sufficiently advanced stupidity is indistinguishable from malice."
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

karekare0 wrote:And also, standard .com files call int 13h, ah=0 to terminate execution, so you have make an interrupt handler for that too.
int 13h is the disk interrupt, ah=0 means 'reset disk system'. DOS .com files may do a simple ret (or retf, can't remember), int 20h (DOS 1.x termination, but still works in later versions), int 21h, ah=0 (same) or the recommended (DOS 2.0+) int 21h, ah=4ch.


JAL
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

I wrote a very simple dos clone (2k in size), that has well commented fasm code, that can load a com or mz exe, it also run some old dos games, so reading the source code may help.
See here:
http://board.flatassembler.net/topic.php?t=5275&start=0
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Post by Fergo »

Thanks for the replies!
Right now I'm not home, but when I get there I read the documents and the sample provided by Dex carefully.
Thanks again!

Fergo
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

Dex wrote:I wrote a very simple dos clone (2k in size)
Thou art the master of tiny code :).


JAL
User avatar
Zenith
Member
Member
Posts: 224
Joined: Tue Apr 10, 2007 4:42 pm

Post by Zenith »

And also, standard .com files call int 13h, ah=0 to terminate execution, so you have make an interrupt handler for that too.
Whoops, I messed that up (I meant int 21h)
"Sufficiently advanced stupidity is indistinguishable from malice."
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Post by Fergo »

Thanks again! I've tried and it worked pretty good.
I have another problem, so instead of creating a new topic I'm gonna ask here.
I've seen MikeOS source and it has a rustic API implementation. It's basically a lof of functions calls at the start of the kernel, and the address of this functions do not change, so third party programs can call them by a simples "call addr".

I'm writing my kernel in C, but I can't figure out how to do something similar. I have my functions (like Putch(), Getch(), etc.) in C using inline asm (using TC++ 3.0), and some of this functions have arguments (like the Putch, where the argument is the character to print):

Code: Select all

void putch(unsigned char c) {
    asm mov ah, 0x0E
    asm mov al, c
    asm int 0x10
}
I don't know exactly how to handle the arguments during the API call (which call the function at the kernel start and then, the real function is called). In asm is simple, because there isn't "arguments" in "functions". The value is passed directly to the registers by "mov" or by "push", and the API call it is really just a "call addr". I want to keep it close to C syntax, so when the user is creating an application to my OS and wants to print a character on screen, he just do "Putch('f');"

I'm sorry if I wasn't clear, and english is not my first language =/

Thanks in advance,
Fergo
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

Fergo wrote:I don't know exactly how to handle the arguments during the API call (which call the function at the kernel start and then, the real function is called).
You should look into how stack frames are organized in C, and how you could manipulate them to get the desired result. It is possible, but not trivial. Also, if you just use the function name in C, the linker is going to link it to that function. This means you need a stub function that calls the single kernel API dispatch function, which in turn calls the real function.


JAL
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Post by Fergo »

Dex, I was analyzing your code from MiniDos again and then I realized that I did not understand what I thought I did. I'm confused in the part where you load the .com file to memory and passes execution to it.
I'm sorry to bother you, but can you explain with more details how the .com file is loaded and executed in MiniDOS and which registers should I change so the executable can run and return properly?

I've created my own code to run the "bounce.com" file included in MiniDos. The application runs, but crash the system when it finishes. That's why I opened MiniDos code to read again.

Thanks in advance,
Fergo
Image
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Post by Fergo »

Sorry for the double post, but here is the code of my Kernel, which is loaded at 0AC0:0000 and the bounce.com resides at 0AC0:0100:

Code: Select all

BITS 16

mov     bx, 0x0AC0
mov     ds, bx

mov     bx, 0x0AC0
mov     es, bx

;video mode to 80x25
mov     ah, 0x00
mov     al, 0x03
int     0x10

;write 'F' just for test
mov 	al, 'F'
mov     ah, 0x0E
int     0x10

;wait for keypress
mov     ah, 0x00
int     0x16

;save some regs, call to the .com address, and restore the regs
push ss
push sp
pusha
call 0x0AC0:0x0100
popa
pop sp
pop ss

;write 'E' for test
mov 	al, 'E'
mov     ah, 0x0E
int     0x10

;wait for or keypress
mov     ah, 0x00
int     0x16

TIMES 256-($-$$) DB 0

incbin "tetris.com"
As I said, bounce.com is loaded and executed, but crashes the system when I press "ESC" to end the application. Tetris and Invaders dont work.

Thanks again,
Fergo
Image
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Hi, first of all you need to code the int 21h functions and hook them up before invader or tetris will work.
Now to run a com file (that does not use any dos int's)
It needs something like this:
COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h
In the above case the com file would be loaded to 60h.

But do you really need a true com file format ?.
For your own OS is much simpler to have your own file format and use a simple "ret" , let me know if you just want a loadable file (eg: simple bin file) or you do want a true com file loader and i will try and help you.
User avatar
Fergo
Member
Member
Posts: 27
Joined: Fri Oct 19, 2007 3:11 pm
Contact:

Post by Fergo »

Thanks for the information Dex.
About the file format: actually the only thing I want is to load applications, don't matter in which format, so I don't need to put everything into the same binary of my kernel.
I chose .com files because I thought they were the most simple ones, and as they are pretty common, I could load "third party" applications in my OS (like you did with Tetris/Invaders in MiniDos) without any troubles (I guess I was wrong...)
I didn't knew about the int 21 thing. I was supposing that the interruptions would be there, intact, and ready for use as long as I don't "overwrite" them.

As running .com files are not like I imagined, right now the only thing I want is some guidelines on how to setup the stack/regs to run some binary file (plain, .com, whatever) and return to my OS without any problem. I accept any suggestions, of course :)

Thanks a lot Dex! I'm sorry for taking you time with this questions.

Regards,
Fergo
Image
User avatar
zaleschiemilgabriel
Member
Member
Posts: 232
Joined: Mon Feb 04, 2008 3:58 am

Post by zaleschiemilgabriel »

If you're writing your OS from scratch, there's no BIOS function that will do that for you, and BIOS is all you have to start with. If you want to load and execute specific file formats, you'll have to find a file format description and use BIOS int 13h to load the file from disk, then execute it:
* If you want to run DOS programs, you have to write support for all the int 21h functions, as DeX said. If you do this, then your question becomes invalid, because there's an int 21h that loads and executes programs and you will have already implemented that too.
* If you just want to run .com programs that don't use or rely on int 21h (or any other interrupts available in DOS), I think it's enough to load the .com file into memory and then jump at the location where you loaded it... This is just an idea. There are many ways to execute programs. It all depends on the format you want to use and what kind of support you are prepared to implement for it.
jal
Member
Member
Posts: 1385
Joined: Wed Oct 31, 2007 9:09 am

Post by jal »

zaleschiemilgabriel wrote:* If you want to run DOS programs, you have to write support for all the int 21h functions
Of course it's not that black&white. You could also implement the most used int 21h calls, and not others. You could decide which programs to run in your OS, check which calls they make, and implement only those.


JAL
Post Reply