Software interrupts
DOS, BIOS or any operating system provides system services via system calls. System calls are software interrupts. These are the interrupts generated by CPU with the execution of INT instruction.
Software interrupt control flow
System calls are kernel services to be used by users. User context runs in higher privilege level with protection and thus user context cannot jump or call to kernel functions directly. Operating system reserves a software interrupt vector for this purpose. This is a vector number which should be invoked with INT <vector>. For MSdos this number is 0x21. BIOS also provides a number of services via software interrupts like 0x10 for display, 0x16 for keyboard, 0x13 for disk storage service.
Now calling these system interrupts are tricky. These are not like function calls where compiler pushes argument one by one and calls the function. Here every arguments has to be in CPU registers. Then arguments are set to the registers using MOV. Last is the INT 0xNN instruction. After INT instruction context will jump to kernel interrupt handler. Kernel saves user context and switch to kernel context. Context is a snapshot of CPU registers. Kernel reads all arguments and does all the operations for this service and moves return value to AX and executes an IRET instruction. IRET woul switch context back to user mode and user will get return values and all output arguments in user context.
System calls like file handling open/close,read/writes are system calls. We do not require to write inline assembly or int86 call as these are already implemented by C runtime library. However some DOS and BIOS system calls are not implemented by C runtime. We can call these system interrupts via inline assembly or via int86 routine.
Software interrupt with Inline Assembly
'INT' instruction of x86 microprocessor is used to generate a software interrupt to the CPU. This instruction takes an argument of a number which is the interrupt vector.
INT86
Int86 is a C library function facilitates access to bare bone DOS and BIOS service interrupts. It is a wrapper over inline assembly interrupt call. It takes CPU register values with object to a structure where member variables are equivalent to CPU registers.
Union REGS in c
REGS is a data structure primarily used as the arguments of int86 and other similar functions. REGS is of type union. It represents the individual CPU registers present in 8086 microprocessor. As we know 8086 is 16 bit microprocessor and CPU registers can be assessed by 16 bit mode as well as by 8bit mode. To facilitates this REGS has WORDREGS (16bit) and BYTEREGS (8 bit) structures as union. structure WORDREGS access the members as 2 bytes or 16 bit mode. Registers are like AX, BX, CX, DX etc. structure BYTEREGS access the members as 1 bytes or 8 bit mode. These can access upper 8bit and lower 8 bit of the same WORD registers. Register AX (16 bit) can be accessed by lower 8 bit with AL and upper 8 bit with AH.
Int86 function in C
int86() Execute x86 software Interrupt
Int86 arguments
- inter_no - Software interrupt number
- input_regs - Register values going into call
- output_regs - Register values on return
int86() executes the x86 software interrupt vector given in 'inter_no'. Caller should provide values of the registers in 'input_regs' before calling this function. 'output_regs' is set to the value of the registers after returning from the function or rather returning from the interrupt is execution. The 'cflag' field of 'output_regs' is set to the status of the system carry flag.
Int86 return values
AX register generally have the return value of the system call.
To indicate if the system interrupt is a success or failure, most of the system call sets AL as zero on success.
System interrupt interface reference guide should be checked for proper interpretation.
If the 'cflag' field in 'output_regs' is non-zero, an error has
occurred and '_doserrno' (defined in
Int86 usage
DOS software interrupt vector is 0x21. intdos function call can be done using int86(0x21) i.e. calling int86 with vector number as 0x21. int86 function is limited to primary registers of CPUs. Segment registers are needed for pointer types of 'far' or 'huge' addresses. int86x should be used instead of int86().
Int86 example
We have an example using int86 function in C to interface with Video modes interrupts. This invokes get VESA information service of the graphics card in BIOS. We provided a FAR buffer of 256 bytes to this service using int86x. This VGA BIOS interrupt populates the graphics card related information in the buffer. We have offset [0-3] as string of VESA signature. This can have a value of 'VESA' or 'VBE2'. Buffer offset [4-5] is a WORD containing the VESA version is BCD format. Buffer [6-9] is a DWORD which is a FAR pointer to video card's OEM vendor string.
Int86 output
Int86x function in C
Set x86 Segment Registers and Execute Software Interrupt
Int86x arguments
- inter_no - Software interrupt number
- input_regs - Register values going into call
- output_regs - Register values on return
- seg_regs - Segment-register values on call
int86x() executes the 8086 software interrupt whose vector is 'inter_no'. Tt is similar to int86() but it has the added advantage of giving segment registers to the interrupt call. DS and ES segment registers can be set and 20bit real mode pointers can be passed to the routine. The 'input_regs' and 'output_regs' parameters are same as of int86 function. The parameter 'segregs' is the addition where caller can set DS and ES segment values.
Int86x usage
Return values are same as discussed in int86.
This should be called when DS and ES segment registers are needed in interrupt. int86() should be used if segment registers are not needed.. The values for the segment registers can be obtained with the segread() function or the FP_SEG macro. This function can be called with vector 0x21 to simulate the call of intdos() and intdosx(). The DS register is restored upon completion of the int86x() call.
Int86x example
Below example is an interesting example using int86x function in C. This invokes get VESA information service of the graphics card in BIOS. We provided a FAR buffer of 256 bytes to this service using int86x. This VGA BIOS interrupt populates the graphics card related information in the buffer. We have offset [0-3] as string of VESA signature. This can have a value of 'VESA' or 'VBE2'. Buffer offset [4-5] is a WORD containing the VESA version is BCD format. Buffer [6-9] is a DWORD which is a FAR pointer to video card's OEM vendor string.
Int86x output
Intdos() function in C
intdos() Call DOS system interrupt (vector 0x21)
Intdos arguments
- input_regs - Register values going into call
- output_regs - Register values on return
intdos() invokes a DOS system call (Interrupt 21h) after setting the registers to the values in 'input_regs'. 'output_regs' is set to the value of the registers after the system call. The 'cflag' field of 'output_regs' is set to the status of the system carry flag; a non-zero value indicates a DOS error. 'input_regs.h.ah' is the DOS function number. (The structure REGS is defined in dos.h.)
Intdos usage
Return values are same as discussed in int86.
intdos() is intended to invoke DOS system calls that expect arguments in registers other than DX or AL, or that indicate errors by setting the carry flag. Services that use only DX and AL and don't use the carry flag, can be invoked via the bdos() function. If 'far' or 'huge' addresses are passed to DOS, you may need to use intdosx() instead of intdos().
Intdos example
Below example shows on how to call intdos function in C. We are calling get system date (2A) service using DOS interrupt. This service returns the system current date values in output registers. AL register should contain the day of week value, DL contains the day of the month, DH has the value of the month, CX has the value of the year.
Intdos output
Intdosx() function in C
intdosx() Set segment registers and call DOS system interrupt (vector 0x21)
Intdosx arguments
- input_regs - Register values going into call
- output_regs - Register values on return
- seg_regs - ES and DS values going into call
intdosx() invokes a DOS system interrupt 21h. Caller should set the registers to the values in 'input_regs' and setting the DS and ES registers to the values in 'seg_regs' before calling this function. 'output_regs' is set to the value of the registers after the system interrupt. The 'cflag' field of 'output_regs' is set to the status of the system carry flag; a non-zero value indicates a DOS error. 'input_regs.h.ah' is the DOS function number.
Intdosx usage
Return values are same as discussed in int86.
The values for segment registers can be obtained with the segread() function or the FP_SEG() macro. If the DS and ES registers don't need to be set, intdos() can be used. DOS functions that use only the DX and AL registers and that don't return error information in the carry flag can be invoked via the bdos() function.
Intdosx example
This is a small source code to demo the intdosx function. It invokes DOS create file 0x3C interrupt. The filename is a FAR pointer of string. This string is passed to the function using segment:offset DS:DX. We also close the file using intdos function 0x3E. We have used DIR DOS command in the command shell to show that file has been created.
Intdosx output
About our authors: Team EQA
You have viewed 1 page out of 252. Your C learning is 0.00% complete. Login to check your learning progress.