PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Cpu/CpuDxe/Cpu.c

https://github.com/SunnyKi/bareBoot
C | 642 lines | 400 code | 38 blank | 204 comment | 33 complexity | fc28ae35d402197edbf816699e755165 MD5 | raw file
  1. /*++
  2. Copyright (c) 2006 - 2009, Intel Corporation
  3. All rights reserved. This program and the accompanying materials
  4. are licensed and made available under the terms and conditions of the BSD License
  5. which accompanies this distribution. The full text of the license may be found at
  6. http://opensource.org/licenses/bsd-license.php
  7. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  9. Module Name:
  10. Cpu.c
  11. Abstract:
  12. --*/
  13. #include "CpuDxe.h"
  14. //
  15. // Global Variables
  16. //
  17. EFI_LEGACY_8259_PROTOCOL *gLegacy8259 = NULL;
  18. THUNK_CONTEXT mThunkContext;
  19. BOOLEAN mInterruptState = FALSE;
  20. UINTN mTimerVector = 0;
  21. volatile EFI_CPU_INTERRUPT_HANDLER mTimerHandler = NULL;
  22. extern UINT32 mExceptionCodeSize;
  23. //
  24. // The Cpu Architectural Protocol that this Driver produces
  25. //
  26. EFI_HANDLE mHandle = NULL;
  27. EFI_CPU_ARCH_PROTOCOL mCpu = {
  28. CpuFlushCpuDataCache, //used in LightMemoryTest
  29. CpuEnableInterrupt, //not-used in LegacyBoot
  30. CpuDisableInterrupt,
  31. CpuGetInterruptState,
  32. CpuInit,
  33. CpuRegisterInterruptHandler, //used in 8254Timer, HPETTimer,
  34. CpuGetTimerValue,
  35. CpuSetMemoryAttributes,
  36. 1, // NumberOfTimers
  37. 4, // DmaBufferAlignment
  38. };
  39. EFI_STATUS
  40. EFIAPI
  41. CpuFlushCpuDataCache (
  42. IN EFI_CPU_ARCH_PROTOCOL *This,
  43. IN EFI_PHYSICAL_ADDRESS Start,
  44. IN UINT64 Length,
  45. IN EFI_CPU_FLUSH_TYPE FlushType
  46. )
  47. /*++
  48. Routine Description:
  49. Flush CPU data cache. If the instruction cache is fully coherent
  50. with all DMA operations then function can just return EFI_SUCCESS.
  51. Arguments:
  52. This - Protocol instance structure
  53. Start - Physical address to start flushing from.
  54. Length - Number of bytes to flush. Round up to chipset
  55. granularity.
  56. FlushType - Specifies the type of flush operation to perform.
  57. Returns:
  58. EFI_SUCCESS - If cache was flushed
  59. EFI_UNSUPPORTED - If flush type is not supported.
  60. EFI_DEVICE_ERROR - If requested range could not be flushed.
  61. --*/
  62. {
  63. if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
  64. AsmWbinvd ();
  65. return EFI_SUCCESS;
  66. } else if (FlushType == EfiCpuFlushTypeInvalidate) {
  67. AsmInvd ();
  68. return EFI_SUCCESS;
  69. } else {
  70. return EFI_UNSUPPORTED;
  71. }
  72. }
  73. EFI_STATUS
  74. EFIAPI
  75. CpuEnableInterrupt (
  76. IN EFI_CPU_ARCH_PROTOCOL *This
  77. )
  78. /*++
  79. Routine Description:
  80. Enables CPU interrupts.
  81. Arguments:
  82. This - Protocol instance structure
  83. Returns:
  84. EFI_SUCCESS - If interrupts were enabled in the CPU
  85. EFI_DEVICE_ERROR - If interrupts could not be enabled on the CPU.
  86. --*/
  87. {
  88. EnableInterrupts ();
  89. mInterruptState = TRUE;
  90. return EFI_SUCCESS;
  91. }
  92. EFI_STATUS
  93. EFIAPI
  94. CpuDisableInterrupt (
  95. IN EFI_CPU_ARCH_PROTOCOL *This
  96. )
  97. /*++
  98. Routine Description:
  99. Disables CPU interrupts.
  100. Arguments:
  101. This - Protocol instance structure
  102. Returns:
  103. EFI_SUCCESS - If interrupts were disabled in the CPU.
  104. EFI_DEVICE_ERROR - If interrupts could not be disabled on the CPU.
  105. --*/
  106. {
  107. DisableInterrupts ();
  108. mInterruptState = FALSE;
  109. return EFI_SUCCESS;
  110. }
  111. EFI_STATUS
  112. EFIAPI
  113. CpuGetInterruptState (
  114. IN EFI_CPU_ARCH_PROTOCOL *This,
  115. OUT BOOLEAN *State
  116. )
  117. /*++
  118. Routine Description:
  119. Return the state of interrupts.
  120. Arguments:
  121. This - Protocol instance structure
  122. State - Pointer to the CPU's current interrupt state
  123. Returns:
  124. EFI_SUCCESS - If interrupts were disabled in the CPU.
  125. EFI_INVALID_PARAMETER - State is NULL.
  126. --*/
  127. {
  128. if (State == NULL) {
  129. return EFI_INVALID_PARAMETER;
  130. }
  131. *State = mInterruptState;
  132. return EFI_SUCCESS;
  133. }
  134. EFI_STATUS
  135. EFIAPI
  136. CpuInit (
  137. IN EFI_CPU_ARCH_PROTOCOL *This,
  138. IN EFI_CPU_INIT_TYPE InitType
  139. )
  140. /*++
  141. Routine Description:
  142. Generates an INIT to the CPU
  143. Arguments:
  144. This - Protocol instance structure
  145. InitType - Type of CPU INIT to perform
  146. Returns:
  147. EFI_SUCCESS - If CPU INIT occurred. This value should never be
  148. seen.
  149. EFI_DEVICE_ERROR - If CPU INIT failed.
  150. EFI_NOT_SUPPORTED - Requested type of CPU INIT not supported.
  151. --*/
  152. {
  153. return EFI_UNSUPPORTED;
  154. }
  155. EFI_STATUS
  156. EFIAPI
  157. CpuRegisterInterruptHandler (
  158. IN EFI_CPU_ARCH_PROTOCOL *This,
  159. IN EFI_EXCEPTION_TYPE InterruptType,
  160. IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
  161. )
  162. /*++
  163. Routine Description:
  164. Registers a function to be called from the CPU interrupt handler.
  165. Arguments:
  166. This - Protocol instance structure
  167. InterruptType - Defines which interrupt to hook. IA-32 valid range
  168. is 0x00 through 0xFF
  169. InterruptHandler - A pointer to a function of type
  170. EFI_CPU_INTERRUPT_HANDLER that is called when a
  171. processor interrupt occurs. A null pointer
  172. is an error condition.
  173. Returns:
  174. EFI_SUCCESS - If handler installed or uninstalled.
  175. EFI_ALREADY_STARTED - InterruptHandler is not NULL, and a handler for
  176. InterruptType was previously installed
  177. EFI_INVALID_PARAMETER - InterruptHandler is NULL, and a handler for
  178. InterruptType was not previously installed.
  179. EFI_UNSUPPORTED - The interrupt specified by InterruptType is not
  180. supported.
  181. --*/
  182. {
  183. if ((InterruptType < 0) || (InterruptType >= INTERRUPT_VECTOR_NUMBER)) {
  184. return EFI_UNSUPPORTED;
  185. }
  186. if ((UINTN)(UINT32)InterruptType != mTimerVector) {
  187. return EFI_UNSUPPORTED;
  188. }
  189. if ((mTimerHandler == NULL) && (InterruptHandler == NULL)) {
  190. return EFI_INVALID_PARAMETER;
  191. } else if ((mTimerHandler != NULL) && (InterruptHandler != NULL)) {
  192. return EFI_ALREADY_STARTED;
  193. }
  194. mTimerHandler = InterruptHandler;
  195. return EFI_SUCCESS;
  196. }
  197. EFI_STATUS
  198. EFIAPI
  199. CpuGetTimerValue (
  200. IN EFI_CPU_ARCH_PROTOCOL *This,
  201. IN UINT32 TimerIndex,
  202. OUT UINT64 *TimerValue,
  203. OUT UINT64 *TimerPeriod OPTIONAL
  204. )
  205. /*++
  206. Routine Description:
  207. Returns a timer value from one of the CPU's internal timers. There is no
  208. inherent time interval between ticks but is a function of the CPU
  209. frequency.
  210. Arguments:
  211. This - Protocol instance structure
  212. TimerIndex - Specifies which CPU timer ie requested
  213. TimerValue - Pointer to the returned timer value
  214. TimerPeriod -
  215. Returns:
  216. EFI_SUCCESS - If the CPU timer count was returned.
  217. EFI_UNSUPPORTED - If the CPU does not have any readable timers
  218. EFI_DEVICE_ERROR - If an error occurred reading the timer.
  219. EFI_INVALID_PARAMETER - TimerIndex is not valid
  220. --*/
  221. {
  222. if (TimerValue == NULL) {
  223. return EFI_INVALID_PARAMETER;
  224. }
  225. if (TimerIndex == 0) {
  226. *TimerValue = AsmReadTsc ();
  227. if (TimerPeriod != NULL) {
  228. //
  229. // BugBug: Hard coded. Don't know how to do this generically
  230. //
  231. *TimerPeriod = 1000000000;
  232. }
  233. return EFI_SUCCESS;
  234. }
  235. return EFI_INVALID_PARAMETER;
  236. }
  237. EFI_STATUS
  238. EFIAPI
  239. CpuSetMemoryAttributes (
  240. IN EFI_CPU_ARCH_PROTOCOL *This,
  241. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  242. IN UINT64 Length,
  243. IN UINT64 Attributes
  244. )
  245. /*++
  246. Routine Description:
  247. Set memory cacheability attributes for given range of memeory
  248. Arguments:
  249. This - Protocol instance structure
  250. BaseAddress - Specifies the start address of the memory range
  251. Length - Specifies the length of the memory range
  252. Attributes - The memory cacheability for the memory range
  253. Returns:
  254. EFI_SUCCESS - If the cacheability of that memory range is set successfully
  255. EFI_UNSUPPORTED - If the desired operation cannot be done
  256. EFI_INVALID_PARAMETER - The input parameter is not correct, such as Length = 0
  257. --*/
  258. {
  259. return EFI_UNSUPPORTED;
  260. }
  261. STATIC
  262. VOID
  263. DumpExceptionDataDebugOut (
  264. IN EFI_EXCEPTION_TYPE InterruptType,
  265. IN EFI_SYSTEM_CONTEXT SystemContext
  266. )
  267. {
  268. UINT32 ErrorCodeFlag;
  269. ErrorCodeFlag = 0x00027d00;
  270. #ifdef MDE_CPU_IA32
  271. DEBUG ((
  272. EFI_D_ERROR,
  273. "!!!! IA32 Exception Type - %08x !!!!\n",
  274. InterruptType
  275. ));
  276. DEBUG ((
  277. EFI_D_ERROR,
  278. "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
  279. SystemContext.SystemContextIa32->Eip,
  280. SystemContext.SystemContextIa32->Cs,
  281. SystemContext.SystemContextIa32->Eflags
  282. ));
  283. if (ErrorCodeFlag & (1 << InterruptType)) {
  284. DEBUG ((
  285. EFI_D_ERROR,
  286. "ExceptionData - %08x\n",
  287. SystemContext.SystemContextIa32->ExceptionData
  288. ));
  289. }
  290. DEBUG ((
  291. EFI_D_ERROR,
  292. "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
  293. SystemContext.SystemContextIa32->Eax,
  294. SystemContext.SystemContextIa32->Ecx,
  295. SystemContext.SystemContextIa32->Edx,
  296. SystemContext.SystemContextIa32->Ebx
  297. ));
  298. DEBUG ((
  299. EFI_D_ERROR,
  300. "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
  301. SystemContext.SystemContextIa32->Esp,
  302. SystemContext.SystemContextIa32->Ebp,
  303. SystemContext.SystemContextIa32->Esi,
  304. SystemContext.SystemContextIa32->Edi
  305. ));
  306. DEBUG ((
  307. EFI_D_ERROR,
  308. "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
  309. SystemContext.SystemContextIa32->Ds,
  310. SystemContext.SystemContextIa32->Es,
  311. SystemContext.SystemContextIa32->Fs,
  312. SystemContext.SystemContextIa32->Gs,
  313. SystemContext.SystemContextIa32->Ss
  314. ));
  315. DEBUG ((
  316. EFI_D_ERROR,
  317. "GDTR - %08x %08x, IDTR - %08x %08x\n",
  318. SystemContext.SystemContextIa32->Gdtr[0],
  319. SystemContext.SystemContextIa32->Gdtr[1],
  320. SystemContext.SystemContextIa32->Idtr[0],
  321. SystemContext.SystemContextIa32->Idtr[1]
  322. ));
  323. DEBUG ((
  324. EFI_D_ERROR,
  325. "LDTR - %08x, TR - %08x\n",
  326. SystemContext.SystemContextIa32->Ldtr,
  327. SystemContext.SystemContextIa32->Tr
  328. ));
  329. DEBUG ((
  330. EFI_D_ERROR,
  331. "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
  332. SystemContext.SystemContextIa32->Cr0,
  333. SystemContext.SystemContextIa32->Cr2,
  334. SystemContext.SystemContextIa32->Cr3,
  335. SystemContext.SystemContextIa32->Cr4
  336. ));
  337. DEBUG ((
  338. EFI_D_ERROR,
  339. "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
  340. SystemContext.SystemContextIa32->Dr0,
  341. SystemContext.SystemContextIa32->Dr1,
  342. SystemContext.SystemContextIa32->Dr2,
  343. SystemContext.SystemContextIa32->Dr3
  344. ));
  345. DEBUG ((
  346. EFI_D_ERROR,
  347. "DR6 - %08x, DR7 - %08x\n",
  348. SystemContext.SystemContextIa32->Dr6,
  349. SystemContext.SystemContextIa32->Dr7
  350. ));
  351. #else
  352. DEBUG ((
  353. EFI_D_ERROR,
  354. "!!!! X64 Exception Type - %016lx !!!!\n",
  355. (UINT64)InterruptType
  356. ));
  357. DEBUG ((
  358. EFI_D_ERROR,
  359. "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
  360. SystemContext.SystemContextX64->Rip,
  361. SystemContext.SystemContextX64->Cs,
  362. SystemContext.SystemContextX64->Rflags
  363. ));
  364. if (ErrorCodeFlag & (1 << InterruptType)) {
  365. DEBUG ((
  366. EFI_D_ERROR,
  367. "ExceptionData - %016lx\n",
  368. SystemContext.SystemContextX64->ExceptionData
  369. ));
  370. }
  371. DEBUG ((
  372. EFI_D_ERROR,
  373. "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
  374. SystemContext.SystemContextX64->Rax,
  375. SystemContext.SystemContextX64->Rcx,
  376. SystemContext.SystemContextX64->Rdx
  377. ));
  378. DEBUG ((
  379. EFI_D_ERROR,
  380. "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
  381. SystemContext.SystemContextX64->Rbx,
  382. SystemContext.SystemContextX64->Rsp,
  383. SystemContext.SystemContextX64->Rbp
  384. ));
  385. DEBUG ((
  386. EFI_D_ERROR,
  387. "RSI - %016lx, RDI - %016lx\n",
  388. SystemContext.SystemContextX64->Rsi,
  389. SystemContext.SystemContextX64->Rdi
  390. ));
  391. DEBUG ((
  392. EFI_D_ERROR,
  393. "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
  394. SystemContext.SystemContextX64->R8,
  395. SystemContext.SystemContextX64->R9,
  396. SystemContext.SystemContextX64->R10
  397. ));
  398. DEBUG ((
  399. EFI_D_ERROR,
  400. "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
  401. SystemContext.SystemContextX64->R11,
  402. SystemContext.SystemContextX64->R12,
  403. SystemContext.SystemContextX64->R13
  404. ));
  405. DEBUG ((
  406. EFI_D_ERROR,
  407. "R14 - %016lx, R15 - %016lx\n",
  408. SystemContext.SystemContextX64->R14,
  409. SystemContext.SystemContextX64->R15
  410. ));
  411. DEBUG ((
  412. EFI_D_ERROR,
  413. "DS - %016lx, ES - %016lx, FS - %016lx\n",
  414. SystemContext.SystemContextX64->Ds,
  415. SystemContext.SystemContextX64->Es,
  416. SystemContext.SystemContextX64->Fs
  417. ));
  418. DEBUG ((
  419. EFI_D_ERROR,
  420. "GS - %016lx, SS - %016lx\n",
  421. SystemContext.SystemContextX64->Gs,
  422. SystemContext.SystemContextX64->Ss
  423. ));
  424. DEBUG ((
  425. EFI_D_ERROR,
  426. "GDTR - %016lx %016lx, LDTR - %016lx\n",
  427. SystemContext.SystemContextX64->Gdtr[0],
  428. SystemContext.SystemContextX64->Gdtr[1],
  429. SystemContext.SystemContextX64->Ldtr
  430. ));
  431. DEBUG ((
  432. EFI_D_ERROR,
  433. "IDTR - %016lx %016lx, TR - %016lx\n",
  434. SystemContext.SystemContextX64->Idtr[0],
  435. SystemContext.SystemContextX64->Idtr[1],
  436. SystemContext.SystemContextX64->Tr
  437. ));
  438. DEBUG ((
  439. EFI_D_ERROR,
  440. "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
  441. SystemContext.SystemContextX64->Cr0,
  442. SystemContext.SystemContextX64->Cr2,
  443. SystemContext.SystemContextX64->Cr3
  444. ));
  445. DEBUG ((
  446. EFI_D_ERROR,
  447. "CR4 - %016lx, CR8 - %016lx\n",
  448. SystemContext.SystemContextX64->Cr4,
  449. SystemContext.SystemContextX64->Cr8
  450. ));
  451. DEBUG ((
  452. EFI_D_ERROR,
  453. "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
  454. SystemContext.SystemContextX64->Dr0,
  455. SystemContext.SystemContextX64->Dr1,
  456. SystemContext.SystemContextX64->Dr2
  457. ));
  458. DEBUG ((
  459. EFI_D_ERROR,
  460. "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
  461. SystemContext.SystemContextX64->Dr3,
  462. SystemContext.SystemContextX64->Dr6,
  463. SystemContext.SystemContextX64->Dr7
  464. ));
  465. #endif
  466. return ;
  467. }
  468. VOID
  469. ExceptionHandler (
  470. IN EFI_EXCEPTION_TYPE InterruptType,
  471. IN EFI_SYSTEM_CONTEXT SystemContext
  472. )
  473. {
  474. DumpExceptionDataDebugOut (InterruptType, SystemContext);
  475. //
  476. // Use this macro to hang so that the compiler does not optimize out
  477. // the following RET instructions. This allows us to return if we
  478. // have a debugger attached.
  479. //
  480. CpuDeadLoop ();
  481. return ;
  482. }
  483. VOID
  484. TimerHandler (
  485. IN EFI_EXCEPTION_TYPE InterruptType,
  486. IN EFI_SYSTEM_CONTEXT SystemContext
  487. )
  488. {
  489. if (mTimerHandler != NULL) {
  490. mTimerHandler (InterruptType, SystemContext);
  491. }
  492. }
  493. EFI_STATUS
  494. EFIAPI
  495. InitializeCpu (
  496. IN EFI_HANDLE ImageHandle,
  497. IN EFI_SYSTEM_TABLE *SystemTable
  498. )
  499. /*++
  500. Routine Description:
  501. Initialize the state information for the CPU Architectural Protocol
  502. Arguments:
  503. ImageHandle of the loaded driver
  504. Pointer to the System Table
  505. Returns:
  506. EFI_SUCCESS - thread can be successfully created
  507. EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
  508. EFI_DEVICE_ERROR - cannot create the thread
  509. --*/
  510. {
  511. EFI_STATUS Status;
  512. EFI_8259_IRQ Irq;
  513. UINT32 InterruptVector;
  514. //
  515. // Find the Legacy8259 protocol.
  516. //
  517. Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &gLegacy8259);
  518. ASSERT_EFI_ERROR (Status);
  519. //
  520. // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver
  521. //
  522. Status = gLegacy8259->GetVector (gLegacy8259, Efi8259Irq0, (UINT8 *) &mTimerVector);
  523. ASSERT_EFI_ERROR (Status);
  524. //
  525. // Reload GDT, IDT
  526. //
  527. InitDescriptor ();
  528. //
  529. // Install Exception Handler (0x00 ~ 0x1F)
  530. //
  531. for (InterruptVector = 0; InterruptVector < 0x20; InterruptVector++) {
  532. InstallInterruptHandler (
  533. InterruptVector,
  534. (VOID (*)(VOID))(UINTN)((UINTN)SystemExceptionHandler + mExceptionCodeSize * InterruptVector)
  535. );
  536. }
  537. //
  538. // Install Timer Handler
  539. //
  540. InstallInterruptHandler (mTimerVector, SystemTimerHandler);
  541. //
  542. // BUGBUG: We add all other interrupt vector
  543. //
  544. for (Irq = Efi8259Irq1; Irq <= Efi8259Irq15; Irq++) {
  545. InterruptVector = 0;
  546. Status = gLegacy8259->GetVector (gLegacy8259, Irq, (UINT8 *) &InterruptVector);
  547. ASSERT_EFI_ERROR (Status);
  548. InstallInterruptHandler (InterruptVector, SystemTimerHandler);
  549. }
  550. //
  551. // Install CPU Architectural Protocol and the thunk protocol
  552. //
  553. mHandle = NULL;
  554. Status = gBS->InstallMultipleProtocolInterfaces (
  555. &mHandle,
  556. &gEfiCpuArchProtocolGuid,
  557. &mCpu,
  558. NULL
  559. );
  560. ASSERT_EFI_ERROR (Status);
  561. return EFI_SUCCESS;
  562. }