Mr. Shickadance
Mr. Shickadance

Reputation: 5473

How to do a call far (x86) to a given 32-bit address?

Ok, I need to perform a CALL FAR to the PCI BIOS service directory (32 bit mode) to verify that the PCI BIOS is present.

NOTE: I am developing a simple disk driver for a simple operating system we are developing a college. I understand that this is very specific, but I will be doing all this from kernel code.

Suppose I already found the relevant address. What is the proper assembly language to perform a far call to a given address? Can someone post some assembly code that does a far call to a given 32-bit address? The syntax of the examples I have seen so far has been confusing.

Thanks!

EDIT: In my specific case, I have already found the PCI BIOS service directory, which gives me the physical address (32-bit). Given this 32-bit address, what type of far call will I need? For example, I was reading in the Intel manuals that far calls can change tasks and what not. How will I know what I have to do to far call this PCI BIOS service directory physical address?

UPDATE:

Here is some code I found which is confusing me (inline):


    asm("lcall (%%edi)"
        : "=a" (return_code),
          "=b" (address),
          "=c" (length),
          "=d" (entry)
        : "0" (service),
          "1" (0),
          "D" (&bios32_indirect));

I found that in this source file: http://www.pell.portland.or.us/~orc/Code/Archive/linux-1.2.13/arch/i386/kernel/bios32.c

I think what I want to do is the equivalent of the above inline in actual assembly.

Upvotes: 5

Views: 4980

Answers (3)

E.T
E.T

Reputation: 1145

It would certainly help if you mentioned what OS you're working on. Let's say that it's Windows 32Bit then assuming that you know the physical address for sure, you still have to get the PTE related to it. You can't just make a call to that particular address since you're in protected mode and the address you have is a virtual address. You can map the physical to virtual but it's complicated.

If you want to see if it you could even look at what's at that address, use WinDBG and do a:

!dd <address>

This will display the DWORD at the physical address you specified. The physical to virtual translation is simple when you know what to do (looking at CR3 won't help you :)

Now, if you're using a different OS, that's a different story because the PTE is mapped differently.

Also, like mentioned before, you can't just make a call to the bios since it's actually 16bit and not 32bit. In protected mode (in the i386 and possibly later) there was a specific technique you could use vx86 or something along those lines, but I forgot the exact term. Was feasible but very costly because it involved a task switch and miscellaneous other things.

If you need to develop a disk driver then the hardware people in your group should be able to provide you with the ports available to you so that you can make IO calls to the device, eliminating the need to access the BIOS.

Upvotes: 0

rajnesh
rajnesh

Reputation: 21

From the manual:

to make a asm call use the below format

asm(  command1 %0
      command2
      :output registers with there mapping to variable
      :input registers with mapping.
   );

example
    asm ("movl %1, %%ebx;"
         "movl %%ebx, %0;"
         : "=r" ( val )
         : "r" ( no )
         : "%ebx"         // clobbered register
        );

    here %1 is input variable %0 is output.

To make a lcall you need segment and actual 32 bit address:

bios32_indirect.address = directoy_address;
  uint32 kernelcodesegment = 0;
  asm ("movl %%cs, %0;"
       : "=r" (kernelcodesegment)
       :);
bios32_indirect.segment = kernelcodesegment;

Upvotes: 2

Michael
Michael

Reputation: 55415

If memory is flat, i.e., CS has a base of 0 and covers entire 32-bit address space

call <address>

Where address is the 32-bit target address.

EDIT: Ah, I see you have a physical address. I'm presuming this is for a device driver running on Linux. I don't have any experience with the linux kernel, but I'd presume that this physical address isn't mapped 1:1 to a virtual address. You need to get it mapped to a virtual address (sorry, don't know how in Linux), and then call that virtual address.

But this raises the question of what PCI BIOS function you need, going directly to the BIOS outside of the OS is usually the wrong approach.

Upvotes: 1

Related Questions