Running bin file from a module

Hi I actually wrote a simple module and I need to call a bin file from that module. Could you give me some hints how to do that?
(I tried with stdlib.h and 'system()', but cannot call that function from a module).

Regards.

I assume module means kernel module.

The reason why system() doesn't work is b/c the libc functions are not available within the kernel. You can only access files and use its functions which are in the kernel. Therefore I don't know a good way of executing it from within the kernel. It actually is not a good thing to do anyway. You don't want to run userspace programs in kernel mode.
FWIW: I'm working on a kernel module myself and also use part of a different program, and what I did was to port the needed sourcecode into my program.

Maybe we can give you more help if you tell us what you want to do in a little more detail

You could check out the way the kernel runs INIT. That's one of the rare, few things the kernel actually runs (often the only one in fact).

I am writing network driver in linux for hardware with UEFI driver onboard (only basic functionality).
My driver is to load that UEFI driver and force it to work. Problem is that actually I do not have mentioned hardware and have to simulate that (just create sort of template).

You could do it with module dependencies instead of hacking it to run a userspace program to load a module dependency...

I will try to be more precise.
In final version my driver would load UEFI driver from hardware's flash.
But I do not have that hardware for now and I have to create sort of dummy driver first.

What I want is to load bin file from HDD (final version would load bin from hardware's flash). I assume, that loading bin from HDD and loading bin from flash is kind of similar task and I can use generic solution.

At this moment it does not matter what that bin file contains.

I wouldn't assume so. It's the kernel's job to make it generic.

Well, Corona688 I see you have very large knowledge about writing linux drivers, so I would be very pleased to receive any help from you.
Let's go to the very begining. I have such files:

SimpleBin:
void main() {
 write(2, "Write\n", 6);
}
CallSimpleBin:
#include <stdlib.h>

void main() {
  system("./SimpleBin");
}

Running 'CallSimpleBin' I can call 'SimpleBin'.
Now I would like to call SimpleBin from module:

SimpleModule:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

static int mymodule_init(void) {
 printk(KERN_ALERT "mymodule init\n");
/* here I would like to call SimpleBin */
 return 0;
}

static int mymodule_exit(void) {
 printk(KERN_ALERT "mymodule exit\n");
}
 
module_init(mymodule_init);
module_exit(mymodule_exit);
 

I also created static library:

SimpleLib:
void writeToScreen(char* str, int length) {
 write(2, str, length);
}

and I can call it from my user space application:

extern void writeToScreen(char* str, int length);

void main() {
 writeToScreen("Hi\n", 3);
}

it works. Unfortunatelly I cannot call 'writeToScreen' from module - it even could not compile.

Could you tell me some hints how I can do that?
I really apreciate any of your help.

I am confused. UEFI drivers are intended to extend firmware, have no OS dependence and have nothing to do with an operating system kernel.

How do you expect the kernel to load and interface with a UEFI driver? UEFI drivers can be 32 bit, 64-bit and more commonly EBC (Efi Byte Code). Have you read the Driver Writers Guide for UEFI?

Are you aware, for example, that 64-bit UEFI uses the Microsoft X64 calling convention whereas Linux uses the AMD64 calling convention.

//
// Unix/Linux arg passing:  RCX, RDX,  R8,  R9
//                                     RSI, RDI scratch 
//   UEFI/EFI arg passing:  RDI, RSI, RDX, RCX, R8, R9
//                                     Callee allocates 32 bytes on stack to spill registers
//                                     RSI, RDI callee-save
//
//   Mapping between registers
//
//   arg1   arg2    arg3   arg4   arg5     arg6      arg7       arg8
//
//   gcc:  (AMD64 ABI)
//   %rdi,  %rsi,  %rdx,  %rcx,    %r8,     %r9,     8(%rsp), 16(%rsp),  ....
//
//   efi:  (Microsoft X64)
//   %rcx,  %rdx,   %r8,   %r9,  32(%rsp), 40(%rsp), 48(%rsp), 56(%rsp), ....
//

You also need a UEFI-aware operating system of which there are a limited number out there. Recent 64-bit versions of Fedora/Redhat/etc.

If you describe exactly what you are trying to achieve - the big picture and not the how to - we can probably help you.

You are right. My friend is creating an UEFI emulator that redefine calls and do all necessary operations.
I need to take advantage of library already loaded (for concept purposes I assume library placed on HDD).
That solution is targeted to work on Redhat.

What I want for now is to make a kind of demo (concept).
It can be simple driver loading simple library and using it for e.g. printing to dmesg.

I've done enough work with them to know they are a severe challenge. I've occasionally had to alter some predefined values. I wrote a linux driver that prints 'hello world' to dmesg. I couldn't write a real driver yet.

But I know enough to tell you that windmills device drivers don't work that way. The kernel isn't going to reach into userspace, rip one function out of your userspace program, and run it raw because you don't get the same kind of stack; you don't get an ordinary heap; you don't get anything from libc; you don't get the same kind of files -- what does stderr even mean when you have no descriptor table? -- you don't get easy system calls like read() and write(); you don't even get easy, direct access to large amounts of available memory, and what memory there is is laid out in an alien way. The ease of all these things in userspace is a convincing illusion created by the kernel, more or less, and the way to use them is to be in userspace. Ordinary code can't run in kernel space any more than you could breathe in a vacuum.

Nearly all communication with the kernel is done through files and system calls instead. Your device driver can create a device file under /dev/ tied to your own kernel functions. someone opens it and your driver's read handler gets called, someone reads it and your device's read-handler gets called, etc. On boot, something in userspace could read from the ROM device and dump it into your special firmware-loading device file, and you'd be done.

1 Like

Well, let me try to summarize what we get for now:

  • it is impossible to load dll library / any other library from hdd/device's flash to RAM memory and take advantage of its functions by device driver (which I used to call just 'module'), isn't it?

  • way to do that is e.g. mount (somehow) that dll / any other library as a device and use it in a way of reading / writing to that

Are there any other possibilities to solve that problem?

If by that you mean "directly run userspace code in kernel space", then yes, it's impossible. Otherwise... it really, really depends what the content of this thing is. You can't run just anything in kernel space, it has to be code compiled for your kernel's environment. It also really, really depends on how it's stored and where. The kernel's capable of reading firmware files on demand, I think, but from the sounds of it that's no file...

If this dll is userspace code that won't help because it will still be userspace code and unable to operate in kernel space.

Extract the userspace code in userspace. Use the userspace code in userspace. Communicate data, not program instructions, in and out of the kernel.

Hmm... so if I create simple doing nothing (or printing text to dmesg) kernel space dynamic library, save it wherever on HDD and try to use from device driver - would that work?
Is there a way to create dynamic library in kernel space and call it from device driver?

You're talking about kernel modules, I think. These can be loaded whenever. Make both these things, your little loader thing and the thing which uses it, both modules, and have the main thing depend on the little thing. Whenever the main module is loaded it will try to load your loader module first. It will look for it in a specific place on the hard drive (/lib/modules/kernel-version/kernel/...).

You can also manually tell the kernel to load a module file whenever with modprobe modulename if the module's installed under /lib/..., or insmod filename.ko to point it to a specific file.

I haven't used module dependencies myself so can't be more specific, sorry.

Create a dynamic library? As in convert from source code into a module? Creating a module takes gcc and dozens of megs of kernel source, all of which happens in userspace. No.

Again though -- what you do really depends on what the contents of this mysterious "block" are and where it will be and how you must get at it. Do you have any information whatsoever on what it actually is? If not, you really don't have the information you need to write a driver.

1 Like

Humm, it is not as easy as refining calls.

If you and your friend are creating a UEFI emulator, I assume that you have studied all 2200 plus pages of the UEFI 2.3 specification and looked at the TianoCore reference implementation sources.

I should point out that the UDK2010 release contains a port of the emulator to OS X which was done by Andrew Fish of Apple. Andrew's port was then ported to Fedora 14 - see UEFI Emulator on Fedora 14.

I still cannot see why you are trying to load a UEFI driver binary into a Linux kernel. That makes absolutely no sense. Loading a UEFI driver into the UEFI emulator makes sense; existing UEFI emulators do that all the time. You can do this programmatically or from a UEFI shell. If you feel that you need extra functionally in the Linux kernel when you load a UEFI driver, you need to write a suitable Linux kernel driver to do the necessary and then write a suitable glue layer in the UEFI emulator.

Working on the internals of a UEFI emulator is not for the faint of heart! Good luck to you.

1 Like

Well, I show you "Big picture" as you asked for.

Actors:
User
PC with preinstalled OS: RedHat from 2010year
Network Interface Card (let's call it "NIC") produced in 2011year

Usage model:

  1. User plugs NIC to PCIe bus in PC
  2. User turns on PC
  3. User has got an internet connection

Do you got the idea? Just plug and play - no drivers, no additional installations, etc.
Of course - there are some limitations I tell about later.
If user wants to install regular drivers - he download it from vendor site and install.

  • how is it possible?
    There is known UEFI API for NIC before NIC is released to the market and even before silicon is created
  • how many adapters it is dedicated for?
    For now it is only one specific adapter model (it may changes in future).
  • what functionality is to be implemented?
    Only very basic options like: send packet, receive packet, obtain IP address from DHCP. It even does not has to run at full speed.
  • how much resources are to do that?
    It is about 8 months, few engineers
  • has user to use UEFI machine?
    No - he can use UEFI based machine or BIOS one

If you have another questions I try to answer but for sure I cannot tell all the details because of copyrights, and other law-connected things.

Now I have to create demos and propositions to solve some problems to set way of doing all the work (and discuss it with other people).

I show you some scenarios (at this moment I do not know exactly how UEFI Emulator presented by fpmurphy works):

Actors:
RedHat with preinstalled MyLinuxDriver
NIC with UEFI Driver

On boot MyLinuxDriver copies UEFI Driver from NIC's flash to HDD/RAM
After that all calls to MyLinuxDriver are translated through UEFI Emulator to UEFI Driver.

Actors:
RedHat with preinstalled MyLinuxDriver
NIC with UEFI Driver

On boot MyLinuxDriver copies UEFI Driver from NIC's flash to HDD/RAM and at the same time UEFI Emulator translates it to linux-understandable format.
All calls to MyLinuxDriver are redirected to UEFI TRANSLATED Driver.

What I need to know:

  • how to load UEFI Driver from NIC's flash? (for demo purposes it could be 'how to load whatever from whenever', just to show that such operation is possible)
  • where to load that driver? (RAM/HDD)
  • when translate UEFI Driver to linux-understandable format (on boot, or on each call)

Thank you very much for your attention and useful information. I really apreciate your help guys!

PS.

I am not trying to do that - I am trying to find proper way to solve my problem described above.

Well that only took three entire pages of begging. THANK YOU.

I think you may be going about this the wrong way still though. The way to do this would be to add general-purpose UEFI support to Linux, not to hack one special thing that supports UEFI. And you'd probably want to use some sort of emulator, not something that converts UEFI code into whatever code your kernel uses.

But the biggest problem is I'm not sure UEFI even applies once an operating system's been loaded. Linux used to support BIOS-mode disk devices, for example, until it became clear that there were just too many corner cases where running in protected mode and controlling your own interrupts and DMA and all that jazz prevented BIOS calls from being able to work the way it was intended no matter how hard you tried to fool them. Sometimes. Very firmware-dependent. So they dropped that and added support for droves of different hard drive controllers instead, and that's how it's worked for a long time. Some coherent standards like AHCI are helping make drivers more generic again though.

You could make something like a DOS around raw UEFI devices -- a small self-contained OS which relies on system firmware to do most of the work. It could be surprisingly sophisticated with the system firmware features available now. Networking and graphics could be sufficient to run a reasonable impression of a web browser to download and save drivers with.

I added one point to my "Big Picture":

  • has user to use UEFI machine?
    No - he can use UEFI based machine or BIOS one

After UEFI loads regular OS it becames useless. I would like to use only UEFI Driver placed in Network Interface Card's flash - no general UEFI OS. My solution has to run on BIOS machine and works as well as on UEFI machine.

I think that "adding general-purpose UEFI support to Linux" is out of range. Such work needs much more resources.

Could you continue your tought? I have never heard about this.

And how do you propose to overcome this problem? Simply loading it in the kernel isn't enough to make it work. Once an OS loads, the environment's not right anymore.

Which is unfortunate since I think that's the only way you'd get linux to do what you want -- use UEFI devices exclusively so you don't have to use your own drivers and in doing so alter the machine's environment.

DOS is an extremely simple operating system. It doesn't have or need device drivers for basic functionality and it doesn't modify the system environment much at all. It relies on BIOS calls(i.e. firmware code) almost exclusively instead.

The original IBM PC BIOS calls were rather limited in function though, so raw DOS doesn't get you anything but disk+console+keyboard, and it's performance is poor compared to what real device drivers could do.

A DOS-like thing that fully utilized UEFI firmware capabilities could have much more features than DOS did. It wouldn't be anything like Linux but might be useful since you could still run many tools in it. You could check out LILO or GRUB to see how they use UEFI.