Written by Garima Lunawat, Lauren Yeung, and Shalini Dangi
A bit more philosophy:
Tradeoffs and scaling have been traditional issues...
Moore’s Law states that the number of transistors on a chip doubles approximately every 18 months.
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
Similarly, Kryder’s Law states that secondary storage capacity also increases exponentially.
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.
There are four basic reasons why using an OS might be a bad idea:
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:
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:
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:
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.
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; } } }