Você está na página 1de 13

When I thought of writing my own OS, I was very much confused where to start?

First thing came to my mind was boot process. Yea, the entire story begins from
booting. Now, how does a computer boot? A lot of details I should give if I go in
depth. I will explain in a simple manner.

Ok, here we go. When u switch on ur PC, the first program that gets executed is
BIOS (Basic Input Output System), stored in a small ROM chip, called BIOS ROM. It
performs POST (Power on Self Test) where it detects different hardware attached
to the computer. It does a lot of things which r not of a interest to an OS
programmer. At the end of this startup routine, it searches for a boot record in
the devices as specified in the BIOS settings & loads it at the physical address
0x7C00. Boot record is a program stored at the very first sector of the disk
device. Boot record has a boot signature 0xAA55 at its 510th offset. BIOS checks
for this signature in every boot record of the devices. If it does not find a valid
boot signature, it goes for the next device & checks its boot signature & so on…if
it does not find a valid boot signature in any of the devices (floppy, CD-ROM,
Hard disk), it simply hangs or displays a message like “Non-system disk”. If it
finds a valid boot record, then it jumps to the execution of the boot code. The
boot program loads the respective Operating system (Linux, Windows, OS/2). This
is how we get booted to an OS.

I will show how to write a small boot code. The following is a small boot code
written in assembly.

;Boot program : file - boot.asm

code_seg segment use16 ;use 16-bit code


assume cs: code_seg

jmp start ; skip all data & jump to code

DisplayMsg db ‘Welcome to my PC’,0

display proc near ;procedure : displays strings


prnt:
lodsb ;loads ds:si to al
or al,al ;check for the end
jz over
mov ah,0Eh ;function number
mov bh,0 ;page no 0
int 10h ;BIOS video service
jmp prnt
over: ret
display endp

start:
mov ax,07C0h
mov ds,ax ; in our code, CS=DS
cli ;setup boot stack
mov ax,1000h
mov ss,ax
mov sp,0ffffh
sti

mov si,offset DisplayMsg ;display start message


call display

mov ah,0 ;wait until a key is hit


int 16h

db 0eah ;machine code for jmp 0xFFFF:0x0000


dw 0000h ;this is BIOS start location, a jump to here
dw 0ffffh ;causes the system to reboot

org 510 ;place the boot signature at 510th offset


dw 0aa55h

code_seg ends
end

That’s it. Just assemble the above program using MASM 6.11.Type ml/AT
boot.asm at command prompt. U will get boot.com. just use any disk utility &
place boot.com in the first sector of a floppy disk, restart & make the first boot
device as floppy & see the magic.

Lets see what is this Master Boot Record (MBR). The MBR is the sector at cylinder 0, head 0, sector 1
of a hard disk. An MBR is created by the FDISK program. The FDISK program of all operating
systems must create a functionally similar MBR. The MBR is first of what could be many partition
sectors, each one containing a four entry partition table.

At the completion of your system's Power On Self Test (POST), INT 19 is called. Usually INT 19 tries
to read a boot sector from the first floppy drive. If a boot sector is found on the floppy disk, then that
boot sector is read into memory at location 0000:7C00 and INT 19 jumps to memory location
0000:7C00. However, if no boot sector is found on the first floppy drive, INT 19 tries to read the MBR
from the first hard drive. If an MBR is found it is read into memory at location 0000:7C00 and INT 19
jumps to memory location 0000:7C00. The small program in the MBR will attempt to locate an active
(bootable) partition in its partition table. If such a partition is found, the boot sector of that partition is
read into memory at location 0000:7C00 and the MBR program jumps to memory location 0000:7C00.
Each operating system has its own boot sector format. The small program in the boot sector must
locate the first part of the operating system's kernel loader program (or perhaps the kernel itself) and
read that into memory.
Inline assembly is a mechanism provided to embed assembly code with in c/c++ code.whats the use of
it? It can be used to write some critical sections of program where time efficiency is at top priority. It
can also be used to write some low level code, that r not possible in c/c++. What all u need is good
assembly programming skills for this. The syntax of assembly code varies from compiler to compiler.
Microsoft C, Turbo c use Intel assembly language syntax where as Gcc uses AT & T syntax. I will
show u how to write inline assembly in turbo c.

1) function to add two integers & return the result

int add(int n1,int n2)


{
int result;
_asm{
mov ax,n1
mov bx,n2
add ax,bx
mov result,ax
}
return result;
}

2)function to show mouse pointer

void show_mouse()
{
_asm{
mov ax,1
int 0x33
}
}

3)functtion to read from a port

unsigned char inportb(int port)


{
unsigned char result;
_asm{
mov dx,port
in al,dx
mov result,al
}
return result;
}

4)function to write to a port


void outportb(int port,unsigned char value)
{
_asm{
mov dx,port
mov al,value
out dx,al
}
}

5)function to copy a block of data from one place to another

void memcpy(void *dest,void *src,int n)


{
_asm{
mov si,src
mov di,dest
mov cx,n //number of bytes to transfer
cld //increment both SI & DI
rep movsb
}
}

6)Macros for no operation, clear interrupts & set interrupts

#define NOP() asm nop


#define CLI() asm cli
#define STI() asm sti

Well, I hope u got an idea of that. enjoy programming assembly.

What is this defragmentation?

I hope all of u guys r familiar with defragmentation utility of windows. Most of u


might have defragmented ur drives for faster access. I will tell this stuff with
some details. We have FAT32 file system supported by windows. FAT32 is
designed to handle the dynamic nature of files. Files may grow & shrink. The disk
space needs to be maintained in such circumstances. I will explain with an
example. Let us suppose u have created two files temp1.txt & temp2.txt. initially
temp1.txt occupies say a cluster (i.e. 4 KB) & its located at 100th cluster,
temp2.txt spans 2 clusters(8 KB) & that file is located at 101st & 102nd clusters.
Now u add another 4 KB of contents to temp1.txt. The file size increases but
there is no space to include the enhanced contents at the next cluster (Bcoz the
next cluster, 101 is occupied by temp2.txt). So, the enhanced contents of
temp1.txt will be placed at some other free cluster, say 500th cluster & a linked
list will be maintained in the table called File Allocation Table (FAT) using which
we can track down the chain of clusters occupied by temp1.txt. The list looks like
the following

100 -> 500 -> NULL.

That means the first part of temp1.txt is stored at 100th cluster, the second part
is stored at 500th cluster & the 500th cluster is the end of this chain (last part of
the file).

The splitting of files is called fragmentation. Fragmentation has a disadvantage of


slow access time due to the movement of heads to another sector. That's why
Microsoft has given the utility called "Defragmentation". A drive after
defragmentation has all its files arranged in a sequential clusters so that the
whole file can be read with in a single head seek. That speeds up ur system.

What to do if BIOS refuses to boot?

2 days back, my frend called me to his home. Was worried pretty much. His
machine was not at all booting, not even entered BIOS setup. I too was not
getting anything abt it.. asked sum details. He said that he changed CD-ROM
power cable, restarted but it failed to boot, he again fixed the previous cable...
again it failed. Well, still was unclear.. i guessed that there might be sum problem
with CMOS configuration. I cleared CMOS memory & booted the system. It
worked this time.

Let me give sum technical details abt that problem. First CMOS (Complimentary
Metal Oxide Semi-conductor). What is this CMOS RAM? Its a low power-
consumption memory. When the system is switched off, it will be supplied power
by a battery back-up. So, the memory contents of CMOS RAM will not be gone
even after switching off the PC. Also called Non-Volatile RAM. This is how the date
& time r kept up-to-date in CMOS. Now, What all the information is stored in
CMOS RAM? It contains various information abt the system configuration such as:
The number of floppy drives & their type The number of Hard drives & their
type Size of RAM .... .... Checksum. .... .... ....Checksum is very important. It
is calculated by sum internal algorithm. When u switch on ur PC, the BIOS checks
the information contents of CMOS RAM against the checksum. Only If both agree,
it continues booting, otherwise it refuses to boot the system. So, I guess this was
the problem in my frends PC, as he replaced sum of the cables, there might have
been sum inconsistency in the CMOS configuration. The solution is to clear the
CMOS memory. All u need is to switchoff, remove all power cables, & short the
pins 2-3 of CMOS jumper. Leave it for few seconds (around 30 secs). This clears
the CMOS memory. Now, again short the pins 1-2 of CMOS jumper. For the
location of CMOS jumper on ur mother board, refer ur motherboard manual. Ok,
now connect the power cables & reboot. Enter CMOS setup & configure the
hardware either manually or better give auto detect. Ur PC boots normally.

I guess the BIOS password is also stored in CMOS. So, If u have given the BIOS
password & forgotten it, just follow the above method. It will work, I think.

How a keyboard works?

There is a chip called Programmable Interrupt Controller (PIC) in our PC. Its job is
to service all the hardware interrupts without any conflicts. Our PC has two PIC`s,
One master & one slave, both having 8 input lines each. These input lines r called
IRQ (Interrupt Request) lines. Various hardware (keyboard, mouse, floppy, Hard
disk, timer...) are connected to these input lines. When ever they need a service,
they raise the signal on the respective line & the PIC informs the CPU abt their
request. In other words, the PIC interrupts the CPU & supplies the interrupt
number to the CPU so that it can call Interrupt Service Routine (ISR). The CPU, On
receipt of interrupt number from the PIC, suspends the current job & calls the ISR
for that interrupt. the ISR in turn calls the driver program written for respective
hardware. The driver services the request.

This is how generally interrupt driven hardware works. Lets go in particular,


keyboard. Keyboard is connected to 1st pin(IRQ1) of the master PIC (the
numbering is 0 based). Keyboard interrupts PIC when ever u press or release a
key. We have 101 keys keyboard. All these 101 keys have a number for them,
called scan code. Some of the values I have given below.

KEY Scan Code

ESC 1
'1' 2
'2' 3
'3' 4
'4' 5
......
......
'q' 16
'w' 17
'e' 18
.....
.....
.....

Ok, when ever u press a key, the keyboard places the scan code for that key in
the port 0x60 & raises the IRQ1 (i,e 1st pin of master PIC). The PIC in turn
interrupts the CPU abt the keyboard request & sends the interrupt number (int
0x9 for keyboard). The CPU, on receipt of interrupt number, suspends the current
job & calls ISR of int 0x9. The ISR calls keyboard driver program, which reads the
scan code from port 0x60, get the ASCII code for that key & places that key in its
queue which is given to application programs which r blocked for keyboard input.
So, this is the story of keyboard. I have given a small keyboard driver program
<keyboard_driver.html> in programs section.

keyboard driver program <keyboard_driver.html> in programs section.

#include <stdio.h>
#include <dos.h>
#include <conio.h>

#define INTR 0X09 /*The interrupt number for keyboard*/

/*These r scan codes of non-displayable keys*/


#define NIL -1
#define ESC 27
#define CTRL 29
#define SHFT 42
#define ALT 56
#define CAPS 58
#define F1 59
#define F2 60
#define F3 61
#define F4 62
#define F5 63
#define F6 64
#define F7 65
#define F8 66
#define F9 67
#define F10 68
#define NUM 69
#define SCRL 70
#define HOME 71
#define UP 72
#define PGUP 73
#define LEFT 75
#define FIVE 76
#define RGHT 77
#define END 79
#define DOWN 80
#define PGDN 81
#define INS 82
#define DEL 83
#define F11 87
#define F12 88
#define WIN 91
#define RTCK 93
#define POWR 94
#define SLEP 95
#define WAKE 99

/*The scancode-to-ASCII table*/

char ascii[]= {
NIL, ESC, '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r',
't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', CTRL,
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
'\'', '`', SHFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n',
'm', ',', '.', '/', SHFT, '*', ALT, ' ', CAPS, F1,
F2, F3, F4, F5, F6, F7, F8, F9, F10, NUM,
SCRL,HOME, UP, PGUP, '-', LEFT, FIVE, RGHT, '+', END,
DOWN, PGDN, INS, DEL, NIL, NIL, NIL, F11, F12, NIL,
NIL, WIN, WIN, RTCK, POWR, SLEP, NIL, NIL, NIL, WAKE
};

/*function pointer to save the old interrupt handler*/


void interrupt ( *oldhandler)(...);

/*our new interrupt handler. When u press a key, this function gets called*/
void interrupt handler(...)
{
unsigned char scan_code = inportb(0x60); /*read scancode byte from port 0x60*/

/* when the key is pressed,the MSB is cleared so check for this condition*/
if(!(scan_code & 0x80))
printf("%c",ascii[scan_code]);

outportb(0x20,0x20); /*acknowledge PIC that we have received interrupt*/


oldhandler(); /*call the old handler to do its work*/
}

void main()
{
/*save the old interrupt vector*/
oldhandler = getvect(INTR);

/*install the new interrupt handler*/


setvect(INTR, handler);

/*A delay of 10 seconds. What ever u type in this period,will be displayed by our
new interrupt handler*/
delay(10000);

/*reset the old interrupt handler*/


setvect(INTR, oldhandler);
}

Explanation:

Ok, time to dissect the code. But read "How keyboard works"
<how_a_keyboard_works.html> before continuing with the explanation.

#define INTR 0x09

This is the interrupt (int 0x09) generated when ever u press a key. The next
#define statements are scan_codes for non-displayable characters. Next comes
the table where scan-to-ascii lookup is made.

void interrupt ( *oldhandler)(...);

We need to save the address of old interrupt handler of int 0x09 before installing
our new handler. So, this is the function pointer to hold the address of old
interrupt handler.

void interrupt handler(...)


{
unsigned char scan_code = inportb(0x60);
if(!(scan_code & 0x80))
printf("%c",ascii[scan_code]);
outportb(0x20,0x20);
oldhandler();
}

This is the new function (interrupt handler) that gets called when we press a key.
The first statement reads the scancode form port 0x60. As we know that
keyboard generates interrupt for both key press & key release, we need to take
care that only key press is serviced. The keyboard clears the MSB of scancode
when the key is pressed, so a test is made whether MSB is cleared in the "if"
loop. If the loop succeeds, the ASCII value is printed with the help of look up
table. Next statement, outportb(0x20,0x20) acknowledges the PIC that we have
received the interrupt. oldhandler() is called to do its usual service.

void main()
{
oldhandler = getvect(INTR);
setvect(INTR, handler);
delay(10000);
setvect(INTR, oldhandler);
}

First, the address of old interrupt handler is saved in oldhanler by getvect()


function. The getvect() takes the interrupt number as the argument & returns the
address of the interrupt handler. Next, the new handler is set using setvect()
function. The setvect() takes two arguments, first is interrupt & the second is the
address of the handler for that interrupt. We have given a delay of 10 seconds.
When ever u press a key in this period, int 0x09 is generated & as we have set
the new handler for int 0x09, our new handler gets called. We have written code
to display the ASCII value of the pressed key in our new handler. The last
statement restores the old interrupt handler for int 0x09.

A way to stop loading Win 98

Simple, create a file called win.com in the root directory of the drive in which win
98 is installed. for eg: create a blank file "win.com" in C:\ drive. reboot ur PC &
see, it will come till command prompt, executes Autoexec.bat & displays a
message "Error loading exe file". Explanation is simple. The startup routine
searches for a file called "win.com" (its actuall location is C:\WINDOWS) to load
windows. It will look in directories specified in PATH environment variable. As we
know current directory is the first directory to search, the root directory will be
searched first for "win.com" & as we have created a blank file named "win.com"
in root directory, it tries to load the file & finds an error in the .EXE header of that
file. So, it displays a message like "Error loading exe file" & stops.

Ok, enuf phun. If u want to restore the normal execution, either change the
directory to C:\WINDOWS & type "win" or delete the blank file we have created &
reboot.

Hang ur system

Program:
void main()
{
asm cli
while(1);
}

Explaination:

"cli" - This is an assembly language instruction which means clear interrupts. We


know most of our hardware r interrupt driven, i,e they issue an interrupt when
ever they need a service. The CPU, after receiving interrupt from hardware
suspends the execution of current instruction & jumps to the corresponding
Interrupt Service Routine(ISR) which serivces the Hardware request.So, by "cli"
instruction we r blocking all those hardware devices, in other words they become
dead.One more important thing. The timer is also a hardware which issues
periodic interrupt to the CPU,say every 100 ms. That means every 100 ms, the
CPU suspends what ever the current process & jumps to the ISR of timer
interrupt. This ISR inturn calls the timer driver. The timer driver is a program
which is coded to look after all the timer requests. One very important task of the
timer driver is to call the scheduler appropriately. The scheduler, after getting
the control, looks after the process table to choose the next runnable process.
This is how generally multitasking is achieved in all Operating Systems. Now,
bcoz of "cli", we have blocked the timer from issuing its regular periodic
interrupts. As there is no interrupt issued from timer, the ISR, the timer driver &
ultimately the scheduler will not be called at all. That means we have stopped
the multitasking. Let us review. Bcoz of "cli" we have blocked all the interrupt
driven hardware & stopped multitasking. In other words, we have made the
system dead. The next statement While(1); is an infinite loop. so.. these two
statements hangs up ur system. I hope u got it.

This code works only in windows 9x. NT based windows & Linux has better
process management techniques & runs smoothly. Try this code in win 98. Make
an .exe of the above program & run it from a DOS prompt...ur system hangs. Not
even the mouse moves. U need to manually reset ur machine.

Flush ur MBR

Program:

#include <bios.h>
void main()
{
static char buf[512];
biosdisk(3,0x80,0,0,1,1,buf);
}
Explaination:

Static char buf fills the 512-byte buffer with 0`s. The next function biosdisk is
used for disk services. Its declared in bios.h. Ok, lets dissect this function. the
declaration of this function is:

biosdisk(cmd, drive, head, track, start_sector, number_of_sectors, buffer);

where,
cmd - command, a value of 3 indicates that a write to disk is requested drive -
The disk drive to write, 0-A, 1-B, 0x80-first Hard disk, 0x81-second harddisk...
head, track, start_sector - The starting location of the write operation. As we
know the MBR resides in the first sector of harddisk, ie 0th head,0th track & 1st
sector, we specify here those values number_of_sectors - number of sectors to
write. As the MBR spans only one sector, we specify here the value 1 buffer - the
address of buffer to copy to the disk sector. Ok, the values specified in the
program causes the buffer contents to be written to the MBR. Plzz dont run this
program. if u do, u have lost ur harddisk. Once again, NT based windows will not
allow any direct disk access so, Nt based windows displays a message such as "A
program is trying to directly access the disk, which is not permitted". But our
great Win 98 promptly executes this code.

Detecting the number & type of floppy drives

program:

#include <iostream.h>
#include <dos.h>

typedef unsigned char byte;

byte read_CMOS(byte register_num)


{
outportb(0x70,register_num);
return inportb(0x71);
}

void main()
{

char *drive[]={
"Not installed",
"360k drive",
"1.2M drive",
"720k drive",
"1.44M drive",
"2.88M drive"
};
byte val = read_CMOS(0x10);
cout<<"Drive A: "<<drive[val>>4]<<endl;
cout<<"Drive B: "<<drive[val&0xF]<<endl;
}

Explanation:

CMOS is a memory where data regarding the configuration of ur PC is stored. One


such data is the number & type of floppy drives installed in the system. To read a
register from CMOS, all we need is to output the register number to port 0x70 &
read the data from port 0x71.

byte read_CMOS(byte register_num)


{
outportb(0x70,register_num);
return inportb(0x71);
}

The floppy drive`s information is stored in the CMOS register number 0x10. So, in
the first statement of the above function, we have output the register_number of
0x10 (see the main function). The obtained byte is then read from CMOS port
0x71. Let us decode this byte. The high nibble of this byte describes the first
floppy drive (drive A) & the low nibble describes the second floppy drive (drive
B). The nibble values & their meanings r given below:

value meaning

0 Drive not installed


1 360KB 5.25in
2 1.2MB 5.25in
3 720KB 3.5in
4 1.44MB3.5in
5 2.88MB3.5in

Just see the main function to display the drive type.

Você também pode gostar