How does a computer know where in the filesystem the bootloader is located? - boot

How does a computer know where in the filesystem the bootloader is located? Is there a common file among all operating systems and all computers (maybe not all computers, but all architectures) that points to the bootloader? I know Raspberry Pi always loads bootcode.bin from the first partition of the SD card. Do PCs share a common file like this?

The Master Boot Record occupies the first 512 bytes of the first hard disk, and is the first thing loaded by the BIOS to hand over control to a program capable of booting the desired operating system. In general, a bootloader gets installed in the MBR, removing its previous content. It is (in dual boot cases) possible for them to live in co-existence, which is known as multi-booting.

It is different among different architectures. But usually there is a register the cpu reads its first instruction from after reset to begin execution. This register is often contains the bits for an assembly jump operation to another memory address which is the address of the boot code. On the next clock cycle it will fetch the operation at that address and so on.
The hardware designer will have to determine how this is implemented. For example the first instruction could be to read from a memory address on an eeprom chip that contains the boot code.
As far as PC's go the motherboard has its own boot process which will load the OS bootloader. Hence the reason you can still startup a pc and see the BIOS without an OS installed
Or at least thats what I remember from my Comp. Arch. class forever ago.

Related

How is the instruction memory initialized?

In my book, in the chapter where they create the CPU (chapter 7), they already assume that the instruction memory contains the instructions in machine code.
In an earlier chapter (chapter 6) this is written about start-up:
On start-up, the processor jumps to the reset vector and begins
execution boot loader code in supervisor mode. The boot loader
typically configures the memory system, initializes the stack pointer,
and reads the OS from disk; then it begins a much longer boot process
in the OS. The OS eventually will load a program, change to
unprivileged user mode, and jump to the start of the program.
But from what I understand the reset vector and the boot loader code must be in memory? Is this correct? Has my book skipped a part before the CPU jumps to the reset vector, and forgot about
how the reset vector and bootloader are loaded into memory? How does the CPU get them into memory?
All CPUs have a fixed start address. This is set in hardware (maybe you can configure it through jumpers but that's it, because the CPU has to start somewhere).
The first instructions are again set in hardware, at such fixed address, usually through a hard coded memory (like a flash). There likely is a piece of hardware that translates accesses to an address-based location to flash (NAND memory), so that means that the flash, even if it's not part of the CPU, is memory mapped.
Some processors do a memory remap, meaning that you will have those addresses accessible for other things, as you likely don't need the first stage bootloader anymore.
We can explore further by taking as an example the STM32 boot process:
Configurable boot mode though physical pins and jumpers:
This means that the CPU can start fetching instructions at startup from different locations, defined by those pins.
Factory bootloader:
The bootloader is stored in the internal boot ROM (system memory part of the flash) of any STM32 device, and is programmed by ST during
production. Its main task is to download the application program to the internal flash memory through one of the available serial peripherals, such as USART, CAN, USB, I2C, or SPI.
So this means that if the factory bootloader is selected, the CPU will start execute a program that then, by means of the selected communication protocol (USART, CAN etc..) can fetch a program from another device. This is useful if you have another processor needed to program your device once already mounted on the PCB.
Another option - Write directly to the internal flash
Another option is to select the internal flash. Since this is a persistent memory it can be programmed externally and when the CPU will start it will find, at 0x8000000, the first instruction to execute. The last section of the page that I linked explain the boot process.

How does windows distinguishes between discs?

I wonder how windows distinguishes between diferrent drives and memory modules, I mean how can windows writte somethig specificaly to disc C or disc D.
In every programming language when you declare variable it gets saved into to the memory, and when you need to store something to hdd, you have to use some library.
So, how does windows handle it?
Does it treat all discs and memory modules as a single line of data, and does it only save each mediums beginning adress? - like 0x00000 is where the disc C begins, 0x15616 is where the disc D begins.
Like #MSalters said,
C: is a symlink to something like Device\HarddiskVolume1.
What it means is that disk drivers on Windows are implemented as virtual filesystems a bit like on Linux. I'll explain for Linux since there's much more documentation but the answer is quite similar for Windows even though both OSes do things differently.
Basically, on Linux everything is a file. Linux ships with disk drivers as these are at the basis of every computer. Linux exposes a driver model like every OS. The Linux driver model for files (including hard disks) exposes functions that will be called by the kernel to read/write to disk. There are open, read and write functions that the kernel expects to be present for a file driver.
If you wanted, you could write a disk driver and replace the existing one. You write drivers as modules that you can then load in the kernel using certain utilities that ship with Linux. I won't share more details as I'm not that much aware. Once your code is loaded in the kernel, it has access to all kernel code and all hardware since it runs in kernel mode.
Today, disk drivers probably use PCI DMA which is a controller connected to the PCI bus which allows to do disk operations which ignore the CPU and load disk data to RAM directly. The PCI convention says that all compatible devices (like PCI DMA controllers) must expose a certain interface to the computer. This interface is mostly some memory mapped registers that can be used to send commands to the controller. The OS will write data in these registers to tell the DMA controller to do disk operations. Then the DMA controller will trigger an interrupt once it is done. The OS will then know that the data is readily loaded into RAM and ready for use. The same applies for writing
The OS knows the location of these registers by looking in the ACPI tables at boot.
In modern Windows (2000 or later) C: is a symlink to something like Device\HarddiskVolume1. The number there can vary. Typically, \Device\Bootpartition is also a symlink to the same HarddiskVolume.
Windows doesn't use libraries to write to disk. Instead, it uses drivers. The chief difference is that drivers run as part of the OS kernel, while libraries run as part of applications.

RootFileSystem vs kernel updating

I know that they are two different things, but what is the difference between the actual Linux kernel and the rootFS file system especially in terms of location in memory and updates?
Regarding partitioning, why is it that the kernel and rootFS are nearly always on different partitions? Won't the kernel code be stored within the rootFS itself? So how are they on different partitions in memory?
Now regarding updating, I've been looking into an OTA update framework which claims to do a full kernel image update. It uses two separate partitions for rootFS. If there is a problem updating one rootFS partition, it can fall back to the working rootFS partition which makes sense. However, how is this actually updating the kernel tho? I don't understand.
I know that they are two different things, but what is the difference between the actual Linux kernel and the rootFS file system especially in terms of location in memory and updates?
Kernel is usually one image file (like zImage). In ARM systems kernel also needs device tree file, but let's avoid it for now. RootFS, in turn, is a file system that contains all files in your /, like binaries (init, bash), config files (/etc), user home directory, and so on. Sometimes RootFs contains kernel image file, sometimes it doesn't, depends on your particular system.
Regarding partitioning, why is it that the kernel and rootFS are nearly always on different partitions? Won't the kernel code be stored within the rootFS itself? So how are they on different partitions in memory?
The key to your questions is to think about bootloader (like U-Boot or GRUB). Once you understand how OS boot process works in bootloader, the answer will automatically reveal itself. As you mentioned, different partitioning schemes exist, which leads to difference in boot process. Actually, there is a lot of different boot schemes out there. Let's review some of them, and hopefully it'll explain what you want to know.
Kernel and rootfs on different partitions. In this case, bootloader usually reads kernel image to RAM, passing rootfs partition via kernel cmdline (via root= parameter). Then bootloader starts kernel execution, and kernel is mounting rootfs from partition specified in root= parameter.
Kernel image is located inside rootfs. In this case, bootloader ought to know where exactly kernel image is located (e.g. in /boot/zImage). Bootloader knows rootfs FS format (e.g. ext4), reads /boot/zImage from rootfs to RAM. Then execution continues as in previous item.
Kernel image and rootfs are passed via network (e.g. TFTP). In such case, sometimes, rootfs is being placed into RAM and mounted as ramdisk (from RAM). No persistent storage is used in such case, and any changes to rootfs will be lost after reboot. Another network case is when rootfs is mounted via NFS, then persistent storage on the server will be used (transparently viewed by the user).
Now regarding updating, I've been looking into an OTA update framework which claims to do a full kernel image update. It uses two separate partitions for rootFS. If there is a problem updating one rootFS partition, it can fall back to the working rootFS partition which makes sense. However, how is this actually updating the kernel tho? I don't understand.
In terms of updates, it's not that different which scheme to use,
(1) or (2). What are you talking about is called (at least in Android) A/B Seamless Updates, meaning that two partitions (A and B) are used for storing the same image (e.g. old rootfs and new rootfs). You need to understand that it's ok to update just rootfs without kernel. There is a rule in kernel development that reads like this: "We don't break userspace". Which means you can rely on different versions of kernel to run the same userspace, or you can rely on one kernel version to run different userspaces.
So it's more like architecture question: do you want to update kernel in your system at all? If yes, then you need to provide two different partitions for kernel and two partitions for rootfs. Or alternatively you can put kernel image and rootfs in the same partition (for example see Android boot image format), and provide second partition for updates.

Are PCIe device drivers beneficial if using Linux as a bootloader for bare-metal code?

I am developing an embedded system on a PowerPC processor and there is need for communication with an FPGA via PCIe. I wish to use Linux/embedded-Linux as a bootloader to leverage its PCIe initialization code and driver API for simplified PCIe driver development. However in the end I want to be running bare-metal code (no OS running). So I am looking at using PetitBoot/kexec to jump from Linux to my own code.
Is this possible?
My current understanding of PCIe drivers leads me to believe that once the device is initialized, so long as I have a pointer to the address space, I should be able to simply execute MMIO R/W operations directly to the memory space. So even if kexec overwrites the driver code I should be able to use the device because the driver has done its job already.
Is this correct?
If not, what are my alternatives?
I don't think this approach would be a good idea. Drivers that were written with the Linux OS in mind are going to assume that all of the OS's resources are available, not just memory allocations. For example, it may configure interrupt handlers, but when the OS is not longer available, your hardware may get hung because nothing is acknowledging and servicing its interrupt requests.
I'm skeptical of the memory initialization as well. I suppose you could theoretically allocate some DMA memory and pass the resulting physical address to your bare-metal application as it takes over, but the whole process seems sketchy. It would be very difficult to make sure everything in Linux is shut down cleanly while leaving the PCIe subsystem running. You'll have to look at the driver's shut down routines and see what it does to the card to make sure it doesn't shut down the device and make it unresponsive to your bare-metal code.
I would suggest that you instead go through the Linux-based driver and use it as a guide to construct a new bare-metal driver. Copy the initialization code that you need, and leave out the Linux-specific configuration details.

using pci to interconnect motherboards

i've got a few old mobos and i was wondering whether it might be possible to create a pair of pci header cards with interconnect wires and write some software to drive the interconnect cards to allow one of the mobos to access the cpu and ram on the other? i'm sure it would be an arduous undertaking involving writing a device driver for the header boards and then writing an application to make use of the interconnect; perhaps a simple demo demonstrating a thread running on each processor and use of both sets of ram, perhaps creating a mini virtual machine that maps 2x3gb ram on 32 bit mobos to a single 6 gb address space. a microcontroller may be needed on each pci header card to act as a translator.
given that mobos almost always have multiple pci slots, i wonder if these interconnected card pairs could be used to daisychain mobos in a sort of high speed beowulf cluster.
i would use debian for each mobo and probably just an atmega128 for each card with a couple of ribbon cables for interconnecting.
pci is basically just an io bus, so i don't see why this shouldn't be possible (but it would be pretty hard going).
does anyone have any advice or has this sort of thing been done before?
Update:
Thanks Martin. What you say makes sense, and it would also seem that if it were possible that it would have already been done before.
Instead, would it be possible to indirectly control the slave cpu by booting it using a "pretend" bootable storage device (hard disk, usb stick, etc)? As long as the slave mobo thinks its being operated by an operating system on a real device it should work.
This could potentially extend to any interface (sata, ide, usb etc); if you connected two pcs together with a sata/ide/usb cable (plug one end of an ide ribbon into one mobo and the other into another mobo), that would be all the hardware you need. the key is in creating a new driver for that interface on the master pc, so instead of the master pc treating that interface as having a storage device on it, it would be driven as a dummy bootable hard disk for the slave computer. this would still be a pretty difficult job for me because i've never done device drivers before, but at least i wouldn't need a soldering iron (which would be much further beyond me). i might be able to take an open source ide driver for linux, study it, and then butcher it to create something that kindof acts in reverse (instead of getting data off it, an application puts data onto it for the slave machine to access like a hard disk). i could then take a basic linux kernel and try booting the slave computer from an application on the master computer (via the butchered master pc ide/sata/usb device driver). for safety, i would probably try to isolate my customised driver as much as possible by targeting an interface not being used for anything else on the master pc (the master pc might use all sata hard disks with the ide bus normally unused, so if i created a custom ide driver it might cause less problems with the host system - because it is sata driven).
Does anyone know if anything like this (faking a bootable hard disk from another pc) has ever been tried before? It would make a pretty cool hackaday on youtube, but also seriously it could add a new dimension to parallel computing if it proved promising.
The PCI bus can't take over the other CPU.
You could make an interconnect that can transfer data from a program on one machine to another. An ethernet card is the most common implementation but for high performance clusters there are faster direct connections like infiband.
Unfortunately PCI is more difficult to build cards for than the old ISA bus, you need surface mount controller chips and specific track layouts to match the impedance requirements of PCI.
Going faster than a few megabit/s involves understanding things like transmission lines and the characteristics of the connection cable.
would use debian for each mobo and probably just an atmega128 for each card with a couple of ribbon cables for interconnecting.
pci is basically just an io bus, so i don't see why this shouldn't be possible (but it would be pretty hard going).
LOL. PCI is an 32-Bit 33MHz Bus at minimum. So simply out of reach for an ATMEGA.
But your idea of:
a pair of pci header cards with interconnect wires and write some software to drive the interconnect cards to allow one of the mobos to access the cpu and ram on the other [...]
This is cheaply possible with just a pair of PCI Firewire (IEEE 1394) cards (and a Firewire cable). There is even a linux driver that allows remote debugging over firewire.

Resources