Loading the Second Part of Code— —Setup

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

1.2 Loading the OS Kernel and Preparing for the Protected Mode

1.2.2 Loading the Second Part of Code— —Setup

Comment

Because of the two side conventions and orientation recognition, Bootsect is “forced”

to load into 0x07C00. Now, it moves itself to 0x90000, which means that the OS starts to arrange memory to meet its own requirements.

After being copied to the new address, Bootsect executes the following:

rep movw

jmpi go,INITSEG

go: mov ax,cs

mov ds,ax

We already know in Figure 1.6 that the original value of CS is 0x07C0; after executing these codes, CS becomes 0x9000 (INITSEG), and IP is the offset from 0x9000 to “go:mov AX,CS 0x9000.” In other words, CS:IP now points to “go:mov AX,CS.” We can learn it clearly from Figure 1.7.

The previous 0x07C00 was built by two side conventions and orientation recognition.

From now on, the OS becomes independent of BIOS, and it can put its own code anywhere.

1. Bootsect memory planning

Now, BIOS has loaded Bootsect into the memory. Then, it loads the second and third sectors into the memory. But first of all, the Bootsect would do some memory planning.

In general, we use a high-level language, such as C, to write programs and run these programs on an OS. We just write the code and do not care about its loca- tion in the memory. It is because the OS and the compiler have done a great deal of ensuring that it works correctly. Since we are now focusing on the OS itself, we have to better understand the memory arrangement to ensure that no matter how the OS runs, there are no collisions between code and code, between data and data, and between code and data. To do so, we would like to discuss the memory plan- ning of the OS.

In the real address mode, the maximum memory is 1 MB. To arrange the mem- ory, Bootsect has the following code first:

SETUPLEN = 4 ! nr of setup-sectors

BOOTSEG = 0x07c0 ! original address of boot-sector INITSEG = 0x9000 ! we move boot here - out of the way SETUPSEG = 0x9020 ! setup starts here

SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).

ENDSEG = SYSSEG + SYSSIZE ! where to stop loading

The code is to set the location of the following variables: the number of setup program sectors (SETUPLEN), the address of the setup (SETUPSEG), the address

ROM BIOS and VGA

0x00000 SETUPSEG=0x9020 0xFFFFF

ENDSEG=SYSSEG+SYSSIZE SYSSEG=0x1000

BOOTSEG=0X07C0 INITSEG=0x9000

ROOT_DEV=0x306

Set the boot file system as the first sector of the second disk

Figure 1.5 Memory arrangement in the real mode.

of Bootsect (BOOTSEG), the new address of Bootsect (INITSEG), the address of the kernel (SYSSEG), the end address of the kernel (SYSEND), and the number of the root file system device (ROOT_DEV). These are shown in Figure 1.5. These addresses are used to make sure that the code and data could be loaded into the cor- rect place. We will find the benefit of memory planning in the following sections.

From now on, we should keep in mind that OS memory planning is very impor- tant. With this concept, let us continue to talk about the execution of Bootsect.

2. Copy the Bootsect

Bootsect copies itself (total 512 B) from 0x07C00 to 0x90000, as shown in Figure 1.6.

The operation code is as follows:

mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax mov cx,#256 sub si,si sub di,di rep

movw

Please note that DS (0x07C0) and SI (0x0000) constitute the source address 0x07C00; ES and DI constitute the target address 0x90000 (see Figure 1.6), and the line mov CX,#256 provides a “word” number (a word is 2 bytes); 256 words is just 512 bytes, which is the byte number of the first sector.

Also, from the code, we can see that the BOOTSEG and INITSEG mentioned in Figure 1.5 start to work. Note that CS points to 0x07C0 now, which is the address of the original Bootsect.

0x00000

ROM BIOS and VGA

copy INITSEG=0x9000 0xFFFFF

go:

0x07C00IP

IP

BOOTSEG=0x07C0

//bootsect program movwjmpi go,INITSEG mov ax,cs mov ds,ax go:

Figure 1.6 Bootsect copies itself.

Comment

Because of the “two side conventions” and “orientation recognition,” Bootsect is

“forced” to load into 0x07C00. Now, it moves itself to 0x90000, which means that the OS starts to arrange memory to meet its own requirements.

After being copied to the new address, Bootsect executes the following:

rep movw

jmpi go,INITSEG go: mov ax,cs

mov ds,ax

We already know in Figure 1.6 that the original value of CS is 0x07C0; after exe- cuting these codes, CS becomes 0x9000 (INITSEG), and IP is the offset from 0x9000 to “go:mov AX,CS 0x9000.” In other words, CS:IP now points to “go:mov AX,CS.” We can learn it clearly from Figure 1.7.

The previous 0x07C00 was built by “two side conventions” and “orientation rec- ognition.” From now on, the OS becomes independent of BIOS, and it can put its own code anywhere.

Comment

jmpi go, INITSEG go: mov ax,cs

These two lines of codes are very tricky. After Bootsect copies itself, the contents in 0x07C00 and 0x90000 are the same. Please note that before “jmpi go, INITSEG,” CS is 0x07C0. After that, CS becomes 0x9000. Then, it executes the next line, “mov ax,cs.” It is a good way to “jump and continue performing the same codes.”

ROM BIOS and VGA

0x00000 INITSEG=0x9000 0xFFFFF

IP

// bootsect program movwjmpi go,INITSEG mov ax,cs mov ds,ax go:

go:

IP

0x90000 CS : IP

BOOTSEG=0x07C0 0x9000:[go]

Figure 1.7 Jump to “go” and continue.

After Bootsect copied itself to a new place, and continued to execute, the segment was changed, and then other segments changed accordingly, including DS, ES, SS, and SP. Let us look into the following lines:

go: mov ax,cs mov ds,ax mov es,ax

! put stack at 0x9ff00.

mov ss,ax

mov sp,#0xFF00 ! arbitrary value >>512

! load the setup-sectors directly after the bootblock.

! Note that ‘es’ is already set up.

The above lines are to set the data segment registers (DS), additional segment registers (ES), and stack base address registers (SS) into the same value as the code segment register (CS) and set SP to point 0xFF00, as shown in Figure 1.8.

Now, let us focus on the register settings that relate to stack operation. SS and SP con- stitute the location of stack data in the memory. Setting the value of these two registers is the foundation of stack operations (e.g., push and pop).

Now, we switch to Bootsect. Before setting SS and SP, there is no stack; after that, the stack is available for operation. It is great significance to set SS and SP, which means that OS could execute more complex instructions then.

Each stack operation has a direction, and the direction of push is depicted in Figure 1.8. Note: that is the direction from high to low address.

Tip:

DS/ES/FS/GS/SS: data segment registers in CPU. SS points to the stack segment, which is managed by the stack mechanism.

SP: stack pointer, points to the current top of the stack segment.

Now, the first operation of Bootsect has arranged the memory and copied itself from 0x07C00 to 0x90000.

0x00000 SETUPSEG=0x9020 Stack (the enlarged direction of the stack)

0xFFFFF ROM BIOS and VGA

0x9FF00 INITSEG=0x9000

SP 0xFF00

DSES

SS CS : IP

0x9000 Figure 1.8 Set the value of the segment register.

3. Load the Setup program into memory

Next, Bootsect will execute the second step, to load the setup program into the memory.

Loading the setup program relies on the INT 0x 13h interrupt vector, which refers to the interrupt service routine in BIOS. Figure 1.9 shows the location of the INT 0x 13h interrupt vector and the entry address of the service routine.

The loading service handler pointed by the INT 0x 19h interrupt vector is executed by BIOS, while the INT 0x 13h interrupt service program is executed by Bootsect, which is part of the OS.

The INT 0x 19h interrupt service routine loads the first sector of the floppy disk to 0x7C00, while INT 0x 13h loads the sector to the specific location of memory.

Actually, it can load the sector to any designated location.

According to this feature of the service routine, it passes the sector and mem- ory position to the service routine when calling INT 0x 13h.

//code path:boot/bootsect.s Load_setup:

Mov dx, #0x0000 Mov cx, #0x0002 Mov bx, #0x0200

Mov ax, #0x0200+SETUPLEN Int 0x13

Jnc load_setup Ok_load_setup:

0x00000 0xFFFFF

ROM BIOS and VGA Interrupt vector table BIOS data area Interrupt service program

0x00000 0x003FF 0x00400 0x004FF 0x0E05B 0x0FFFE

0x13h Interrupt 0x0E6FE

Disk service program Figure 1.9 Call INT 0x 13h interrupt.

We can see from the four mov operators that the system passes parameters to the BIOS interrupt service routine by using several general-purpose registers. This is com- monly used by the assembly program, which differs from C.

After passing the parameters, BIOS executes INT 0x13, to fire 0x13 interrupt and look up the interrupt service routine in the interrupt vector table. Then, it loads setup.s to SETUPSEG. According to Figure 1.5, Bootsect starts from 0x90000 with a size of 512 bytes. Obviously, 0x90200 is next to the end of Bootsect; thus, they combine each other.

Figure 1.10 indicates the locations of sectors, the number of sectors, address, and length, which will be loaded from the floppy disk.

Now, the OS has loaded five sectors from the floppy disk. Setup begins to work after the execution of Bootsect.

The address of SS:PP is 0x9FF00. There is abundant space between 0x90200 and the setup program. The system has enough space to execute any operation (e.g., push) after loading setup. During startup, the data pushed are countable, and we will find out that the OS designer has calculated the space precisely.

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

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

(524 trang)