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 }