Page 1 of 1

dynamic far call in 32-bit protected mode

Posted: Mon Aug 31, 2015 1:12 pm
by thxbb12
Hello all,

I'm writing a kernel that uses hardware task switching. To call a task, I need to do a far call to the TSS descriptor of the task (each task has a TSS descriptor in the GDT).
For example, to run task1, one would write:

Code: Select all

call_task1:
    call 0x20:0
    ret
For task2 (provided it's the next descriptor in the GDT), it would be:

Code: Select all

call_task1:
    call 0x28:0
    ret
and so on...
It's totally unflexible and I don't want to hardcode the segment selector. It needs to by dynamic. Ideally, it should be something like this, where the argument is the task selector of the task we want to call:

Code: Select all

call_task:
    call [esp+4]:0
    ret
However, such code is not permitted. Therefore, I thought of writing some self-modifying code to change the segment descriptor, like this:

Code: Select all

call_task:
    ; Opcodes for the far call 0x1234:0x2694
    ; 9a 94 26 00 00 34 12 	lcall  $0x1234,$0x2694
    push    ebp
    mov     ebp,esp
    push    ds
    push    ebx
    push    eax
    mov     bx,cs
    mov     ds,bx
    mov     dword ebx,(.selfmod+4)
    mov     ax,[ebp+8]
    mov     word [ebx],ax    ; change the 0xFF below to the contents of AX
    pop     eax
    pop     ebx
    pop     ds
    pop     ebp
.selfmod:
    call    0xFF:0
    ret
Basically, I store cs into ds in order to be able to reference the .selfmod label. Then, I modify the 16-bit data located 4 dword further to the value of the selector passed in argument.
However, it doesn't work.
I suspect the way I get the address of the .selfmod label is not correct.

Does anyone have an idea how I can write a version of my call_task where the code would do a far jump to the selector passed in argument?

Thanks a lot!

Re: dynamic far call in 32-bit protected mode

Posted: Mon Aug 31, 2015 1:44 pm
by kzinti
Looks like you need to use the "far indirect" addressing mode (opcode FF/3).

See:
http://x86.renejeschke.de/html/file_mod ... id_26.html

Re: dynamic far call in 32-bit protected mode

Posted: Mon Aug 31, 2015 2:33 pm
by thxbb12
kiznit wrote:Looks like you need to use the "far indirect" addressing mode (opcode FF/3).

See:
http://x86.renejeschke.de/html/file_mod ... id_26.html
Thanks.

However, I'm not sure about the right syntax. The nasm manual isn't very clear on this.
I tried various syntaxes without any success.
What's the proper syntax?

Thanks!

Re: dynamic far call in 32-bit protected mode

Posted: Mon Aug 31, 2015 2:56 pm
by kzinti
Something like:

Code: Select all

call far [ebx]
where ebx points to 6 bytes (2 high order bytes = selector for CS and 4 low order bytes = offset for EIP).

From http://www.posix.nl/linuxassembly/nasmd ... mdoca.html, section A.13:
The CALL FAR mem forms execute a far call by loading the destination address out of memory. The address loaded consists of 16 or 32 bits of offset (depending on the operand size), and 16 bits of segment. The operand size may be overridden using CALL WORD FAR mem or CALL DWORD FAR mem.

Re: dynamic far call in 32-bit protected mode

Posted: Mon Aug 31, 2015 4:26 pm
by thxbb12
Thanks for the clarification.
Here is the implementation I wrote which works perfectly :-)

Code: Select all

section .bss:
tss_sel_seg  dw 0
tss_sel_offs  dd 0

section .text:

; void call_task(uint16_t task_tss_selector)
call_task:
    lea      ebx,[tss_sel_seg]
    mov    ax,[esp+4]
    mov    [ebx+4],ax
    call     far [ebx]
    ret