prochw.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. prochw.c
  9. Abstract:
  10. This module implements support functionality for hardware that is specific
  11. to the ARM architecture.
  12. Author:
  13. Evan Green 13-Aug-2013
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "../ueficore.h"
  21. #include <minoca/kernel/mm.h>
  22. #include <minoca/kernel/hmod.h>
  23. #include <minoca/kernel/kdebug.h>
  24. #include <minoca/kernel/ksignals.h>
  25. #include <minoca/kernel/arm.h>
  26. //
  27. // ---------------------------------------------------------------- Definitions
  28. //
  29. #define DOUBLE_FAULT_STACK_SIZE 1024
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. //
  34. // Internal assembly routines
  35. //
  36. VOID
  37. EfipInitializeExceptionStacks (
  38. PVOID ExceptionStacksBase,
  39. ULONG ExceptionStackSize
  40. );
  41. VOID
  42. EfipUndefinedInstructionEntry (
  43. VOID
  44. );
  45. VOID
  46. EfipSoftwareInterruptEntry (
  47. VOID
  48. );
  49. VOID
  50. EfipPrefetchAbortEntry (
  51. VOID
  52. );
  53. VOID
  54. EfipDataAbortEntry (
  55. VOID
  56. );
  57. VOID
  58. EfipIrqEntry (
  59. VOID
  60. );
  61. VOID
  62. EfipFiqEntry (
  63. VOID
  64. );
  65. VOID
  66. EfipInvalidateInstructionCache (
  67. VOID
  68. );
  69. VOID
  70. EfipCpuid (
  71. PARM_CPUID Features
  72. );
  73. //
  74. // Internal C routines
  75. //
  76. VOID
  77. EfipInitializeInterrupts (
  78. VOID
  79. );
  80. VOID
  81. EfipDispatchException (
  82. PTRAP_FRAME TrapFrame,
  83. BOOL PrefetchAbort
  84. );
  85. VOID
  86. EfipDispatchUndefinedInstructionException (
  87. PTRAP_FRAME TrapFrame
  88. );
  89. VOID
  90. EfipDoubleFaultHandler (
  91. PTRAP_FRAME TrapFrame
  92. );
  93. //
  94. // ------------------------------------------------------ Data Type Definitions
  95. //
  96. //
  97. // -------------------------------------------------------------------- Globals
  98. //
  99. ULONG EfiExceptionStacks[EXCEPTION_STACK_COUNT * EXCEPTION_STACK_SIZE];
  100. //
  101. // Global containing a partially initialized interrupt table. This table will
  102. // be copied to the real location, either 0 or 0xFFFF0000.
  103. //
  104. extern ARM_INTERRUPT_TABLE EfiArmInterruptTable;
  105. //
  106. // ------------------------------------------------------------------ Functions
  107. //
  108. ULONG
  109. MmPageSize (
  110. VOID
  111. )
  112. /*++
  113. Routine Description:
  114. This routine returns the size of a page of memory.
  115. Arguments:
  116. None.
  117. Return Value:
  118. Returns the size of one page of memory (ie the minimum mapping granularity).
  119. --*/
  120. {
  121. return PAGE_SIZE;
  122. }
  123. VOID
  124. EfipInitializeProcessor (
  125. VOID
  126. )
  127. /*++
  128. Routine Description:
  129. This routine initializes processor-specific structures.
  130. Arguments:
  131. None.
  132. Return Value:
  133. None.
  134. --*/
  135. {
  136. EfipInitializeExceptionStacks(EfiExceptionStacks, EXCEPTION_STACK_SIZE);
  137. EfipInitializeInterrupts();
  138. return;
  139. }
  140. //
  141. // --------------------------------------------------------- Internal Functions
  142. //
  143. VOID
  144. EfipInitializeInterrupts (
  145. VOID
  146. )
  147. /*++
  148. Routine Description:
  149. This routine initializes and enables interrupts.
  150. Arguments:
  151. None.
  152. Return Value:
  153. None.
  154. --*/
  155. {
  156. ARM_CPUID CpuInformation;
  157. ULONG SystemControl;
  158. //
  159. // The interrupt table must be 32-byte aligned to make it into VBAR.
  160. //
  161. ASSERT(((UINTN)&EfiArmInterruptTable & 0x0000001F) == 0);
  162. //
  163. // Initialize the vectors to jump to for each type of interrupt.
  164. //
  165. EfiArmInterruptTable.UndefinedInstructionVector =
  166. EfipUndefinedInstructionEntry;
  167. EfiArmInterruptTable.SoftwareInterruptVector = EfipSoftwareInterruptEntry;
  168. EfiArmInterruptTable.PrefetchAbortVector = EfipPrefetchAbortEntry;
  169. EfiArmInterruptTable.DataAbortVector = EfipDataAbortEntry;
  170. EfiArmInterruptTable.IrqVector = EfipIrqEntry;
  171. EfiArmInterruptTable.FiqVector = EfipFiqEntry;
  172. //
  173. // Get the CPU information to determine if the processor supports security
  174. // extensions. If security extensions are supported, then the interrupt
  175. // table can be remapped to another address using the VBAR register.
  176. //
  177. SystemControl = ArGetSystemControlRegister();
  178. EfipCpuid(&CpuInformation);
  179. if ((CpuInformation.ProcessorFeatures[1] &
  180. CPUID_PROCESSOR1_SECURITY_EXTENSION_MASK) !=
  181. CPUID_PROCESSOR1_SECURITY_EXTENSION_UNSUPPORTED) {
  182. //
  183. // Security extensions are supported, so turn off the high vectors and
  184. // set the address using VBAR.
  185. //
  186. SystemControl &= ~MMU_HIGH_EXCEPTION_VECTORS;
  187. ArSetVectorBaseAddress(&EfiArmInterruptTable);
  188. //
  189. // Security extensions are not supported, so the vectors will have to go
  190. // at 0 or 0xFFFF0000, as VBAR may not work.
  191. //
  192. } else {
  193. //
  194. // In physical mode, copy the exception table over the firmware's,
  195. // whether it be at the low or high address.
  196. //
  197. if ((SystemControl & MMU_HIGH_EXCEPTION_VECTORS) != 0) {
  198. RtlCopyMemory((PVOID)EXCEPTION_VECTOR_ADDRESS,
  199. &EfiArmInterruptTable,
  200. sizeof(ARM_INTERRUPT_TABLE));
  201. } else {
  202. RtlCopyMemory((PVOID)EXCEPTION_VECTOR_LOW_ADDRESS,
  203. &EfiArmInterruptTable,
  204. sizeof(ARM_INTERRUPT_TABLE));
  205. }
  206. }
  207. if ((((UINTN)EfipUndefinedInstructionEntry) & ARM_THUMB_BIT) != 0) {
  208. SystemControl |= MMU_THUMB_EXCEPTIONS;
  209. }
  210. ArSetSystemControlRegister(SystemControl);
  211. return;
  212. }
  213. VOID
  214. EfipDispatchException (
  215. PTRAP_FRAME TrapFrame,
  216. BOOL PrefetchAbort
  217. )
  218. /*++
  219. Routine Description:
  220. This routine receives a generic exception and dispatches it to the correct
  221. handler based on the type of exception and the previous execution mode.
  222. Arguments:
  223. TrapFrame - Supplies a pointer to the state immediately before the
  224. exception.
  225. PrefetchAbort - Supplies a boolean indicating if this is a prefetch abort
  226. or data abort. For non-aborts, this parameter is undefined.
  227. Return Value:
  228. None.
  229. --*/
  230. {
  231. PVOID FaultingAddress;
  232. ULONG FaultStatus;
  233. ASSERT(EfiAreInterruptsEnabled() == FALSE);
  234. //
  235. // The SVC mode stack pointer is wrong because it has the trap frame on it.
  236. // "Add" that off to get the real stack pointer.
  237. //
  238. TrapFrame->SvcSp += sizeof(TRAP_FRAME);
  239. //
  240. // Dispatch the exception according to which mode it came from.
  241. //
  242. switch (TrapFrame->ExceptionCpsr & ARM_MODE_MASK) {
  243. case ARM_MODE_FIQ:
  244. case ARM_MODE_IRQ:
  245. TrapFrame->Pc -= 4;
  246. EfiCoreDispatchInterrupt();
  247. break;
  248. case ARM_MODE_ABORT:
  249. //
  250. // The trap handlers set the overflow flag of the exception-mode PSR for
  251. // prefetch (instruction) aborts. This helps determine which Fault
  252. // Address Register to read.
  253. //
  254. if (PrefetchAbort != FALSE) {
  255. FaultingAddress = ArGetInstructionFaultingAddress();
  256. FaultStatus = ArGetInstructionFaultStatus();
  257. } else {
  258. FaultingAddress = ArGetDataFaultingAddress();
  259. FaultStatus = ArGetDataFaultStatus();
  260. }
  261. //
  262. // Translate the fault status register a bit.
  263. //
  264. RtlDebugPrint(" *** Page Fault: Faulting Address 0x%08x, "
  265. "Instruction 0x%08x",
  266. FaultingAddress,
  267. TrapFrame->Pc);
  268. if (IS_ARM_PAGE_FAULT(FaultStatus)) {
  269. RtlDebugPrint(", Page Not Present");
  270. } else {
  271. RtlDebugPrint(", Protection Violation");
  272. }
  273. if ((FaultStatus & ARM_FAULT_STATUS_WRITE) != 0) {
  274. RtlDebugPrint(", Write ***\n");
  275. } else {
  276. RtlDebugPrint(", Read ***\n");
  277. }
  278. KdDebugExceptionHandler(EXCEPTION_ACCESS_VIOLATION, NULL, TrapFrame);
  279. break;
  280. case ARM_MODE_UNDEF:
  281. KdDebugExceptionHandler(EXCEPTION_UNDEFINED_INSTRUCTION,
  282. NULL,
  283. TrapFrame);
  284. break;
  285. default:
  286. KdDebugExceptionHandler(EXCEPTION_ACCESS_VIOLATION, NULL, TrapFrame);
  287. break;
  288. }
  289. //
  290. // Re-adjust the SVC stack pointer. If it was changed since the first
  291. // adjustment, the routine changing it *must* copy the trap frame over.
  292. //
  293. TrapFrame->SvcSp -= sizeof(TRAP_FRAME);
  294. return;
  295. }
  296. VOID
  297. EfipDispatchUndefinedInstructionException (
  298. PTRAP_FRAME TrapFrame
  299. )
  300. /*++
  301. Routine Description:
  302. This routine is called from the assembly trap handlers to handle the
  303. undefined instruction exception, which is usually an intentional debug
  304. break.
  305. Arguments:
  306. TrapFrame - Supplies a pointer to the state immediately before the
  307. exception.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. PVOID Address;
  313. ULONG Exception;
  314. ULONG Instruction;
  315. PVOID Parameter;
  316. //
  317. // The SVC mode stack pointer is wrong because it has the trap frame on it.
  318. // "Add" that off to get the real stack pointer.
  319. //
  320. TrapFrame->SvcSp += sizeof(TRAP_FRAME);
  321. //
  322. // Since this is an undefined instruction entry and not a data abort,
  323. // the memory at PC must be valid. If this is a debug service
  324. // exception, get parameters.
  325. //
  326. Exception = EXCEPTION_UNDEFINED_INSTRUCTION;
  327. Parameter = NULL;
  328. if ((TrapFrame->Cpsr & PSR_FLAG_THUMB) != 0) {
  329. Address = (PVOID)REMOVE_THUMB_BIT(TrapFrame->Pc) -
  330. THUMB16_INSTRUCTION_LENGTH;
  331. Instruction = *((PUSHORT)Address);
  332. if (Instruction == THUMB_DEBUG_SERVICE_INSTRUCTION) {
  333. Exception = TrapFrame->R0;
  334. Parameter = (PVOID)TrapFrame->R1;
  335. }
  336. } else {
  337. Instruction = *((PULONG)(TrapFrame->Pc - ARM_INSTRUCTION_LENGTH));
  338. if (Instruction == ARM_DEBUG_SERVICE_INSTRUCTION) {
  339. Exception = TrapFrame->R0;
  340. Parameter = (PVOID)TrapFrame->R1;
  341. }
  342. }
  343. //
  344. // Dispatch the exception according to which mode it came from.
  345. //
  346. KdDebugExceptionHandler(Exception, Parameter, TrapFrame);
  347. //
  348. // Re-adjust the SVC stack pointer. If it was changed since the first
  349. // adjustment, the routine changing it *must* copy the trap frame over.
  350. //
  351. TrapFrame->SvcSp -= sizeof(TRAP_FRAME);
  352. return;
  353. }