Binding with the Interrupt Service Routine of Peripherals and

Một phần của tài liệu The art of linux kernel design (Trang 76 - 81)

2. Device Initialization and Process 0 Activation 45

2.7 Binding with the Interrupt Service Routine of Peripherals and

Computer Interaction Interface

Linus Torvalds originally designed chr_dev_init() in the OS to initialize the character device, but it does nothing. Linus then implemented tty_init() to initialize the character device. Note that people sometimes explain tty as teletype.

Character device initialization builds work environment for process and serial port, which means initializing serial port, display and keyboard, and binding the relevant interrupt service routine with IDT (interrupt descriptor table). In tty_init, it first calls rs_init to set the serial port and then calls con_init to set the display. The specific code is as follows:

2.7.1 Set the Serial Port

The two serial port interrupt service programs and IDT are connected, and two serial ports are initialized based on the content of the tty_table data structure, including the following: setting the line control register DLAB bit, setting the send baud rate factor, and setting the DTR and RTS. Finally, IRQ3 and IRQ4 of 8259A are enabled to send the inter- rupt request.

The specific process of binding is shown in the upper part of Figure 2.12.

The specific code is as follows:

//Code path:init/main.c:

void main(void) {

……

tty_init();

……

}

//Code path:kernel/chr_dev/tty_io.c:

void tty_init(void) {

rs_init();

con_init() }

//Code Path:kernel/chr_dev/serial.c:

void rs_init(void) {

set_intr_gate(0x24,rs1_interrupt); //Set interrupt of serial port 1, //referring 2.5

set_intr_gate(0x23,rs2_interrupt); //Set interrupt of serial port 2 init(tty_table[1].read_q.data); //initialize serial port 1 init(tty_table[2].read_q.data); //initialize serial port 2 outb(inb_p(0x21)&0xE7,0x21); //allow IRQ3,IRQ4

}

The function set_intr_gate that hooks the two serial port interrupt service programs with IDT is similar to set_trap_gate introduced before. The difference is that the type of set_trap_gate is 15(1111), but it is 14(1110) for set_intr_gate.

2.7.2 Set the Display

As the system provides information to indicate whether the graphics card is “monochrome or color,” the OS sets the matching information. At the time of Linux 0.11, most graphics devices are monochrome, so we assume that the attribute of the graphics card is mono- chromatic EGA, the graphics memory location is 0xb0000–0xb8000, the index register port is set to 0x3b4, the data port is set to 0x3b5, and the graphics card attribute, EGA, is printed on the screen. Furthermore, initialize the variables used for scrolling screen, including the origin, scr_end, top and bottom.

The effect is shown in Figure 2.13.

2.7.3 Set the Keyboard

How is the keyboard set? First, the OS hooks the interrupt service routine with IDT and then removes the keyboard interrupt mask of 8259A, enabling IRQ1 to send an interrupt signal.

After disabling the keyboard work, the keyboard is enabled to be ready. The function set_

intr_gate() is designed to do so, which is similar with the set_trap_gate() introduced before.

Kernel

Disable interrupt 0x00000

ROM BIOS and VGA

0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

Kernel code area Kernel data area

(IDT)

0 47 255

rs1_interrupt rs2_interrupt

tty_table[1].read_q.data tty_table[2].read_q.dataSend

Motherboard

Serial port1 Serial port2

IRQ3 IRQ4

Hook the serial port service program to IDT

After setting serial port Before setting serial port Kernel code area Kernel data area

(IDT)

0 47 255

rs1_interrupt rs2_interrupt

Figure 2.12 Hanging serial port interrupt service routine.

The execution process is shown in Figure 2.14.

The specific code is as follows:

Kernel

Mem addr Len Name

0x90000 0x90002 0x90004 0x90006 0x90007 0x90008 0x9000A 0x9000B 0x9000C

...

0x90080 0x90090 0x901FC

2 22 1 1 12 1 2 16

Cursor position

Extended memory number Display page

Display mode

Character column number Display memory Display state

Characteristic parameter Cursor position Disk parameter table Disk parameter table Root device number 16

2

Disable interrupt ROM BIOS

and VGA 0x00000

EGAm

“EGAm”

0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

Kernel code area Kernel data area 0xb0000 0xb8000

After display setting Before display setting

Step 2 Step 1

Setting display attribute data

Kernel code area Kernel data area

Figure 2.13 Set the display.

//Code Patvh:kernel/chr_dev/console.c:

……

#define ORIG_X (*(unsigned char *)0x90000)

#define ORIG_Y (*(unsigned char *)0x90001)

#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)

#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)

#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)

#define ORIG_VIDEO_LINES (25)

#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)

#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)

#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)

#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */

#define VIDEO_TYPE_CGA 0x11 /* CGA Display */

#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */

#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */

#define NPAR 16

……

void con_init(void) {

register unsigned char a;

char *display_desc = “????”;

char *display_ptr;

video_num_columns = ORIG_VIDEO_COLS;//see the machine system data video_size_row = video_num_columns * 2;

video_num_lines = ORIG_VIDEO_LINES;

video_page = ORIG_VIDEO_PAGE;//see the machine system data video_erase_char = 0x0720;

if (ORIG_VIDEO_MODE = = 7) /* Is this a monochrome display? */

{

video_mem_start = 0xb0000;

video_port_reg = 0x3b4;

video_port_val = 0x3b5;

if ((ORIG_VIDEO_EGA_BX & 0xff) ! = 0x10)//see the machine system data {

video_type = VIDEO_TYPE_EGAM;

video_mem_end = 0xb8000;

display_desc = “EGAm”;

} else {

video_type = VIDEO_TYPE_MDA;

video_mem_end = 0xb2000;

display_desc = “*MDA”;

} }

else /* If not, it is color. */

{

video_mem_start = 0xb8000;

video_port_reg = 0x3d4;

video_port_val = 0x3d5;

if ((ORIG_VIDEO_EGA_BX & 0xff) ! = 0x10)//see the machine system data {

video_type = VIDEO_TYPE_EGAC;

video_mem_end = 0xbc000;

display_desc = “EGAc”;

} else {

video_type = VIDEO_TYPE_CGA;

video_mem_end = 0xba000;

display_desc = “*CGA”;

} }

/* Let the user known what kind of display driver we are using */

display_ptr = ((char *)video_mem_start) + video_size_row - 8;

while (*display_desc)

Kernel

Disable interrupt ROM BIOS

and VGA

0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF

Kernel code area Kernel data area

(IDT)

0 47 255

Motherboard Step 2

Step 3 Step 1

IRQ1

Hook keyboard interrupt service program to IDT keyboard_interrupt

keyboard_interrupt

After keysettings Before keysettings Kernel code area Kernel data area

(IDT)

0 47 255

Figure 2.14 Set the keyboard.

{

*display_ptr++ = *display_desc++;

display_ptr++;

}

/* Initialize the variables used for scrolling (mostly EGA/VGA) */

origin = video_mem_start;

scr_end = video_mem_start + video_num_lines * video_size_row;

top = 0;

bottom = video_num_lines;

gotoxy(ORIG_X,ORIG_Y);//see the machine system data

set_trap_gate(0x21,&keyboard_interrupt); //set the interrupt of keyboard, //reference Section 2.5

outb_p(inb_p(0x21)&0xfd,0x21);//Cancel the keyboard interrupt mask,

//allow IRQ1

a = inb_p(0x61);

outb_p(a|0x80,0x61); //disable the keyboard outb(a,0x61); //allow the keyboard }

Một phần của tài liệu The art of linux kernel design (Trang 76 - 81)

Tải bản đầy đủ (PDF)

(524 trang)