CS 301 Lecture, Dr. Lawlor

Interrupts as a cry for help

The OS normally doesn't care what you're working on.  It doesn't hover over your shoulder, watching your reads and writes to registers or memory.  It's got better things to do.  Instead, if you want the OS's attention, you've got to break something--do something the CPU will generate an error for!  The standard unignorable operation is to throw an "software interrupt", which on x86 CPUs you can do with the special "INT" (generate software interrupt) instruction.

Hardware interrupts are used by the hardware to get the CPU's attention--for example, the IDE controller will raise an I/O interrupt when a read is complete.  The OS (the BIOS, or Windows, or Linux) handles all interrupts, both hardware and software.  We'll talk a lot more about hardware interrupts when we talk about I/O.

Interrupts The "protection bit" ("supervisor bit") System call

How interrupts work as system calls ("syscalls")

So the standard way to ask the OS to do something is to issue a special interrupt, normally called a system call or "syscall":
  1. Stash the information about what you want done.  Usually there's some sort of "selector code" that tells the OS what you want done (on Linux, the "syscall number", which goes into eax), and then a set of arguments.  The selector and arguments can be stored:
  2. Call the OS, by issuing an interrupt.  You could also imagine a machine where you ask the OS to do stuff by just segfaulting--accessing a special off-limits memory location.
  3. The OS's "interrupt service routine" (just normal code, called by the CPU when an interrupt happens) then reads the selector code from your registers, does what you want done, and then returns control back to you.
  4. The OS might have stashed return information (like an error code) in registers, the stack, or elsewhere.  As usual, you've got to read each OS's docs to figure out how it works.
Linux can use either interrupt 0x80 (INT 0x80) for system calls, or the slightly-faster SYSENTER instruction.  The selector code goes in eax, arguments go in ebx, ecx, edx, esi, and edi.  Nothing goes on the stack.

The PC BIOS uses interrupts 0x10 and 0x16.  MS-DOS mostly uses interrupt 0x21.  Ralph Brown's Interrupt List is the definitive reference for all BIOS and MS-DOS interrupt functions.  The selector code goes in ax.

Windows XP now uses the special SYSENTER x86 instruction for system calls.  Windows 2000 and earlier versions of NT used INT 0x2e to access OS.  Unfortunately, Windows randomly reassigns system call numbers, so it's quite uncommon to make Windows system calls directly (except possibly from inside a virus!).

Nowadays, you almost never make system calls directly, since the system call interfaces require assembly code to load parameters into registers.  Instead, from C/C++ you normally call nice system library routines, like UNIX "write" or Windows "WriteFile", that hide the ugly assembly.  Or you use Visual Basic/Perl/PHP to hide the ugly C/C++.  Or you just surf the net.  Whichever.

Syscall example--Linux

Konstantin Boldyshev has a good writeup and examples of Linux, BSD, and BeOS x86 syscalls, and a list of common Linux syscalls.  He uses NASM for the examples. Here's a slightly cleaned up version of his Linux example:
	; To make a Linux syscall, we load up the registers and call INT 0x80
mov eax,4 ;system call number (sys_write)
mov ebx,1 ;file descriptor (stdout)
mov ecx,msg ;message to write
mov edx,8 ;message length, in bytes
int 0x80 ;call kernel
; Kernel call return value is in eax-- it'll do as a function return code.

section ".data" ;<- this puts the string into writeable memory...
db 'Wazzup?',0xa ; our little string, followed by a newline
(Executable NetRun Link)