As we will see a little later on,specific devices require specific routines to be written to use them,so,for example ,a floppy disk device requires us to explicitly turn on and off the motor that spins the disk under the read-and-write head before we can use it,
whereas most hard disk devices have more functionality automated on local chips,but again the bus technologies with which such devices connect to the cpu (e.g. ATA/IDE,SATA,SCSI,USB,etc.) affect how we access them.Thankfully,BIOS can offer a few disk routines that abstract all of these differences for common disk devices.
The specific BIOS routine we are interested in here is accessed by raising interrupt 0x13 after setting the register al to 0x02.This BIOS routine expects us to set up a few other registers with details of which disk device to use , which blocks we wish to read from the disk,and where to store the blocks in memory. The most difficult part of using this routine is that we must specify the first block to be read using a CHS addressing scheme;otherwise,it is just a case of filling in the expected registers,as detailed in next code snippet
GDT
The main differences in 32-bit protected mode are:
Registers are extended to 32 bits,with their full capacity being accessed by prefixing an e to the register name , for example:mov ebx, 0x274fe8fe
For convenience, there are two additional general purpose segment registers, fs and gs
32-bit memory offsets are available , so an offset can reference a whopping 4 GB of memory (0xffffffff)
The CPU supports a more sophisticated --- though slightly more complex --- means of memory segmentation , which offers two big advantages:
----Code in one segment can be prohibited from executing code in a more privilidged segment , so you can protect your kernel code from user applications
----The CPU can implement virtual memory for user processes,such that pages (i.e. fixed-sized chunks)of a process's memory can be swapped transparently between the disk and memory on an as-needed basis.This ensure main memory is used efficiently , in that code or data that is rarely executed needn't hog valuable memory.
Interrupt handling is also more sophisticated.
Understanding the Global Descriptor Table
It is important to understand the main point of this GDT, that is so fundamental to
the operation of protected mode, before we delve into the details. Recall from Section
XXX that the design rationale of segment-based addressing in the classical 16-bit real
mode was to allow the programmer to access (albeit slightly, by today's standards) more
memory than a 16-bit offset would allow. As an example of this, suppose that the
programmer wanted to store the value of ax at the address 0x4fe56. Without segment-based addressing, the best the programmer could do is this:
理解GDT的主要思想非常重要,当我们深入细节时,它是操作系统安全模式的基础。
回想一下,在经典的16位实模式中,基于分段寻址的设计原理是允许程序员访问比16位偏移量所允许的内存更多的内存(尽管以今天的标准来看是很小的)
例如,假设程序员希望将ax的值存储在地址0x4fe56处。没有基于分段的寻址,程序员访问的最大地址为:
mov [0xffff ], ax
which falls way short of the intended address. Whereby, using a segment register, the
task could be achieved as follows:
这与预计要访问的最大地址相差甚远,然而如果使用段地址的方式,这个任务可以这样完成。
mov bx , 0x4000
mov es , bx
mov [es :0 xfe56 ], ax
Although the general idea of segmenting memory and using offsets to reach into those segments has remained the same, the way that it is implented in protected mode has completely changed, primarily to afford more exibility. Once the CPU has been switched into 32-bit protected mode, the process by which it translates logical addresses (i.e. the combination of a segment register and an offset) to physical address is completely different: rather than multiply the value of a segment register by 16 and then add to it the offset, a segment register becomes an index to a particular segment descriptor (SD) in the GDT.
虽然分割内存和使用操作集来访问这些段的一般思想保持不变,但是在受保护模式下执行它的方式已经完全改变,主要是为了提供更多的存在性。一旦转换成32位CPU保护模式,它将逻辑地址转换的过程(即段寄存器和一个偏移量)的结合物理地址是完全不同的: 与将段寄存器的值乘以16然后向其添加偏移量不同,段寄存器将成为GDT中特定段描述符(SD)的索引
在GDT。
A segment descriptor is an 8-byte structure that denes the following properties of a protected-mode segment:
Base address (32 bits), which denes where the segment begins in physical memory
基址(32位),指定在物理内存中的起始位置。
Segment Limit (20 bits), which denes the size of the segment
段限制(20位),定义段的大小。
Various flags, which affect how the CPU interprets the segment, such as the privilige level of code that runs within it or whether it is read- or write-only.
影响CPU如何解释段的各种标志,比如运行的代码的权限,或者标记是只读或写。
Figure 4.2 shows the actual structure of the segment descriptor. Notice how, just to add to the confusion, the structure fragments the base address and segment limit throughout the structure, so, for example, the lower 16 bits of the segment limit are in the first two bytes of the structure but the higher 4-bits are at the start of the seventh byte of the structure. Perhaps this was done as some kind of joke, or more likley it has historic roots or was in uenced by the CPU's hardware design.
图4.2显示了段描述符的实际结构。注意这结构是如何分割基地址与段内地址,低16bit 。也许这是一个玩笑,或者更有可能它有历史根源,或者是CPU的硬件设计造成的。
We will not concern ourselves with details of all of the possible congurations of segment descriptors, a full explanation of which is given in Intel's Developer Manual [?], but we will learn what we have to in order to get our code running in 32-bit protected
mode. The simplest workable conguration of segment registers is described by Intel as the basic at model, whereby two overlapping segments are dened that cover the full 4 GB of addressable memory, one for code and the other for data. The fact that in this model these two segments overlap means that there is no attempt to protect one segment from the other, nor is there any attempt to use the paging features for virtual memory. It pays to keep things simple early on, especially since later we may alter the segment descriptors more easily once we have booted into a higher-level language.
In addition to the code and data segments, the CPU requires that the rst entry in the GDT purposely be an invalid null descriptor (i.e. a structure of 8 zero bytes). The null descriptor is a simple mechanism to catch mistakes where we forget to set a particular segment register before accessing an address, which is easily done if we had some segment registers set to 0x0 and forgot to update them to the appropriate segment descriptors after switching to protected mode. If an addressing attempt is made with the null descriptor, then the CPU will raise an exception, which essentially is an interrupt ---