Lecture 2 Scribe Notes

Written by Garima Lunawat, Lauren Yeung, and Shalini Dangi

Table of Contents

  1. Moore's Law
  2. Kryder's Law
  3. Why Not To Use an OS?
  4. Word Count Program

A bit more philosophy:

Tradeoffs and scaling have been traditional issues...

Moore's Law

Moore’s Law states that the number of transistors on a chip doubles approximately every 18 months.

Moore's Law

https://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Transistor_Count_and_Moore's_Law_-_2011.svg/1139px-Transistor_Count_and_Moore's_Law_-_2011.svg.png



Kryder's Law

Similarly, Kryder’s Law states that secondary storage capacity also increases exponentially.

Kryder's Law

http://regmedia.co.uk/2014/11/10/disk_capacity_increase.jpg



Note: Moore’s Law and Kryder’s Law do not address speed or performance because they haven’t grown nearly as fast as complexity (storage space). Operating systems have to deal with greater complexity, but hardware capabilities are not increasing at the same rate. This is a problem of incommensurate scaling.


Why Not to Use an OS?

There are four basic reasons why using an OS might be a bad idea:


Word Count Program

1. Requirements

Suppose we are writing a program for a paranoid English professor in order to help him count the number of words in his academic proposal. The program must be run without an operating system. We know the following:

2. Bootstrapping Problem

Bootstrapping is the process of loading software into the memory of a computer after the computer has been powered on. In this case, the word count program must be loaded into RAM so that it can be executed after the computer is started.

This is done by the BIOS, or the basic input/output system. At startup, the BIOS is used to get the computer system started. Additionally, it is also used to manage data flow between the operating system and any devices. The BIOS is stored in ROM and at startup does the following:

  1. Runs hardware sanity checks
  2. Searches for devices
  3. Looks for Master Boot Record
  4. Attempts to boot off of Master Boot Record

3. Master Boot Record

The 1st sector on the disk, consisting of 512 bytes, is the Master Boot Record (MBR). The first part of this sector is the boot program which is run by the firmware in EEPROM. When the computer starts up, the EEPROM searches for the first device with an MBR and loads it into memory. Normally, the MBR would then read the volume boot record, VBR, into memory. However since the VBR is OS-specific and the MBR is OS-agnostic (and we do not want to use an OS), we will go straight from the MBR to the program. The MBR is structured as follows:

Structure of a Master Boot Record

The first 446 bytes are the boot program. The next 64 bytes are a partition table. Each partition is 16 bytes long and contains information such as type and bootability. The remaining two bytes are the signature and are required to be 0x55 and 0xAA (using little endian convention). This ensures that this sector is, in fact, the Master Boot Record.

4. Code Implementation

To summarize, the load sequence that we want is: Firmware → MBR → word count program. In order to implement this, we will need a subroutine that allows us to read data from the disk. The following subroutine requires the sector number to read from and the memory address to read into.

Note: There are no error checks in this code (assumed that there are no I/O or parity errors). Due to this, read_ide_sector can return void.


void read_ide_sector(int s, char* a)       //s is the sector number, a is the memory address
{
    while ((inb (0x1f7) & 0xC0) != 0x40)        // waits for disk to be ready   
        continue;
    outb(0x1f2,1);                              // sector count
    outb(0x1f3, s);                             // low order byte
    outb (0x1f4, s >> 8);                       // 0x1f3 - 0x1f7 = sector number
    outb (0x1f5, s >> 16);          
    outb (0x1f6, s >> 24);                      // high order byte
    outb (0x1f7, 0x20);                         // status and command register
    while ((inb (0x1f7) & 0xC0) != 0x40)
        continue;
    insl (0x1f0, a, 128);                       // write to memory address a
}

Additionally, we must implement a routine that allows us to print the result to the display screen. This function takes in the number of words as parameter.

void output_to_screen(long n)
{
    short *p = (short*)0xb8000 + 80*25/2 - 80/2;
    do
    {
        // make sure that the digits print in the correct order
        *--p = (0x700)| (n % 10 + '0'); 
        n /= 10;
    } while (n != 0);
}

Finally, we must use the halt instruction once the program is finished.

void done(long nwords)
{
    output_to_screen(nwords);
    halt();
}

Now, using all of the subroutines, we can put together our main function.

void main(void)
{
    long nwords = 0;        // number of words
    bool inword = 0;        // are we in the middle of a word?
    int s = 1000;
    char buf[512];
    for (;;)
    {
        read_ide_sector(s++, buf);      // read the sector into the buffer
        for (int ix = 0; ix < sizeof(buf); ix++)
        {   
            // assume a null byte indicates the end of the file
            if (!buf[ix])       
                done(nwords);
            // check if the letter is valid (a-z)
            bool isletter = 'A' | 'a' <= buf[ix] && buf[ix] <= 'z' || 'z'
            nwords += isletter & ~inword;
            inword = isletter;
        }
    }
}