|
|
1.1 root 1: /*
2: * Copyright (c) 1995-1994 The University of Utah and
3: * the Computer Systems Laboratory at the University of Utah (CSL).
4: * All rights reserved.
5: *
6: * Permission to use, copy, modify and distribute this software is hereby
7: * granted provided that (1) source code retains these copyright, permission,
8: * and disclaimer notices, and (2) redistributions including binaries
9: * reproduce the notices in supporting documentation, and (3) all advertising
10: * materials mentioning features or use of this software display the following
11: * acknowledgement: ``This product includes software developed by the
12: * Computer Systems Laboratory at the University of Utah.''
13: *
14: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
15: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
16: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17: *
18: * CSL requests users of this software to return to [email protected] any
19: * improvements that they make and grant CSL redistribution rights.
20: *
21: * Author: Bryan Ford, University of Utah CSL
22: */
23: /*
24: This file rovides a default implementation
25: of real/pmode switching code.
26: Assumes that, as far as it's concerned,
27: low linear address always map to physical addresses.
28: (The low linear mappings can be changed,
29: but must be changed back before switching back to real mode.)
30:
31: Provides:
32: i16_raw_switch_to_pmode()
33: i16_raw_switch_to_real_mode()
34:
35: i16_raw_start()
36: Called in real mode.
37: Initializes the pmode switching system,
38: switches to pmode for the first time,
39: and calls the 32-bit function raw_start().
40:
41: Depends on:
42:
43: paging.h:
44: raw_paging_enable()
45: raw_paging_disable()
46: raw_paging_init()
47:
48: a20.h:
49: i16_enable_a20()
50: i16_disable_a20()
51:
52: real.h:
53: real_cs
54: */
55:
56: #include <mach/boolean.h>
57: #include <mach/machine/code16.h>
58: #include <mach/machine/vm_param.h>
59: #include <mach/machine/proc_reg.h>
60: #include <mach/machine/pio.h>
61: #include <mach/machine/seg.h>
62: #include <mach/machine/eflags.h>
63: #include <mach/machine/pmode.h>
64:
65: #include "config.h"
66: #include "cpu.h"
67: #include "i16.h"
68: #include "vm_param.h"
69: #include "pic.h"
70: #include "debug.h"
71: #include "i16_a20.h"
72: #include "i16_switch.h"
73:
74: int irq_master_base, irq_slave_base;
75:
76: /* Set to true when everything is initialized properly. */
77: static boolean_t inited;
78:
79: /* Saved value of eflags register for real mode. */
80: static unsigned real_eflags;
81:
82:
83:
84: #ifdef ENABLE_PAGING
85: #define RAW_PAGING_ENABLE() raw_paging_enable()
86: #define RAW_PAGING_DISABLE() raw_paging_disable()
87: #define RAW_PAGING_INIT() raw_paging_init()
88: #else
89: #define RAW_PAGING_ENABLE() ((void)0)
90: #define RAW_PAGING_DISABLE() ((void)0)
91: #define RAW_PAGING_INIT() ((void)0)
92: #endif
93:
94:
95: CODE16
96:
97: void i16_raw_switch_to_pmode()
98: {
99: /* No interrupts from now on please. */
100: i16_cli();
101:
102: /* Save the eflags register for switching back later. */
103: real_eflags = get_eflags();
104:
105: /* Enable the A20 address line. */
106: i16_enable_a20();
107:
108: /* Load the GDT.
109: Note that we have to do this each time we enter pmode,
110: not just the first,
111: because other real-mode programs may have switched to pmode
112: and back again in the meantime, trashing the GDT pointer. */
113: {
114: struct pseudo_descriptor pdesc;
115:
116: pdesc.limit = sizeof(cpu[0].tables.gdt)-1;
117: pdesc.linear_base = boot_image_pa
118: + (vm_offset_t)&cpu[0].tables.gdt;
119: i16_set_gdt(&pdesc);
120: }
121:
122: /* Switch into protected mode. */
123: i16_enter_pmode(KERNEL_16_CS);
124:
125: /* Reload all the segment registers from the new GDT. */
126: set_ds(KERNEL_DS);
127: set_es(KERNEL_DS);
128: set_fs(0);
129: set_gs(0);
130: set_ss(KERNEL_DS);
131:
132: i16_do_32bit(
133:
134: if (inited)
135: {
136: /* Turn paging on if necessary. */
137: RAW_PAGING_ENABLE();
138:
139: /* Load the CPU tables into the processor. */
140: cpu_tables_load(&cpu[0]);
141:
142: /* Program the PIC so the interrupt vectors won't
143: conflict with the processor exception vectors. */
144: pic_init(PICM_VECTBASE, PICS_VECTBASE);
145: }
146:
147: /* Make sure our flags register is appropriate. */
148: set_eflags((get_eflags()
149: & ~(EFL_IF | EFL_DF | EFL_NT))
150: | EFL_IOPL_USER);
151: );
152: }
153:
154: void i16_raw_switch_to_real_mode()
155: {
156: /* Make sure interrupts are disabled. */
157: cli();
158:
159: /* Avoid sending DOS bogus coprocessor exceptions.
160: XXX should we save/restore all of CR0? */
161: i16_clts();
162:
163: i16_do_32bit(
164: /* Turn paging off if necessary. */
165: RAW_PAGING_DISABLE();
166:
167: /* Reprogram the PIC back to the settings DOS expects. */
168: pic_init(0x08, 0x70);
169: );
170:
171: /* Make sure all the segment registers are 16-bit.
172: The code segment definitely is already,
173: because we're running 16-bit code. */
174: set_ds(KERNEL_16_DS);
175: set_es(KERNEL_16_DS);
176: set_fs(KERNEL_16_DS);
177: set_gs(KERNEL_16_DS);
178: set_ss(KERNEL_16_DS);
179:
180: /* Switch back to real mode. */
181: i16_leave_pmode(real_cs);
182:
183: /* Load the real-mode segment registers. */
184: set_ds(real_cs);
185: set_es(real_cs);
186: set_fs(real_cs);
187: set_gs(real_cs);
188: set_ss(real_cs);
189:
190: /* Load the real-mode IDT. */
191: {
192: struct pseudo_descriptor pdesc;
193:
194: pdesc.limit = 0xffff;
195: pdesc.linear_base = 0;
196: i16_set_idt(&pdesc);
197: }
198:
199: /* Disable the A20 address line. */
200: i16_disable_a20();
201:
202: /* Restore the eflags register to its original real-mode state.
203: Note that this will leave interrupts disabled
204: since it was saved after the cli() above. */
205: set_eflags(real_eflags);
206: }
207:
208: void i16_raw_start()
209: {
210: /* Make sure we're not already in protected mode. */
211: if (i16_get_msw() & CR0_PE)
212: i16_die("The processor is in an unknown "
213: "protected mode environment.");
214:
215: do_debug(i16_puts("Real mode detected"));
216:
217: /* Minimally initialize the GDT. */
218: i16_gdt_init_temp();
219:
220: /* Switch to protected mode for the first time.
221: This won't load all the processor tables and everything yet,
222: since they're not fully initialized. */
223: i16_raw_switch_to_pmode();
224:
225: /* We can now hop in and out of 32-bit mode at will. */
226: i16_do_32bit(
227:
228: /* Now that we can access all physical memory,
229: collect the memory regions we discovered while in 16-bit mode
230: and add them to our free memory list.
231: We can't do this before now because the free list nodes
232: are stored in the free memory itself,
233: which is probably out of reach of our 16-bit segments. */
234: phys_mem_collect();
235:
236: /* Initialize paging if necessary.
237: Do it before initializing the other processor tables
238: because they might have to be located
239: somewhere in high linear memory. */
240: RAW_PAGING_INIT();
241:
242: /* Initialize the processor tables. */
243: cpu_init(&cpu[0]);
244:
245: /* Initialize the hardware interrupt vectors in the IDT. */
246: irq_master_base = PICM_VECTBASE;
247: irq_slave_base = PICS_VECTBASE;
248: idt_irq_init();
249:
250: inited = TRUE;
251:
252: /* Switch to real mode and back again once more,
253: to make sure everything's loaded properly. */
254: do_16bit(
255: i16_raw_switch_to_real_mode();
256: i16_raw_switch_to_pmode();
257: );
258:
259: raw_start();
260: );
261: }
262:
263: void (*i16_switch_to_real_mode)() = i16_raw_switch_to_real_mode;
264: void (*i16_switch_to_pmode)() = i16_raw_switch_to_pmode;
265:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.