Actually my objective is not to generate EFI binaries/applications but to make OS running in EFI environment. The only EFI binary required for me is multiboot-compliant loader such as GRUB2. The next step would be accessing EFI services from OS kernel to get memory maps, MP tables, ACPI tables etc - all the stuff which used to be retrieved from BIOS. I'm not yet very competent how to do this because I just started feasibility study for this task. Currently I have working Qemu with EFI BIOS and EFI GRUB2 which is able to load and start my old kernel. So compiling for EFI and "Hello world" running from EFI shell is a little bit out of scope of my project. But I strongly agree that this topic should represented in details somewhere. I would gladly share all my findings and experience in this area.
If you are interested in details of what is achieved in my case now, here they are:
* Qemu: Nothing special has been yet done - just compile latest version for required architecture with required options. When launching specify with "-bios" parameter the EFI firmware image available from
http://wiki.qemu.org/Download/.
There is also requirement for disk image. It should contain so called ESP - EFI System Partition which can be formatted only in FAT filesystem. Partitioning could be either MBR or GPT (GUID partition table). I am using the second one. It can be created, for example, in such way:
Code: Select all
# 32MB raw disk image
dd if=/dev/zero of=efi.disk bs=1024 count=32768
# gdisk utility used for creating GPT from http://sourceforge.net/projects/gptfdisk/
gdisk efi.disk
# use "o" to create new GPT, "n" to add partition with "ef00" type, "w" to write it in the file
# Check start sector number of your system partition by "p" command or with "gdisk -l efi.disk", e.g.:
#Number Start (sector) End (sector) Size Code Name
# 1 2048 65502 31.0 MiB EF00 EFI System
# mount partition to loopback device
sudo losetup -o $((2048*512)) /dev/loop0 efi.disk
# create FAT12 filesystem, for larger disks it could FAT16 or FAT32
sudo mkdosfs -F 12 /dev/loop0
# mount new partition to some directory and fill it with your files
mkdir mnt
sudo mount /dev/loop0 mnt
....
# unmount when done
sudo umount mnt
sudo losetup -d /dev/loop0
You can create "startup.nsh" file in the root of your ESP. It is interpreted as EFI shell script and executed at startup if present. I have following line there to boot GRUB:
Actually I am using Perl script to create system image. I have attached it to the post.
* GRUB: I have configured GRUB 1.98 with the following command:
Code: Select all
../src/configure --prefix=$PREFIX --with-platform=efi --target=i686 --disable-nls --enable-efiemu=no
Qemu EFI currently can launch only 32-bit binaries so you need to compile GRUB with target i686 even if you plan to emulate 64-bit system.
After compilation you can build your GRUB2 EFI binary specifying list of modules to build-in:
Code: Select all
grub-mkimage -o grub.efi boot linux part_gpt fat ext2 normal sh configfile lspci ls reboot datetime loadenv search lvm help multiboot elf
Note that I am using "part_gpt" module because I use GPT. I have spent some time to figure out why GRUB cannot find its modules and configuration file on disk image which is provided with TianoCore EFI. The reason was that it had MBR partitions table so if you still use it you should add "part_msdos" module.
You should copy your GRUB binary, its modules and configuration file on your disk image:
Code: Select all
sudo mkdir -p mnt/efi/grub
cp grub.efi $YOUR_PREFIX/lib/grub/i386-efi/*.mod $YOUR_PREFIX/lib/grub/i386-efi/*.lst mnt/efi/grub/
# create mnt/efi/grub/grub.cfg if necessary
"multiboot" command in GRUB could boot your multiboot-compliant kernel:
Code: Select all
search --file --set /boot/kernel
menuentry "YourOS" {
multiboot /boot/kernel --root ramdisk0
}
I have also tried to found why some delay occurs when it loads my kernel and found that disk cache blocks size is set to too small value. I have increased it up to 64k and it started to load the kernel almost instantly. Increasing this value more gives no effect.
Code: Select all
--- include/grub/disk.h.old 2010-03-06 22:51:37.000000000 +0200
+++ include/grub/disk.h 2011-02-24 08:39:37.893224987 +0200
@@ -135,8 +135,8 @@
#define GRUB_DISK_CACHE_NUM 1021
/* The size of a disk cache in sector units. */
-#define GRUB_DISK_CACHE_SIZE 8
-#define GRUB_DISK_CACHE_BITS 3
+#define GRUB_DISK_CACHE_SIZE 128
+#define GRUB_DISK_CACHE_BITS 7
/* This is called from the memory manager. */
void grub_disk_cache_invalidate_all (void);
As I already said I'm not interested in creating applications for EFI so I did not perform any study in this direction. As far as I know it should not be very difficult - GNU binutils could be compiled for efi-app-ia32 or efi-app-x86_64 target. Also there is some gnu-efi package with some useful tools available there:
http://sourceforge.net/projects/gnu-efi/.
Currently it is all my progress in this area because now I have temporarily switched to problem with GDB + Qemu (I have also started migration to 64 bits architecture and there is a problem in the latest Qemu - when it is emulating x86_64 it always sends 64-bits registers to remote GDB, even if CPU is currently in 32-bit mode. I have initiated discussion with Qemu developers which could probably lead to patch (at least for me I will definitely have a private patch)) so studying in this area from my side is frozen for a little. Probably some time will be spent before I will return to EFI topic because for now I need to redesign my kernel linkage to make it compilable by x86_64 gcc and have 32-bit entry point. After that I will continue investigation about accessing EFI services from my kernel. If someone is interested in this story continuation I could post new details either here or on some wiki page.