summaryrefslogtreecommitdiff
path: root/sos-code-article4/extra
diff options
context:
space:
mode:
authorAlex AUVOLAT <alex.auvolat@ens.fr>2014-03-28 09:10:23 +0100
committerAlex AUVOLAT <alex.auvolat@ens.fr>2014-03-28 09:10:23 +0100
commitbb55beef914e7488350ad1d0419d4bc60ad63c99 (patch)
treeb1cfe0e5c76cbca16e7e3c16e108c23e366a2902 /sos-code-article4/extra
downloadSOS-bb55beef914e7488350ad1d0419d4bc60ad63c99.tar.gz
SOS-bb55beef914e7488350ad1d0419d4bc60ad63c99.zip
Import code for article1, 2, 3, 4
Diffstat (limited to 'sos-code-article4/extra')
-rw-r--r--sos-code-article4/extra/Makefile40
-rw-r--r--sos-code-article4/extra/README73
-rw-r--r--sos-code-article4/extra/bootsect.S393
-rw-r--r--sos-code-article4/extra/dot.mkvars29
-rw-r--r--sos-code-article4/extra/grub.img.gzbin0 -> 67535 bytes
-rw-r--r--sos-code-article4/extra/mtoolsrc2
-rw-r--r--sos-code-article4/extra/qemu-port-e9.diff73
-rw-r--r--sos-code-article4/extra/sos_bsect.lds61
8 files changed, 671 insertions, 0 deletions
diff --git a/sos-code-article4/extra/Makefile b/sos-code-article4/extra/Makefile
new file mode 100644
index 0000000..f858aa6
--- /dev/null
+++ b/sos-code-article4/extra/Makefile
@@ -0,0 +1,40 @@
+OBJCOPY=objcopy
+
+all: sos_qemu.img
+
+-include ../.mkvars
+
+# The image is the simple concatenation of the boot sector and the kernel
+# It may be use in bochs or on a real floppy, but NOT in qemu (see below)
+sos_bsect.img: bsect.bin sos.bin
+ cat $^ > $@
+ @echo "You can use the $@ image in bochs or on a real floppy (NOT qemu)"
+
+# For qemu, the trick is to tell it we have *more* than 1440 sectors (720kB).
+# Rtherwise the qemu disk geometry will be configured to be that of a 720kB
+# floppy, while our boot sector assumes it to be 1.44MB
+sos_qemu.img: sos_bsect.img
+ # Padding with 0s after the bsect/kernel image
+ cat $< /dev/zero | dd of=$@ bs=1k count=1440
+ @echo "You can use the $@ image in qemu, bochs, or on a real floppy"
+
+# we extract the boot sector from the main ELF binary
+bsect.bin: sos_bsect.elf
+ $(OBJCOPY) -v -O binary -j .bootsect $< $@
+
+# we extract the kernel code from the main ELF binary
+sos.bin: sos_bsect.elf
+ $(OBJCOPY) -v -O binary -R .bootsect $< $@
+
+# The main ELF binary contains the boot sector and the kernel code
+# linked together (hence we deal with a SINGLE image that we split
+# above) because they share some symbol definitions
+sos_bsect.elf: bootsect.o compile_kernel
+ $(LD) --warn-common -T ./sos_bsect.lds -o $@ \
+ bootsect.o $(wildcard ../hwcore/*.o ../drivers/*.o ../sos/*.o)
+
+compile_kernel:
+ $(MAKE) -C ..
+
+clean:
+ $(RM) *.img *.elf *.bin *~ *.o *.out
diff --git a/sos-code-article4/extra/README b/sos-code-article4/extra/README
new file mode 100644
index 0000000..0272f1f
--- /dev/null
+++ b/sos-code-article4/extra/README
@@ -0,0 +1,73 @@
+
+Contents of the extra/ directory
+================================
+
+Data and configuration files to support generation of sos on non-x86
+and/or grub-less hosts:
+ - dot.mkvars: file to copy as .mkvars in the root directory to
+ compile on a non-x86 host, and to generate the grub floppy image on
+ a grub-less host
+ - grub.img.gz: compressed image of a Grub floppy (without any
+ kernel). Used by dot.mkvars.
+ - mtoolsrc: file needed by .mkvars to compile a the floppy image
+
+Support of a sos-specific boot sector:
+ - Makefile: rules to compile sos_bsect.img, the floppy image with the
+ boot sector and the Sos
+ - bootsect.S: x86 Sos boot sector (GNU as). Depends on sos_bsect.lds
+ - sos_bsect.lds: ld script to bind the boot sector with the remaining
+ of the kernel
+
+Misc:
+ - qemu-port-e9.diff: patch over qemu to support the bochs "port 0xe9 hack"
+
+
+What you can do with these files
+================================
+
+
+*** Compile SOS from another architecture:
+------------------------------------------
+ - compile a cross-compiler for the i586-gnu target. This involves
+ compiling the binutils and gcc. Here are example configuration
+ options for them:
+ binutils (replace sparc-cun-solaris with your arch):
+ ../binutils-2.13/configure --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/binutils-2.11 --host=sparc-sun-solaris2.7 i586-gnu
+ make && make install
+ gcc (ditto):
+ CFLAGS="-O2 -Dinhibit_libc" ../gcc-3.2/configure --target=i586-gnu --prefix=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/stow/gcc-3.2 --with-as=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/as --with-ld=/udd/ddecotig/temp_dd/xgcc/host-sparc-solaris7/bin/ld --with-gnu-as --with-gnu-ld --enable-languages=c --disable-shared --disable-multilib --disable-nls --enable-threads=single
+ make && make install
+ - compile the mtools
+ - copy dot.mkvars to the root directory of SOS, as ".mkvars"
+ - customize the CC/LD/... variables to suit your cross-compiler
+ installatioon
+ - now you may run make from the SOS root directory, it should
+ generate the Grub boot floppy image. The following warning is
+ normal:
+ .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img »
+ Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img »
+
+
+*** To compile SOS from an x86 where grub is not or incorrectly installed:
+--------------------------------------------------------------------------
+ - copy dot.mkvars to the root directory of SOS, as ".mkvars"
+ - customize the CC/LD/... variables to suit your cross-compiler
+ installatioon
+ - now you may run make from the SOS root directory, it should
+ generate the Grub boot floppy image. The following warning is
+ normal:
+ .mkvars:16: attention : écrasement des commandes pour la cible « grub-sos.img »
+ Makefile:92: attention : anciennes commandes ignorées pour la cible « grub-sos.img »
+
+
+*** To compile SOS with its own bootloader:
+-------------------------------------------
+ - for cross-architecture compilation: see above
+ - cd to this extra/ directory
+ - run 'make'
+ - the floppy image is: sos_bsect.img
+ NOTE : SOS will not boot correctly this way after article 2 !
+
+
+--
+David Decotigny
diff --git a/sos-code-article4/extra/bootsect.S b/sos-code-article4/extra/bootsect.S
new file mode 100644
index 0000000..f01ca20
--- /dev/null
+++ b/sos-code-article4/extra/bootsect.S
@@ -0,0 +1,393 @@
+
+/*
+ * @(#) $Id: bootsect.S,v 1.6 2004/06/18 07:43:51 d2 Exp $
+ * Description : Bootsecteur en syntaxe AT&T
+ * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty
+ * Jerome Petazzoni & Bernard Cassagne & coffeeman
+ * David Decotigny
+ * Bug reports to kos-misc@enix.org
+ */
+
+/*
+ * But global de ce bootsecteur :
+ *
+ * - Initialiser la becane
+ * - Charger le kernel
+ * - Passer en mode protege
+ * - Executer le kernel
+ *
+ * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire
+ * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55. Sur
+ * les 510 octets reellement utilisables, il reste 3 octets dispo (60
+ * si on decide d'enlever le BPB un jour) !!!
+ *
+ * thomas_petazzoni : - detection des codes d'erreurs de chargement
+ * David_Decotigny : - Passage en GNU as
+ * David_Decotigny : - Chargement du noyau au-dela du 1er Mega (taille
+ * max = 0x9e000 octets = 632ko), pour avoir le
+ * meme noyau sous grub et avec le bootsecteur
+ */
+
+ /*
+ * Sequence d'operations :
+ * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit
+ * la representation 0x7c0:0000 pour que le .org 0 reste valide
+ * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On
+ * choisit la representation 0x9f00:0000 pour que le .org 0 reste
+ * valide
+ * - Le bootsect verifie que le processeur est du type 386+
+ * - Il charge le noyau depuis la disquette en memoire a partir de
+ * 0x1000 (LOAD_ADRESS). Le noyau peut au max tenir sur
+ * SECTORS_TO_LOAD secteurs
+ * - Il passe en pmode flat (apres ouverture a20)
+ * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse
+ * finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace
+ * LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets =
+ * 632ko. Le noyau peut donc au max faire 632ko. Le nombre max de
+ * secteurs de disquette qu'on peut charger est donc 1264
+ */
+
+
+/* La taille de la pile */
+#define BOOT_STACK_SIZE 0x4000
+
+ .file "bootsect.S"
+
+ /* Tout est place dans une seule section */
+ .section ".bootsect"
+
+ /* L'essentiel du bootsector (sauf les 1eres instructions)
+ sont a un offset 0. On fait en sorte que le compilo soit
+ d'accord la-dessus. Quand on a des adresse realm exotiques
+ (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un
+ offset de 0 => on choisira le segment adapte (0x7c0,
+ 0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */
+ .org 0
+
+ /* Pour que gas genere du 16bits, afin que ca marche en realm */
+ .code16
+
+#define SECTORS_TO_LOAD 128 /* 64 ko */ /* MAX=1264 */
+
+/*
+ * Parametres de la disquette. Comme c'est chiant de faire une
+ * procedure de detection auto, et que ca prend de la place, on fait
+ * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une
+ * 1.44 Mo a 18 secteurs/pistes
+ */
+#define CYLS 80
+#define HEADS 1
+#define SECTS 18
+
+#define BOOT_ADRESS 0x07C00 /* Adresse de demarrage (lineaire) */
+#define BOOT_SEG (BOOT_ADRESS>>4) /* Segment de Boot */
+#define BOOT_SIZE 512 /* Taille bu bootsecteur */
+#define COPY_ADRESS 0x9F000 /* La ou on va copier le
+ bootsecteur (lineaire) */
+#define COPY_SEG (COPY_ADRESS>>4) /* Segment de la ou on va
+ copier le bootsecteur */
+#define LOAD_ADRESS 0x01000 /* 1er chargement du systeme */
+#define LOAD_SEG (LOAD_ADRESS>>4) /* Segment du 1er chargement du */
+#define MAX_KERN_LEN COPY_ADRESS-LOAD_ADRESS /* Taille noyau maxi */
+
+/* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente
+ dans sos.lds ! */
+#define FINAL_ADDRESS 0x200000 /* Adresse finale (physique de 0 a 4G)
+ ou est charge le noyau */
+
+#define OP16 .byte 0x66 ;
+#define OP32 .byte 0x66 ;
+
+/*
+ * Procedure qui vide le buffer clavier.
+ */
+#define WAITKB \
+ 1: ;\
+ .word 0xeb ;\
+ .word 0xeb ;\
+ inb $0x64, %al ;\
+ andb $0x2, %al ;\
+ jnz 1b
+
+ /* Le point d'entree dans le bootsect */
+.globl _bsect
+_bsect:
+
+ /*
+ * La portion qui suit est situee a un offset 0x7c00 en
+ * memoire. Attention donc aux references memoire dans cette
+ * partie. On choisit de rester en offset 0 (.org 0), mais on
+ * charge correctement les segments a 0x7c0.
+ */
+
+ movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */
+ movw %ax, %ds /* on le copie a l'adresse COPY_ADRESS */
+ xorw %si, %si /* comme cette adresse est la plus haute de la mem */
+ xorw %di, %di /* on pourra charger un kernel + gros */
+ movw $(BOOT_SIZE>>1), %cx
+ movw $COPY_SEG, %ax
+ movw %ax, %es
+ cld
+ rep ; movsw
+
+ /* on continue a executer le bootsecteur, mais maintenant a
+ partir de 0x9F000, qu'on represente sous la forme
+ 0x9f00:offset */
+ ljmp $COPY_SEG, $here
+
+ /*
+ * A partir de maintenant, on est a un offset 0 en memoire
+ * (segment 0x9f00), conformement a ce que veut le compilo.
+ */
+here:
+ movw %ax, %ds
+
+ /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k
+ correspondent au vecteur d'interruptions). */
+ movw %ax, %ss
+ movw $(LOAD_ADRESS - 0x10), %sp
+
+ /* Efface l'ecran */
+ movb $0x0, %ah
+ movb $0x3, %al
+ int $0x10
+
+ /* Affiche les messages d'attente */
+ movw $loadkern, %si
+ call message
+ movw $check, %si
+ call message
+
+check386:
+ /*
+ * la attention, plus complexe : on teste si le proc est un
+ * 386+ pour cela, on va essayer de modifier les bits 12 ? 14
+ * du registre E-flag si la modification reste, alors le proc
+ * est un 386+, sinon, c'est =< 286
+ *
+ * Merci a Emmanuel Marty pour la compatibilite avec les 386
+ * "pre-jurassique"
+ */
+
+ pushf /* on sauvegarde le E-Flag */
+ movb $0x70, %ah
+ pushw %ax
+ popf
+ pushf
+ popw %ax
+ orb %ah, %ah
+ je no386 /* si la modif n'est pas valable, alors on saute a
+ no386 */
+ popf /* on les restaure ? la fin ... */
+
+ /* Message de confirmation de 386+ et d'attente */
+ movw $found386, %si
+ call message
+ movw $loading, %si
+ call message
+
+/* Copie du noyau disquette => RAM a partir de 0x1000
+ L'adresse de destination est définie par es:0, où es vaut
+ initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4
+ ko). Chaque itération incrémente ce registre es de 32, ce qui
+ correspond à un bond de 32*16 en mémoire, soit la taille d'un
+ secteur. De cette façon, puisqu'on joue sur les segments plutôt que
+ sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle
+ est limitée par contre à la taille de la mémoire disponible sous
+ les 1Mo, \ie 640 ko (0x9f000 - 0x1000). */
+copyKernel:
+ /* Chargement du noyau en LOAD_SEG:0 */
+ /* 3 iterateurs :
+ - load_size : le nbre de secteurs a charger
+ - cl : le secteur ou on en est pour le
+ cylindre en cours (<= SECTS)
+ - dh : la tete en cours (0/1)
+ */
+ movb $0, %dl
+ movw $LOAD_SEG, %ax
+ movw %ax, %es
+
+ xorw %bx, %bx
+ xorw %dx, %dx
+ movw $1, %cx /* premier secteur */
+
+.nextsector: /* prochain secteur */
+ incb %cl /* en incrementant CL */
+ cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes)
+ alors on charge */
+ jbe .sector
+ movb $1, %cl /* sinon on revient au secteur 1 */
+ incb %dh /* mais sur l'autre tete */
+ cmpb $1, %dh /* on recompare, si DH =< 1 */
+ je .sector /* on charge */
+ movb $0, %dh /* sinon on repasse a la tete 0 */
+ incb %ch /* mais on change de cylindre */
+
+.sector:
+ pushw %es
+ movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */
+ int $0x13 /* Go ! */
+ jc halt /* erreur */
+ popw %ax
+ addw $32, %ax /* on a charge un secteur, donc on doit
+ charger 512 bytes plus loin */
+ movw %ax, %es /* on avance donc le segment du buffer de
+ 32bytes, ie 1 secteur en RAM (car 32*16=512) */
+
+ movw $(0x0E*256+'.'), %ax /* affiche un point */
+ int $0x10
+
+ decw (load_size) /* et on repart pour le prochain secteur
+ tant qu'on n'a pas fini ! */
+ jnz .nextsector
+
+after:
+ movw $0x03f2, %dx
+ inb %dx, %al /* stoppe le moteur */
+ andb $0x0f, %al
+ outb %al, %dx
+
+ cli /* on interdit les interruptions */
+
+fincopie:
+ pushw %cs
+ popw %ds
+
+ /* on ouvre la porte A20 */
+ WAITKB /* on vide le buffer */
+ movb $0xd1, %al /* on met a jour le port */
+ outb %al, $0x64
+ WAITKB
+ movb $0xdf, %al /* bit 2 = ouverture/fermeture */
+ outb %al, $0x60
+
+ /*
+ * init gdt
+ */
+InitGDT:
+ /* Préparation du flat mode */
+ lgdt gdtr
+
+GoPMode:
+ /* Passage en mode protégé */
+ movl %cr0, %eax
+ orb $1, %al /* set PE bit to 1 */
+ movl %eax, %cr0
+
+ /* we are not yet in Pmode jump 'in' pmode clearing prefetch
+ * queue and loading a new selector */
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+/*
+ * Code 32 bits ============================================================
+ */
+ .code32
+
+JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits
+ et en utilisant la gdt, et vide la prefetch queue */
+ .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est
+ encore en 16 bits */
+ ljmp $0x8, $(COPY_ADRESS+(Here32))
+Here32:
+ /* Et voila : On est en 32 bits vrai */
+
+MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa
+ destination finale (FINAL_ADDRESS) */
+ movl $0x10, %eax
+ movl %eax, %ds /* Seg Src = DSeg */
+ movl %eax, %es /* Sed Dest = DSeg */
+ cld
+ movl $LOAD_ADRESS, %esi /* On commence la copie au debut du noyau */
+ movl $FINAL_ADDRESS, %edi /* On copie vers cette adresse */
+ movl $MAX_KERN_LEN, %ecx /* Taille recopie */
+ shrl $2, %ecx
+ rep
+ movsl
+
+LaunchKernel:
+ /* Met en place une pile au niveau du symbole "stack" */
+ movl %eax, %ss
+ movl $(stack + BOOT_STACK_SIZE), %ebp
+ movl %ebp, %esp
+
+ /* Saut vers le noyau. La GDT est en place (flat mode), les
+ * selecteurs aussi, a20 est ouverte, et les interruptions sont
+ * cli + pas de idt. Le PIC n'est pas programme */
+ ljmp $0x8, $sos_main
+
+/*
+ * Utilities ============================================================
+ */
+ .code16
+
+message:
+ lodsb /* charge ds:si dans al et incremente si */
+ orb %al, %al /* si al = 0 */
+ jz 1f
+ movb $0x0e, %ah /* service 0Eh (affichage d'un caractere) */
+ movw $0x0007, %bx /* Parametres : blanc sur fond noir */
+ int $0x10 /* Appel de l'interruption 10h */
+ jmp message /* On repart au début ... */
+ 1: ret /* si la chaine est finie alors on retourne
+ dans la fonction appelante */
+
+halt:
+ pushw %cs
+ popw %es
+ movw $haltmsg, %si
+ call message
+ cli
+ 1: jmp 1b
+ ret
+
+no386:
+ movw $need386, %si
+ call message
+ call halt
+
+ /*
+ * GDT
+ */
+
+gdt:
+gdtr:
+NULL_Desc:
+ .word (EndGDT)-(gdt)-1 /* Taille GDT */
+ .long (gdt)+COPY_ADRESS
+unused:
+ .word 0
+
+CS_Desc: /* 0x8 */
+ .word 0xFFFF, 0
+ .byte 0, 0x9B, 0xCF, 0
+
+DS_Desc: /* 0x10 */
+ .word 0xFFFF, 0
+ .byte 0, 0x93, 0xCF, 0
+
+EndGDT:
+
+ /* quelques messages */
+
+loadkern: .string "-= S O S =- : The Simple Operating System \r\n"
+check: .string "Checking for a 386+ processor... "
+found386: .string " [OK]\r\n"
+need386: .string " [FAILED]\r\n"
+diskerror: .string "Disk Error\r\n"
+loading: .string "Loading... "
+haltmsg: .string "System Halted\r\n"
+
+/*** Les code/données du boot secteur se terminent ICI. le marqueur de
+ * fin (aa55) est ajouté automatiquement par le script ld
+ * sos_bsect.lds ***/
+
+/* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve
+ declaree avec le noyau, dans sa section ".bss", cad HORS du boot
+ secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la
+ définir directement dans le sos_bsect.lds, ou dans un fichier .c
+ auxiliaire pour plus de clarté */
+.comm stack, BOOT_STACK_SIZE
diff --git a/sos-code-article4/extra/dot.mkvars b/sos-code-article4/extra/dot.mkvars
new file mode 100644
index 0000000..1f7dca5
--- /dev/null
+++ b/sos-code-article4/extra/dot.mkvars
@@ -0,0 +1,29 @@
+# For cross-compilation and/or installations without grub available,
+# copy this file as .mkvars to the root directory of the SOS sources,
+# and customize the CC/LD/... variables. You still need the mtools
+# installed and running
+
+CC := i586-gnu-gcc
+LD := i586-gnu-ld
+OBJCOPY := i586-gnu-objcopy
+CFLAGS += -O3
+
+# Configuration of mtools
+MTOOLSRC = extra/mtoolsrc
+export MTOOLSRC
+
+$(MULTIBOOT_IMAGE): $(KERNEL_OBJ) menu.txt
+ gzip -dc < extra/grub.img.gz > $@
+ mcopy menu.txt v:/boot/grub/
+ mmd v:/system
+ mcopy sos.elf v:/system/sos.elf
+
+menu.txt:
+ echo timeout 0 > $@
+ echo default 0 >> $@
+ echo title SOS >> $@
+ echo "root (fd0)" >> $@
+ echo kernel /system/sos.elf >> $@
+
+runbochs: all
+ echo c | bochs -q
diff --git a/sos-code-article4/extra/grub.img.gz b/sos-code-article4/extra/grub.img.gz
new file mode 100644
index 0000000..4f98e74
--- /dev/null
+++ b/sos-code-article4/extra/grub.img.gz
Binary files differ
diff --git a/sos-code-article4/extra/mtoolsrc b/sos-code-article4/extra/mtoolsrc
new file mode 100644
index 0000000..df1a26e
--- /dev/null
+++ b/sos-code-article4/extra/mtoolsrc
@@ -0,0 +1,2 @@
+# For older versions of mtools, you may have to remove "filter"
+drive v: file="fd.img" 1.44M filter
diff --git a/sos-code-article4/extra/qemu-port-e9.diff b/sos-code-article4/extra/qemu-port-e9.diff
new file mode 100644
index 0000000..d8be044
--- /dev/null
+++ b/sos-code-article4/extra/qemu-port-e9.diff
@@ -0,0 +1,73 @@
+--- Makefile.target 17 Mar 2004 23:46:04 -0000 1.19
++++ Makefile.target 18 Mar 2004 14:20:29 -0000
+@@ -217,7 +217,8 @@
+ # must use static linking to avoid leaving stuff in virtual address space
+ VL_OBJS=vl.o osdep.o block.o monitor.o \
+ ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \
+- fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
++ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o \
++ port-e9.o
+ ifeq ($(TARGET_ARCH), ppc)
+ VL_OBJS+= hw.o
+ endif
+--- hw/pc.c 14 Mar 2004 21:46:48 -0000 1.2
++++ hw/pc.c 18 Mar 2004 14:20:29 -0000
+@@ -371,6 +371,7 @@
+ SB16_init();
+
+ fdctrl_init(6, 2, 0, 0x3f0, fd_table);
++ port_e9_init();
+
+ cmos_init(ram_size, boot_device);
+ }
+--- /dev/null 2003-01-30 11:24:37.000000000 +0100
++++ port-e9.c 2004-03-18 15:18:52.660493187 +0100
+@@ -0,0 +1,38 @@
++/*
++ * QEMU Port 0xe9 hack
++ *
++ * Copyright (c) 2000-2004 E. Marty, the bochs team, D. Decotigny
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++ * THE SOFTWARE.
++ */
++#include <stdio.h>
++#include <unistd.h>
++#include <inttypes.h>
++
++#include "vl.h"
++
++static void bochs_e9_write(void *opaque, uint32_t address, uint32_t data)
++{
++ write(fileno(stdout), &data, 1);
++}
++
++void port_e9_init ()
++{
++ register_ioport_write(0xe9, 1, 1, bochs_e9_write, NULL);
++}
+--- vl.h 17 Mar 2004 23:17:16 -0000 1.14
++++ vl.h 18 Mar 2004 14:29:06 -0000
+@@ -268,4 +268,7 @@
+ void term_flush(void);
+ void term_print_help(void);
+
++/* port-e9.c */
++void port_e9_init(void);
++
+ #endif /* VL_H */
diff --git a/sos-code-article4/extra/sos_bsect.lds b/sos-code-article4/extra/sos_bsect.lds
new file mode 100644
index 0000000..ac42f23
--- /dev/null
+++ b/sos-code-article4/extra/sos_bsect.lds
@@ -0,0 +1,61 @@
+/* Copyright (C) 2004, David Decotigny
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA.
+*/
+
+SECTIONS
+{
+ /* ***********************************************
+ * The bootsector is here. We link it against the remaining of the kernel
+ * in order to automatically figure out its size that must be loaded
+ * from file to memory (see the load_size definition below)
+ */
+
+ /* If we use one, we put the boot sector here. We don't set its
+ * address to 0x7c000 (aka 0x7c00:0), since it reloads itself to
+ * 0x9f000, causing the 0x7c000 address to be meaningless too. So we
+ * chose to pretend that the address is 0x0, and to make a little
+ * address arithmetic in bootsect.S */
+ .bootsect 0x0 :
+ {
+ /* The code for the boot sector goes here */
+ *(.bootsect);
+
+ /* The load_size symbol contains the size of the area (in
+ * sectors, aka 512 Bytes) that the boot sector should copy from
+ * the disk. The bss section is not included since it uses 0
+ * bytes on disk */
+ load_size = .;
+ LONG((__e_load - __b_load + 511) >> 9);
+ /* ---> This is equivalent to ceil( (__e_load - __b_load) / 512 ) */
+
+ /* At offsets 511 and 512, we set the boot sector signature (AA55h) */
+ . = 0x1fe;
+ SHORT(0xAA55);
+ }
+}
+
+
+/* This is to avoid a cut/paste here. Please notice that a multiboot
+ * section WILL be inserted, which is NOT mandatory (we could have
+ * removed it without getting into trouble). Please note however that
+ * the *.bin files will NOT be multiboot compatible (they are not in ELF
+ * format): they are expected to be directly booted by the BIOS (or
+ * by the "chainloader" command of Grub). */
+INCLUDE ../support/sos.lds
+
+/* We overload the entry set in sos.lds, just to avoid an ld warning */
+ENTRY(sos_main);