From 89bfdd4db183cbe75a3a0c2254ca48a50e37276f Mon Sep 17 00:00:00 2001
From: Russ Cox <rsc@swtch.com>
Date: Tue, 11 Jan 2011 13:27:45 -0500
Subject: [PATCH] multiboot support and memory-only (no disk) kernel

---
 Makefile    | 24 +++++++++++++++--
 multiboot.S | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 2 deletions(-)
 create mode 100644 multiboot.S

diff --git a/Makefile b/Makefile
index 95247ff..980543a 100644
--- a/Makefile
+++ b/Makefile
@@ -82,6 +82,11 @@ xv6.img: bootblock kernel fs.img
 	dd if=bootblock of=xv6.img conv=notrunc
 	dd if=kernel of=xv6.img seek=1 conv=notrunc
 
+xv6memfs.img: bootblock kernelmemfs
+	dd if=/dev/zero of=xv6memfs.img count=10000
+	dd if=bootblock of=xv6memfs.img conv=notrunc
+	dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc
+
 bootblock: bootasm.S bootmain.c
 	$(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c
 	$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S
@@ -102,11 +107,23 @@ initcode: initcode.S
 	$(OBJCOPY) -S -O binary initcode.out initcode
 	$(OBJDUMP) -S initcode.o > initcode.asm
 
-kernel: $(OBJS) bootother initcode
-	$(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernel $(OBJS) -b binary initcode bootother
+kernel: $(OBJS) multiboot.o bootother initcode
+	$(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernel multiboot.o $(OBJS) -b binary initcode bootother fs.img
 	$(OBJDUMP) -S kernel > kernel.asm
 	$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
 
+# kernelmemfs is a copy of kernel that maintains the
+# disk image in memory instead of writing to a disk.
+# This is not so useful for testing persistent storage or
+# exploring disk buffering implementations, but it is
+# great for testing the kernel on real hardware without
+# needing a scratch disk.
+MEMFSOBJS = $(filter-out ide.o,$(OBJS)) memide.o
+kernelmemfs: $(MEMFSOBJS) multiboot.o bootother initcode fs.img
+	$(LD) $(LDFLAGS) -Ttext 0x100000 -e main -o kernelmemfs multiboot.o $(MEMFSOBJS) -b binary initcode bootother fs.img
+	$(OBJDUMP) -S kernelmemfs > kernelmemfs.asm
+	$(OBJDUMP) -t kernelmemfs | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernelmemfs.sym
+
 tags: $(OBJS) bootother.S _init
 	etags *.S *.c
 
@@ -187,6 +204,9 @@ QEMUOPTS = -hdb fs.img xv6.img -smp $(CPUS)
 qemu: fs.img xv6.img
 	$(QEMU) -serial mon:stdio $(QEMUOPTS)
 
+qemu-memfs: xv6memfs.img
+	$(QEMU) xv6memfs.img -smp $(CPUS)
+
 qemu-nox: fs.img xv6.img
 	$(QEMU) -nographic $(QEMUOPTS)
 
diff --git a/multiboot.S b/multiboot.S
new file mode 100644
index 0000000..2579b6d
--- /dev/null
+++ b/multiboot.S
@@ -0,0 +1,75 @@
+# Multiboot header, for multiboot boot loaders like GNU Grub.
+# http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
+#
+# Using GRUB 2, you can boot xv6 from a file stored in a
+# Linux file system by copying kernel or kernelmemfs to /boot
+# and then adding this menu entry:
+#
+# menuentry "xv6" {
+# 	insmod ext2
+# 	set root='(hd0,msdos1)'
+# 	set kernel='/boot/kernel'
+# 	echo "Loading ${kernel}..."
+# 	multiboot ${kernel} ${kernel}
+# 	boot
+# }
+
+#include "asm.h"
+
+#define STACK 4096
+
+#define SEG_KCODE 1  // kernel code
+#define SEG_KDATA 2  // kernel data+stack
+
+# Multiboot header.  Data to direct multiboot loader.
+.p2align 2
+.text
+.globl multiboot_header
+multiboot_header:
+  #define magic 0x1badb002
+  #define flags (1<<16 | 1<<0)
+  .long magic
+  .long flags
+  .long (-magic-flags)
+  .long multiboot_header  # beginning of image
+  .long multiboot_header
+  .long edata
+  .long end
+  .long multiboot_entry
+
+# Multiboot entry point.  Machine is mostly set up.
+# Configure the GDT to match the environment that our usual
+# boot loader - bootasm.S - sets up.
+.globl multiboot_entry
+multiboot_entry:
+  lgdt gdtdesc
+  ljmp $(SEG_KCODE<<3), $mbstart32
+
+mbstart32:
+  # Set up the protected-mode data segment registers
+  movw    $(SEG_KDATA<<3), %ax    # Our data segment selector
+  movw    %ax, %ds                # -> DS: Data Segment
+  movw    %ax, %es                # -> ES: Extra Segment
+  movw    %ax, %ss                # -> SS: Stack Segment
+  movw    $0, %ax                 # Zero segments not ready for use
+  movw    %ax, %fs                # -> FS
+  movw    %ax, %gs                # -> GS
+
+  # Set up the stack pointer and call into C.
+  movl $(stack + STACK), %esp
+  call main
+spin:
+  jmp spin
+
+# Bootstrap GDT
+.p2align 2                                # force 4 byte alignment
+gdt:
+  SEG_NULLASM                             # null seg
+  SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg
+  SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg
+
+gdtdesc:
+  .word   (gdtdesc - gdt - 1)             # sizeof(gdt) - 1
+  .long   gdt                             # address gdt
+
+.comm stack, STACK
-- 
GitLab