Assignment #1: Bootup Mechanism
CS422/522: Operating Systems, Spring 2008, Yale University
The "bootblock" and "createimage" from this assignment will be used throughout the semester.
We have provided code for project 1 for you to use as a starting point. The code can be found on the ZOO machines in /c/cs422/as/1/*. The 1 directory should contain nine files:
Since our entire project will be using the USB flash disk, please do not read/modify the hard disk.
To sign up for the design review, please send an email to the TA.
A PC can be booted up in two modes: cold boot or warm boot. Cold boot means you power down and power up the machine by pressing the power button of a PC. Warm boot means that you press <ctrl><alt><del> keys together. Either way, the PC will reset the processor and run a piece of code in the BIOS to try to read the first sector from the first bootable device. So you should set the computer to try to boot from the USB flash device if the computer BIOS supports that. Otherwise, it will try to read a sector from other bootable device (say 1st hard disk drive). Once this sector is read in, the CPU will jump to the beginning of the loaded code. In this project, the bootup code will be in the so called real mode (instead of protected mode, see links for more information).
A word about debugging: unless you are already familiar with assembly programming, you may find debugging low-level boot code more difficult at first. We will cover some general strategies for debugging the boot strap in section, but you may also find it useful to use a PC simulator such as Bochs or Qemu. More information on Bochs may be found here.
The bootblock gets loaded at memory address 0x07c0:0000. Your bootblock should load the OS starting at 0x0000:1000. In real mode, you have 640 KBytes starting at 0x0000:0000. The low memory area has some system data like the interrupt vectors and BIOS data. So, to avoid overwriting them, you should only use memory above 0x0000:1000 for this assignment.
To design and implement this, you need to learn about x86 architecture, CPU resets and how to read a sector from the USB flash drive with BIOS (described below). We have provided you with a trivial and useless kernel (kernel.s) to test whether your implementation works.
Note: You can assume that the entire OS is less or equal to 127 sectors for this project. If you are working on your home machines rather than the lab machines, please make sure your program also run on lab machine before submit it because your TA will be testing your program on lab machine.
The links on the main page provide assistance in understanding x86 assembly language and architecture. The precept will also give assistance in understanding these topics.
To test your bootblock you can use the createimage.given file. Type './createimage.given --extended ./bootblock ./kernel' then 'cat image > /dev/sda' to copy the image onto the USB flash disk. If you use Bochs on the zoo machines, make sure that bochsrc is linked to bochs-diskette or bochs-disk (may require image padding), and run /c/cs422/bochs/bin/bochs. The debugger will activate, and you will have to issue "c", to continue execution.
Note: On the lab machines, the USB flash disk will be detected as /dev/sda. But on other linux machines you might have, USB flash disk could be detected as /dev/sdb or even sd? depending on whether other SCSI devices are present in the system. Please be careful and make sure your USB flash disk is mounted on /dev/sda before saving the image to /dev/sda. Otherwise, you risk ruin your file system on your exististing hard disk.
man -M man createimage
Please ignore the "-vm" option for this project.
Essentially, createimage takes a bootloader and several executables and places them all into one image file. The bootloader must be placed in the first sector, while all other executables should be placed at offset specified in the ELF header. To read an ELF file use fopen, fread, and fseek (see man pages for descriptions). The program header (figure 2-1 of the ELF Documentation) contains information about each segment in the ELF and should be used to determine the address at which to place the segment. Be aware of the following:
One more thing you will have to do is to mark the USB flash disk as "bootable device". You will have to put a signature in the boot sector B(first sector) of the USB flash disk so that the BIOS will recognize this device as bootable. The signature consists of two bytes: "0x55 0xaa", and you will need to put this signature at the end of the boot sector at offset 0x1fe.
You should read:
/c/cs422/bin/submit 1 README Makefile bootblock.s createimage.cEach group needs to submit only one copy. This means that only one of you needs to submit.
# Setup the registers - see chapter 3 of Intel ISA reference volume 2 movw DATA_SEGMENT, %ax movw %ax, %ds movw OTHER_DATA_SEGMENT, %ax movw %ax, %es
movw STRING_FROM_ADDRESS, %si movw STRING_TO_ADDRESS, %di # Move a byte from one string to the other - implictly DS:SI to ES:DI movsb
# The values in %si and %di are automatically incremented/decremented based on the DF flag
So, the following code sequence writes the character 'K' (ascii
0x4b) to the top left corner of the screen.
movw 0xb800,%bx movw %bx,%es movw $0x074b,%es:(0x0)This code sequence is very useful for debugging.
Called with: ah = 2
al = number of sectors to read,
ch = cylinder number, (lowest 8 bits of the 10-bit cylinder
number, 0 based)
cl, bits 6&7 = cylinder number bits 8 and 9.
bits 0-5 = starting sector number, 1 to 63
dh = starting head number, 0 to 255
dl = drive number, (0x80 + zero based hard driver number)
(Note: use dl = 0x80 for the first hard disk. For this project, if you
want to boot USB flash disk on the lab machines, you can set dl to be
0x80 because on our lab machines, the USB flash disk will be treated as
the first bootable hard disk with dl=0x80. On other machines, this
might not be true since different BIOS could treat the USB flash disk
as different devices like floppy disk, see note below for
es:bx = pointer where to place information read from diskette
ah = return status (0 if successful)
al = burst error length if ah = 11; undefined on most BIOSes for
other ah return status values.
carry = 0 successful, = 1 if error occurred
ah = 0x0e
al = character to write
bh = active page number (Use 0x00)
bl = foreground color (graphics mode only) (Use 0x02)
This function gets the drive parameters for the specified driver.
ah = 8
dl = driver number (0x80 + zero based hard driver number)
ah = 0
al = undefined
carry = 0
ch = maximum cylinder number (lowest 8 bits of the 10-bits cylinder number, 0 based)
cl, bits 6&7 = cylinder number bits 8 and 9.
bits 0-5 = maximum sector number, 1 to 63
dh = maximum head number, 0 to 255
ah = 7
carry = 1
al = cx = dx = 0
if failed (because no hard disk exists)
ah = 1
carry = 1
al = bx = cx = dx = es = 0