summaryrefslogtreecommitdiff
path: root/doc/www.independent-software.com_operating-system-development-jumping-to-protected-mode.txt
blob: 9098d4473cef2f0bfd1cb6c0ba3bba98ce212233 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
    #[1]Independent Software

   [2][independent-software-logo.svg] [ ]
   [3]About [4]Philosophy [5]Web Development [6]Portfolio [7]Blog

   [8]osdev [9]asm

   OPERATING SYSTEM DEVELOPMENT
   JUMPING TO PROTECTED MODE

   -

   Oct 24, 2013

   In the [10]previous section of this tutorial for writing your own toy
   operating system, we discussed memory and focused on the 21st address
   line (the "A20 line") that must be enabled before we can have access to
   the full 4GB of memory, which is a prerequisite to entering protected
   mode. Now it's time to jump to protected mode.

   In fact, all we've done in the last few articles is prepare for
   entering protected mode. We've set up a global descriptor table (GDT),
   an interrupt descriptor table (IDT) and enabled the A20 line. All that
   remains is actually jumping to protected mode where we'll finally be
   able to execute 32-bit code so we can focus on our kernel.

   This article is part of a series on toy operating system development.

   [11]View the series index
   [INS: :INS]

   In the [12]previous section of this tutorial for writing your own toy
   operating system, we discussed memory and focused on the 21st address
   line (the "A20 line") that must be enabled before we can have access to
   the full 4GB of memory, which is a prerequisite to entering protected
   mode. Now it's time to jump to protected mode.

   In fact, all we've done in the last few articles is prepare for
   entering protected mode. We've set up a global descriptor table (GDT),
   an interrupt descriptor table (IDT) and enabled the A20 line. All that
   remains is actually jumping to protected mode where we'll finally be
   able to execute 32-bit code so we can focus on our kernel.

   This article is part of a series on toy operating system development.

   [13]View the series index

Control registers

   What we've seen so far while rolling our own first-stage and
   second-stage boot loaders, is familiar processor registers: AX, BX, CX,
   DX, segments like CS, DS, ES, SS, the instruction pointer IP and the
   stack pointer SP. The 80386+ processors actually introduce some new
   registers what will become important when we switch to 32-bit
   programming.

   For one thing, existing registers get wider. Where we used to have
   access to AX (16 bits wide), we will soon have access to EAX (32-bits
   wide), as well as EBX, ECX and EDX. We'll gain additional segment
   registers as well (FS and GS). Similarly, the instruction pointer
   becomes EIP (32 bits again) and so on. That's great, and requires no
   great deal of explanation.

   However, we gain other registers as well. The Intel 80386 processor
   comes armed with a set of control registers, and we'll need one of them
   to switch to protected mode so we might as well talk about it now.
   These control registers change or control the behavior of the CPU. This
   includes interrupt control, switching addressing mode, paging and
   coprocessor control. The new registers are called CR0, CR1, CR2, CR3
   and CR4.

   The first control register, CR0, has various control flags that modify
   the basic operation of the processor.
   Bit Name Full name Description
   31 PG Paging If 1, enable paging and use the CR3 register, else disable
   paging
   30 CD Cache disable Globally enables/disable the memory cache
   29 NW Not-write through Globally enables/disable write-back caching
   18 AM Alignment mask Alignment check enabled if AM set, AC flag (in
   EFLAGS register) set, and privilege level is 3
   16 WP Write protect Determines whether the CPU can write to pages
   marked read-only
   5 NE Numeric error Enable internal x87 floating point error reporting
   when set, else enables PC style x87 error detection
   4 ET Extension type On the 386, it allowed to specify whether the
   external math coprocessor was an 80287 or 80387
   3 TS Task switched Allows saving x87 task context upon a task switch
   only after x87 instruction used
   2 EM Emulation If set, no x87 floating point unit present, if clear,
   x87 FPU present
   1 MP Monitor co-processor Controls interaction of WAIT/FWAIT
   instructions with TS flag in CR0
   0 PE Protected mode enable If 1, system is in protected mode, else
   system is in real mode

   Some of these bits will become important for us later on, but for now,
   we're interested in the very first bit: the PE bit. It enables
   protected mode.

Switching to protected mode

   In order to make the switch to protected mode, all we have to do is
   enable the PE-bit in the CR0 register, like so:
.macro mGoProtected
  mov    eax, cr0
  or     eax, 1
  mov    cr0, eax
.endm

Clearing the prefetch queue

   By setting the PE bit in the CR0 register, we have just switched to
   protected mode. This means that all instructions are now in 32-bit
   format. As a result, some of them are encoded differently. Some
   instructions may take up more bytes in their binary form, some others
   maybe less, and other still remain unchanged. At any rate, we can't
   continue executing any more code just yet, because of the prefetch
   queue.

   You see, CPUs are built to be fast. One of the tricks of the trade that
   make CPUs ever faster is to have the CPU load a range of instructions
   from memory to be executed at the same time, rather than just one. This
   is called prefetching. After all, the CPU in the Intel 80386 processor
   can read 4 bytes (32 bits) at the same time from memory, and that might
   well be more than one instruction. For technical reasons, even more
   might be read and decoded before it's actually executed by the CPU.

   The consequence of this is that the CPU may have read some instructions
   from memory when it was still in 16-bits mode, decoded them, and is now
   ready to execute them. They won't work, because the processor is now in
   protected 32-bits mode!

   Luckily, there is trick to make the processor discard the instructions
   it has already prefetched, and that trick is jumping. Whenever the
   processor encounters a jump instruction, any instructions it had read
   past that instructions become worthless and must be discarded.
   Consequently, jumping clears the prefetch queue:
.macro mClearPrefetchQueue
    jmp clear_prefetch_queue:
    nop
    nop
  clear_prefetch_queue:
.endm

   There are some nop instructions after the jump, to make doubly sure
   that the prefetch queue is fully emptied.

Setting up the 80386's registers

   We've talked the talk, now the time has come to walk the walk. Next,
   we'll set up the memory segments that our future kernel code will use.
   This is no longer done by putting in memory addresses, but by
   specifying selector numbers. We'll set all our data segments (ds, es,
   fs and gs) as well as the stack segment (ss) to use selector 2 from the
   global descriptor table, which corresponds to the data segment that we
   had defined in our GDT:
.macro mSetup386Segments
    mov    ax, 0x10      # Byte offset for selector 2
    mov    ds, ax        # (remember, each descriptor is 8 bytes)
    mov    es, ax
    mov    fs, ax
    mov    gs, ax
    mov    ss, ax
    mov    esp, 0x2ffff  # Set stack to grown downwards from 0x30000
.endm

Jumping to the kernel

   Yes! Assuming that our second-stage boot loader had previously loaded
   our kernel image into memory at linear address 0x20000 (using the same
   FAT reading at file reading routines we had already developed for the
   first-stage bootloader), we can now jump to it and start executing it.

   The jump to the kernel must be done with a 32-bit long jump
   instruction. Here we face a small snag. All the code in our
   second-stage boot loader is 16-bit code, because that's the way it's
   compiled. Therefore, we cannot actually specify a 32-bit long jump; it
   will get compiled as a 16-bit jump. To get around this, we'll encode
   the long jump instruction ourselves just like a 32-bit assembler would
   do it.

   Our long jump instruction will jump to linear memory address 0x20000,
   in the first selector of the GDT (our code segment), which has offset
   0x8:
.macro mJumpToKernel
  .byte 0x66
  .byte 0xEA
  .int  0x20000            # offset
  .word 0x0008             # selector word
.endm

   This will transfer control to the kernel code, which we have yet to
   write. If you're feeling adventurous, why not write a small 32-bit
   assembly program that places the value 0x41 at linear address 0xb8000?
   That will show the letter "A" at the top-left corner of the screen and
   can be executed in protected mode (you can't use the BIOS interrupts to
   write to the screen anymore).

   Actually, we'll do that in the next part of this tutorial anyway!

Summary

   Whew! It's been quite a trip, but we have now reached protected mode
   and are ready to write a simple kernel. At least at this point, all of
   the machine's memory and protected mode features will be at our
   disposal.

   In this tutorial, we've wrapped up the final bits necessary to enter
   protected mode:
     * We've enabled the PE-bit in the CR0 register, thus switching to
       protected mode
     * We've cleared the prefetch queue so that no 16-bit instructions
       remained in the CPU which can no longer be executed
     * We've setup the registers for use by the 32-bit kernel program
     * We've executed a long jump to the kernel code

   [14]Continue on to the next part of this guide!
   [INS: :INS]
   Please enable JavaScript to view the [15]comments powered by Disqus.

   [independent-software-logo.svg]
     * 1513 Av. Vladimir Lenine
     * Maputo, Mozambique
     * [16]info@independent-software.com
     * +258 82 304 26 35

Links

     * [17]Web Development
     * [18]Portfolio
     * [19]Operating System Development

Social

     * [20]Facebook
     * [21]Github
     * [22]LinkedIn
     * [23]Twitter
     * [24]Google+
     * [25]Atom feed

References

   Visible links:
   1. http://www.independent-software.com/feed.xml
   2. http://www.independent-software.com/
   3. http://www.independent-software.com/about-independent-software.html
   4. http://www.independent-software.com/philosophy.html
   5. http://www.independent-software.com/web-development.html
   6. http://www.independent-software.com/portfolio.html
   7. http://www.independent-software.com/blog.html
   8. http://www.independent-software.com/category/osdev.html
   9. http://www.independent-software.com/category/asm.html
  10. http://www.independent-software.com/{{%20site.baseurl%20}}{%%20post_url%20/osdev/2013-10-23-operating-system-development-enabling-a20-line%20%}
  11. http://www.independent-software.com/operating-system-development.html
  12. http://www.independent-software.com/operating-system-development-enabling-a20-line.html
  13. http://www.independent-software.com/operating-system-development.html
  14. http://www.independent-software.com/operating-system-development-first-and-second-stage-bootloaders.html
  15. https://disqus.com/?ref_noscript
  16. mailto:info@independent-software.com
  17. http://www.independent-software.com/web-development.html
  18. http://www.independent-software.com/portfolio.html
  19. http://www.independent-software.com/operating-system-development.html
  20. https://www.facebook.com/Independent-Software-295360497495620/
  21. https://github.com/henck
  22. https://www.linkedin.com/company/independent-software-mozambique-
  23. https://twitter.com/IndependentSw
  24. https://google.com/+Independent-software
  25. http://www.independent-software.com/feed.xml

   Hidden links:
  27. http://www.independent-software.com/operating-system-development-jumping-to-protected-mode.html