Friday, April 22, 2016

Write Your Own Operating System Tutorial: Lesson 5: Let’s Make It Interactive

[This is part of a larger tutorial.
Previous lesson     Table of Contents     Next lesson]

All of this printing stuff to the screen is fun, but no operating system would be any good at all if it did not provide any interactivity. Let’s make it read input from the keyboard. Again we will be using calls to a function in BIOS to read the keyboard.

We are going to be using function 0, interrupt 0x16. This is done easily with the following two instructions.

     xor  ah, ah    ; we want function zero
     int  0x16 ; wait for a keypress

This function causes the computer to pause and does not return until a key is pressed. This can be used in a “Press any key to continue” situation, or also if you want to get input from the user. The scan code of the key pressed will be returned in register AH, and the ASCII code is returned in AL.

Your assignment for this lesson is to write a simple boot program that demonstrates a bit of interactivity. Perhaps it could print a message each time a key is pressed. Or maybe allow the user to type at the keyboard and echo each character to the screen as it is typed.

If you get stuck, below is an example of my own. But it's no fair peeking until you’ve tried by yourself!

In the next lesson we will learn how to make our operating system larger than the single sector of the Boot Record.

;----------------------------------------------------------------------
; Interactivity Example Boot Program
;
; Joel Gompert 2001
;
; Disclaimer: I am not responsible for any results of the use of the contents
;   of this file
;----------------------------------------------------------------------
   org 0x7c00 ; This is where BIOS loads the bootloader


; Execution begins here
entry:
   jmp short begin ; jump over the DOS boot record data


; ----------------------------------------------------------------------
; data portion of the "DOS BOOT RECORD"
; ----------------------------------------------------------------------
brINT13Flag     DB      90H             ; 0002h - 0EH for INT13 AH=42 READ
brOEM           DB      'MSDOS5.0'      ; 0003h - OEM name & DOS version (8 chars)
brBPS           DW      512             ; 000Bh - Bytes/sector
brSPC           DB      1               ; 000Dh - Sectors/cluster
brResCount      DW      1               ; 000Eh - Reserved (boot) sectors
brFATs          DB      2               ; 0010h - FAT copies
brRootEntries   DW      0E0H            ; 0011h - Root directory entries
brSectorCount   DW      2880            ; 0013h - Sectors in volume, < 32MB
brMedia         DB      240             ; 0015h - Media descriptor
brSPF           DW      9               ; 0016h - Sectors per FAT
brSPH           DW      18              ; 0018h - Sectors per track
brHPC           DW      2               ; 001Ah - Number of Heads
brHidden        DD      0               ; 001Ch - Hidden sectors
brSectors       DD      0               ; 0020h - Total number of sectors
                DB      0               ; 0024h - Physical drive no.
                DB      0               ; 0025h - Reserved (FAT32)
                DB      29H             ; 0026h - Extended boot record sig 
brSerialNum     DD      404418EAH       ; 0027h - Volume serial number (random)
brLabel         DB      'Joels disk '   ; 002Bh - Volume label  (11 chars)
brFSID          DB      'FAT12   '      ; 0036h - File System ID (8 chars)
;------------------------------------------------------------------------


; --------------------------------------------
;  Boot program code begins here
; --------------------------------------------
; boot code begins at 0x003E
begin:
 xor ax, ax  ; zero out ax
 mov ds, ax  ; set data segment to base of RAM
 mov si, msg  ; load address of our message
 call putstr  ; print the message

loop1:
 xor ah, ah  ; function 0
 int 0x16  ; get a key from the keyboard

 mov si, charmsg ; load address of message
 call putstr  ; print the message

 mov ah, 0x0e ; function print character
 mov bl, 0x07 ; white on black
 int 0x10

 mov si, newline ; print a newline
 call putstr

 jmp loop1  ; just loop forever.

; --------------------------------------------
; data for our program

msg db 'Press a key.'
newline db 13,10,0
charmsg db 'Character: ',0

; ---------------------------------------------
; Print a null-terminated string on the screen
; ---------------------------------------------
putstr:
 push ax
putstrl:
 lodsb   ; AL = [DS:SI]
 or al, al  ; Set zero flag if al=0
 jz putstrd  ; jump to putstrd if zero flag is set
 mov ah, 0x0e ; video function 0Eh (print char)
 mov bx, 0x0007 ; color
 int 0x10
 jmp putstrl
putstrd:
 pop ax
 retn
;---------------------------------------------

size equ $ - entry
%if size+2 > 512
  %error "code is too large for boot sector"
%endif
 times (512 - size - 2) db 0

 db 0x55, 0xAA  ;2  byte boot signature
Previous lesson     Table of Contents     Next lesson

Write Your Own Operating System Tutorial: Lesson 4: Hello, World

[This is part of a larger tutorial.
Previous lesson     Table of Contents     Next lesson]

Now is the time you’ve all been waiting for. Finally we get to the classic “first” program. Every decent programming book has a “Hello, World” program, and now we know enough to make a “Hello, World” operating system. We will create a function to print a string and use it to display our message.

It will get tedious to print one character at a time to the screen, so we’ll create a function to print a zero-terminated string to the screen. This is just a simple loop that prints all the characters in a string one at a time.

; ---------------------------------------------
; Print a null-terminated string on the screen
; ---------------------------------------------

putstr:
     lodsb         ; AL = [DS:SI]
     or al, al     ; Set zero flag if al=0
     jz putstrd    ; jump to putstrd if zero flag is set
     mov ah, 0x0e  ; video function 0Eh (print char)
     mov bx, 0x0007 ; color
     int 0x10
     jmp putstr
putstrd:
     retn

Now, a little on how to use this function. First you have to load the address of the first character of the string into the register SI. Then simply call this subroutine putstr.

You can create a string like this in your assembly file.

msg  db 'Hello, World!', 0

The zero on the end adds a null terminator to the string. Then you can print the string to the screen using the following instructions.

mov si, msg    ; Load address of message
call putstr    ; Print the message

There is just one more thing that needs to be set up before this will work. The address msg, loaded into the register SI, is actually an offset off the beginning of the segment that is pointed to by the register DS. So, before you can use the address msg, you must set up the current data segment. For now, we will use flat addressing from the bottom of physical RAM. To set the data segment to start from the bottom, set the DS register to zero. The following two instructions will do this.

xor  ax, ax    ; Zero out ax
mov  ds, ax    ; Set data segment to base of RAM

Try putting all of these parts together using the boot program from Lesson 3 as a starting point. Then, using the same method described in Lesson 3, assemble your file, copy it to your floppy disk and boot with it. Have fun. If you get stuck, you can look at my solution below, but it’s no fair peeking until you’ve tried!

Once you have finished, proceed to the next lesson where we will learn how to make our operating system interactive.

;----------------------------------------------------------------------
; Hello World Operating System Boot Program
;
; Joel Gompert 2001
;
; Disclaimer: I am not responsible for any results of the use of the contents
;   of this file
;----------------------------------------------------------------------
 org 0x7c00 ; This is where BIOS loads the bootloader


; Execution begins here
entry:
 jmp short begin ; jump over the DOS boot record data


; ----------------------------------------------------------------------
; data portion of the "DOS BOOT RECORD"
; ----------------------------------------------------------------------
brINT13Flag     DB      90H             ; 0002h - 0EH for INT13 AH=42 READ
brOEM           DB      'MSDOS5.0'      ; 0003h - OEM name & DOS version (8 chars)
brBPS           DW      512             ; 000Bh - Bytes/sector
brSPC           DB      1               ; 000Dh - Sectors/cluster
brResCount      DW      1               ; 000Eh - Reserved (boot) sectors
brFATs          DB      2               ; 0010h - FAT copies
brRootEntries   DW      0E0H  ; 0011h - Root directory entries
brSectorCount   DW      2880  ; 0013h - Sectors in volume, < 32MB
brMedia         DB      240  ; 0015h - Media descriptor
brSPF           DW      9               ; 0016h - Sectors per FAT
brSPH           DW      18              ; 0018h - Sectors per track
brHPC           DW      2  ; 001Ah - Number of Heads
brHidden        DD      0               ; 001Ch - Hidden sectors
brSectors       DD      0         ; 0020h - Total number of sectors
  DB      0               ; 0024h - Physical drive no.
  DB      0               ; 0025h - Reserved (FAT32)
  DB      29H             ; 0026h - Extended boot record sig 
brSerialNum     DD      404418EAH       ; 0027h - Volume serial number (random)
brLabel         DB      'Joels disk '   ; 002Bh - Volume label  (11 chars)
brFSID          DB      'FAT12   '      ; 0036h - File System ID (8 chars)
;------------------------------------------------------------------------


; --------------------------------------------
;  Boot program code begins here
; --------------------------------------------
; boot code begins at 0x003E
begin:
 xor ax, ax  ; zero out ax
 mov ds, ax  ; set data segment to base of RAM
 mov si, msg  ; load address of our message
 call putstr  ; print the message

hang:
 jmp hang  ; just loop forever.

; --------------------------------------------
; data for our program

msg db 'Hello, World!', 0

; ---------------------------------------------
; Print a null-terminated string on the screen
; ---------------------------------------------
putstr:
 lodsb  ; AL = [DS:SI]
 or al, al ; Set zero flag if al=0
 jz putstrd ; jump to putstrd if zero flag is set
 mov ah, 0x0e ; video function 0Eh (print char)
 mov bx, 0x0007 ; color
 int 0x10
 jmp putstr
putstrd:
 retn
;---------------------------------------------

size equ $ - entry
%if size+2 > 512
  %error "code is too large for boot sector"
%endif
 times (512 - size - 2) db 0

 db 0x55, 0xAA  ;2  byte boot signature
Previous lesson     Table of Contents     Next lesson

Write Your Own Operating System Tutorial: Lesson 3: NASM

[This is part of a larger tutorial.
Previous lesson     Table of Contents     Next lesson]

In this lesson we will learn to use an assembler to write our programs. In previous lessons we have assembled them using DEBUG. After playing around with this for a while, you will quickly see that it would be a pain to use DEBUG to create a program of more than a handful of instructions (even harder to modify). We need a simpler way. We will start by using the Netwide Assembler” (NASM). Follow that link to the official web page and download a copy of the assembler.

Now we’ll use this assembler to create the same “operating system” that we did at the end of Lesson 2. Save the following boot program as h.asm

;----------------------------------------------------------------------
; Simple boot program that prints the letter 'H'
;  and then hangs
; Joel Gompert 2001
;
; Disclaimer: I am not responsible for any results of the use of the contents
;   of this file
;----------------------------------------------------------------------
   org 0x7c00 ; This is where BIOS loads the bootloader


; Execution begins here
entry:
   jmp short begin ; jump over the DOS boot record data


; ----------------------------------------------------------------------
; data portion of the "DOS BOOT RECORD"
; ----------------------------------------------------------------------
brINT13Flag     DB      90H             ; 0002h - 0EH for INT13 AH=42 READ
brOEM           DB      'MSDOS5.0'      ; 0003h - OEM name & DOS version (8 chars)
brBPS           DW      512             ; 000Bh - Bytes/sector
brSPC           DB      1               ; 000Dh - Sectors/cluster
brResCount      DW      1               ; 000Eh - Reserved (boot) sectors
brFATs          DB      2               ; 0010h - FAT copies
brRootEntries   DW      0E0H            ; 0011h - Root directory entries
brSectorCount   DW      2880            ; 0013h - Sectors in volume, < 32MB
brMedia         DB      240             ; 0015h - Media descriptor
brSPF           DW      9               ; 0016h - Sectors per FAT
brSPH           DW      18              ; 0018h - Sectors per track
brHPC           DW      2               ; 001Ah - Number of Heads
brHidden        DD      0               ; 001Ch - Hidden sectors
brSectors       DD      0               ; 0020h - Total number of sectors
                DB      0               ; 0024h - Physical drive no.
                DB      0               ; 0025h - Reserved (FAT32)
                DB      29H             ; 0026h - Extended boot record sig 
brSerialNum     DD      404418EAH       ; 0027h - Volume serial number (random)
brLabel         DB      'Joels disk '   ; 002Bh - Volume label  (11 chars)
brFSID          DB      'FAT12   '      ; 0036h - File System ID (8 chars)
;------------------------------------------------------------------------


; --------------------------------------------
;  Boot program code begins here
; --------------------------------------------
; boot code begins at 0x003E
begin:
   mov ah, 0x0e   ; Function to print a character to the screen
   mov al, 'H'    ; Which character to print
   mov bl, 7      ; color/style to use for the character
   int 0x10       ; print the character

hang:
   jmp hang       ; just loop forever.

;---------------------------------------------

size equ $ - entry
%if size+2 > 512
  %error "code is too large for boot sector"
%endif
   times (512 - size - 2) db 0

   db 0x55, 0xAA  ;2  byte boot signature

The first instruction should be somewhat familiar by now. This is the instruction to jump over the Boot Record data. In this case, it’s a jump to the label begin . After the jump instruction is 20 bytes of data. This is the data that I read off my floppy disk using the DEBUG program. These values should work fine. If you want, try replacing the data with the data from your own disk. Most of it should be the same.

(NOTE: Keep in mind that numbers made up of more than 1 byte will look “byte swapped” when viewed in DEBUG because on the Intel architecture, the least significant byte is stored at the lowest memory address and vice versa. The bytes will look backwards.)

The code starting at the label

begin
should look similar to the code we wrote for Lesson 2. It simply prints the letter ‘H’ to the screen and loops forever. At the bottom of this file you will see first a check to make sure the code all fits within 512 bytes (the size of one sector), then the line beginning with the word “times” adds zeros to the end of the file to pad the executable to 510 bytes. Finally, the two-byte signature 0x55, 0xAA is added to the end of the file. Assemble the file at the command prompt with the following command.

nasmw h.asm –o h.bin

This assembles the assembly file to a pure binary executable h.bin. Check the size of the binary file. If we have done things right, it should be exactly 512 bytes. This is exactly the size needed to fit in the boot sector of the floppy.

Now we need to copy this file onto our floppy. With the floppy in the disk, run DEBUG, and type the following commands

debug
-n h.bin
-l 0

This loads our file into memory starting at address 0. Use the dump (d) and unassemble (u) commands if you wish to confirm that our file has assembled and been loaded correctly. You will be able to see the few instructions that we have written. Notice that the file has been correctly padded with zeros up until bytes 0x1FE and 0x1FF at the end of the sector. Also note that DEBUG fills the CX register with the number of bytes loaded from the file. (Display the contents of the registers with the r command.)

With the floppy disk in the drive, write the file to the disk with the usual command.

-w 0 0 0 1

Reboot the computer with the floppy and see the program in action. Try some more things with the source code, now. For example, maybe modify the code to print more characters. When you are ready, proceed to the next lesson where we will create a “Hello, World” operating system.

Previous lesson     Table of Contents     Next lesson

Write Your Own Operating System Tutorial: Lesson 2: Making Our First Bootable Disk

[This is part of a larger tutorial.
Previous lesson     Table of Contents     Next lesson]

In this lesson, we will learn how to create a boot program on a floppy disk. We will start by modifying the Microsoft DOS Boot Record.

For our purposes, we want to replace the boot loader code without changing the other data in the boot sector. If we change the data to something invalid, then DOS and Windows will not recognize the disk as being valid. Windows will give an error saying the disk is not formatted. This will cause you to be unable to access any of the files on the disk. However, we can change the boot program code all we want and, as long as we don’t mess with the other data, DOS and Windows will be able to read and write the files on the disk just fine.

We will leave the first instruction (jmp 0x3E) alone, because we need to jump over the Boot Record data. Thus we can begin modifying the code at 0x3E. Run the DOS DEBUG program and load the first sector of a formatted floppy disk into memory at address 0. Then type the command

-u 3E

to view the instructions there. Now, we will begin modifying the code. Type the command

-a 3E

to begin assembling instructions. The prompt changes from a hyphen to the address at the location that we gave. Type the following instruction and press enter.

jmp 3E

The instruction is assembled to machine code and placed into memory, and the following prompt is the next available memory after the instruction you just entered. Press Enter once more to exit the assembly mode. The whole procedure on my computer looked like this.

-a 3E
0AFC:003E jmp 3E
0AFC:0040
-

The segment address (0x0AFC, in my case) can (an probably will be) different on your computer, or even between different sessions of DEBUG. Now view the instruction you just entered by giving the unassembled command.

-u 3E

As you can see, the first instruction is now our jump instruction. This will create an infinite loop. If we quit DEBUG now, no changes will be saved, but we can now write our modified boot sector back to the disk (overwriting the previous one) by typing this command.

-w 0 0 0 1

This "write" command uses the same syntax as the "load" command. This writes the data found at memory address 0 to disk 0, starting with sector 0 and writing 1 sector. Be very careful when using the write command. This command can be used to overwrite sectors on any drive, and cause loss of data.

You can now boot with this floppy. When you boot, BIOS will load the first sector off the disk into memory and begin execution at the beginning of the sector. This will be the jump to 0x3E instruction. The instruction there is one to jump to 0x3E, so this will continue forever. Try it. Boot up a computer with this disk. Nothing appears to happen. The computer will just sit there and do nothing. But your new “operating system” is running.

Okay, I know what you’re saying, you want to see some sign that the code you wrote is actually is running and that you haven’t done something to mess up your computer. In order to do this, we are going to make function calls to BIOS (at least at first). As of the time of this writing, you can find a short list of BIOS function calls at http://users.win.be/W0005997/GI/biosref.html. A longer list of software interrupts can be found at http://burak1.virtualave.net/Interrup.txt, but keep in mind that some of those interrupts are BIOS calls, while others are MS-DOS calls which cannot be used since, of course, MS-DOS is not running. You would have to implement those functions yourself before using them.

We are going to use interrupt 0x10, function 0x0E to write a character to the screen. The registers must be set as follows.

AH = 0x0E
AL = ASCII code of the character to be printed
BL = color/style of character

Now, repeat the instructions in this lesson, only instead of entering the jump instruction as we did before, this time enter the following instructions.

-a 3E
0AF6:003E mov ah, 0e
0AF6:0040 mov al, 48
0AF6:0042 mov bl, 07
0AF6:0044 int 10
0AF6:0046 jmp 46
0AF6:0048
-

First we set AH to 0x0e, AL to 0x48 (ASCII for the letter ‘H’), BL to 7 (color code for white-on-black), and then we call interrupt 0x10, which handles the video controller. The last instruction creates an infinite loop like before, so things stop there. Save the modified boot sector to a disk (-w 0 0 0 1) and try booting with the disk. This time you should see the character ‘H’ printed on the screen before the system hangs.

Play around with this for a while. You can repeat the code for printing a character multiple times to print a phrase, or you can try out other software interrupts. When you are done, continue on to the next lesson where we will learn to use a full-blown assembler to write our programs rather than DEBUG.

Previous lesson     Table of Contents     Next lesson

Write Your Own Operating System Tutorial: Lesson 1: The Boot Sector

[This is part of a larger tutorial.
Previous lesson     Table of Contents     Next lesson]

In this lesson we’ll learn about the contents of the boot sector so that we can learn to write our own boot program.

When the computer boots from a floppy, BIOS (Basic Input/Output System) reads the disk and loads the first sector into memory at address 0000:7C00. This first sector is called the DOS Boot Record (DBR). BIOS jumps to the address 0x7C00 and begins executing instructions there. It is these instructions (the “boot loader”) that will load the operating system (OS) into memory and begin the OS’s boot process.

The first thing to do is to take a look inside the Boot Record. The DOS utility DEBUG is a widely available tool that can be used to view the contents of memory and disks. We’ll use DEBUG to look at a floppy disk’s Boot Record.

At a DOS (or Windows) command prompt type debug. This will leave you with just a hyphen as a prompt. If you enter letter ‘d’ as a command and press Enter, it will show you a portion of the contents of RAM. Typing the question mark as a command will give you a list of all the available commands in DEBUG. (Be very careful when using the DEBUG utility. This utility can be used to overwrite data on any disk drive, possibly causing loss of data.)

Place a freshly formatted disk in the A: drive. To load the Boot Record off your floppy disk, type the following command.

-l 0 0 0 1

(The first character is the letter ‘l’, not the number ‘1’.) This command loads sectors off a disk into a portion of RAM. The 4 numbers after the ‘l’ represent in order, the beginning address where you want the data loaded, the drive number (0 for first floppy driver), the first sector on the disk to load, and how many sectors to load. Typing this command will load the first sector of the floppy into memory starting at address 0.

Now that we have the Boot Record loaded into memory, we want to view its contents. Type the following command.

-d 0

What you see are 8 lines that represent the first 128 (0x80 in hex) bytes in the floppy’s Boot Record. The results (for my floppy disk) are the following.

0AF6:0000  EB 3C 90 4D 53 44 4F 53-35 2E 30 00 02 01 01 00   .<.MSDOS5.0.....
0AF6:0010  02 E0 00 40 0B F0 09 00-12 00 02 00 00 00 00 00   ...@............
0AF6:0020  00 00 00 00 00 00 29 F6-63 30 88 4E 4F 20 4E 41   ......).c0.NO NA
0AF6:0030  4D 45 20 20 20 20 46 41-54 31 32 20 20 20 33 C9   ME    FAT12   3.
0AF6:0040  8E D1 BC F0 7B 8E D9 B8-00 20 8E C0 FC BD 00 7C   ....{.... .....|
0AF6:0050  38 4E 24 7D 24 8B C1 99-E8 3C 01 72 1C 83 EB 3A   8N$}$....<.r...:
0AF6:0060  66 A1 1C 7C 26 66 3B 07-26 8A 57 FC 75 06 80 CA   f..|&f;.&.W.u...
0AF6:0070  02 88 56 02 80 C3 10 73-EB 33 C9 8A 46 10 98 F7   ..V....s.3..F...

At first glance, this doesn’t tell me much. I can see that it looks like this is a MS-DOS 5.0 disk with no name and a FAT12 file system. The numbers in the far left column show the memory addresses in RAM. The hexadecimal numbers in the middle show all the bytes in this portion of memory, and the column on the right shows the ASCII characters that the hex bytes represent (a period is shown if the byte does not translate to any visible character). Some of the bytes you see in this portion of the Boot Record are parts of instructions in the boot loader, and some of them hold information about the disk such as the number of bytes per sector, the number of sectors per track, etc…

Now it’s time to take a glance at the code for the boot loader. Type the following command.

-u 0

This performs an “unassemble” operation. This shows us the same bytes as before (starting with address 0), but this time DEBUG shows us the Intel instructions that these bytes represent. The results for my floppy are the following.

0AF6:0000 EB3C          JMP     003E
0AF6:0002 90            NOP
0AF6:0003 4D            DEC     BP
0AF6:0004 53            PUSH    BX
0AF6:0005 44            INC     SP
0AF6:0006 4F            DEC     DI
0AF6:0007 53            PUSH    BX
0AF6:0008 352E30        XOR     AX,302E
0AF6:000B 0002          ADD     [BP+SI],AL
0AF6:000D 0101          ADD     [BX+DI],AX
0AF6:000F 0002          ADD     [BP+SI],AL
0AF6:0011 E000          LOOPNZ  0013
0AF6:0013 40            INC     AX
0AF6:0014 0BF0          OR      SI,AX
0AF6:0016 0900          OR      [BX+SI],AX
0AF6:0018 1200          ADC     AL,[BX+SI]
0AF6:001A 0200          ADD     AL,[BX+SI]
0AF6:001C 0000          ADD     [BX+SI],AL
0AF6:001E 0000          ADD     [BX+SI],AL

The first instruction says to jump to address 0x3E. The bytes after this are the data about the disk I mentioned before and do not really correspond to instructions, but DEBUG does its duty and tries to interpret them as such.

The first instruction jumps over this data to the boot program code that follows starting at address 0x3E. Let’s look at the instructions there. Type

-u 3E

Here you can see the beginning of the code that will load the DOS (or Windows) operating system. This code (for MS-DOS) looks on the disk for the files IO.SYS and MSDOS.SYS. These files contain the code for the operating system. The boot loader code will load these files into memory and begin executing them. If the files are not found on the disk, then the boot loader will display the famous error message.

Invalid system disk
Disk I/O error
Replace the disk, and then press any key

This message can be seen if you look towards the end of the DOS Boot Record. You can see this on my floppy below.

-d 180

0AFC:0180  18 01 27 0D 0A 49 6E 76-61 6C 69 64 20 73 79 73   ..'..Invalid sys
0AFC:0190  74 65 6D 20 64 69 73 6B-FF 0D 0A 44 69 73 6B 20   tem disk...Disk
0AFC:01A0  49 2F 4F 20 65 72 72 6F-72 FF 0D 0A 52 65 70 6C   I/O error...Repl
0AFC:01B0  61 63 65 20 74 68 65 20-64 69 73 6B 2C 20 61 6E   ace the disk, an
0AFC:01C0  64 20 74 68 65 6E 20 70-72 65 73 73 20 61 6E 79   d then press any
0AFC:01D0  20 6B 65 79 0D 0A 00 00-49 4F 20 20 20 20 20 20    key....IO     
0AFC:01E0  53 59 53 4D 53 44 4F 53-20 20 20 53 59 53 7F 01   SYSMSDOS   SYS..
0AFC:01F0  00 41 BB 00 07 60 66 6A-00 E9 3B FF 00 00 55 AA   .A...`fj..;...U.

This shows the very end of the Boot Record. The Boot Record is exactly one sector (512 bytes) on the disk. If it is loaded into memory starting with address 0, then the last byte will be in address 0x1FF. If you look at the last two bytes of the Boot Record (0x1FE and 0x1FF), you will notice that they are 0x55 and 0xAA. The last two bytes of the Boot Record must be set to these values or else BIOS will not load the sector and begin executing it.

So, to recap, the DOS Boot Record starts with an instruction to jump over the data that follows that instruction. These 60 bytes of data starts at address 0x02 and ends on 0x3D, with the boot code resuming at 0x3E and going all the way to 0x1FD, which is followed by the two bytes, 0x55 and 0xAA. In the next lesson we will use this knowledge to start making our own boot program.

Previous lesson     Table of Contents     Next lesson

Write Your Own Operating System Tutorial: Introduction

[This is part of a larger tutorial.
First Lesson     Table of Contents]

This is a tutorial to give an idea on how to get started writing an operating system of your very own.It will show one possible way to go about doing things.This tutorial does not intend to explain all of the theoretical aspects of operating systems and does not claim to have the best or fastest techniques or methods.All source code examples were written with readability in mind and not optimization.

I will assume that the reader is running a standard “PC architecture” computer with an Intel x86 (or compatible) processor.Later lessons may require a processor with the IA-32 architecture (i386 to Pentium 4). Some lessons will assume the use of a FAT file system.Some lessons require the use of the MS-DOS/Windows utility DEBUG.I assume any similar utility would work fine.I will not go into great detail about BIOS, assembly language programming, Intel or PC architecture, etc… since detailed references on the subjects can be found elsewhere.Great manuals on assembly programming for Intel processors can be found at Intel’s web site.

I, myself, am in the learning process of playing around with this stuff, so the lessons actually reflect some of my own experiences and discoveries as I learn new things.Thus, the number lessons will continue to increase, so keep checking back here.If you have suggestions on topics for future lessons, let me know.Indeed, if you have any suggestions, questions, or comments please feel free to email them to me.

Disclaimer:Use this tutorial at your own risk.I am not responsible for anything bad that occurs as a result of the use of any information here.

First Lesson     Table of Contents