utility.cc (5294:7222bdaed33b) utility.cc (5299:e61b9f2a9732)
1/*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *

--- 248 unchanged lines hidden (view full) ---

257}
258
259#endif
260
261#if FULL_SYSTEM
262void startupCPU(ThreadContext *tc, int cpuId)
263{
264 if (cpuId == 0) {
1/*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *

--- 248 unchanged lines hidden (view full) ---

257}
258
259#endif
260
261#if FULL_SYSTEM
262void startupCPU(ThreadContext *tc, int cpuId)
263{
264 if (cpuId == 0) {
265 // This is the boot strap processor (BSP). Initialize it to look like
266 // the boot loader has just turned control over to the 64 bit OS. We
267 // won't actually set up real mode or legacy protected mode descriptor
268 // tables because we aren't executing any code that would require
269 // them. We do, however toggle the control bits in the correct order
270 // while allowing consistency checks and the underlying mechansims
271 // just to be safe.
272
273 const int NumPDTs = 4;
274
275 const Addr PageMapLevel4 = 0x70000;
276 const Addr PageDirPtrTable = 0x71000;
277 const Addr PageDirTable[NumPDTs] =
278 {0x72000, 0x73000, 0x74000, 0x75000};
279 const Addr GDTBase = 0x76000;
280
281 const int PML4Bits = 9;
282 const int PDPTBits = 9;
283 const int PDTBits = 9;
284
285 // Get a port to write the page tables and descriptor tables.
286 FunctionalPort * physPort = tc->getPhysPort();
287
288 /*
289 * Set up the gdt.
290 */
291 // Place holder at selector 0
292 uint64_t nullDescriptor = 0;
293 physPort->writeBlob(GDTBase, (uint8_t *)(&nullDescriptor), 8);
294
295 //64 bit code segment
296 SegDescriptor csDesc = 0;
297 csDesc.type.c = 0; // Not conforming
298 csDesc.dpl = 0; // Privelege level 0
299 csDesc.p = 1; // Present
300 csDesc.l = 1; // 64 bit
301 csDesc.d = 0; // default operand size
302 //Because we're dealing with a pointer and I don't think it's
303 //guaranteed that there isn't anything in a nonvirtual class between
304 //it's beginning in memory and it's actual data, we'll use an
305 //intermediary.
306 uint64_t csDescVal = csDesc;
307 physPort->writeBlob(GDTBase, (uint8_t *)(&csDescVal), 8);
308
309 tc->setMiscReg(MISCREG_TSG_BASE, GDTBase);
310 tc->setMiscReg(MISCREG_TSG_LIMIT, 0xF);
311
312 /*
313 * Identity map the first 4GB of memory. In order to map this region
314 * of memory in long mode, there needs to be one actual page map level
315 * 4 entry which points to one page directory pointer table which
316 * points to 4 different page directory tables which are full of two
317 * megabyte pages. All of the other entries in valid tables are set
318 * to indicate that they don't pertain to anything valid and will
319 * cause a fault if used.
320 */
321
322 // Put valid values in all of the various table entries which indicate
323 // that those entries don't point to further tables or pages. Then
324 // set the values of those entries which are needed.
325
326 // Page Map Level 4
327
328 // read/write, user, not present
329 uint64_t pml4e = X86ISA::htog(0x6);
330 for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) {
331 physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8);
332 }
333 // Point to the only PDPT
334 pml4e = X86ISA::htog(0x7 | PageDirPtrTable);
335 physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8);
336
337 // Page Directory Pointer Table
338
339 // read/write, user, not present
340 uint64_t pdpe = X86ISA::htog(0x6);
341 for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) {
342 physPort->writeBlob(PageDirPtrTable + offset,
343 (uint8_t *)(&pdpe), 8);
344 }
345 // Point to the PDTs
346 for (int table = 0; table < NumPDTs; table++) {
347 pdpe = X86ISA::htog(0x7 | PageDirTable[table]);
348 physPort->writeBlob(PageDirPtrTable + table * 8,
349 (uint8_t *)(&pdpe), 8);
350 }
351
352 // Page Directory Tables
353
354 Addr base = 0;
355 const Addr pageSize = 2 << 20;
356 for (int table = 0; table < NumPDTs; table++) {
357 for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) {
358 // read/write, user, present, 4MB
359 uint64_t pdte = X86ISA::htog(0x87 | base);
360 physPort->writeBlob(PageDirTable[table] + offset,
361 (uint8_t *)(&pdte), 8);
362 base += pageSize;
363 }
364 }
365
366 /*
367 * Transition from real mode all the way up to Long mode
368 */
369 CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
370 //Turn off paging.
371 cr0.pg = 0;
372 tc->setMiscReg(MISCREG_CR0, cr0);
373 //Turn on protected mode.
374 cr0.pe = 1;
375 tc->setMiscReg(MISCREG_CR0, cr0);
376
377 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
378 //Turn on pae.
379 cr4.pae = 1;
380 tc->setMiscReg(MISCREG_CR4, cr4);
381
382 //Point to the page tables.
383 tc->setMiscReg(MISCREG_CR3, PageMapLevel4);
384
385 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
386 //Enable long mode.
387 efer.lme = 1;
388 tc->setMiscReg(MISCREG_EFER, efer);
389
390 //Activate long mode.
391 cr0.pg = 1;
392 tc->setMiscReg(MISCREG_CR0, cr0);
393
394 /*
395 * Far jump into 64 bit mode.
396 */
397 // Set the selector
398 tc->setMiscReg(MISCREG_CS, 1);
399 // Manually set up the segment attributes. In the future when there's
400 // other existing functionality to do this, that could be used
401 // instead.
402 SegAttr csAttr = 0;
403 csAttr.writable = 0;
404 csAttr.readable = 1;
405 csAttr.expandDown = 0;
406 csAttr.dpl = 0;
407 csAttr.defaultSize = 0;
408 csAttr.longMode = 1;
409 tc->setMiscReg(MISCREG_CS_ATTR, csAttr);
410
411 tc->setPC(tc->getSystemPtr()->kernelEntry);
412 tc->setNextPC(tc->readPC());
413
414 // We should now be in long mode. Yay!
415
416 tc->activate(0);
417 } else {
418 // This is an application processor (AP). It should be initialized to
419 // look like only the BIOS POST has run on it and put then put it into
420 // a halted state.
421 tc->suspend();
422 }
423}
424
425#else
426
427void startupCPU(ThreadContext *tc, int cpuId)
428{
429 tc->activate(0);
430}
431
432#endif
433
434} //namespace X86_ISA
265 tc->activate(0);
266 } else {
267 // This is an application processor (AP). It should be initialized to
268 // look like only the BIOS POST has run on it and put then put it into
269 // a halted state.
270 tc->suspend();
271 }
272}
273
274#else
275
276void startupCPU(ThreadContext *tc, int cpuId)
277{
278 tc->activate(0);
279}
280
281#endif
282
283} //namespace X86_ISA