awesome... :) i am definitely trying this out today...
{% raw %}
On mac OS X, for some reason,
dd - (0xe85250d6 + 0 + (header_end - header_start))
had no compiler warnings, while
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
led to
multiboot_header.asm:7: warning: numeric constant 0x100000000 does not fit in 32 bitsMac OS X 10.11.1
NASM version 0.98.40 (Apple Computer, Inc. build 11) compiled on Oct 5 2015
Well, that's unfortunate… Thank you for the hint, I opened an issue: https://github.com/phil-opp...
If (in my case on Mac OS X) grub-mkrescue (after you've installed it) gives the error "grub-mkrescue: warning: Your xorriso doesn't support `--grub2-boot-info'.", you just need to install xorriso. You probably don't have it at all yet.
This is an awesome series of blog posts!
If you don't see a green "OK", look for a "GRUB" message. If you don't see "GRUB", then the weak link is probably grub-mkrescue. Two common failure modes:
1. If your grub-mkrescue isn't installed correctly, it may silently do nothing or make bad ISO files. Try mounting your ISO file to make sure that it has your kernel and grub.cfg.
2. If you run Linux on an EFI machine, grub-mkrescue will produce EFI boot images that don't work with BIOS-based systems like QEMU. To fix this, see this article, which recommends installing grub-pc-bin and running:
grub-mkrescue /usr/lib/grub/i386-pc -o myos.iso isodir
This is definitely fun! I tried to do this from my Mac OS X (Yosemite) and could not properly boot my fresh ISO disk. Compilation works fine, I have installed a cross-compiler for x86_64-elf architecture, compiled grub following instructions here https://wiki.osdev.org/GRUB_...... I generate a correct ISO file (checked it by mounting using Disk Utility) but it does not boot and I cannot see the GRUB message.
Not sure how to troubleshoot this issue.... I suspect this might be a problem with incorrect format in grub as the last stage of compilation shows this message:
../grub/configure --build=x86_64-elf --target=x86_64-elf --disable-werror TARGET_CC=x86_64-elf-gcc TARGET_OBJCOPY=x86_64-elf-objcopy TARGET_STRIP=x86_64-elf-strip TARGET_NM=x86_64-elf-nm TARGET_RANLIB=x86_64-elf-ranlib LD_FLAGS=/usr/local/opt/flex/ CPP_FLAGS=/usr/local/opt/flex/include/
[..]
config.status: linking ../grub/include/grub/i386 to include/grub/cpu
config.status: linking ../grub/include/grub/i386/pc to include/grub/machine
config.status: executing depfiles commands
config.status: executing po-directories commands
config.status: creating po/POTFILES
config.status: creating po/Makefile
*******************************************************
GRUB2 will be compiled with following components:
Platform: i386-pc
With devmapper support: No (need libdevmapper header)
With memory debugging: No
With disk cache statistics: No
With boot time statistics: No
efiemu runtime: Yes
grub-mkfont: Yes
grub-mount: No (need FUSE headers)
starfield theme: No (No DejaVu found)
With libzfs support: No (need zfs library)
Build-time grub-mkfont: No (no fonts)
Without unifont (no build-time grub-mkfont)
With liblzma from -llzma (support for XZ-compressed mips images)
*******************************************************
I don't know what the i386-pc refer too, but if this is the target platform then it's probably incorrect. Note that I tried to boot using qemu-system-i386 but to no avail.
Regards,
What would happen if we didn't put hlt? Would the cpu start reading random bytes and execute them as code? I tried without hlt and qemu seems to go into an infinite boot loop, but I'm just wondering what's going on.
Yes, that exactly what happens. The CPU simply tries to read the next instruction, even if it doesn't exist, until it causes some exception. QEMU can print these exceptions, the "Setup Rust" post explains how. I just tried it and it hits an Invalid Opcode exception at some point because some memory is no valid instruction.
Bonus: You can use GDB to disassemble the “code” behind the start label. You need to start `qemu-system-x86_64 -hda build/os-x86_64.iso -s -S` in one console and `gdb build/kernel-x86_64.bin` in another. Then you need the following gdb commands:
- `set architecture i386` because we are still in 32-bit mode
- `target remote :1234` to connect to QEMU
(- `disas /r start,+250` to disassemble the 250 bytes after the `start` label. Everything will be 0 as GRUB did not load our kernel yet)
- `break start` to set a breakpoint at `start`
- `continue` to continue execution until start is reached. Now the kernel is loaded and we can use
- `disas /r start,+250` to disassemble the 250 bytes after the `start` label
Then you can look at the faulting address you got from the QEMU debugging to see your invalid instruction. For me it seems to be an `add (%eax),%al` with the Opcode `02 00`.
Nice post! I am on OS X, but I find it easier to use Linux for this assembly stuff. Using VirtualBox, I have created a minimal Debian machine running an SSH server and with a folder shared between the OS X host and the Debian guest. So, I may install all the needed tools and cross-compile in Debian and have the final .iso accessible in OS X (to use it with QEMU), all of this while working in Terminal.app as usual.
As a side note, I had to set LDEMULATION="elf_x86_64" before linking, because I was getting this error: `ld: i386:x86-64 architecture of input file `multiboot_header.o' is incompatible with i386 output`. This may be because I have used Debian's 32-bit PC netinst iso instead of the 64-bit version.
Thanks for sharing your experiences! There is an issue about Mac OS support, but it seems like using a virtual machine is the easiest way…
On my system and on some others grub-makerescue is actually called grub2-makerescue and should be represented accordingly in the makefile. Perhaps this merits a comment in the text since I was not alone (https://www.reddit.com/r/os... in spending some time trying to figure out what was happening after a rather meaningless error message from make.
Thanks! I opened an issue.
When I run grub-mkrescue I got no output an just silence
after install xorriso I got error like this
-----
xorriso 1.3.2 : RockRidge filesystem manipulator, libburnia project.
Drive current: -outdev 'stdio:os.iso'
Media current: stdio file, overwriteable
Media status : is blank
Media summary: 0 sessions, 0 data blocks, 0 data, 861g free
Added to ISO image: directory '/'='/tmp/grub.pI5jyq'
xorriso : UPDATE : 276 files added in 1 seconds
Added to ISO image: directory '/'='/path/to/my/work/isofiles'
xorriso : FAILURE : Cannot find path '/efi.img' in loaded ISO image
xorriso : UPDATE : 280 files added in 1 seconds
xorriso : aborting : -abort_on 'FAILURE' encountered 'FAILURE'
-----
and I search for resolve this error, I arrive here[ https://bugs.archlinux.org/42334 ]
after isntall mtools, grub-mkrescue create os.iso
After creating the iso, I can boot to it on QEMU with no problem. Even burning it on to a disk and booting on a different machine works like a charm. However, I am having trouble getting it on to an USB thumb drive. I have tried packing it on to a USB with UNetbootin, but as soon as the UNetbootin screen appears after booting to the USB device, (The OS selection screen, giving you the options [Default] and [my_os]), nothing happens. I can select either of those options, but nothing happens.
EDIT: Got it to work using the command line tool dd!
Thanks you for your great articles.
I have created my OS in Rust, and these are really useful for me.
I have been revising my OS based on your articles.
Also, I have been writing an article which is similar to your
http://mopp.github.io/articles/os/os00_intro
I added link into my articles to this website.
If you feel unpleasant, please tell me and I will remove it.
Thanks
I really enjoyed your accessible blog format and your awesome osdev tutorials!
I was inspired by your articles and decided to write my own :)
Let me know what you think.
http://tutorialsbynick.com/...
Thanks,
Nick
Hi guys if you want to boot the kernel in VirtualBox just modify the grub cfg file by setting the following variable properly, check https://www.gnu.org/softwar... for the options.
GRUB_TERMINAL_OUTPUT
This blog is just a treasure! I'm so happy that I found it. Thank you so much Phil!
By the way, my Arch Linux is booted in legacy BIOS mode (my BIOS doesn't even support EFI), but without '-d /usr/lib/grub/i386-pc/' grub-mkrescue didn't work for me.
P.S. Aside from this project, I think I will refer to your Makefile lot of times in future just to learn techniques that you used. I think it is the shortest example of so many Makefile best practices.
Ough.. probably you replied to first edition of my comment, but I didn't reload the page and didn't see your reply. Then I found my mistake (I put grub directory into the root of image, not into boot directory). And while thinking that nobody have seen my comment yet I edited it and removed the question about error. Sorry for my careless.
Why for the development of the core operation system, the language Rust? Why not C++? Does Rust have such opportunities as in C++?
Rust aims to be comparable to C++, both it terms of capabilities and in terms of performance. However, it has some great advantages over C++:
The greatest advantage of Rust is its memory safety. It prevents common bugs such as use after free or dangling pointers at compile time. So you get the safety of a garbage collected language, but without garbage collection. In fact, the safety guarantees go even further: The compiler also prevents data races and iterator invalidation bugs. So we should get a much safer kernel compared to C++.
(One caveat: Sometimes we need unsafe blocks for OS development, which weaken some safety guarantees. However, we try to use them only when it's absolutely needed and try to check them thoroughly.)
Another advantage of Rust is the great type system. It allows us to create powerful, generic abstractions, even for low level things such as page tables.
The tooling is great, too. Rust uses a package manager called “cargo”, which makes it easy to add various libraries to our project. Cargo automatically downloads the correct version and compiles/links it. Thus, we can use awesome libraries such as x86 easily.
For anyone else struggling with "Boot failed: Could not read from CDROM (code 0009)", you need to install `grub-pc-bin` and then regenerate the .iso. Solution from here: http://intermezzos.github.io/book/appendix/troubleshooting.html#could-not-read-from-cdrom-code-0009.
By the way, I'm loving the tutorial style. Very clear, thank you!
This is completely awesome!
YMMV but FWIW in Fedora 25, I needed to install three packages, `sudo dnf install nasm xorriso qemu-system-x86`. The last one installs fewer packages than installing "qemu" which adds two dozen ARM, m68k, S390, sparc, ... emulators as well 8-)
I find the example displays "OK" fine, but it erases the console before this so the boot messages disappear. I'm not sure if the fix lies in grub configuration or the qemu command line.
It is interesting to look at the contents of the CD-ROM image, though it mostly reveals the complexity of the GRUB bootloader. I used `mkdir temp_mount && sudo mount -t iso9660 -o loop os.iso temp_mount` then looked around in temp_mount.
I had 2 issues with making the iso. First, there was no output file, yet grub-mkrescue didn't complain, I fixed this by running "apt install xorriso" (Ubuntu). The other issue was that qemu couldn't read the cdrom (error 0009), fixed that one by running "apt install grub-pc-bin". Hope this helps some of you... and thanks for the awesome post Phil :)
The Makefile doesn't work for me. It gives only the error No rule to make target ' build/arch/x86_64/boot.o' needed by 'build/kernel-x86_64.bin'. I don't know what's going wrong....
It seems like there is some problem with this lines:
build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm
Do you have a file named build/arch/x86_64/boot.asm? For debugging, you could use explicit names instead of the wildcards (%):
build/arch/$(arch)/boot.o: src/arch/$(arch)/boot.asm
(Note that you need to copy this rule for every .asm file without wildcards.)
This is incredible, just fantastic..
I did have a couple of hiccups following along using Win10 WSL on a UEFI PC, maybe these details can be folded in to the tutorial?
1) Couldn't boot QEMU with emulated video device
warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
Could not initialize SDL(No available video device) - exiting
Solution: Use -curses option for qemu
qemu-system-x86_64 -curses -cdrom os-x86_64.iso
2) Could not boot from ISO (on a UEFI system)
Booting from DVD/CD...
Boot failed: Could not read from CDROM (code 0004)
Booting from ROM...
Solution: sudo -S apt-get install grub-pc-bin
I'm trying to do this, but I can't get the OK to actually display and I've kind of ran out of ideas. Trying to run with QEMU on Arch Linux.
Things I've tried: Adding the multiboot tag that should tell grub I want a text mode, 80x25. Just gives me a black screen, instead of saying "Booting 'my os'"
Switching grub to text mode with every possible switch I can find that looks related, with and without ^. Just gives me a black screen for all of them too.
I can confirm my code actually seems to be executed - or, at least, hits the hlt instruction. Just that there's no output, which makes me think VGA problems, hence me trying all of the above. That seems to leave trying to parse the multiboot header or something, and that seems like... something I don't really want to try to do in assembly, including pushing it over assembly? I don't really want to move unless this works, though, because I see you still are using text mode extensively further on. :/
Hi. Thanks for write, but i have an error when i run it in qemu - "error: no multiboot header found, error: you need to load kernel first". Whats wrong?
For anyone trying to push themselves into using the GNU assembler (i.e. as), if you're getting "no multiboot header" errors with QEMU, put the line:
.align 8
before the end tags.
great work in explaining how all the different pieces of hardware/software come together
Thank you!