Now that we have a boot loader that will load our operating system, and thus can make our operating system larger than one sector, we can now begin to add some complexity to our system. One of the first things to do is to loosen our tie to BIOS. So far we have been using BIOS functions for all of our input and output. BIOS hides all of the input and output from us with its interface, so we don’t know exactly how it goes about performing its functions. BIOS can often be slower than handling I/O by ourselves, and in doing it ourselves, we can know exactly what is going on, thus giving us more power, control, and flexibility with the design of our operating system. Of course, my main reason for learning to perform the I/O myself it simply to see how it is done. If anyone has any arguments for or against the use of BIOS for I/O, let me know. Perhaps we could discuss it further.
The area we will begin with is that of text output to the screen. So far we have been using BIOS interrupt 0x10, function 0x0E. We will begin performing text output ourselves. Before we can even start to do this, we need to know a few things. First of all, video memory is mapped to main memory addresses starting at address 0xB0000 (flat address from base of the physical address space). The region of memory holding the text content of the screen starts at 0xB0000 for monochrome displays and 0xB8000 for color displays. Try the latter address first, and if you can’t get it working, perhaps try the former. I will proceed assuming the use of a color display.
The first byte (0xB8000) holds the ASCII code for the upper-leftmost character on the screen. The next byte (0xB8001) holds the color/style code for that character. These bytes are followed by two more bytes that hold the ASCII code and color/style code for the next character to the right. The video memory continues alternating ASCII code and style/color code to the end of the first row of text. The next bytes after this represent the first character on the second row, and so on for the rest of the screen.
So, all that is necessary to output text to the screen is to write ASCII codes into this region of memory. (This is referred to as memory-mapped I/O.) However, you will now need to keep track of the location of the cursor.
Speaking of the cursor, you can write characters to anywhere on the screen (anywhere in video memory). But it will look odd to the user if they are typing on the keyboard and characters are appearing one place on the screen and the little blinking cursor is elsewhere on the screen. The video controller chip (6845 on the IBM PC) takes care of drawing the blinking cursor on the screen; we just need to tell it where to move the cursor.
The 6845 video controller is connected to I/O port 0x3B4-0x3B5 for a mono display and 0x3D4-0x3D5 for a color display. As far as I can tell, the 6845 has various registers, and (assuming a color display) port 0x3D4 is used to indicate which port we would like to write to, and then we write the data to port 0x3D5. Registers 14-15 tell the 6845 where to draw the blinky cursor. The following is psuedo-code for moving the cursor.
outbyte(0x3D4, 14); // write to register 14 first
outbyte(0x3D5, (cursorpos>>8) & 0xFF); // output high byte
outbyte(0x3D4, 15); // again to register 15
outbyte(0x3D5, cursorpos & 0xFF); // low byte in this register
The cursor position (in cursorpos) is the character number, starting with 0 and number all the characters in the order that they are arranged in video memory. (The offset in video memory for a given cursor position is cursorpos*2 for the ASCII code and (cursorpos*2)+1 for the color/style code.)
Using this region of video memory to output characters and the I/O ports to tell the video controller where to draw the cursor, it is now your job to write a text driver for your operating system. Create a set of functions that you can call to output characters, strings, numbers, pointers, etc to the screen without using BIOS (this means no software interrupts). Make sure that your text driver handles scrolling the text on the screen upward before going off the bottom. Write a function to clear the screen.
Try allowing the user to type characters with the keyboard (you can still use BIOS for keyboard input for now), and echo each character to the screen as it is typed. If you have any troubles writing your text driver, let me know and perhaps I can give you some hints.
As far as the color/style byte is concerned, you can simply use 07 (white on black) for most purposes, but for those of you who are curious, I will explain the different color/style settings. The color/style of a character is one byte. Those 8 bits are used as follows.
These four bits can be used in any and all 16 combinations. If bit 3 is 1, it indicates full intensity, 0 indicates half intensity. For example, 3 would be cyan (blue + green) while 11 would be bright cyan (intensity+blue+green).
Bit 6: Black on colored background, color given by bits 3-0