Nice but very incomplete article. Some observations below...
You will need to build a cross compiler toolchain (binutils and GCC). I.e. i686-pc-elf-gcc for 32 bit or x86_64-pc-elf-gcc for 64 bit. The compiler that comes with your OS is built for a different target and may have downstream patches, esp. if you're on Ubuntu. Things may seem to work initially but you will encounter strange bugs sooner or later.
Build a bootable and debuggable ELF file, not a flat binary. All it takes is a slightly different linker script. You won't get very far without a debugger on bare metal projects.
You need to zero fill .bss section in the boot code before jumping to C code.
I recommend using gas instead of nasm. You might like Intel syntax but you'll need inline (at&t) assembly in C code anyway. Nicer to have just one syntax. It's just an assembler syntax, you will get used to it in a matter of hours
Use a makefile. Fancy build systems (e.g. cmake) aren't nice with kernel images.
See below for examples. The first one isn't my project but I contributed the linker script, Makefile and README for making bootable ELFs. The latter is my x86_64 toy kernel project from years ago.
Using a linker script was more painful than it should have been. Pre-processed assembly files (.S) didn't work (they should run through C pre processor). Writing toolchain file for cross compiling wasn't easy.
CMake works great for user space apps, and cross compiling works very well for them. But bare metal projects, kernel modules, etc just are not great.
I'm impressed they got grub onto a hard disk image without needing root; I didn't think you could do that. I struggled with that for a while, before I found grub2-mkrescue, which I think is much easier if you're just starting out. The entire sequence to create a CD ISO is,
# Stage the data we want in our image:
mkdir -p isofiles/boot/grub
cp grub.cfg isofiles/boot/grub/.
cp kernel.bin isofiles/boot/.
# Make the image:
grub2-mkrescue -o os.iso isofiles
# Clean up:
rm -rf isofiles
Which I got from the tutorial here[1], which is also excellent.
As pjc50 notes, it shouldn't; absolutely nothing about creating either ISOs or hard disk images requires root, in theory — it's just a file, after all. But in practice, tools like losetup and mount both require it. The part I found novel in the article was the mtools package, which I didn't know about.
Linux has made progress here, such as FUSE for mounting in user space. But FUSE doesn't support file systems that the OS inherently supports, for example. My understanding is that you need to write a FUSE driver for, e.g., ext2, even though Linux is perfectly capable of mounting ext2 as root.
Block devices and partition tables present another hassle.
I suspect ISOs are more easily done simply because non-root users have more need to create them: UI applications for making ISOs readily exist, but I can't think of any common applications that deal with disk images that don't already have root.
About a few years ago I was offered a $10K bounty to make Solaris 7 work with QEMU, and the only progress anyone ever made was mounting the ISO image as a hard drive image and install from there. Nobody ever got the NIC card to get on the Internet. I found out CDROM0: or something could access the ISO image. Everytime I set up TCP/IP it would cause a kernel panic, or lock the system up, or crash. I was given like a week and could not do it. Then I found out about Hackers in Russia trying to do the same thing and not getting anywhere. Apparently the Solaris 7 Kernel has a NIC bug in it where some pointers are out of place. It was solved in a Y2K CD-ROM from Sun which is no longer offered.
Client who wanted me to make it work has a failing SPARC Server with Solaris 7 and needed everything the same. Problem was fixed in Solaris 9, but they needed Solaris 7 even if 9 is backward compatible.
Writing a new Kernel for Solaris 7 based on the old Kernel that works with QEMU might just work. Remember it is QEMU SPARC that I was working with to get networking going.
But if the best and brightest Hackers couldn't get Solaris 7 to have networking, then I for sure couldn't do it either.
But there is a need to emulate any sort of hardware no longer supported or made anymore because many businesses run on software created for those old hardware and software standards and when they can't buy the old hardware or it costs too much, it is better to just run it on QEMU.
> businesses run on software created for those old hardware and software standards and when they can't buy the old hardware or it costs too much, it is better to just run it on QEMU.
Or rewrite the software. At some point they're just going to pay more for not upgrading than it would cost them to start from scratch. And that's not including the cost of teaching people to manage old solaris boxes and dealing with non-accelerated QEMU draining your power budget.
Or port the software. I was given the task to port a soap-based MLOC client-server application from kylix-apache to modern delphi xe-apache.
All I had to do was to fix everywhere that used ansistring which meant rewriting compression, variants handling, hashing and porting a bunch of delphi library stuff that changed in the past 14 years.
After a few months and a gigantic commit on a few dozen files we can now debug everything, all apache modules run smoothly on windows and even android clients work.
If you have access to the source, that's possible of course. But I'm assuming that Solaris 7 also means you're stuck with proprietary, closed solution.
Yeah but they had a problem. The people who wrote the software for their business never gave them the source code and either died or retired. It apparently only works with Solaris 7 under SPARCServers and SPARC Stations.
They claim without the source code, the cost of rewriting it would be more than the cost of running a QEMU virtual machine on a Linux box.
They even had an OpenBSD Box with the same problem using an old version of software with no source code. But I think they could run the old OpenBSD on an X86 box or QEMU machine as there was no SPARC factor like with Solaris 7.
Apparently a lot of small IT shops pay people to write software in the 1990s, and get binaries but no source code because the contract didn't specify they get the source code. Contractors had the source code but kept it from the client to make sure they still get business to modify the software and the client doesn't hire someone else. During the Dotcom busts the contractors went out of business or one of them died from being old and nobody knows where the source code is located. Might be in a storage locker, they forgot to pay, and it was auctioned off. Might belong to a lawyer or underwriting who bought out the stock and IP and nobody knows who that person is.
If a lightweight operating system won't do and you don't want to create a full OS from scratch you can try a unikernel based on includeOS or mirageOS (the few ones I know of).
This mentions ubuntu 7.10, so must be from early 2008 - still very educational and interesting, but probably worth mentioning the age, since x86_64 has become ubiquitous, kvm / bhyve / xhyve have appeared, EFI, virtio, directly booted kernels, other stuff I'm sure ...
UEFI applications are kind of weird, as until ExitBootServices is called they are regular hosted applications that need to call the EFI boot services to do things like allocating memory, once ExitBootServices is called they take full control of the system
You will need to build a cross compiler toolchain (binutils and GCC). I.e. i686-pc-elf-gcc for 32 bit or x86_64-pc-elf-gcc for 64 bit. The compiler that comes with your OS is built for a different target and may have downstream patches, esp. if you're on Ubuntu. Things may seem to work initially but you will encounter strange bugs sooner or later.
Build a bootable and debuggable ELF file, not a flat binary. All it takes is a slightly different linker script. You won't get very far without a debugger on bare metal projects.
You need to zero fill .bss section in the boot code before jumping to C code.
I recommend using gas instead of nasm. You might like Intel syntax but you'll need inline (at&t) assembly in C code anyway. Nicer to have just one syntax. It's just an assembler syntax, you will get used to it in a matter of hours
Use a makefile. Fancy build systems (e.g. cmake) aren't nice with kernel images.
See below for examples. The first one isn't my project but I contributed the linker script, Makefile and README for making bootable ELFs. The latter is my x86_64 toy kernel project from years ago.
https://github.com/Overv/MineAssemble
https://github.com/rikusalminen/danjeros