ZeePedia

Software Interrupts: Hooking an Interrupt, BIOS and DOS Interrupts

<< String Instructions: String Processing, Clearing Screen, String Printing, Length
Real Time Interrupts and Hardware Interfacing >>
img
8
Software Interrupts
8.1. INTERRUPTS
Interrupts in reality are events that occurred outside the processor and the
processor must be informed about them. Interrupts are asynchronous and
unpredictable. Asynchronous means that the interrupts occur, independent
of the working of the processor, i.e. independent of the instruction currently
executing. Synchronous events are those that occur side by side with
another activity. Interrupts must be asynchronous as they are generated by
the external world which is unaware of the happenings inside the processor.
True interrupts that occur in real time are asynchronous with the execution.
Also it is unpredictable at which time an interrupt will come. The two
concepts  of  being  unpredictable  and  asynchronous  are  overlapping.
Unpredictable means the time at which an interrupt will come cannot be
predicted, while asynchronous means that the interrupt has nothing to do
with the currently executing instruction and the current state of the
processor.
The 8088 processor divides interrupts into two classes. Software interrupts
and hardware interrupts. Hardware interrupts are the real interrupts
generated by the external world as discussed above. Software interrupts on
the contrary are not generated from outside the processor. They just provide
an extended far call mechanism. Far all allows us to jump anywhere in the
whole megabyte of memory. To return from the target we place both the
segment and offset on the stack. Software interrupts show a similar
behavior. It however pushes one more thing before both the segment and
offset and that is the FLAGS register. Just like the far call loads new values
in CS and IP, the interrupt call loads new values in CS, IP, and FLAGS.
Therefore the only way to retain the value of original FLAGS register is to
push and pop as part of interrupt call and return instructions. Pushing and
popping inside the routine will not work as the routine started with an
already tampered value.
The discussion of real time interrupts is deferred till the next chapter. They
play the critical part in control applications where external hardware must
be control and events and changes therein must be appropriately responded
by the processor. To generate an interrupt the INT instruction is used. The
routine that executes in response to an INT instruction is called the interrupt
service routine (ISR) or the interrupt handler. Taking example from real time
interrupts the routine to instruct an external hardware to close the valve of a
boiler in response to an interrupt from the pressure sensor is an interrupt
routine.
The software interrupt mechanism in 8088 uses vectored interrupts
meaning that the address of the interrupt routine is not directly mentioned
in an interrupt call, rather the address is lookup up from a table. 8088
provides a mechanism for mapping interrupts to interrupt handlers.
Introducing a new entry in this mapping table is called hooking an interrupt.
Syntax of the INT instruction is very simple. It takes a single byte
argument varying from 0-255. This is the interrupt number informing the
processor, which interrupt is currently of interest. This number correlates to
the interrupt handler routine by a routing or vectoring mechanism. A few
interrupt numbers in the start are reserved and we generally do not use
them. They are related to the processor working. For example INT 0 is the
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
divide by zero interrupt. A list of all reserved interrupts is given later. Such
interrupts are programmed in the hardware to generate the designated
interrupt when the specified condition arises. The remaining interrupts are
provided by the processor for our use. Some of these were reserved by the
IBM PC designers to interface user programs with system software like DOS
and BIOS. This was the logical choice for them as interrupts provided a very
flexible architecture. The remaining interrupts are totally free for use in user
software.
The correlation process from the interrupt number to the interrupt handler
uses a table called interrupt vector table. Its location is fixed to physical
memory address zero. Each entry of the table is four bytes long containing
the segment and offset of the interrupt routine for the corresponding
interrupt number. The first two bytes in the entry contain the offset and the
next two bytes contain the segment. The little endian rule of putting the more
significant part (segment) at a higher address is seen here as well.
Mathematically offset of the interrupt n will be at nx4 while the segment will
be at nx4+2. One entry in this table is called a vector. If the vector is changed
for interrupt 0 then INT 0 will take execution to the new handler whose
address is now placed at those four bytes. INT 1 vector occupies location 4,
5, 6, and 7 and similarly vector for INT 2 occupies locations 8, 9, 10, and 11.
As the table is located in RAM it can be changed anytime. Immediately after
changing it the interrupt mapping is changed and now the interrupt will
result in execution of the new routine. This indirection gives the mechanism
extreme flexibility.
The operation of interrupt is same whether it is the result of an INT
instruction (software interrupt) or it is generated by an external hardware
which passes the interrupt number by a different mechanism. The currently
executing instruction is completed, the current value of FLAGS is pushed on
the stack, then the current code segment is pushed, then the offset of the
next instruction is pushed. After this it automatically clears the trap flag and
the interrupt flag to disallow further interrupts until the current routine
finishes. After this it loads the word at nx4 in IP and the word at nx4+2 in CS
if interrupt n was generated. As soon as these values are loaded in CS and IP
execution goes to the start of the interrupt handler. When the handler
finishes its work it uses the IRET instruction to return to the caller. IRET
pops IP, then CS, and then FLAGS. The original value of IF and TF is
restored which re-enables further interrupts. IF and TF will be discussed in
detail in the discussion of real time interrupts. We have discussed three
things till now.
1. The INT and IRET instruction format and syntax
2. The formation of IVT (interrupt vector table)
3. Operation of the processor when an interrupt in generated
Just as discussed in the subroutines chapter, the processor will not match
interrupt calls to interrupt returns. If a RETF is used in the end of an ISR the
processor will still return to the caller but the FLAGS will remain on the
stack which will destroy the expectations of the caller with the stack. If we
know what we are doing we may use such different combination of
instructions. Generally we will use IRET to return from an interrupt routine.
Apart from indirection the software interrupt mechanism is similar to CALL
and RET. Indirection is the major difference.
The operation of INT can be written as:
·  sp sp+2
·  [sp] flag
·  sp sp+2
·  if 0
·  tf 0
·  [sp] cs
·  sp sp+2
·  [sp] ip
96
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
·  ip [0:N*4]
·  cs [0:N*4+2]
The operation of IRET can be written as:
·  ip [sp]
·  sp sp-2
·  cs [sp]
·  sp sp-2
·  flag [sp]
·  sp sp-2
The above is the microcode description of INT and IRET. To obey an
assembly language instruction the processor breaks it down into small
operations. By reading the microcode of an instruction its working can be
completely understood.
The interrupt mechanism we have studied is an extended far call
mechanism. It pushes FLAGS in addition to CS and IP and it loads CS and IP
with a special mechanism of indirection. It is just like the table of contents
that is located at a fixed position and allows going directly to chapter 3, to
chapter 4 etc. If this association is changed in the table of contents the
direction of the reader changes. For example if Chapter 2 starts at page 220
while 240 is written in the table of contents, the reader will go to page 240
and not 220. The table of contents entry is a vector to point to map the
chapter number to page number. IVT has 256 chapters and the interrupt
mechanism looks up the appropriate chapter number to reach the desired
page to find the interrupt routine.
Another important similarity is that table of contents is always placed at
the start of the book, a well known place. Its physical position is fixed. If
some publishers put it at some place, others at another place, the reader will
be unable to find the desired chapter. Similarly in 8088 the physical memory
address zero is fixed for the IVT and it occupies exactly a kilobyte of memory
as the 256x4=1K where 256 is the number of possible interrupt vectors while
the size of one vector is 4 bytes.
Interrupts introduce temporary breakage in the program flow, sometimes
programmed (software interrupts) and un-programmed at other times
(hardware interrupts). By hooking interrupts various system functionalities
can be controlled. The interrupts reserved by the processor and having
special functions in 8088 are listed below:
·  INT 0, Division by zero
Meaning the quotient did not fit in the destination register. This is a bit
different as this interrupt does not return to the next instruction,
rather it returns to the same instruction that generated it, a DIV
instruction of course. Here INT 0 is automatically generated by a DIV
when a specific situation arises, there is no INT 0 instruction.
·  INT 1, Trap, Single step Interrupt
This interrupt is used in debugging with the trap flag. If the trap flag is
set the Single Step Interrupt is generated after every instruction. By
hooking this interrupt a debugger can get control after every
instruction and display the registers etc. 8088 was the first processor
that has this ability to support debugging.
·  INT 2, NMI-Non Maskable Interrupt
Real interrupts come from outside the processor. INT 0 is not real as it
is generated from inside. For real interrupts there are two pins in the
processor, the INT pin and the NMI pin. The processor can be directed
to listen or not to listen to the INT pin. Consider a recording studio,
when the recording is going on, doors are closed so that no
interruption occurs, and when there is a break, the doors are opened
so that if someone is waiting outside can come it. However if there is an
urgency like fire outside then the door must be broken and the
recording must not be catered for. For such situations is the NMI pin
97
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
which informs about fatal hardware failures in the system and is tied
to interrupt 2. INT pin can be masked but NMI cannot be masked.
·  INT 3, Debug Interrupt
The only special thing about this interrupt is that it has a single byte
opcode and not a two byte combination where the second byte tells the
interrupt number. This allows it to replace any instruction whatsoever.
It is also used by the debugger and will be discussed in detail with the
debugger working.
·  INT 4, Arithmetic Overflow, change of sign bit
The overflow flag is set if the sign bit unexpectedly changes as a result
of a mathematical or logical instruction. However the overflow flag
signals a real overflow only if the numbers in question are treated as
signed numbers. So this interrupt is not automatically generated but
as a result of a special instruction INTO (interrupt on overflow) if the
overflow flag is set. Otherwise the INTO instruction behaves like a NOP
(no operation).
These are the five interrupts reserved by Intel and are generally not used in
our operations.
8.2. HOOKING AN INTERRUPT
To hook an interrupt we change the vector corresponding to that interrupt.
As soon as the interrupt vector changes, that interrupt will be routed to the
new handler. Our first example is with the divide by zero interrupt. The
normal system defined behavior in response to divide by zero is to display an
error message and terminate the program. We will change it to display our
own message.
Example 8.1
001
; hooking divide by zero interrupt
002
[org 0x0100]
003
jmp  start
004
005
message:
db
'You divided something by zero.', 0
006
007-029
;;;;; COPY LINES 028-050 FROM EXAMPLE 7.4 (strlen) ;;;;;
030-049
;;;;; COPY LINES 005-024 FROM EXAMPLE 7.1 (clrscr) ;;;;;
050-090
;;;;; COPY LINES 050-090 FROM EXAMPLE 7.4 (printstr) ;;;;;
091
092
; divide by zero interrupt handler
093
myisrfor0:
push ax
; push all regs
094
push bx
095
push cx
096
push dx
097
push si
098
push di
099
push bp
100
push ds
101
push es
102
103
push cs
104
pop  ds
; point ds to our data segment
105
106
call
clrscr
; clear the screen
107
mov
ax, 30
108
push
ax
; push x position
109
mov
ax, 20
110
push
ax
; push y position
111
mov
ax, 0x71
; white on blue attribute
112
push
ax
; push attribute
113
mov
ax, message
114
push
ax
; push offset of message
115
call
printstr
; print message
116
117
pop
es
118
pop
ds
119
pop
bp
98
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
120
pop
di
121
pop
si
123
pop
dx
124
pop
cx
125
pop
bx
126
pop
ax
127
iret
; return from interrupt
128
129
; subroutine to generate a divide by zero interrupt
130
genint0:
mov  ax, 0x8432
; load a big number in ax
131
mov  bl, 2
; use a very small divisor
132
div  bl
; interrupt 0 will be generated
133
ret
134
135
start:
xor
ax, ax
136
mov
es, ax
; load zero in es
137
mov
word [es:0*4], myisrfor0 ; store offset at n*4
138
mov
[es:0*4+2], cs
; store segment at n*4+2
139
call
genint0
; generate interrupt 0
140
141
mov ax, 0x4c00
; terminate program
142
int 0x21
We often push all registers in an interrupt service routine just to be
93-101
sure that no unintentional modification to any register is made.
Since any code may be interrupted an unintentional modification
will be hard to debug
Since interrupt can be called from anywhere we are not sure about
103-104
the value in DS so we reset it to our code segment.
When this program is executed our desired message will be shown instead
of the default message and the computer will hang thereafter. The first thing
to observe is that there is no INT 0 call anywhere in the code. INT 0 was
invoked automatically by an internal mechanism of the processor as a result
of the DIV instruction producing a result that cannot fit in the destination
register. Just by changing the vector we have changed the response of the
system to divide overflow situations.
However the system stuck instead of returning to the next instruction.
This is because divide overflow is a special type of interrupt that returns to
the same instruction instead of the next instruction. This is why the default
handler forcefully terminates the program instead of returning. Now the IRET
will take control back to the DIV instruction which will again generate the
same interrupt. So the computer is stuck in an infinite loop.
8.3. BIOS AND DOS INTERRUPTS
In IBM PC there are certain interrupts designated for user programs to
communicate with system software to access various standard services like
access to the floppy drive, hard drive, vga, clock etc. If the programmer does
not use these services he has to understand the hardware details like which
particular controller is used and how it works. To avoid this and provide
interoperability a software interface to basic hardware devices is provided
except in very early computers. Since the manufacturer knows the hardware
it burns the software to control its hardware in ROM. Such software is called
firmware and access to this firmware is provided through specified
interrupts.
This basic interface to the hardware is called BIOS (basic input output
services). When the computer is switched on, BIOS gets the control at a
specified address. The messages at boot time on the screen giving BIOS
version, detecting different hardware are from this code. BIOS has the
responsibility of testing the basic hardware including video, keyboard, floppy
drive, hard drive etc and a special program to bootstrap. Bootstrap means to
load OS from hard disk and from there OS takes control and proceeds to load
its components and display a command prompt in the end. There are two
99
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
important programs; BIOS and OS. OS services are high level and build upon
the BIOS services. BIOS services are very low level. A level further lower is
only directly controlling the hardware. BIOS services provide a hardware
independent layer above the hardware and OS services provide another
higher level layer over the BIOS services. We have practiced direct hardware
access with the video device directly without using BIOS or DOS. The layer of
BIOS provides services like display a character, clear the screen, etc. All
these layers are optional in that we can skip to whatever lower layer we want.
The most logical way to provide access to firmware is to use the interrupt
mechanism. Specific services are provided at specific interrupts. CALL could
also have been used but in that case every manufacturer would be required
to place specific routines at specific addresses, which is not a flexible
mechanism. Interrupts provide standard interrupt number for the caller and
flexibility to place the interrupt routine anywhere in the memory for the
manufacturer. Now for the programmer it is decided that video services will
be provided at INT 10 but the actual address of the video services can and do
vary on computers from different manufacturers. Any computer that is IBM
compatible must make the video services accessible through INT 10.
Similarly keyboard services are available at INT 16 and this is standard in
every IBM compatible. Manufacturers place the code wherever they want and
the services are exported through this interrupt.
BIOS exports its various services through different interrupts. Keyboard
services are exported through INT 16, parallel port services through INT 17
and similarly others through different interrupts. DOS has a single entry
point through INT 21 just like a pin hole camera, this single entry points
leads to a number of DOS services. So how one interrupt provides a number
of different services. A concept of service number is used here which is a
defecto standard in providing multiple services through an interrupt. INT 10
is for video services and each of character printing service, screen clearing
service, cursor movement service etc. has a service number associated to it.
So we say INT 10 service 0 is used for this purpose and INT 10 service 1 is
used for that purpose etc. Service numbers for different standard services are
also fixed for every IBM compatible. The concept of exported services through
interrupts is expanded with the service numbering scheme.
The service number is usually given in the AH register. Sometimes these
256 services seem less. For example DOS exports thousands of services. So
will be often seen an extension to a level further with sub-services. For
examples INT 10 character generator services are all provided through a
single service number and the services are distinguished with a sub-service
number.
The finally selected service would need some arguments for it to work. In
interrupts arguments are usually not given through stack, rather registers
are used. The BIOS and DOS specifications list which register contains
which argument for a particular service of a particular interrupt.
We will touch some important BIOS and DOS services and not cover it
completely neither is it possible to cover it in this space. A very
comprehensive reference of interrupts is the Ralph Brown List. It is just a
reference and not to be studied from end to end. All interrupts cannot be
remembered and there is no need to remember them.
The service number is almost always in AH while the sub-service number
is in AL or BL and sometimes in other registers. The documentation of the
service we are using will list which register should hold what when the
interrupt is invoked for that particular service.
Our first target using BIOS is video so let us proceed to our first program
that uses INT 10 service 13 to print a string on the screen. BIOS will work
even if the video memory is not at B8000 (a very old video card) since BIOS
knows everything about the hardware and is hardware specific.
100
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
Example 8.2
001
; print string using bios service
002
[org 0x0100]
003
jmp  start
004
message:
db
'Hello World'
005
006
start:
mov
ah, 0x13
;
service 13 - print string
007
mov
al, 1
;
subservice 01 ­ update cursor
008
mov
bh, 0
;
output on page 0
009
mov
bl, 7
;
normal attrib
010
mov
dx, 0x0A03
;
row 10 column 3
011
mov
cx, 11
;
length of string
012
push
cs
013
pop
es
; segment of string
014
mov
bp, message
; offset of string
015
int
0x10
; call BIOS video service
016
017
mov
ax, 0x4c00
; terminate program
018
int
0x21
The sub-service are versions of printstring that update and do not
007
update the cursor after printing the string etc.
Text video screen is in the form of pages which can be upto 32. At
008
one time one page is visible which is by default the zeroth page
unless we change it.
When we execute it the string is printed and the cursor is updated as well.
With direct access to video memory we had no control over the cursor. To
control cursor a different mechanism to access the hardware was needed.
Our next example uses the keyboard service to read a key. The
combination of keyboard and video services is used in almost every program
that we see and use. We will wait for four key presses; clear the screen after
the first, and draw different strings after the next key presses and exiting
after the last. We will use INT 16 service 1 for this purpose. This is a blocking
service so it does not return until a key has been pressed. We also used the
blinking attribute in this example.
101
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
Example 8.3
001
; print string and keyboard wait using BIOS services
002
[org 0x100]
003
jmp  start
004
005
msg1:
db
'hello world', 0
006
msg2:
db
'hello world again', 0
007
msg3:
db
'hello world again and again', 0
008
009-028
;;;;; COPY LINES 005-024 FROM EXAMPLE 7.1 (clrscr) ;;;;;
029-069
;;;;; COPY LINES 050-090 FROM EXAMPLE 7.4 (printstr) ;;;;;
070-092
;;;;; COPY LINES 028-050 FROM EXAMPLE 7.4 (strlen) ;;;;;
093
094
start:
mov
ah, 0x10
;
service 10 ­ vga attributes
095
mov
al, 03
;
subservice 3 ­ toggle blinking
096
mov
bl, 01
;
enable blinking bit
097
int
0x10
;
call BIOS video service
098
099
mov
ah, 0
; service 0 ­ get keystroke
100
int
0x16
; call BIOS keyboard service
101
102
call clrscr
; clear the screen
103
104
mov
ah, 0
; service 0 ­ get keystroke
105
int
0x16
; call BIOS keyboard service
106
107
mov
ax, 0
108
push
ax
; push x position
109
mov
ax, 0
110
push
ax
; push y position
111
mov
ax, 1
; blue on black
112
push
ax
; push attribute
113
mov
ax, msg1
114
push
ax
; push offset of string
115
call
printstr
; print the string
116
117
mov
ah, 0
; service 0 ­ get keystroke
118
int
0x16
; call BIOS keyboard service
119
120
mov
ax, 0
121
push
ax
; push x position
123
mov
ax, 0
124
push
ax
; push y position
125
mov
ax, 0x71
; blue on white
126
push
ax
; push attribute
127
mov
ax, msg2
128
push
ax
; push offset of string
129
call
printstr
; print the string
130
131
mov
ah, 0
; service 0 ­ get keystroke
132
int
0x16
; call BIOS keyboard service
133
134
mov
ax, 0
135
push
ax
; push x position
136
mov
ax, 0
137
push
ax
; push y position
138
mov
ax, 0xF4
; red on white blinking
139
push
ax
; push attribute
140
mov
ax, msg3
141
push
ax
; push offset of string
142
call
printstr
; print the string
143
144
mov
ah, 0
; service 0 ­ get keystroke
145
int
0x16
; call BIOS keyboard service
146
147
mov
ax, 0x4c00
; terminate program
148
int
0x21
This service has no parameters so only the service number is
099-100
initialized in AH. This is the only service so there is no sub-service
number as well. The ASCII code of the char pressed is returned in
AL after this service.
102
img
Computer Architecture & Assembly Language Programming
Course Code: CS401
CS401@vu.edu.pk
EXERCISES
1. Write a TSR that forces a program to exit when it tries to become a
TSR using INT 21h/Service 31h by converting its call into INT
21h/Service 4Ch.
2. Write a function to clear the screen whose only parameter is always
zero. The function is hooked at interrupt 80h and may also be called
directly both as a near call and as a far call. The function should
detect how it is called and return appropriately. It is provided that the
direction flag will be set before the function is called.
3. Write a function that takes three parameters, the interrupt number
(N) and the segment and offset of an interrupt handler XISR. The
arguments are pushed in the order N, XISR's offset and XISR's
segment. It is known that the first two instructions of XISR are
PUSHF and CALL 0:0 followed by the rest of the interrupt handler.
PUSHF instruction is of one byte and far call is of 5 bytes with the
first byte being the op-code, the next two containing the target offset
and the last two containing the target segment. The function should
hook XISR at interrupt N and chain it to the interrupt handler
previously hooked at N by manipulating the call 0:0 instruction
placed near the start of XISR.
4. Write a TSR that provide the circular queue services via interrupt
0x80 using the code written in Exercise 5.XX. The interrupt
procedure should call one of qcreate, qdestroy, qempty, qadd,
qremove, and uninstall based on the value in AH. The uninstall
function should restore the old interrupt 0x80 handler and remove
the TSR from memory.
103