grub interview questions
Top grub frequently asked interview questions
I've written a simple kernel that tries to write two characters to the frame buffer.
If I define a string literal in the kernel, I get the following output when it boots:
Booting 'os'
kernel /boot/kernel.elf
Error 13: Invalid or unsupported executable format
Press any key to continue...
Otherwise, if I define two characters I get the following (note 'ab' at the start of the output):
abBooting 'os'
kernel /boot/kernel.elf
[Multiboot-elf, <0x100000:0x201:0x0>, <0x101000:0x0:0x1000>, shtab=0x102168,
entry=0x1001f0]
loader
I wrote the loader in assembly:
global loader ; the entry symbol for ELF
MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
FLAGS equ 0x0 ; multiboot flags
CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum
; (magic number + checksum + flags should equal 0)
KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes
section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number to the machine code,
dd FLAGS ; the flags,
dd CHECKSUM ; and the checksum
loader: ; the loader label (defined as entry point in linker script)
mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax
mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the
; stack (end of memory area)
extern run
call run
.loop:
jmp .loop ; loop forever
section .bss
align 4 ; align at 4 bytes
kernel_stack: ; label points to beginning of memory
resb KERNEL_STACK_SIZE ; reserve stack for the kernel
The kernel is written in c
#include "io.h"
#include "fb.h"
void run()
{
// try writing message to port
char* c = (char *) 10000;
c[0] = 'a';
c[1] = 'b';
fb_write(c, 2); // this does not cause the error
// fb_write("ab",2); // this line would cause the error
}
External headers
There are two external headers. One for IO ports called io.h and one for writing to the frame buffer called fb.h
Here is io.h and the implementation io.s
io.h:
#ifndef INCLUDE_IO_H
#define INCLUDE_IO_H
/** outb:
* Sends the given data to the given I/O port. Defined in io.s
*
* @param port The I/O port to send the data to
* @param data The data to send to the I/O port
*/
void outb(unsigned short port, unsigned char data);
#endif /* INCLUDE_IO_H */
io.s:
global outb ; make the label outb visible outside this file
; outb - send a byte to an I/O port
; stack: [esp + 8] the data byte
; [esp + 4] the I/O port
; [esp ] return address
outb:
mov al, [esp + 8]
mov dx, [esp + 4]
out dx, al
ret
fb.h
#include "io.h"
// FRAME BUFFER ================================
// Text colors
#define FB_BLACK 0
#define FB_BLUE 1
#define FB_GREEN 2
#define FB_CYAN 3
#define FB_RED 4
#define FB_MAGENTA 5
#define FB_BROWN 6
#define FB_LT_GREY 7
#define FB_DARK_GREY 8
#define FB_LT_BLUE 9
#define FB_LT_GREEN 10
#define FB_LT_CYAN 11
#define FB_LT_RED 12
#define FB_LT_MAGENTA 13
#define FB_LT_BROWN 14
#define FB_WHITE 15
// IO PORTS
#define FB_COMMAND_PORT 0x3D4
#define FB_DATA_PORT 0x3D5
// IO PORT COMMANDS
#define FB_HIGH_BYTE_COMMAND 14 // move cursor command low
#define FB_LOW_BYTE_COMMAND 15 // move cursor command high
/** fb_write_cell:
* used to write a character to a cell in the framebuffer
*
* param i which cell to write to
* param c the ascii char to write
* param fg foreground color
* param bf background color
*/
void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg);
/** fb_move_cursor:
* used to move the cursor within the frame buffer
*
* param pos position within frame buffer to move cursor to
*/
void fb_move_cursor(unsigned short pos);
/** fb_write:
* write some text to the cursor
*
* param buf pointer to character string
* param len length of string to write
*/
int fb_write(char *buf, unsigned int len);
fb.c
#include "fb.h"
void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg)
{
char *fb = (char *) 0x000B8000;
fb[i*2] = c;
fb[i*2 + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F);
}
void fb_move_cursor(unsigned short pos) {
outb(FB_COMMAND_PORT, FB_HIGH_BYTE_COMMAND);
outb(FB_DATA_PORT, ((pos>>8) & 0x00FF));
outb(FB_COMMAND_PORT, FB_LOW_BYTE_COMMAND);
outb(FB_DATA_PORT, pos & 0x00FF);
}
int fb_write(char *buf, unsigned int len) {
unsigned int i = 0;
for(i = 0; i < len; i++) {
fb_write_cell(i, buf[i], FB_BLACK, FB_WHITE);
}
return 0;
}
Building it
I have a linker script called link.ld and a Makefile. I'm using gcc cross compiler for i386-elf That I compiled using this guide (http://wiki.osdev.org/GCC_Cross-Compiler).
ENTRY(loader) /* the name of the entry label */
SECTIONS {
. = 0x00100000; /* the code should be loaded at 1 MB */
.text ALIGN (0x1000) : /* align at 4 KB */
{
*(.text) /* all text sections from all files */
}
.rodata ALIGN (0x1000) : /* align at 4 KB */
{
*(.rodata*) /* all read-only data sections from all files */
}
.data ALIGN (0x1000) : /* align at 4 KB */
{
*(.data) /* all data sections from all files */
}
.bss ALIGN (0x1000) : /* align at 4 KB */
{
sbss = .;
*(COMMON) /* all COMMON sections from all files */
*(.bss) /* all bss sections from all files */
ebss = .;
}
}
And here is my makefile
OBJECTS = io.o fb.o loader.o kmain.o
#CC = gcc
CC = /home/albertlockett/opt/cross/bin/i386-elf-gcc
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
-nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c
LDFLAGS = -T link.ld -melf_i386
AS = nasm
ASFLAGS = -f elf
all: kernel.elf
kernel.elf: $(OBJECTS)
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
os.iso: kernel.elf
cp kernel.elf iso/boot/kernel.elf
genisoimage -R \
-b boot/grub/stage2_eltorito \
-no-emul-boot \
-boot-load-size 4 \
-A os \
-input-charset utf8 \
-quiet \
-boot-info-table \
-o os.iso \
iso
run: os.iso
bochs -f bochsrc.txt -q
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
%.o: %.s
$(AS) $(ASFLAGS) $< -o $@
clean:
rm -rf *.o kernel.elf os.iso
Run it
The makefile builds an iso from the contents of a directory called iso. That folder contains a preconfigured version of grub that I got here (https://github.com/littleosbook/littleosbook/blob/master/files/stage2_eltorito) and a menu.lst file for grub
menu.lst:
default=0
timeout=0
title os
kernel /boot/kernel.elf
contents of iso directory:
iso
`-- boot
|-- grub
| |-- menu.lst
| `-- stage2_eltorito
`-- kernel.elf
The iso image boots in bochs. Here is my bochsrc.txt file
megs: 32
display_library: term
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
ata0-master: type=cdrom, path=os.iso, status=inserted
boot: cdrom
log: bochslog.txt
clock: sync=realtime, time0=local
cpu: count=1, ips=1000000
com1: enabled=1, mode=file, dev=com1.out
Does anyone know why the string literal in the kernel file produces the error when I try to boot the iso?
Source: (StackOverflow)
I would like to ask if it is GRUB that switch the CPU to protected mode during boot up or is it the Linux kernel that does it. And also I would like to ask - is the kernel itself (vmlinuz) an ELF or is it plain binary format? Thanks.
Source: (StackOverflow)
When building the latest grub2 (2.00) I get this error.
I have tried adding -Wno-unused-function
to both HOST_CFLAGS
, HOST_CPPFLAGS
, TARGET_CPPFLAGS
and TARGET_CFLAGS
in the Makefile
. I even tried deleting that function whilst make
was running!
Unfortunately the error remains.
Source: (StackOverflow)
I'm trying to write a grub2 bootloader script but if statements always evaluate to true:
if [ -s blabla ] ; then set zzz0="1" ; fi
if [ ! -s blabla ] ; then set zzz1="1" ; fi
set TEST_VAR=foo
if [ "x${TEST_VAR}" = "xfoo" ] ; then set zzz2="1" ; fi
if [ "x${TEST_VAR}" = "xbar" ] ; then set zzz3="1" ; fi
if [ $TEST_VAR = foo ] ; then set zzz4="1" ; fi
if [ $TEST_VAR = bar ] ; then set zzz5="1" ; fi
So, after running this script, I see all zzz (zzz0, zzz1, zzz2, zzz3, zzz4, zzz5)variables set to 1. What am I doing wrong?
Thanks,
Johnny
Source: (StackOverflow)
I'm trying to boot into read only mode to test some software. I don't want to remount a drive after booting as that would not meet the requirements to test the software which checks the file system at boot.
Is there a way to do this without editing grub.conf? Preferably adding something via the grub UI when interrupting boot?
If I do edit the grub.conf to boot in read only, how am I supposed to edit it back?
I understand that the kernel mounts root as RO but it's remounted as RW later in the boot process.
Source: (StackOverflow)
Can I run some some custom code at the time when GRUB loads up? In other words does GRUB provide a facility to run some custom code before loading any operating system?
Source: (StackOverflow)
I'm having an issue with Grub 2 (and QEMU's -kernel
) not detecting the Multiboot v1 header in my kernel. I have the header in a separate section before .text
.
linker.ld
:
SECTIONS
{
. = 1M;
.multiboot ALIGN(4K) :
{
*(.multiboot)
}
.text ALIGN(4K) :
{
*(.text)
}
[snip]
boot.s
(GNU as syntax):
.set MAGIC, 0x1badb002
.set FLAGS, (1<<0 | 1<<1) # align, provide mem map
.set CHECKSUM, -(MAGIC + FLAGS)
.section .multiboot
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .text
[snip]
I have verified that the header section is being added as specified with the magic number:
kernel.bin: file format elf32-i386
Contents of section .multiboot:
101000 02b0ad1b 03000000 fb4f52e4 .........OR.
Contents of section .text:
[snip]
Yet Grub 2 says that the kernel does not have a valid Multiboot header, and using QEMU's -kernel
option causes:
qemu: fatal: Trying to execute code outside RAM or ROM at 0x000a000
which seems to be an address in the BIOS-mapped range, not where Multiboot should be.
I've compared against the usual code in Bran's and OSDev (plus a previous kernel of mine) yet I can't seem to figure out what I'm doing wrong.
Source: (StackOverflow)
Recently, I have been experimenting with things like arch Linux and this raised a few questions. I constantly see the use of graphics in very low level parts of an OS(things like the GRUB or almost all boot menus). Some of these even feature images. I can also see graphical manipulation in things like the "pacman" command, where the loading bar will change with out disturbing the text above it. Another example would be a program like cfdisk. I would just like to know how these types of features are programmed?
Edit: By this I mean what system calls are used to make this possible?
Boot menu
Source: (StackOverflow)
So I upgraded kernel yum -y update kernel
on my AWS EC2 base image, and I get the following:
Running Transaction
Installing : kernel-2.6.32-504.3.3.el6.x86_64
grubby fatal error: unable to find a suitable template
Here is the contents of /boot/grub/grub.conf:
default=0
timeout=0
hiddenmenu
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
So grub.conf is not getting updated, and since I already have kernel-2.6.32-504.1.3.el6.x86_64 installed, grub did not get updated the last time I updated kernel either. I tried adding the kernel manually:
grubby --grub --add-kernel="/boot/vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs \
console=ttyS0" --title="CentOS (2.6.32-504.3.3.el6.x86_64)" \
--initrd=/boot/initramfs-2.6.32-504.3.3.el6.x86_64.img
and then /boot/grub/grub.conf looked like this:
default=0
timeout=0
hiddenmenu
title CentOS (2.6.32-504.3.3.el6.x86_64)
kernel /vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /initramfs-2.6.32-504.3.3.el6.x86_64.img
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
However, /vmlinuz-2.6.32-504.3.3.el6.x86_64
is not the kernel I entered. So I removed that and tried again with:
grubby --grub --add-kernel="/boot/boot/vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs \
console=ttyS0" --title="CentOS (2.6.32-504.3.3.el6.x86_64)" \
--initrd=/boot/boot/initramfs-2.6.32-504.3.3.el6.x86_64.img
which resulted in this:
timeout=0
default=1
hiddenmenu
title CentOS (2.6.32-504.3.3.el6.x86_64)
kernel /boot/vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs console=ttyS0 root=(hd0,0)
initrd /boot/initramfs-2.6.32-504.3.3.el6.x86_64.img
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
At this point, I manually edited /boot/grub/grub.conf to default=0
and rebooted, and my EC2 wouldn't boot. So I tried a new instance copy and got all these same errors, so I copied the existing settings to a new entry:
default=0
timeout=0
hiddenmenu
title CentOS (2.6.32-504.3.3.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /boot/initramfs-2.6.32-504.3.3.el6.x86_64.img
And rebooted, and it fails to boot again. Yet another try, I repeated the above but with root=/dev/xvda3
, and that failed to boot as well. So at this point, I have no way at all of upgrading my kernel. What do I do?
UPDATE: I figured out the /boot/boot/ stuff, and my /boot/grub/grub.conf now looks like this:
default=0
timeout=0
hiddenmenu
title CentOS (2.6.32-504.3.3.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-504.3.3.el6.x86_64 ro root=LABEL=rootfs console=ttyS0
initrd /initramfs-2.6.32-504.3.3.el6.x86_64.img
And I can successfully boot my system, however everything else about this remains true: installing a new kernel still results in "grubby fatal error: unable to find a suitable template", and grubby --default-kernel
still results in no output. I have to edit my /boot/grub/grub.conf manually for any kernel update.
Source: (StackOverflow)
I was following these tutorials to make a simple kernel that I would then load using GRUB. The instructions for compiling didn't work (ld couldn't find the -T option) and when I finally got a compiled file it was in Macho format. What are the correct steps to take when compiling these files on Mac.
Edit:
I compiled the code on an Ubuntu virtual machine and I so I have the kernel.bin file. Now how can I make a bootable image that runs the kernel?
Source: (StackOverflow)
I want to boot a custom kernel (non-multiboot) with GRUB2, I've read that I need grub.cfg
like this:
menuentry "custom kernel" {
set root=(hd0,0)
chainloader +1
}
So, I have some questions:
- How grub detect kernel? (with multiboot spec I used
kernel /boot/kernel.bin
)
- How my kernel must look like (sorry for my bad english)? Must it be 512 bytes at all (like custom bootloader, which loaded into 0x7c00)?
(hd0,0)
is hard drive partition and what I must put if I use CD? Maybe (cdrom0,0)
?
- To boot Linux kernel we can use
linux
command, can I use it to boot my custom kernel (with some changes)?
- Will Grub enter
Protected mode
or not?
Source: (StackOverflow)
I was following along with this series of articles, and on the last page, he linked an iso image of the kernel that he produced. He doesn't mention this in the series, so that's my question... how do I generate an iso image from my kernel executable?
Source: (StackOverflow)
From the past week I am puzzled with the question that how the grub first stage boot loader which is only 446 bytes is able to search for the second stage, when the second stage is in a complex file system! How does it locate the second stage?
When a complex partitioning scheme of windows and linux is in place, and the linux system is entirely in the extended partition, then how does the stage 1 finds the stage 2? Even stage 1.5?
All of the grub tutorials skim through this important part. I have searched though the internet but couldn't find anything that explains this. Sadly, I am not an assembly programmer.
I want to understand the boot process intricately in terms of which sectors of the hard disk are tickled (and roughly how) during bootup. *Please point me to a good resource or answer here. It will greatly help me to play with grub wisely.*
Some Resources Searched:
- How Linux Works : What every superuser should know by Brian Ward
- http://www.dedoimedo.com/computers/grub.html
- some past stackoverflow questions.
Source: (StackOverflow)
I have grub v1.98
installed and after disassembling the MBR I find the following code snippet that I don't understand:
xor ax,ax
mov [si+0x4],ax
inc ax
mov [si-0x1],al
mov [si+0x2],ax
mov word [si],0x10
mov ebx,[0x7c5c]
mov [si+0x8],ebx
mov ebx,[0x7c60]
mov [si+0xc],ebx
mov word [si+0x6],0x7000
mov ah,0x42
int 0x13
It seems this piece of code tries to set up disk address of stage 1.5 code, then load and run it. However, how could I figure out which physical block it tries to read? What's more, what is the destination of the stage 1.5 code? 0x7000
?
I refer to MBR for Windows 7, where subsequent boot up code is loaded 0x7c00
. Given MBR is first loaded at address 0x7c00
, it contains a piece of code copying MBR from 0x7c00
to 0x0600
and then branch to 0x0600
in case the original code corrupted. Will loading stage 1.5 code to address 0x7000
conflict the original code? What's more, I also find:
jmp short 0x65
nop
sar byte [si+0x7c00],1
mov es,ax
mov ds,ax
mov si,0x7c00
mov di,0x600
mov cx,0x200
cld
rep movsb
push ax
push word 0x61c
retf
at the beginning of the MBR. It seems the code tries to do the same thing as in MBR of windows 7 to copy the original MBR from 0x7c00
to 0x0600
, except for the first jmp
instruction. Will these codes in fact executed? If yes, when will control jumps here.(I believe the answer is YES, but am confused by the leading jmp
).
Source: (StackOverflow)
I'm using a barebones tutorial as the basis for an OS I'm working on, and it seems to be an older tutorial: it has be compiling the kernel down to a floppy image, and then loading it with GRUB.
Basically, I still want to use GRUB, but I'd like to have my OS run from a CD instead. The main reason is that I don't actually have a real floppy drive available (I'm testing in VirtualBox currently) and I thus have no way to test my OS on real hardware.
I've been poking around on the net, and I can find lots of utilities that create a bootable CD from a floppy image, but these all seem to require an actual floppy drive, plus it's not really what I'm looking for. I'd like to be able to end up with a bootable CD during my make step ideally, without needing to first place the image on a floppy, which seems rather pointless.
I guess the easy way to answer this: How do I set up GRUB to read my kernel image from a CD? Will I need a special utility to do this from Windows? (The kernel can't compile itself yet, that's not for a looong while)
Thanks!
Source: (StackOverflow)