flat assembler
Message board for the users of flat assembler.

Index > OS Construction > far calls

Author
Thread Post new topic Reply to topic
andy1101



Joined: 05 Jul 2017
Posts: 2
andy1101 07 Jul 2017, 06:23
I'm sorry if my question is silly, I'm new to fasm and x86 architecture. I am trying to write a bootloader which loads the second part of bootloader. Everything works pretty fine, i saw in the memory dump that next part of the bootloader has been loaded correctly and i was able to execute code from the next part of bootloader. The problem is that i have difficulties with jmps and calls to the code in the first part of bootloader. I managed to jmp to the code in the first part of bootloader using jmp 0x0000:label. But i still can't call functions from the first part, i tried call far label, call 0x0000:label, far call label etc. Nothing of these worked. So how to implement far calls in fasm in real mode??? (I'm testing my bootloader in bochs by the way).

Here is my code (The next bootloader starts in line 260 (boot2) where i have troubles with calling function from the previous part):


Code:
; kernel's boot loader for x86 architecture
format Binary as "bin"                                                                                                          ;control directive, as "bin" is specifying the default file extension
org 0x7C00                                                                                                                                      ;base address of the code in RAM (to calculate labels)
jmp boot                                                                                                                                ;unconditional transition to boot (main part of boot loader)

;header of ListFS
align 4                                                                                                                                         ;next address will be multiple of 4 bytes

fs_magic dd ?                                                                                                                           ;dd - define double word (4 bytes)
fs_version dd ?
fs_flags dd ?
fs_base dq ?                                                                                                                            ;dq - define quadro word (8 bytes)
fs_size dq ?
fs_map_base dq ?
fs_map_size dq ?
fs_first_file dq ?
fs_uid dq ?
fs_block_size dd ?

;File header

virtual at 0x800
f_info:
        f_name rb 256                                                          ;rb - reverse number of bytes
        f_next dq ?
        f_prev dq ?
        f_parent dq ?
        f_flags dq ?
        f_data dq ?
        f_size dq ?
        f_ctime dq ?
        f_mtime dq ?
        f_atime dq ?
end virtual

;data of boot loader                                                                                                                                            ;
label sector_per_track word at $$                                                                                       ; The number of sectors on one track
label head_count byte at $$ + 2                                                                                         ; The number of heads in the drive
label disk_id byte at $$ + 3                                                                                            ; $$ is the base address of code (0x7C00)
;boot_msg db "YarzOS boot loader. Version 0.04",13,10,0                                         ; db - define byte right here (or array of bytes) 
reboot_msg db "Press any key...",13,10,0                                                                        ;13 - new line, 10 - back to the begining 0 - end of string
boot_file_name db "boot.bin",0
;Print function
write_str:
        push ax                                                                                                                                 ;save the values of ax (data reg) and si (index reg) in steck so they won't be erased
        push si 
        mov ah, 0x0E                                                                                                                    ; ah sets the mode for BIOS int 0x10 function ah=0Eh - Teletype output, al -character
@@:                                                                                                                                     ;@ is anonymus label @b - backward @f - forward
        lodsb                                                                                                   ; [DS:SI] --> AL/AX and SI++
        test al, al                                                                                                                         ; check if at least one bit is equal to one 
        jz @f                                                                                                   ;conditional transition if zero condition 
        int 0x10                                                                                                                                ; BIOS int function (Video Services)
        jmp @b                                                                                                                                  ;return back
@@:
        pop si                                                                                                                                  ;grab si and ax old values from steck (si and ax go in the opposit order couse steck is FILO memory)
        pop ax
        retf
; critical error
error:
        pop si
        call write_str
;Reboot
reboot:
        mov si,reboot_msg                                                                                                               ;move the address of reboot_msg to SI (index reg)
        call write_str
        xor ah, ah                                                                                                                              ;ah = 0 - Read key press for BIOS int func 0x16
        int 0x16                                                                                                                                ;BIOS int func 0x16 - Keyboard services
        jmp 0xFFFF:0                                                                                                                    ;reboot (entry point to BIOS)
; Loading of sector DX:AX (flash) in buffer ES:DI (RAM)
load_sector:
        cmp byte[sector_per_track], 0xFF
        je .use_EDD
        push ax 
        push bx
        push cx
        push dx
        push si
        div [sector_per_track]                                                                                                  ;DX:AX/sector_per_track = AX - quotient DX - excess
        mov cl, dl                                                                                                                              ; quotient is sector number - load it to CL
        inc cl                                                                                                                                  ; Sectors unlike the other things starts with one
        div [head_count]                                                                                                                ; quotient/head_count 
        mov dh, ah
        mov ch, al
        mov dl, [disk_id]
        mov bx, di                                                                                                                              ; BX = offset (in RAM).  ES=segment already (in RAM)
        mov al, 1                                                                                                                               ; AL = number of sectors to load
        mov si, 3                                                                                                                               ; Number of trys
 @@:
        mov ah, 2                                                                                                                               ; ah = BIOS func number
        int 0x13                                                                                                        
        jnc @f                                                                                                                                  ; error (carry flag has been set)
        xor ah, ah                                                                                                                              ; ah=0
        int 0x13
        dec si
        jnz @b
 .error:
        call error
        db "DISK ERROR",13,10,0
 @@:
        pop si 
        pop dx
        pop cx 
        pop bx
        pop ax
        ret
 .use_EDD:                                                                                                      ;Enhanced Disk Drive
        push ax 
        push ax
        push dx
        push si
        mov byte[0x600], 0x10                                                                   ;loading stracture for BIOS service function 0x10 - 16 bytes the size of the stracture
        mov byte[0x601], 0                                                                              ;unused - should be zero
        mov word[0x602], 1                                                                              ;Read one sector (the number of sectors to be loaded)
        mov [0x604], di                                                                                 ;offset
        push es
        pop word[0x606]                                                                                 ;segment(in RAM)
        mov [0x608], ax                                                                                 ;less significant part of sector number (on Flash)
        mov [0x60A], dx                                                                                 ;most significant part of sector number (on Flash)
        mov word[0x60C], 0                                                                              ;                                                               
        mov word[0x60E], 0                                                                              ; 2 Tb max 
        mov ah, 0x42                                                                                    ;code of 0x13 BIOS interrupt func, loading from disk
        mov dl, [disk_id]                                                                               ;restore disk number for func 
        mov si, 0x600                                                                                   ;the address of stracture for func
        int 0x13                                                                                                ;call the function
        jc .error                                                                                               ; if carry flag is on then an error occured
        pop si 
        pop dx
        pop ax
        ret


; Searching for file with name in DS:SI in the catalog in DX:AX
find_file:
        push cx dx di                                                                                   ; Save the registers
.find:
        cmp ax, -1                                                                                          ; Check if we are in the end of the list
        jne @f
        cmp dx, -1
        jne @f
.not_found:                                                                                             ; If we have reached it then we should print an error message
        call error
        db "NOT FOUND",13,10,0
 @@:
        mov di, f_info
        call load_sector                                                                                ; Load sector with file info
        push di                                                                                                 ; Following is the code of determination of file name length (DI = f_info = f_name)
        mov cx, 0xFFFF
        xor al, al
        repne scasb                                                                                             ; repne - repeat string operation (until not equal) scasb (scan string) - Compare AL with byte at ES:(E)DI and set status flags
        neg cx                                                                                                  ; scasb decrements cx
        dec cx                                                                                                  ; now cx contains the number of bytes in file name                                                                                      
        pop di
        push si                                                                                                 ; compare the names of files
        repe cmpsb                                                                                              ; repe - repeat while equal, cmpsb - compare bytes
        pop si                                          
        je .found                                                                                               ; If it matches then quit
        mov ax, word[f_next]                                                                    ; Load the number of next file 
        mov dx, word[f_next + 2]
        jmp .find                                                                                               ; Continue the cycle
 .found:
        pop di dx cx                                                                                    ; Restore the registers
        ret                                                                                                     ; Quit
        
; Loading of current file into RAM on address in BX:0. The number of loaded sectors is in AX
load_file_data:
        push bx cx dx si di                                                                     ; Save the registers
        mov ax, word[f_data]                                                                    ; Load to DX:AX the number of sector with first list of file's sectors
        mov dx, word[f_data + 2]
 .load_list:    
        cmp ax, -1                                                                                              ; Check if we are in the end of the list
        jne @f
        cmp dx, -1
        jne @f  
 .file_end:                                                                                             ; We have loaded the file 
        pop di si dx cx                                                                                 ; Restore all registers exept BX
        mov ax, bx                                                                                              ; Memorize BX
        pop bx                                                                                                  ; Restore its old value
        sub ax, bx                                                                                              ; Find the difference - this will be the size of file in blocks of 16 bytes
        shr ax, 9 - 4                                                                                   ; Convert to sectors
        ret                                                                                                     ; Quit
 @@:
        mov di, f_info                                                                                  ; Load the list of file's sectors in the temproraly buffer
        call load_sector
        mov si, di                                                                                              ; SI := DI
        mov cx, 512 / 8 - 1                                                                     ; Number of sectors in the list
 .load_sector:
        lodsw                                                                                                   ; Load the next number of sector, lodsw - loads next char into ax or ax,ax
        mov dx, [si]
        add si, 2
        cmp ax, -1                                                                                              ; Check if we are in the end of the list
        jne @f
        cmp dx, -1
        je .file_end                                                                                    ; If we are in the end then quit
 @@:
        push es
        mov es, bx                                                                                              ; Load the next sector to the right address
        call load_sector
        add bx, 0x200 / 16                                                                              ; The address of the next sector is 512 bytes more
        pop es
        loop .load_sector                                                                               ; Данная команда уменьшает CX на 1 и, если он ещё больше нуля, переходит на метку .load_sector
        lodsw                                                                                                   ; Загружаем в DX:AX номер следующего списка
        mov dx, [si]
        jmp .load_list                                                                                  ; Переходим в начало цикла по спискам секторов
        
        
;Boot loader entry point
boot:
        jmp 0:@f                                                                                                                                ;??? jump to the first @ label of the boot loader 
@@:
        mov ax,cs                                                                                                                               ;ax - data reg, cs - code segment reg (segment = 512 bytes), ds - data segment reg, es - another data segment reg                                                                                                                               
        mov ds,ax                                                                                                                               ;set to zero all address regs (maybe cs = 0 - first code segment)
        mov es,ax 
;stack settings
        mov ss,ax                                                                                                                               ;ss - stack segment ( = 0) 
        mov sp,$$                                                                                                                               ;sp -stack pick , $$ - base address of boot loader set by org 
;enable interrupts
        sti
;memorize the number of boot drive
        mov [disk_id],dl
;Prin the message
        ;mov si, boot_msg                                                                                                               ;SI is needed for lodsb
        ;call write_str
;Determining the parameters of boot drive
        mov ah, 0x41
        mov bx, 0x55AA                                                                                                                  ;???
        int 0x13
        jc @f
        mov byte[sector_per_track], 0xFF
        jmp .disk_detected
 @@:
        mov ah, 0x08                                                                                                                    ;0x0800 - address in Flash to be loaded from 
        xor di, di                                                                                                                              ;offset 
        push es                                                                                                                                 ;ES=segment already
        int 0x13
        pop es
        jc load_sector.error
        inc dh                                                                                                                                  ;load the parameters
        mov [head_count], dh
        and cx, 111111b
        mov [sector_per_track], cx
 .disk_detected:
        ; Loading of the next bootloader
        mov si, boot_file_name
        mov ax, word[fs_first_file]
        mov dx, word[fs_first_file + 2]
        call find_file
        mov bx, 0x7E00 / 16
        call load_file_data
        ; jump to the next bootloader
        jmp boot2       
;Empty space for boot loader signature (0x55,0xAA)
        rb 510 - ($ - $$)
        db 0x55,0xAA
        
; data for the next bootloader
load_msg_preffix db "Loading '",0
load_msg_suffix db "'...",0
ok_msg db "OK",13,10,0
        ; next bootloader entry point 
boot2:
        ; turminating
        mov si, load_msg_preffix                                                                                                                ;SI is needed for lodsb
        call write_str
        jmp 0x0000:reboot               
        
; Spliting the string DS:SI by slash
split_file_name:
        push si
 @@:
        lodsb
        cmp al, "/"
        je @f
        jmp @b
 @@:
        mov byte[si - 1], 0
        mov ax, si
        pop si
        ret
                
; Loading of the file with name in DS:SI in buffer BX:0. The size of the file in sectors returns in AX
load_file:
        push si
        mov si, load_msg_preffix
        call write_str
        pop si
        call write_str
        push si
        mov si, load_msg_suffix
        call write_str
        pop si
        push si bp
        mov dx, word[fs_first_file + 2]
        mov ax, word[fs_first_file]
 @@:
        push ax
        call split_file_name
        mov bp, ax
        pop ax
        call find_file
        test byte[f_flags], 1
        jz @f
        mov si, bp
        mov dx, word[f_data + 2]
        mov ax, word[f_data]
        jmp @b  
 @@:
        call load_file_data
        mov si, ok_msg
        call write_str
        pop bp si
        ret


        

    
Post 07 Jul 2017, 06:23
View user's profile Send private message Reply with quote
Enko



Joined: 03 Apr 2007
Posts: 676
Location: Mar del Plata
Enko 07 Jul 2017, 15:12
I am probably not the best to answer this but as I remember in the far jump the first parameter was the index on the gdt table but that in protecte mode.


For real mode I think this could help:
Quote:
1.2.5 Jumps and calls
The operand of any jump or call instruction can be preceded not only by the size operator, but also by one of the operators specifying type of the jump: short, near of far. For example, when assembler is in 16-bit mode, instruction jmp dword [0] will become the far jump and when assembler is in 32-bit mode, it will become the near jump. To force this instruction to be treated differently, use the jmp near dword [0] or jmp far dword [0] form.

More reference:
here
https://flatassembler.net/docs.php?article=manual#2.1.6
and here
https://flatassembler.net/docs.php?article=manual#1.2.5

Cheers
Post 07 Jul 2017, 15:12
View user's profile Send private message Reply with quote
andy1101



Joined: 05 Jul 2017
Posts: 2
andy1101 07 Jul 2017, 16:23
Thank you for replaying, Enko. I read the fasm manual and tried both call dword 0x0000:write_str and call far dword 0x0000:write_str (write_str - is label of my function from the previous part of bootloader), but none of this worked, it seemed that my function hadn't been executed (bochs printed the following message:
[DMA] io write to address 0000000, len=2)

Also as far as i understood i don't need far calls at all cause the code segment limit should be 0x0000ffff, so i guess it means that i'm able to address 0xffff bytes of code.
So why i'm facing troubles with calls from the next part of bootloader?
Post 07 Jul 2017, 16:23
View user's profile Send private message Reply with quote
Enko



Joined: 03 Apr 2007
Posts: 676
Location: Mar del Plata
Enko 07 Jul 2017, 21:52
Wouldnt you need an org instruction in the second bootloader?

As I remember the bios will load the first 512bytes to 0x7C00 .
In the first part of the bootloader you read from the disk and copy it to memory.
If you don´t copy the second part of bootloader to memory the jump will fail because there wouldn´t be nothing after rb 510 - ($ - $$) db 0x55,0xAA

If you do indeed read the second stage of bootloader "boot2:" you should have something like:
Code:
org     0xZZZZZZ
boot2: 
; turminating 
        mov si, load_msg_preffix                                                                                                                ;SI is needed for lodsb 
        call write_str 
        jmp 0x0000:reboot 
    


I could be wrong of course.
Best regards
Post 07 Jul 2017, 21:52
View user's profile Send private message Reply with quote
Mike Gonta



Joined: 26 Dec 2010
Posts: 243
Mike Gonta 07 Jul 2017, 23:03
Enko wrote:
Wouldnt you need an org instruction in the second bootloader? ...
I could be wrong of course.
org 0x7C00 plus 512 is the load address (0x7E00) of the second sector.

_________________
Mike Gonta
look and see - many look but few see

https://mikegonta.com
Post 07 Jul 2017, 23:03
View user's profile Send private message Visit poster's website Reply with quote
Mike Gonta



Joined: 26 Dec 2010
Posts: 243
Mike Gonta 07 Jul 2017, 23:06
andy1101 wrote:
So why i'm facing troubles with calls from the next part of bootloader?
Wouldn't it be simpler to call load_sector directly.

_________________
Mike Gonta
look and see - many look but few see

https://mikegonta.com
Post 07 Jul 2017, 23:06
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 09 Jul 2017, 08:17
when you inspected memory in your debugger are you SURE that the data you saw was, in fact, the code that should have been there? opcodes require quite a bit of experience to interpret.

it looks like a bug in your CHS calculator.

-Stefan

_________________
byte me.
Post 09 Jul 2017, 08:17
View user's profile Send private message Visit poster's website 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.