Interrupt handler

Preface

Blog records the operation of the experiment in Chapter 7 of "Operating System Truth Restore"~

Experimental environment : ubuntu18.04+VMware, download and install Bochs

Experiment content :

  1. Write an interrupt handler (operation 8259A to turn on interrupts).
  2. Improve the interrupt handler (call the C language version of the interrupt handler function in the assembly version of intrXXentry).
  3. Use the counter/timer 8253 to set the frequency at which the clock interrupt occurs. (Speed ​​up the interrupt signal).

prerequisite knowledge

Interruption concept

The concept of interrupt processing (interruption) : Since the CPU knows something that happened in the computer, the CPU suspends the program being executed, and then executes the program that handles the event. After the execution of this program is completed, the CPU continues to execute the program just now . The whole process is called interrupt handling, also known as interrupt.

The OS operating system is interrupt driven. Without interrupts, the OS can barely do anything!

Interrupt classification

Interrupts can be divided into the following 2 types.

  1. External interrupt: Interrupts from outside the CPU are called external interrupts.
  2. Internal Interrupts: Interrupts from within the CPU are called internal interrupts.

The essence of the interrupt mechanism : The essence of the interrupt mechanism is to call the corresponding interrupt handler after an interrupt signal is passed in. Therefore, the CPU attributes various interrupt types from external devices and internal instructions to a management method, that is, assigning an integer to each interrupt signal, using this integer as the ID of the interrupt (the integer is the interrupt vector), and then using this The ID is used as an index in the interrupt descriptor table to find the corresponding entry and then the corresponding interrupt handler.

external interrupt

An external interrupt refers to an interrupt from outside the CPU, and this external interrupt source must be a certain hardware. Therefore, external interrupts are also called hardware interrupts.

External hardware interrupts are notified to the CPU through two signal lines, namely INTR (INTeRrupt) and NMI (Non Maskable Interrupt). As shown below

Insert image description here

Because tasks have priorities, they can be subdivided into maskable interrupts (maskable interrupts) and non-maskable interrupts (NMI).

  • Maskable interrupt
    Concept: The CPU can ignore the interrupt issued by this external device, because it will not cause the system to go down.
    [Note] The CPU can also ignore it and divide the interrupt into the upper half and the lower half for separate processing.

  • Non-maskable interrupt
    concept: an emergency interrupt that can cause the CPU to crash if it is serious.
    Interrupt processing flow: After the CPU receives an interrupt, it needs to know what happened before it can execute the corresponding processing method. This is achieved by checking the interrupt vector table or the interrupt descriptor table through the interrupt vector number (the interrupt vector table is an array of interrupt handlers in real mode, which has been replaced by the interrupt descriptor table in protected mode).

Interrupted within

Internal interrupts can be divided into soft interrupts and exceptions.

  • Soft interrupts: Soft interrupts refer to interrupts initiated by software. (ex. "int 8-bit immediate value")
  • Exception: Exceptions are caused by errors that occur inside the CPU during instruction execution. (ex. "int3")

Experimental operation

experiment one

Start interrupt process

  1. The init_all function is used to initialize all devices and data structures.
  2. init_all calls idt_init to initialize interrupt-related content.
  3. The initialization is completed in two parts, namely pic_init and idt_desc_init. Among them, pic_init (Programmable Interrupt Controller) is used to initialize the programmable interrupt controller 8259A, and ide_desc_init is used to initialize the interrupt descriptor table IDT.
  4. After idt_init is completed, IDT is loaded.

Insert image description here
Experiment 1 uses assembly language to implement an interrupt handler, which is saved in the kernel.S file.

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim kernel.S

Having finished writing the interrupt handlers, we now need to install them into the interrupt descriptor table. That is, create an interrupt descriptor table IDT and install an interrupt handler. This program is saved in the file interrupt.c (the file interrupt.c contains the current content about interrupts).

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.c

After completing the interrupt-related data preparation, you need to set up the interrupt agent 8259A. Here, inline assembly is used to implement the port I/O function. io.h declares function definitions for port operations.

(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim io.h

Next, you need to define the file for initialization-related work, that is, init_all.

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim init.c

init_all is called by the main function main in main.c to update the main function.

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  main.c

Complete the creation of the remaining files

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim global.h
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim init.h
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.h

Check kernelout the file

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ ls
global.h  init.h       interrupt.h  kernel.S
init.c    interrupt.c  kernel.bin   main.c

Create a new build folder to store the output files (all target files and compiled kernel files)

(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir build

After completing the basic file creation work, now enter the steps of compiling, linking, and writing to disk.

Compilation work

sudo nasm -f elf -o build/print.o lib/kernel/print.S
sudo nasm -f elf -o build/kernel.o kernel/kernel.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -f elf -o build/print.o lib/kernel/print.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -f elf -o build/kernel.o kernel/kernel.S
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c

link work

Note here that the directory of the new kernel.bin is in the build directory.

sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o
(base) user@ubuntu:/home/cooiboi/bochs$ sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o

write to disk

sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs$ sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
14+1 records in
14+1 records out
7236 bytes (7.2 kB, 7.1 KiB) copied, 0.00014881 s, 48.6 MB/s

If there is a problem with the hard disk content, you can delete it and rewrite it. The following is the content written before (posted for ease of implementation)

sudo dd if=/home/cooiboi/bochs/boot/mbr.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 conv=notrunc
sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=3 seek=2 conv=notrunc

Start Bochs

sudo bin/bochs -f boot/bochsrc.disk
(base) user@ubuntu:/home/cooiboi/bochs$ sudo bin/bochs -f boot/bochsrc.disk

Insert image description here

Let's see what the interrupt descriptor looks like after installation eight! Order:info idt

Insert image description here

  • The first column is the serial number of the interrupt gate descriptor, 0x20 in total.
  • Interrupt Gate targetIs the interrupt handler address pointed to in the gate descriptor, expressed in the form of selector: offset.

Suppose you want to view an interrupt gate descriptor, you can use info idt 序号the command. [The interrupt gate descriptor corresponding to the interrupt vector number 0x20 is shown in the figure below]

Insert image description here

Experiment 2

Improve the interrupt handler and call the C language version of the interrupt handler function in the assembly version of intrXXentry.

Modify interrupt.c and kernel.S files

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim interrupt.c
(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  kernel.S 

The subsequent steps are exactly the same as those in Experiment 1~

"int vector: 0x20" is constantly printed in the running chart (only the clock interrupt is turned on, and the interrupt vector number of the clock is 0x20)

Insert image description here

Experiment 3

Create a new device directory to store device codes.

(base) user@ubuntu:/home/cooiboi/bochs$ sudo mkdir  device

Create timer.c and timer.h.

(base) user@ubuntu:/home/cooiboi/bochs/device$ sudo vim timer.c
(base) user@ubuntu:/home/cooiboi/bochs/device$ sudo vim timer.h

Next, add the timer_init function to the file init.c

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim  init.c

After completing the basic file creation work, now enter the steps of compiling, linking, and writing to disk.

The following commands are executed /home/cooiboi/bochs$below .

compile

sudo nasm -f elf -o build/print.o lib/kernel/print.S
sudo nasm -f elf -o build/kernel.o kernel/kernel.S
sudo gcc -m32 -I lib/kernel -c -o build/timer.o device/timer.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
sudo gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c

link work

sudo ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o build/print.o build/kernel.o build/timer.o

write to disk

sudo dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc

Start Bochs

sudo bin/bochs -f boot/bochsrc.disk

Insert image description here
References

Guess you like

Origin blog.csdn.net/weixin_42888638/article/details/128610791