flat assembler
Message board for the users of flat assembler.

Index > OS Construction > loading program (real mode)

Author
Thread Post new topic Reply to topic
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 25 Mar 2009, 23:28
Hi,
I'm writing a real mode os,till now I'm able to load and execute .com programs,I load my kernel and programs at the same segment
which is 0x1000:0x0000,right now I'm trying to load programs at different
segment which is 0x2000:0x0000,but all what I get is garbage,
here's my code:
please note offset starts with the value 0x100

Code:
loadfile:
    mov     ax,[cluster]                    
    call    load_fat                        ;load fat table into memory
 mov     ax,word [cluster]
   xor     bx,bx
load_file:
        push    ax                                   ;save cluster number                  
        sub     ax,2                    
        add     ax,33
 call    lba_to_chs                      ;convert from LBA to CHS
    push    ax      
    mov     ax, 0x2000                      ;load program into 0x2000:offset                            
    mov     es, ax
      xor     ax                              
    mov     bx,[.offset]                    ;now load...
        mov     ah,02                           
    mov     al,01
       int     13h
 pop     ax                              ;get cluster back
   call    getcluster                      ;check for the next cluster
 cmp     ax,0x0FF8                       ;is it the end of the file?
 jae     .end                            ;yes...
     add     word [.offset],512              ;no,add 512 byte to the offset
      jmp     load_file                       ;continue
.end:
      call    execute_program
     ret
    


Code:
execute_program:

  pusha                           ;save everything...                     
    push ds
     push es
     pushf
        call 0x2000:0x0100         ;jump to the program
        popf
        pop es                          ;restore everything
 pop ds
      popa
        clc
 ret
    
Post 25 Mar 2009, 23:28
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4073
Location: vpcmpistri
bitRAKE 26 Mar 2009, 04:12
Nothing posted here seems incorrect.

Where does it go wrong?

The CALL to $2000:$0100 does not happen?
Post 26 Mar 2009, 04:12
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 26 Mar 2009, 13:37
humm...

when I load my programs at the same segment of my kernel,
I just call like this:
Code:
call      0x100    

and every ting works well.

my kernel is loaded at segment 0x1000:0x0000,and I want to load
programs at 0x2000:0x0100
when I execute the previous code I get garbage,what do I need to change?do I need to change the CS to 0x2000?
Post 26 Mar 2009, 13:37
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1905
DOS386 26 Mar 2009, 14:28
> when I load my programs at the same segment

What address inside ?

> of my kernel, I just call like this:
> call 0x100

How big is your "kernel" ?

> do I need to change the CS to 0x2000?

YES. You need a far call and far return.

> call 0x2000:0x0100 ;jump to the program

But this seems to do the job.

But you seem to load at $2000:0 and start at $2000:$0100 ... do your executables begin with 256 empty Bytes ?
Post 26 Mar 2009, 14:28
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4353
Location: Now
edfed 26 Mar 2009, 17:10
cool tip:

instead of manipulating immediate values for far addresses,
use a single dword to store that address
Code:
address dd 1234h:5678h  ; all theses three lines output the same 
offset = 0
segment = 2
; address dw 5678h,1234h 
; address dd 12345678h
...
mov word[address+offset],100h
mov word[address+segment],1000h
mov eax,address
call far dword[eax]
jmp far dword[eax]
...
    


this have the advantage to manipulate a structure

about .com loading in another segment:
the PSP (the memory between cs:0 and cs:0ffh) is there for system interfacing.
__1/ create the psp
Code:
psp dd 1000h:0

    

____a/ copy this basic bloc of instructions at psp=[1000h:0]
Code:
        org 0  
        ...; initialise registers
        mov ax,100h
        call ax
        ...; check error messages
        retf ; return to OS
        ...
    

____b/ create the features you want within the spare memory before 100h

__2/ copy the .com program at psp=[1000h:0+100h]
______° the .com program should begin with this bloc of instructions:
Code:
org 100h
    

______° the .com program should quit with this bloc of instructions:
Code:
;mov ax,3 ; for msDOS Sad
;int 10h   ; for msDOS Sad
ret   
    

__3/ call the PSP
Code:
mov eax,psp
call far dword[eax]
    
Post 26 Mar 2009, 17:10
View user's profile Send private message Visit poster's website Reply with quote
Dex4u



Joined: 08 Feb 2005
Posts: 1601
Location: web
Dex4u 27 Mar 2009, 07:06
You need to set the reg before jumping to it eg:
Code:
ImageLoadSeg              equ     60h
;;;;;;;;;;;;;;;;;;;
;; Type checking ;;
;;;;;;;;;;;;;;;;;;;

        cli                             ; for stack adjustments
     mov     ax, ImageLoadSeg
    mov     es, ax
      cmp     word [es:0], 5A4Dh  ; "MZ" signature?
 je      RelocateEXE             ; yes, it's an EXE program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     ax, es
      sub     ax, 10h                 ; "org 100h" stuff Smile
     mov     es, ax
      mov     ds, ax
      mov     ss, ax
      xor     sp, sp
      push    es
  push    word 100h
   jmp     Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relocate, setup and run EXE program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RelocateEXE:
      mov     ds, ax
      add     ax, [ds:08h]                ; ax = image base
   mov     cx, [ds:06h]                ; cx = reloc items
  mov     bx, [ds:18h]                ; bx = reloc table pointer
  jcxz    RelocationDone
ReloCycle:
    mov     di, [ds:bx]         ; di = item ofs
     mov     dx, [ds:bx+2]               ; dx = item seg (rel)
       add     dx, ax                  ; dx = item seg (abs)
       push    ds
  mov     ds, dx                  ; ds = dx
   add     [ds:di], ax         ; fixup
     pop     ds
  add     bx, 4                   ; point to next entry
       loop    ReloCycle
RelocationDone:
    mov     bx, ax
      add     bx, [ds:0Eh]
    mov     ss, bx                  ; ss for EXE
        mov     sp, [ds:10h]                ; sp for EXE
        add     ax, [ds:16h]                ; cs
        push    ax
  push    word [ds:14h]               ; ip
Run:
    mov     dl, [cs:bsDriveNumber]      ; let program know boot drive
       mov     dh, 0xff                ; let DexOS know it booted from bootprog
    sti
 retf

    

Example if ImageLoadSeg is 60h, than a com would be
dl = boot drive number
cs:ip = program entry point
ss:sp = program stack (don't confuse with boot sector's stack)
COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h

Also take a look at MiniDos
Post 27 Mar 2009, 07:06
View user's profile Send private message Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 28 Mar 2009, 11:33
Hi,
Thank you guys for your help,now I can execute programs
successfully Smile ,but I still have a problem,so after finishing the execuion
of the program I can't return to my os.

The os sometimes reboot,and sometimes just freeze
here's my code:

Code:
loadfile:
    mov     ax,[cluster]                    
    call    load_fat                        ;load fat table into memory
 mov     ax,word [cluster]
   xor     bx,bx
load_file:
        push    ax                                   ;save cluster number                  
        sub     ax,2                    
        add     ax,33
 call    lba_to_chs                      ;convert from LBA to CHS
    push    ax es   
    mov     ax,0x2000
   mov     es,ax                           
    mov     bx,[.offset]                    ;now load...
        mov     ah,02                           
    mov     al,01
       int     13h
 pop     ax                              ;get cluster back
   call    getcluster                      ;check for the next cluster
 cmp     ax,0x0FF8                       ;is it the end of the file?
 jae     .end                            ;yes...
     add     word [.offset],512              ;no,add 512 byte to the offset
      pop     es ax
       jmp     load_file                       ;continue
.end:
      pop     es ax
       call    execute_program
     ret
    


Code:
execute_program:

  mov     ax,0x2000               ;set regs to the adress of the loaded program
       mov     ds,ax
       mov     es,ax
       mov     fs,ax
       mov     gs,ax
       
    call 0x2000:0x0100          ;jump to the program
                                                
.end:                   

        sti
 retf                            ;get cs/ip back from the stack
      mov     ax,0x1000               ;set regs to the adress of the kernel   
    mov     ds,ax
       mov     es,ax
       mov     fs,ax
       mov     gs,ax
       ret

    


Please note that my kernel is loaded at 0x1000:0x0000 and it's less than
64k and programs are loaded at 0x2000:0x100
Post 28 Mar 2009, 11:33
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 28 Mar 2009, 11:57
What is the retf for? I think you don't need it.

BTW: You seem to be running your program on the kernel's stack. Your program can also corrupt your ret address on the stack.
Post 28 Mar 2009, 11:57
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 28 Mar 2009, 13:06
Quote:
What is the retf for? I think you don't need it.

when I do call 0x2000:0x100 the current values of CS/IP are pushed onto
the stack before executing at the new position.
the retf will pops the return segment/offset from the stack into CS/IP and switches execution to that address.

Quote:
BTW: You seem to be running your program on the kernel's stack. Your program can also corrupt your ret address on the stack

humm...
in this case I need to make a stack for the programs,
if so does it need to be in the same segment?
I mean does it need to be in 0x2000 segment?

Thanx.
Post 28 Mar 2009, 13:06
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 28 Mar 2009, 13:24
abuashraf wrote:
Quote:
What is the retf for? I think you don't need it.

when I do call 0x2000:0x100 the current values of CS/IP are pushed onto
the stack before executing at the new position.
the retf will pops the return segment/offset from the stack into CS/IP and switches execution to that address.
In that case then, nothing you put after the retf is executed because the CPU will execute from the restored address on the stack by the retf. But you already have you near call return address on the stack (from the "call execute_program" line which will corrupt your retf return address.
abuashraf wrote:
Quote:
BTW: You seem to be running your program on the kernel's stack. Your program can also corrupt your ret address on the stack

humm...
in this case I need to make a stack for the programs,
if so does it need to be in the same segment?
I mean does it need to be in 0x2000 segment?
Your stack can be anywhere you like. But it might be a good idea to keep the program stack separate from the kernel stack.
Post 28 Mar 2009, 13:24
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 28 Mar 2009, 17:21
I've tried everything ,but nothing seems working,
I'm confused ,I satup a stack segment for the loaded programs,but
It didn't work Sad

Code:
execute_program:
      
    mov     ax, 0x3000
  mov     ss, ax                  ;set stack segment and pointer
      mov     sp, 0xF000
  
    mov     ax,0x2000               ;set regs to the adress of the loaded program
       mov     ds,ax
       mov     es,ax
       mov     fs,ax
       mov     gs,ax
       
    call 0x2000:0x0100          ;jump to the program
                                                
.end:                   

        mov     ax, 0
       mov     ss, ax                  ;get kernel stack back 
     mov     sp, 0xF000
  
    mov     ax,0x1000               ;set regs to the adress of the kernel   
    mov     ds,ax
       mov     es,ax
       mov     fs,ax
       mov     gs,ax
       retf                            ;get cs/ip back from the stack
    


would you please guide me, what's wrong with my code?

thanx.
Post 28 Mar 2009, 17:21
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 28 Mar 2009, 18:12
You can't use retf to return from execute_program because you called it with a near call, so the return must match with a retn. BUT, you are setting your stack to 0:f000 after the program returns (can I assume the program returns with retf? Since you called it with a far call.) so your original return address is most probably lost in some other part of memory.

You should save the position of the kernel stack SS and SP somewhere and then restore is again to the original values, then use a matching near return retn.
Code:
execute_program:
   ;save the kernal stack somewhere first
      mov     [mySavedKernelStackSS],ss
   mov     [mySavedKernelStackSP],sp
   ;save other kernel segments
 mov     [mySavedKernelStackES],es
   mov     [mySavedKernelStackFS],fs
   mov     [mySavedKernelStackGS],gs

        mov     ax, 0x3000
        mov     ss, ax                  ;set stack segment and pointer
        mov     sp, 0xF000             ;can also make it 0x0000

        mov     ax,0x2000               ;set regs to the adress of the loaded program
        mov     ds,ax
        mov     es,ax
        mov     fs,ax
        mov     gs,ax

        call 0x2000:0x0100              ;call the program

  ;restore other kernel segments
        mov   ax,0x1000
   mov     ds,ax
       mov     es,[mySavedKernelStackES]
   mov     fs,[mySavedKernelStackFS]
   mov     gs,[mySavedKernelStackGS]
   ;restore the kernel stack
   mov     ss,[mySavedKernelStackSS]
   mov     sp,[mySavedKernelStackSP]

        retn                            ;a matching near return, can't use retf since it was called with a near call    
Post 28 Mar 2009, 18:12
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4353
Location: Now
edfed 29 Mar 2009, 11:32
i gave you the solution of this kind of stuff but nobody saw it.

the PSP is there to help you.

the system is at a segment.
the program is at another segment.
the system will call the programm with a far call.
and the program will return with a near ret.
then, the psp is the bridge between the two.
and permitt to pass parameters too.
Post 29 Mar 2009, 11:32
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 29 Mar 2009, 17:31
Please guys be patient with me...

unfortunately It didn't work Sad ,some programs just restart itself from the
begining...
I've been trying this for more than 6 hours.
I'm testing my os using Bochs,so when
I quit I took a look at bochsout.txt it says:

Code:
prefetch: EIP [00010000] > CS.limit [0000ffff]
IRET: top 6 bytes of stack not within stack limits    


and here's the cpu registers:
Code:
  CS:f000( 1e00| 0|  0) 000f0000 0000ffff 0 0
  DS:0045( 0000| 0|  0) 00000450 0000ffff 0 0
  SS:41c3( 0000| 0|  0) 00041c30 0000ffff 0 0
  ES:2000( 0000| 0|  0) 00020000 0000ffff 0 0
  FS:2000( 0000| 0|  0) 00020000 0000ffff 0 0
  GS:2000( 0000| 0|  0) 00020000 0000ffff 0 0
  EIP=0000ff53 (0000ff53)    


and here's my int 20h implementation (quit from the program):

Code:
int20:
        cli                                 
        push          cs                            
        pop           bx                              
        mov         ds,bx                         
        mov           es,bx                         
        mov           ss,bx                         
        xor           sp,sp                        
        sti 
       call    _shell
      iret    


My kernel is loaded at 0x1000,and programs are loaded at 0x2000
so I think DS,SS,ES,FS,and gs should equal 0x2000
Post 29 Mar 2009, 17:31
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 29 Mar 2009, 17:38
You entered you app with call far so your app should return in kind with retf.

You can't mix your call/ret models because the stack will not be correct to get back the various registers.

If you want to use an int function to return from your app then the int function must restore the stack to the same state as the the kernel left it and then do a retf to get back the to original code after the call to the app.
Post 29 Mar 2009, 17:38
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 29 Mar 2009, 19:39
so in my int 20 function
I should do retf to get the CS/IP back from the stack
then restore kernel segments and restore the kernel stack
then return to my os,Am I right?
if this is right,what do I need to do in the "execute_program"
after the call?

Thanx.
Post 29 Mar 2009, 19:39
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20445
Location: In your JS exploiting you and your system
revolution 30 Mar 2009, 00:24
If your app does not properly preserve the stack then the int 20 function will have to do that. In your case above you have this:
Code:
        mov     ax, 0x3000
        mov     ss, ax                  ;set stack segment and pointer
        mov     sp, 0xF000              ;can also make it 0x0000    
so now the stack pointer is 3000:f000. And then you have this:
Code:
        call 0x2000:0x0100              ;call the program    
So now the stack pointer is 3000:effc and the top two words are the return address to the kernel restore location. So inside int 20 you could try this:
Code:
int20:
        mov     ax, 0x3000
        mov     ss, ax                  ;set stack segment and pointer
        mov     sp, 0xEFFC
        retf    
Post 30 Mar 2009, 00:24
View user's profile Send private message Visit poster's website Reply with quote
abuashraf



Joined: 11 Nov 2006
Posts: 88
abuashraf 30 Mar 2009, 14:29
Hi,

I've changed some stuff,so now I start loading my kernel at 0x2000:0x000
and programs are loaded at 0x3000:0x0000

after this changes and after trying what you adviced me in the last reply
now I'm able to successfuly quit of a simple "hello world" program,and
also another game called pitman.com.

but there are other games that I couldn't get out successfuly.
In the past when I loaded my kernel and programs at the same segment
I was able to get out of this games without any troubles.

so when I took a look at bochsout after trying the nonworking games
it gave me:

Code:
00266478000i[CPU0 ] |  CS:3000( 1e00| 0|  0) 00030000 0000ffff 0 0
00266478000i[CPU0 ] |  DS:3000( 0000| 0|  0) 00030000 0000ffff 0 0
00266478000i[CPU0 ] |  SS:4000( 0000| 0|  0) 00040000 0000ffff 0 0
00266478000i[CPU0 ] |  ES:3000( 0000| 0|  0) 00030000 0000ffff 0 0
00266478000i[CPU0 ] |  FS:3000( 0000| 0|  0) 00030000 0000ffff 0 0
00266478000i[CPU0 ] |  GS:3000( 0000| 0|  0) 00030000 0000ffff 0 0
00266478000i[CPU0 ] | EIP=00000c15 (00000c15)
00266478000i[CPU0 ] | CR0=0x00000010 CR1=0 CR2=0x00000000
00266478000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000    


I think this means that the cpu couldn't get its regs right values back.

So what do you think?what can I else do?
Post 30 Mar 2009, 14:29
View user's profile Send private message Reply with quote
GhostXoPCorp



Joined: 13 Dec 2008
Posts: 199
Location: 01F0:0100
GhostXoPCorp 04 Jun 2009, 21:38
this all makes my os seem simple Sad
Post 04 Jun 2009, 21:38
View user's profile Send private message Reply with quote
DOS386



Joined: 08 Dec 2006
Posts: 1905
DOS386 05 Jun 2009, 04:27
abuashraf wrote:
I'm writing a real mode os,till now I'm able to load and execute .com programs,I load my kernel and programs at the same segment


DOS compatible ???

Quote:
I've changed some stuff,so now I start loading my kernel at 0x2000:0x000 and programs are loaded at 0x3000:0x0000 after this changes and after trying what you adviced me in the last reply now I'm able to successfuly quit of a simple "hello world" program,and also another game called pitman.com. but there are other games that I couldn't get out successfuly. In the past when I loaded my kernel and programs at the same segment I was able to get out of this games without any troubles.

I think this means that the cpu couldn't get its regs right values back.

So what do you think? what can I else do?


What are the applications ? DOS COM ones ? You can exit a DOS COM by a near RET or INT $20 or INT $21 / AH=$4C ... also, DOS COM expects org $0100 while DOS MZ EXE expects org 0, both COM and MZ EXE expect to be preceded by a PSP serving various purposes, among others exiting a COM with a near RET Idea
Post 05 Jun 2009, 04:27
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.