[FrontPage] [TitleIndex] [WordIndex

Note: You are looking at a static copy of the former PineWiki site, used for class notes by James Aspnes from 2003 to 2012. Many mathematical formulas are broken, and there are likely to be other bugs as well. These will most likely not be fixed. You may be able to find more up-to-date versions of some of these notes at http://www.cs.yale.edu/homes/aspnes/#classes.

1. Overview

This is the first of six course projects originally developed by Kai Li at Princeton and his colleagues at the University of Tromsø.

Over the course of these projects, you are going to develop a simple operating system, which will cover most of the topics discussed throughout the course. In this first project, you will build the basic environment that will be needed to develop the operating system for the rest of the semester. Specifically, your job is to implement two programs: bootblock.s and creatimage.c.

The bootblock resides on the first sector of the booting device (USB flash disk for this project) and is automatically loaded and executed at system booting process. It is responsible for loading the rest of the operating system from the booting device into memory. Because GCC, the compiler used to compile the bootblock and kernel source, generates executable files in a specific format which needs operating system support (of course not available before the operating system itself is loaded) to run, we need the createimage tool to transform and pack them up into an image file that can be directly loaded and run on a bare machine. This file is called an image because it is loaded into the memory exactly as what it is like on a disk.

2. Background

To complete this project, you will need to learn about:

3. Mechanics

3.1. Getting the files

For both of these programs, you should start with a skeleton version that we will provide. Assuming you have obtained a Subversion login and password password as described in CS422/Assignments/HW0, you can check out a working copy of your Subversion directory with the command

svn co http://pine.cs.yale.edu/422/user/your-user-name-here


svn co http://pine.cs.yale.edu/422/group/your-group-name-here

Use the second command if you are working in a group. Your group name consists of your id and your partner's id in alphabetical order separated by a hyphen, e.g. pinky-thebrain. You can also find your group directory under your user directory as group.

You will find the initial project files in the common/1 directory underneath your working directory. You do not have commit access to this directory, so you will need to copy the files to your own working directory before working on them with the commands

svn cp common/1 .
svn commit -m"Hey, I just copied hw1!"

You can now modify the files in your new 1 subdirectory. You should find the following files:

The subdirectory also includes a man page for createimage.

You are expected to modify the files bootblock.s and createimage.c. You may create additional files if needed.

3.2. Submitting your assignment

To submit your assignment, run svn commit. We recommend that you commit early and often during development. This will not only guarantee that you have submitted something before the deadline (in case you succumb to tragedy), but will also (a) allow you to back out of any particularly bad mistakes you might make along the way, and (b) allow us to admire your progress and examine your code if you need to ask any questions about what you are doing.

Unless you make other arrangements, we will base your grade on the last version of your code committed.

If you only modify existing files, you will most likely not need to use any Subversion commands except up (to get changes made by your partner) and commit (to send your changes to the server). But if you add new files, remember to add them to the repository version with svn add. (Please do not add any files beyond your source files—especially not binaries!)

3.3. Design review

You should complete a design review one week before the final project deadline. This involves a face-to-face meeting with the TA to discuss your plans for completing the project. You should be prepared to demonstrate a stub bootloader that does something useful beyond the initial bootloader stub provided to you (e.g. prints a friendly message). The intent of the review is not to force you to have fully-functional code or even a perfect design at this point; instead, we want to make sure that you are on the right track and thinking about the project well before the final deadline. The design review accounts for roughly 20% of the project grade.

4. Details of the bootloader

The file bootblock.s will contain the code that will be written on the boot sector of your disk image. This should be written in IA32 assembly language (or C using the asm feature) and cannot exceed 510 bytes (1 sector less 2 bytes for the boot flag). This code will be responsible for (a) loading in the rest of the operating system, (b) setting up a stack for the kernel, and (c) invoking the kernel. You are required to handle kernels of size up to 127 sectors. You will get extra credit if your bootblock can handle sizes greater than 128 sectors.

After the BIOS has initialized the system, the bootblock gets loaded at memory address 0x07c0:0000 and control is jumped to that address. Your bootblock should load the OS starting at 0x0000:1000. In real mode, you have 640 KBytes between 0x0000:0000 and 0xA000:0000. The low memory area has system data like the interrupt vectors and BIOS data. To avoid overwriting them, you should only use memory above 0x0000:1000 for this assignment.

Note that even though you can assume that the entire OS is less or equal to 127 sectors for this project, this may still be large enough to overwrite your bootblock loaded at 0x0000:7c00. Your bootblock code should deal with this.

We have provided you with a working binary version of createimage so you don't have to get your own version done before you test the bootblock. To test your bootblock you can use the createimage.given file. Type ./createimage.given --extended ./bootblock ./kernel to generate an image file; the command bochs should then load this image file (if you have not modified the provided bochsrc).

5. Details of createimage

This program is a Linux tool to create a bootable kernel image. To make your life a bit easier, we have provided you with a man page in the man directory included in the project directory. You can view the man page by typing man -M man createimage.

Note: Please ignore the "-vm" option for this project.

Essentially, createimage takes a bootloader and one or more ELF-format 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. 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.

The output image file should contain the kernel segments in linear order starting at address 0x0000:1000. Since the kernel segments may be provided in any order and are not necessarily contiguous, you will probably have to do some padding in the output file. The output file should be an even multiple of 512 bytes.

One more thing you will have to do is to mark the image as a "bootable device". You will have to put a signature in the boot sector (first sector) of the disk image so that the BIOS will recognize it 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 will also have to figure out a way to inform the bootloader how many sectors to read.

6. Assembly language examples

Here are some examples of x86 assembly language. The file bootblock_examples.s also contains several x86 assembly language

6.1. Loading a segment:offset

The project will require you to load values into the segment registers to setup the stack and data segments. The code segment register (CS) cannot be loaded directly, only indirectly through a JMP type instruction. When loading a value into the stack segment register (SS), interrupts are disabled for the next instruction, thus allowing you to set the stack pointer (SP). As an example of setting up segment registers for data, consider the following string copy:

# Setup the registers - see chapter 3 of Intel ISA reference volume 2
movw DATA_SEGMENT, %ax
movw %ax, %ds
movw %ax, %es

# Move a byte from one string to the other - implictly DS:SI to ES:DI 

# The values in %si and %di are automatically incremented/decremented based on the DF flag.

6.2. Display memory

During booting, you can write directly to the screen by writing to the display RAM which is mapped starting at 0xb800:0000. Each location on the screen requires two bytes---one to specify the attribute (use 0x07) and the second for the character itself. The text screen is 80x25 characters. So, to write to row i and column j (counting from zero), you write the 2 bytes starting at offset (i*80+j)*2.

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.

7. Useful BIOS features

You are allowed to use these BIOS functions to complete this assignment.

7.1. BIOS Int 0x13 Function 2

Reads a number of 512-byte disk sectors starting from a specified location. The data read is placed into RAM at the location specified by ES:BX. The buffer must be sufficiently large to hold the data AND must not cross a 64K linear address boundary. (For our project, for simplicity, you can assume cylinder number bits 8 and 9, i.e. bits 6 and 7 of cl are zero).

Called with:


7.2. BIOS Int 0x10 Function 0x0e

This function sends a character to the display at the current cursor position on the active display page. As necessary, it automatically wraps lines, scrolls and interprets some control characters for specific actions. Note: Linefeed is 0x0a and carriage return is 0x0d.

Called with:

7.3. (For extra credfit) BIOS Int 0x13 Function 8

For extra credit, your bootloader will need to be able to load more than 128 sectors. In order to do that, you will need to use another BIOS Int 0x13 call listed below. With this BIOS call, you will be able to get the disk parameter and then read sector by sector to load more than 128 sectors.

Called with:


2014-06-17 11:58