Hard Disk Interruption Occurs during the

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

3.3.1 Preparing to Install the Hard Disk File System by Process 1

3.3.1.6 Hard Disk Interruption Occurs during the

After executing repeatedly, the hard drive reads out the data of one sector at some point, resulting in hard disk interruption. After the CPU receives the interrupt instruction, it terminates the program being executed. The position of termination is certainly in the following line instruction: pause(), sys_pause(), schedule(), switch_to (n). This is shown as the first step in Figure 3.30.

//code path:init/main.c:

void main(void) {

……

for(;;) pause();

}

//code path:kernel/sched.h:

#define switch_to(n) {\

struct {long a,b;} __tmp; \

__asm__(“cmpl%%ecx,_current\n\t” \

“je 1f\n\t” \

“movw%%dx,%1\n\t” \

“xchgl%%ecx,_current\n\t” \

“ljmp%0\n\t” \

“cmpl%%ecx,_last_task_used_math\n\t” \

“jne 1f\n\t” \

“clts\n” \

“1:” \

::“m” (*&__tmp.a),“m” (*&__tmp.b), \

“d” (_TSS(n)),“c” ((long) task[n])); \ }

Then, change to execute the disk interrupt service program. The execution code is as follows:

//code path:kernel/system_call.s:

……

_hd_interrupt:

pushl%eax //save the state of CPU

pushl%ecx pushl%edx push%ds push%es push%fs

movl $0x10,%eax mov%ax,%ds mov%ax,%es movl $0x17,%eax mov%ax,%fs movb $0x20,%al outb%al,$0xA0 jmp 1f

Kernel

Enable interrupt

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

Kernel code area Kernel data area

Schedule

switch_to EIP

Disk Process status

Process 0 Process 1

Uninterruptible Interruptible

Current process

Step 1:

execute sys_pause repeatedly

Step 2:

process scheduling processing Current process is still process 0

“je 1f\n\t”\

Reading data continuously from disk

ROM BIOS and VGA

Figure 3.29 The repeatedly executing process of process 0.

Do not forget that the interrupt can automatically push ss, esp, eflags, cs, and eip, and the hard interrupt service program code continues to push register data to save the program interrupt site. Then, execute the reading disk interrupt program of _do_hd. The corresponding code is the line of “call *% edx”; the edx is the address of the reading disk interrupt program read_intr; see the explanation and code comments of the hd_out() function.

1: jmp 1f

1: xorl%edx,%edx xchgl _do_hd,%edx testl%edx,%edx jne 1f

movl $_unexpected_hd_interrupt,%edx 1: outb%al,$0x20

call *%edx

……

Kernel

Enable interrupt ROM BIOS

and VGA

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

Kernel code area Kernel data area

hd_interrupt read_intr

Buffer block

Disk Process status

Process 0 Process 1

Uninterruptible Interruptible

Current process Step 1:

the disk interrupt service function starts to run

Step 2:

load data to the appointed buffer block Reading data continuously from disk

Figure 3.30 The process of executing disk interrupt.

The read_intr() function will copy the data that have already been read into the hard disk cache to the locked buffer block (note: the lock is to stop the operation of the process but does not prevent the operation of the peripherals); then, the data of one sector and 256 words (512 bytes) are read into the buffer block which was applied before. This is shown as the second step in Figure 3.30. The execution code is as follows:

However, the boot block data is 1024 bytes, request requirement is 1024 bytes. Now, half of it has been read, the hard drive will continue to read disk. At the same time, learned that the request corresponding to the buffer block of data is not fully read, the kernel will again binding read_intr() with the hard disk interrupt service routine in order to the next use, then the interrupt service routine return.

Process 1 is still in a suspended state; the pause(), sys_pause(), schedule(), switch_to (0) cycle continues to repeat from the site interrupted by the hard disk, and the hard drive continues to read the disk.

This process is shown in Figure 3.31.

After a period of time, another half data of the hard disk has been read. The hard disk generates an interrupt, and the read disk interrupt service program again responds to the interrupt and enters the read_intr function. It still will determine whether the request corresponding to the buffer data finished reading. The corresponding code is as follows:

//code path:kernel/blk_dev/hd.c:

static void read_intr(void) {

if (win_result()) { bad_rw_intr();

do_hd_request();

return;

}

port_read(HD_DATA,CURRENT->buffer,256);

CURRENT->errors = 0;

CURRENT->buffer + = 512;

CURRENT->sector++;

if (— — CURRENT->nr_sectors) { do_hd = &read_intr;

return;

}

end_request(1);

do_hd_request();

}

//code path:kernel/blk_dev/hd.c:

static void read_intr(void) {

……

if (— — CURRENT->nr_sectors)

……

end_request(1);

……

}

The data that request requires has been read. After confirmation is complete, do not execute the inside content of if and skip to the end_request function to performing, as shown in Figure 3.32.

After entering end_request and the content of the buffer block has been read, it sets the buffer update flag b_uptodate to 1. The execution code is as follows:

//code path:kernel/blk_dev/blk.h:

extern inline void end_request(int uptodate) {

DEVICE_OFF(CURRENT->dev);

if (CURRENT->bh) {

CURRENT->bh->b_uptodate = uptodate; //uptodate is //parameter, its //value is 1 unlock_buffer(CURRENT->bh);

}

if (!uptodate) {

printk(DEVICE_NAME “ I/O error\n\r”);

printk(“dev%04x, block%d\n\r”,CURRENT->dev, CURRENT->bh->b_blocknr);

}

wake_up(&CURRENT->waiting);

wake_up(&wait_for_request);

CURRENT->dev = -1;

CURRENT = CURRENT->next;

}

ROM BIOS and VGA

Kernel

Enable interrupt

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

Kernel code area Kernel data area

Schedule

switch_to EIP

Disk Process status

Process 0 Process 1

Uninterruptible Interruptible

Current process

Step 1:

execute sys_pause continuously

Step 2:

process scheduling processing Current process is still process 0

“je 1f\n\t”\

Reading data continuously from disk

Figure 3.31 Process 0 continued to repeatedly execute.

Then, unlock_buffer() is called to unlock the buffer block. Call the wake_up() func- tion in the unlock_buffer() function, set process 1 to ready state, and operate the request, for example, set its corresponding request to free....

The code is as follows:

//code path:kernel/blk_dev/blk.h:

extern inline void unlock_buffer(struct buffer_head * bh) {

if (!bh->b_lock)

printk(DEVICE_NAME “: free buffer being unlocked\n”);

bh->b_lock = 0;

wake_up(&bh->b_wait);

}

//code path:kernel/sched.c:

void wake_up(struct task_struct **p) {

if (p && *p) {

(**p).state = 0; //set the ready state

*p = NULL;

} }

Kernel

Enable interrupt

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

Kernel code area Kernel data area

read_intr end_request Step 1:

raise disk interrupt again, the disk interrupt service function starts to run

Step 2:

load data to the specific buffer block

ROM BIOS and VGA

Step 3:

unlock buffer block

Disk Process status

Process 0 Process 1

Ready Interruptible

Current process

Figure 3.32 Respond to disk interrupt again and wake up process 1.

After the hard disk interrupt handling ends, which means the end of the loading boot block of hard disk, the computer continues to execute in pause(), sys_pause(), schedule(), and switch_to (0), repeatly, shown as the second step in Figure 3.32.

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

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

(524 trang)