I've been playing around modifying the MBR of an old USB stick, booting from it, testing the various BIOS functions, etc...
But I don't seem to understand - What does the BIOS look for when deciding which device to boot from?
The obvious 2 requirements are:
Changing the BIOS boot order so it tries to boot from the USB when it is connected.
Have the MBR singature - 0x55aa at offset 0x1fe.
For some reason, my laptop only boots from the USB for some of the MBRs I wrote, and for others it boots from the main HD, ignoring the USB. Of course all are signed with 0x55aa.
Why does it happen? What else does the BIOS look for?
After a valid MBR is found (via the signature you mentioned), the BIOS checks the first byte of each of the MBR's 16-byte partition records. 0x80 means the partition is bootable (or "active"), 0x00 otherwise.
If a bootable partition is found, the code in the first sector of that partition -- the Volume Boot Record -- is loaded. The VBR contains the OS bootstrapping code.
Some implementations may also validate checksums and other flags.
Related
First of all, I would say to you that I write this question from nothing because I have attempt to find good documentation but nothing stand out...
What happens when we squeeze a key?
I think this is complex but I hope you can help me.
What I search to know : all (but especially the program start on the host machine and how the key electric signal is encoded and send...)
The eXtensible Host Controller (xHC) has a Periodic Transfer Ring. Windows programs this ring to trigger a transfer every time an interval in milliseconds has passed. The right interval is specified in the USB descriptor returned by the USB device. When the transfer occurs, the xHC puts a Transfer Event TRB on the event ring and triggers an MSI-X interrupt which bypasses the IOAPIC as some kind of inter-processor interrupt. If Windows detects some change in the keys pressed, it will send a message to the application which currently has focus (calling the window's procedure) with the key pressed in one of the argument.
I don't know about electrical signals but I know the eXtensible Host Controller is the USB controller responsible to interact with USB on modern Windows systems. Since Windows nowadays requires an x64 processor, the xHC must be present on your motherboard. The xHC is a PCI-Express device which is compliant with the PCI-Express specification.
To find an xHC, you:
Find the RSDP ACPI table in RAM;
This table will be found by the UEFI firmware which acts as some kind of small operating-system (OS) during boot of the computer. Then, the OS developers will write a small UEFI application named bootx64.efi that they will place on a FAT32 partition on the hard-disk. They will place this app in the /boot/efi directory. The UEFI firmware will directly launch that application on boot of the computer which allows to have an OS which doesn't require user input to be launched (similarly to how it used to work with the legacy BIOS fetching the first sector of the hard-disk and executing the instructions found there).
The UEFI application is compiled in practice with either EDK2 or gnu-efi. These compilers are aware of the UEFI environment and specification. They thus compile the code to system calls that are present during boot and available for the UEFI application written by the OS developers. The System Tables (often the ACPI tables) are given as an argument to the "main" function (often called UefiMain) called by the UEFI firmware in the UEFI application. The code of the application can thus simply use these arguments to find the RSDP table and pass it to the OS.
Find the MCFG ACPI table using the RSDP;
The chain of table is RSDP -> XSDT -> MCFG. Once the OS found the MCFG, this table specifies the base address of the PCI configuration space. To interact with PCI devices you use memory mapped IO (MMIO). You write to some position in RAM and it will instead write to the registers of the PCI devices. The MCFG thus specifies the base address at which you will start finding MMIO registers for the different PCI devices that are plugged into the computer.
Iterate on the PCI devices and look at their IDs until you find an xHC.
To iterate on the PCI devices, the PCI convention specifies a formula which is the following:
UINT64 physical_address = base_address + ((bus - first_bus) << 20 | device << 15 | function << 12);
The base_address is for a specific segment group. Each segment group can have 256 buses (suitable for large servers or large computers with lots of components). There can be up to 65536 segment groups and each can have up to 256 PCI buses. Each PCI bus can have up to 32 devices plugged onto it and each device can have up to 8 functions. Each function can also be a PCI bridge. This is quite straightforward to understand because the terminology is clear. The bus here is an actual serial bus that the PCI devices (like a network card, a graphics card, an xHC, an AHCI, etc.) use to communicate with RAM. The function is a functionality of the PCI device like controlling USB devices, hard-disks, HDMI screens (for graphics cards), etc. The PCI bridge bridges a PCI bus to another PCI bus. It means you can have almost an infinite amount of devices with the PCI specification because the bridges allow to extend the tree of devices by adding other PCI host controllers.
Meanwhile, the bus is simply a number between 0 and 255. The first bus is specified in the MCFG ACPI table for a specific segment group. The device is a number between 0 and 31 and the function is a number between 0 and 7. This formula returns a physical address which points to a conventional configuration space (it is the same for all functions) which has specific registers. These registers are used to determine what is the type of device and to load a proper driver for it. Each function of each device thus gets a configuration space.
For the xHC, there will be only one function and the IDs returned by its configuration space will be 0x0C for the class ID and 0x03 for the subclass ID (https://wiki.osdev.org/EXtensible_Host_Controller_Interface).
Once you found an xHC, it gets rather complex. You need to initialize it and get the USB devices which are plugged in the computer at the current moment. You need to take several steps to get the xHC operational. For this part, I'll leave you to read the xHCI specification which (on chapter 4) specifies exactly the steps which need to be taken (https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf).
For the keyboard portion I'll leave you to read one of my answer on the stackexchange for computer science: https://cs.stackexchange.com/questions/141870/when-are-a-controllers-registers-loaded-and-ready-to-inform-an-i-o-operation/141918#141918.
Some good links:
https://wiki.osdev.org/Universal_Serial_Bus
https://wiki.osdev.org/PCI
Background:
I have an embedded system (I CANNOT change hardware) with a self-built Linux system (I have complete control over software).
This system has several (3-wire, 3.3V) serial lines and I have no control over what is connected where (I can find out after boot).
Problem:
If some external apparatus is connected to serial line, "mark" on RX line(s) (which I cannot prevent, in general), directly connected to microcontroller (MT7628AN, if it matters) is enough to give some power to system.
The only place where it matters is SD card (again, connected directly to microcontroller) which is never powered completely off.
In this condition I often see at boot:
[ 4.679850] mmc0: card never left busy state
[ 4.684203] mmc0: error -145 whilst initialising SD card
This is repeated four times in the boot-sequence and later SD devices (/dev/mmcblk0*) are unavailable.
Similar situation if I compile mmc drivers (mtk_mmc.ko, if it matters) and modprobe mtk_mmc later.
Question:
Is there any command sequence I can send to MMC via software, before/during/after initialization sequence to completely reset it "as-if" power had been removed?
Note:
This is particularly bad because (part of) my root filesystem is on that MMC card and thus any tweaking should be done in kernel/initrd.
If it matters: all MMC card are: "Transcend 8GB C10 MicroSD HC".
I think FS stands for filesystem, but I don't know what BLK stands for. Not only that, but what are the meanings behind the pci hierarchy parameters. i.e. When I see HD(1,MBR,0x0003B) what does "1","MBR", and what looks to be an address, stand for?
Here's the mapping table I'm looking at in UEFI shell:
Mapping table
FS0: Alias(s):HD21a0e0b:;BLK1:
PciRoot(0x0)/Pci(0x1D,0x0)/USB(0x0,0x0)/USB(0x4,0x0)/HD(1,MBR,0x0003B)
FS1: Alias(s):HD23a0a1:;BLK4:
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0x0,0x0)/HD(1,MBR,0x00000000,0x3F)
BLK3: Alias(s):
PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0x0,0x0)
BLK0: Alias(s):
PciRoot(0x0)/Pci(0x1D,0x0)/USB(0x0,0x0)/USB(0x4,0x0)
BLK2: Alias(s):
PciRoot(0x0)/Pci(0x1D,0x0)/USB(0x0,0x0)/USB(0x4,0x0)/HD(2,MBR,0x0003B)
I'm guessing BLK's are available ports and FS's are physical things that are plugged into those ports. It looks like once somethign is plugged into a BLK, it becomes an FS, but still retains its BLK value. i.g. FS0=BLK1
According to archwiki:
fsX means filesystem
blkX means block device or data storage device
MBR should mean Master Boot Record
HD should mean Hard Drive
1 might mean Primary, 2 Secondary Partition
That hex number after MBR could be the device signature or disk identifier. Or maybe an offset of that device to important information.
Links that might help further:
RHEL 5 Installation Guide EFI Shell Guide
Red Hat 7.1 Itanium EFI Shell Guide
HP Knowledge Base: "UEFI Shell 'fs' devices gone after restore from image backup"
OpenVMS: Firmware upgrades from a USB stick (on UEFI)
SourceForge EFI Shell Development Documentation
I'd like to boot the raspberry pi with a device-tree-driven linux kernel, is there anything special to do to do that?
Can anyone point what are required to set up a device-tree-based kernel boot up for the raspberry pi.
I may need to have raspberry pi kernel source where drivers for devices should be compatible with device tree. If so, where can I find such kernel sources for Raspberry Pi?
Device-Tree support on Raspberry Pi
Raspberry Pi embeds an ARM11 SoC: Broadcom BCM2835. Device Tree (DT) support for ARM is fairly new, but it seems that it has made its way to the Raspberry Pi CPU. You can find a DT for the Raspberry Pi in arch/arm/boot/dts/bcm2835.dts*.
However the default config file bcm2835_defconfig does not enable device tree:
$ grep DT arch/arm/configs/bcm2835_defconfig
<nothing interesting>
I expected something like CONFIG_OF*=y or CONFIG_USE_OF=y. Bad news: that is going to be tough and long (3 noob.month ?).
is there anything special to do to do that?
It depends on your current linux kernel version. Chances are that your current linux already uses the device-tree (linux-3.7 or later ?).
If not, there are wide changes that you need to study:
Device-Tree impact on a system
Device Tree completely changes the way Linux kernel boots. It impacts:
your bootloader (e.g. u-boot.bin). U-Boot must know how to handle device-tree. Old U-Boots do not know what a device-tree is...
the Linux kernel image (e.g. zImage). Linux must know that it has to fetch its hardware description in the device-tree.
the flash/SD card partition layout. You need to make room for the device tree file itself.
Impact means: you need a way to compile/program these images: full-source, build environment, UART access, potentially JTAG hardware. Changing the bootloader without JTAG is usually suicide, except (today) you can reprogram your SD card off the board safely.
You might find references to OpenFirmware (OF) when talking about device tree. OpenFirmware was the original specification on IBM PowerPC before the Device Tree convention was chosen. Code related to device-tree is prefixed with of_ in linux. Not intuitive, I know...
Please read:
http://devicetree.org/Main_Page
Documentation/devicetree
How to generate the Device-Tree Binary (.dtb)?
Example on a PowerPC board using buildroot:
/usr/bin/make -j5 HOSTCC="/usr/bin/gcc" HOSTCFLAGS="" ARCH=powerpc INSTALL_MOD_PATH=/home/evigier/buildroot/output/target CROSS_COMPILE=" /home/evigier/buildroot/output/host/usr/bin/powerpc-buildroot-linux-gnu-" DEPMOD=/home/evigier/buildroot/output/host/sbin/depmod -C /home/evigier/buildroot/output/build/linux-master mpc8347.dtb
Example U-Boot console output on a PowerPC board:
Uncompressing Kernel Image ... OK
kernel loaded at 0x00000000, end = 0x006f8780
## cmdline at 0x0ff1b900 ... 0x0ff1b925
## initrd_high = 0xffffffff, copy_to_ram = 1
ramdisk load start = 0x00000000, ramdisk load end = 0x00000000
## device tree at 00780000 ... 00781f57 (len=20312 [0x4F58])
Loading Device Tree to 0ff16000, end 0ff1af57 ... OK
## Transferring control to Linux (at address 00000000) ...
Booting using OF flat tree..
Happy hacking :-)
I'm going to write and test a bootloader. In order to do this, I am planning to copy the bootloader onto a floppy image file and mount it in a VM.
However, I'm not sure where to put the bootloader's machine code. Does it just get dumped into the first few bytes of the file?
The boot sector of the floppy was the first sector. If you're talking about a raw floppy image (1440K), it should be the first 512 bytes of the image file.
From memory, this gets loaded by the BIOS into 7c00:0000 (real mode) and then jumps to that address.
The DOS boot floppies had a 3-byte JMP instruction there to jump over the Disk Parameter Block (DPB), which detailed the attributes of the disk. But, if you're in total control of the disk and your boot code, I don't think you need to follow that convention. I don't recall any BIOS' checking what was loaded for validity (though admittedly it was a long time ago).
its been a VERY long time but if i recall in DOS it was stored in the MBR. i believe its still the same today
http://en.wikipedia.org/wiki/Master_boot_record