MmuLibCore.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. /** @file
  2. Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. @par Glossary:
  5. - Pgd or Pgd or PGD - Page Global Directory
  6. - Pud or Pud or PUD - Page Upper Directory
  7. - Pmd or Pmd or PMD - Page Middle Directory
  8. - Pte or pte or PTE - Page Table Entry
  9. - Val or VAL or val - Value
  10. - Dir - Directory
  11. **/
  12. #include <Uefi.h>
  13. #include <Library/BaseMemoryLib.h>
  14. #include <Library/MemoryAllocationLib.h>
  15. #include <Library/BaseLib.h>
  16. #include <Library/DebugLib.h>
  17. #include "Library/Cpu.h"
  18. #include "pte.h"
  19. #include "page.h"
  20. #include "mmu.h"
  21. BOOLEAN mMmuInited = FALSE;
  22. /**
  23. Check to see if mmu successfully initializes.
  24. @param VOID.
  25. @retval TRUE Initialization has been completed.
  26. FALSE Initialization did not complete.
  27. **/
  28. BOOLEAN
  29. MmuIsInit (VOID) {
  30. if ((mMmuInited == TRUE) ||
  31. (PcdGet64 (PcdSwapPageDir) != 0)) {
  32. return TRUE;
  33. }
  34. return FALSE;
  35. }
  36. /**
  37. Iterates through the page directory to initialize it.
  38. @param Dst A pointer to the directory of the page to initialize.
  39. @param Num The number of page directories to initialize.
  40. @param Src A pointer to the data used to initialize the page directory.
  41. @retval VOID.
  42. **/
  43. VOID
  44. PageDirInit (
  45. IN VOID *Dst,
  46. IN UINTN Num,
  47. IN VOID *Src
  48. )
  49. {
  50. UINTN *Ptr;
  51. UINTN *End;
  52. UINTN Entry;
  53. Entry = (UINTN)Src;
  54. Ptr = (UINTN *)Dst;
  55. End = Ptr + Num;
  56. for ( ;Ptr < End; Ptr++) {
  57. *Ptr = Entry;
  58. }
  59. return ;
  60. }
  61. /**
  62. Gets the virtual address corresponding to the page global directory table entry.
  63. @param Address the virtual address for the table entry.
  64. @retval PGD A pointer to get the table item.
  65. **/
  66. PGD *
  67. PgdOffset (
  68. IN UINTN Address
  69. )
  70. {
  71. return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
  72. }
  73. /**
  74. Gets the virtual address corresponding to the page upper directory table entry.
  75. @param Pgd A pointer to a page global directory table entry.
  76. @param Address the virtual address for the table entry.
  77. @retval PUD A pointer to get the table item.
  78. **/
  79. PUD *
  80. PudOffset (
  81. IN PGD *Pgd,
  82. IN UINTN Address
  83. )
  84. {
  85. UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
  86. return (PUD *)PgdVal + PUD_INDEX (Address);
  87. }
  88. /**
  89. Gets the virtual address corresponding to the page middle directory table entry.
  90. @param Pud A pointer to a page upper directory table entry.
  91. @param Address the virtual address for the table entry.
  92. @retval PMD A pointer to get the table item.
  93. **/
  94. PMD *
  95. PmdOffset (
  96. IN PUD *Pud,
  97. IN UINTN Address
  98. )
  99. {
  100. UINTN PudVal = PUD_VAL (*Pud);
  101. return (PMD *)PudVal + PMD_INDEX (Address);
  102. }
  103. /**
  104. Gets the virtual address corresponding to the page table entry.
  105. @param Pmd A pointer to a page middle directory table entry.
  106. @param Address the virtual address for the table entry.
  107. @retval PTE A pointer to get the table item.
  108. **/
  109. PTE *
  110. PteOffset (
  111. IN PMD *Pmd,
  112. IN UINTN Address
  113. )
  114. {
  115. UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
  116. return (PTE *)PmdVal + PTE_INDEX (Address);
  117. }
  118. /**
  119. Sets the value of the page table entry.
  120. @param Pte A pointer to a page table entry.
  121. @param PteVal The value of the page table entry to set.
  122. @retval VOID
  123. **/
  124. VOID
  125. SetPte (
  126. IN PTE *Pte,
  127. IN PTE PteVal
  128. )
  129. {
  130. *Pte = PteVal;
  131. }
  132. /**
  133. Sets the value of the page global directory.
  134. @param Pgd A pointer to a page global directory.
  135. @param Pud The value of the page global directory to set.
  136. @retval VOID
  137. **/
  138. VOID
  139. SetPgd (
  140. IN PGD *Pgd,
  141. IN PUD *Pud
  142. )
  143. {
  144. *Pgd = (PGD) {((UINTN)Pud)};
  145. }
  146. /**
  147. Sets the value of the page upper directory.
  148. @param Pud A pointer to a page upper directory.
  149. @param Pmd The value of the page upper directory to set.
  150. @retval VOID
  151. **/
  152. VOID
  153. SetPud (
  154. IN PUD *Pud,
  155. IN PMD *Pmd
  156. )
  157. {
  158. *Pud = (PUD) {((UINTN)Pmd)};
  159. }
  160. /**
  161. Sets the value of the page middle directory.
  162. @param Pmd A pointer to a page middle directory.
  163. @param Pte The value of the page middle directory to set.
  164. @retval VOID
  165. **/
  166. VOID
  167. SetPmd (
  168. IN PMD *Pmd,
  169. IN PTE *Pte
  170. )
  171. {
  172. *Pmd = (PMD) {((UINTN)Pte)};
  173. }
  174. /**
  175. Free up memory space occupied by page tables.
  176. @param Pte A pointer to the page table.
  177. @retval VOID
  178. **/
  179. VOID
  180. PteFree (
  181. IN PTE *Pte
  182. )
  183. {
  184. FreePages ((VOID *)Pte, 1);
  185. }
  186. /**
  187. Free up memory space occupied by page middle directory.
  188. @param Pmd A pointer to the page middle directory.
  189. @retval VOID
  190. **/
  191. VOID
  192. PmdFree (
  193. IN PMD *Pmd
  194. )
  195. {
  196. FreePages ((VOID *)Pmd, 1);
  197. }
  198. /**
  199. Free up memory space occupied by page upper directory.
  200. @param Pud A pointer to the page upper directory.
  201. @retval VOID
  202. **/
  203. VOID
  204. PudFree (
  205. IN PUD *Pud
  206. )
  207. {
  208. FreePages ((VOID *)Pud, 1);
  209. }
  210. /**
  211. Requests the memory space required for the page upper directory,
  212. initializes it, and places it in the specified page global directory
  213. @param Pgd A pointer to the page global directory.
  214. @retval EFI_SUCCESS Memory request successful.
  215. @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
  216. **/
  217. INTN
  218. PudAlloc (
  219. IN PGD *Pgd
  220. )
  221. {
  222. PUD *Pud = (PUD *) AllocatePages (1);
  223. if (!Pud) {
  224. return EFI_OUT_OF_RESOURCES;
  225. }
  226. PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
  227. if (pgd_none (*Pgd)) {
  228. SetPgd (Pgd, Pud);
  229. } else { /* Another has populated it */
  230. PudFree (Pud);
  231. }
  232. return EFI_SUCCESS;
  233. }
  234. /**
  235. Requests the memory space required for the page middle directory,
  236. initializes it, and places it in the specified page upper directory
  237. @param Pud A pointer to the page upper directory.
  238. @retval EFI_SUCCESS Memory request successful.
  239. @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
  240. **/
  241. EFI_STATUS
  242. PmdAlloc (
  243. IN PUD *Pud
  244. )
  245. {
  246. PMD *Pmd;
  247. Pmd = (PMD *) AllocatePages (1);
  248. if (!Pmd) {
  249. return EFI_OUT_OF_RESOURCES;
  250. }
  251. PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
  252. if (pud_none (*Pud)) {
  253. SetPud (Pud, Pmd);
  254. } else {/* Another has populated it */
  255. PmdFree (Pmd);
  256. }
  257. return EFI_SUCCESS;
  258. }
  259. /**
  260. Requests the memory space required for the page table,
  261. initializes it, and places it in the specified page middle directory
  262. @param Pmd A pointer to the page middle directory.
  263. @retval EFI_SUCCESS Memory request successful.
  264. @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
  265. **/
  266. INTN
  267. PteAlloc (
  268. IN PMD *Pmd
  269. )
  270. {
  271. PTE *Pte;
  272. Pte = (PTE *) AllocatePages (1);
  273. if (!Pte) {
  274. return EFI_OUT_OF_RESOURCES;
  275. }
  276. Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
  277. if (pmd_none (*Pmd)) {
  278. SetPmd (Pmd, Pte);
  279. } else { /* Another has populated it */
  280. PteFree (Pte);
  281. }
  282. return EFI_SUCCESS;
  283. }
  284. /**
  285. Requests the memory space required for the page upper directory,
  286. initializes it, and places it in the specified page global directory,
  287. and get the page upper directory entry corresponding to the virtual address
  288. @param Pgd A pointer to the page global directory.
  289. @retval Gets the page upper directory entry
  290. **/
  291. PUD *
  292. PudAllocGet (
  293. IN PGD *Pgd,
  294. IN UINTN Address
  295. )
  296. {
  297. return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
  298. NULL : PudOffset (Pgd, Address));
  299. }
  300. /**
  301. Requests the memory space required for the page middle directory,
  302. initializes it, and places it in the specified page upper directory,
  303. and get the page middle directory entry corresponding to the virtual address
  304. @param Pud A pointer to the page upper directory.
  305. @retval Gets the page middle directory entry
  306. **/
  307. PMD *
  308. PmdAllocGet (
  309. IN PUD *Pud,
  310. IN UINTN Address
  311. )
  312. {
  313. PMD * ret = (pud_none (*Pud) && PmdAlloc (Pud))?
  314. NULL: PmdOffset (Pud, Address);
  315. DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
  316. Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
  317. return ret;
  318. }
  319. /**
  320. Requests the memory space required for the page table,
  321. initializes it, and places it in the specified page middle directory,
  322. and get the page table entry corresponding to the virtual address
  323. @param Pmd A pointer to the page upper directory.
  324. @retval Gets the page table entry
  325. **/
  326. PTE *
  327. PteAllocGet (
  328. IN PMD *Pmd,
  329. IN UINTN Address
  330. )
  331. {
  332. return (pmd_none (*Pmd) && PteAlloc (Pmd))?
  333. NULL: PteOffset (Pmd, Address);
  334. }
  335. /**
  336. Gets the physical address of the page table entry corresponding to the specified virtual address.
  337. @param Address the corresponding virtual address of the page table entry.
  338. @retval A pointer to the page table entry.
  339. @retval NULL
  340. **/
  341. PTE *
  342. GetPteAddress (
  343. IN UINTN Address
  344. )
  345. {
  346. PGD *Pgd;
  347. PUD *Pud;
  348. PMD *Pmd;
  349. Pgd = PgdOffset (Address);
  350. if (pgd_none (*Pgd)) {
  351. return NULL;
  352. }
  353. Pud = PudOffset (Pgd, Address);
  354. if (pud_none (*Pud)) {
  355. return NULL;
  356. }
  357. Pmd = PmdOffset (Pud, Address);
  358. if (pmd_none (*Pmd)) {
  359. return NULL;
  360. }
  361. if (IS_HUGE_PAGE (Pmd->PmdVal)) {
  362. return ((PTE *)Pmd);
  363. }
  364. return PteOffset (Pmd, Address);
  365. }
  366. /**
  367. Gets the Attributes of Huge Page.
  368. @param Pmd A pointer to the page middle directory.
  369. @retval Value of Attributes.
  370. **/
  371. UINTN
  372. GetHugePageAttributes (
  373. IN PMD *Pmd
  374. )
  375. {
  376. UINTN Attributes;
  377. UINTN GlobalFlag;
  378. UINTN HugeVal = PMD_VAL(*Pmd);
  379. Attributes = HugeVal & (~HUGEP_PAGE_MASK);
  380. GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT;
  381. Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT);
  382. Attributes |= GlobalFlag;
  383. return Attributes;
  384. }
  385. /**
  386. Establishes a page table entry based on the specified memory region.
  387. @param Pmd A pointer to the page middle directory.
  388. @param Address The memory space start address.
  389. @param End The end address of the memory space.
  390. @param Attributes Memory space Attributes.
  391. @retval EFI_SUCCESS The page table entry was created successfully.
  392. @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed due to resource exhaustion.
  393. **/
  394. EFI_STATUS
  395. MemoryMapPteRange (
  396. IN PMD *Pmd,
  397. IN UINTN Address,
  398. IN UINTN End,
  399. IN UINTN Attributes
  400. )
  401. {
  402. PTE *Pte;
  403. PTE PteVal;
  404. BOOLEAN UpDate;
  405. Pte = PteAllocGet (Pmd, Address);
  406. if (!Pte) {
  407. return EFI_OUT_OF_RESOURCES;
  408. }
  409. DEBUG ((DEBUG_VERBOSE,
  410. "%a %d Address %p End %p Attributes %llx\n",
  411. __func__, __LINE__, Address, End, Attributes));
  412. do {
  413. UpDate = FALSE;
  414. PteVal = MAKE_PTE (Address, Attributes);
  415. if ((!pte_none (*Pte)) &&
  416. (PTE_VAL(*Pte) != PTE_VAL(PteVal)))
  417. {
  418. UpDate = TRUE;
  419. }
  420. SetPte (Pte, PteVal);
  421. if (UpDate) {
  422. LoongarchInvalidTlb(Address);
  423. }
  424. } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
  425. return EFI_SUCCESS;
  426. }
  427. /**
  428. Convert Huge Page to Page.
  429. @param Pmd A pointer to the page middle directory.
  430. @param Address The memory space start address.
  431. @param End The end address of the memory space.
  432. @param Attributes Memory space Attributes.
  433. @retval EFI_SUCCESS The page table entry was created successfully.
  434. @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed due to resource exhaustion.
  435. **/
  436. EFI_STATUS
  437. ConvertHugePageToPage (
  438. IN PMD *Pmd,
  439. IN UINTN Address,
  440. IN UINTN End,
  441. IN UINTN Attributes
  442. )
  443. {
  444. UINTN OldAttributes;
  445. UINTN HugePageEnd;
  446. UINTN HugePageStart;
  447. EFI_STATUS Status;
  448. if ((pmd_none (*Pmd)) ||
  449. (!IS_HUGE_PAGE (Pmd->PmdVal)))
  450. {
  451. Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
  452. } else {
  453. OldAttributes = GetHugePageAttributes(Pmd);
  454. SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte));
  455. HugePageStart = Address & PMD_MASK;
  456. HugePageEnd = HugePageStart + HUGE_PAGE_SIZE;
  457. ASSERT (HugePageEnd >= End);
  458. if (Address > HugePageStart) {
  459. Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes);
  460. }
  461. Status |= MemoryMapPteRange (Pmd, Address, End, Attributes);
  462. if (End < HugePageEnd) {
  463. Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes);
  464. }
  465. }
  466. return Status;
  467. }
  468. /**
  469. Establishes a page middle directory based on the specified memory region.
  470. @param Pud A pointer to the page upper directory.
  471. @param Address The memory space start address.
  472. @param End The end address of the memory space.
  473. @param Attributes Memory space Attributes.
  474. @retval EFI_SUCCESS The page middle directory was created successfully.
  475. @retval EFI_OUT_OF_RESOURCES Page middle directory establishment failed due to resource exhaustion.
  476. **/
  477. EFI_STATUS
  478. MemoryMapPmdRange (
  479. IN PUD *Pud,
  480. IN UINTN Address,
  481. IN UINTN End,
  482. IN UINTN Attributes
  483. )
  484. {
  485. PMD *Pmd;
  486. UINTN Next;
  487. Pmd = PmdAllocGet (Pud, Address);
  488. if (!Pmd) {
  489. return EFI_OUT_OF_RESOURCES;
  490. }
  491. do {
  492. Next = PMD_ADDRESS_END (Address, End);
  493. if (((Address & (~PMD_MASK)) == 0) &&
  494. ((Next & (~PMD_MASK)) == 0) &&
  495. (pmd_none (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal)))
  496. {
  497. DEBUG ((DEBUG_VERBOSE,
  498. "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p\n",
  499. __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
  500. MAKE_HUGE_PTE (Address, Attributes)));
  501. SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
  502. } else {
  503. ConvertHugePageToPage (Pmd, Address, Next, Attributes);
  504. }
  505. } while (Pmd++, Address = Next, Address != End);
  506. return 0;
  507. }
  508. /**
  509. Establishes a page upper directory based on the specified memory region.
  510. @param Pgd A pointer to the page global directory.
  511. @param Address The memory space start address.
  512. @param End The end address of the memory space.
  513. @param Attributes Memory space Attributes.
  514. @retval EFI_SUCCESS The page upper directory was created successfully.
  515. @retval EFI_OUT_OF_RESOURCES Page upper directory establishment failed due to resource exhaustion.
  516. **/
  517. EFI_STATUS
  518. MemoryMapPudRange (
  519. IN PGD *Pgd,
  520. IN UINTN Address,
  521. IN UINTN End,
  522. IN UINTN Attributes
  523. )
  524. {
  525. PUD *Pud;
  526. UINTN Next;
  527. Pud = PudAllocGet (Pgd, Address);
  528. if (!Pud) {
  529. return EFI_OUT_OF_RESOURCES;
  530. }
  531. do {
  532. Next = PUD_ADDRESS_END (Address, End);
  533. if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
  534. return EFI_OUT_OF_RESOURCES;
  535. }
  536. } while (Pud++, Address = Next, Address != End);
  537. return EFI_SUCCESS;
  538. }
  539. /**
  540. Establishes a page global directory based on the specified memory region.
  541. @param Start The memory space start address.
  542. @param End The end address of the memory space.
  543. @param Attributes Memory space Attributes.
  544. @retval EFI_SUCCESS The page global directory was created successfully.
  545. @retval EFI_OUT_OF_RESOURCES Page global directory establishment failed due to resource exhaustion.
  546. **/
  547. EFI_STATUS
  548. MemoryMapPageRange (
  549. IN UINTN Start,
  550. IN UINTN End,
  551. IN UINTN Attributes
  552. )
  553. {
  554. PGD *Pgd;
  555. UINTN Next;
  556. UINTN Address = Start;
  557. EFI_STATUS Err;
  558. Pgd = PgdOffset (Address);
  559. do {
  560. Next = PGD_ADDRESS_END (Address, End);
  561. Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
  562. if (Err) {
  563. return Err;
  564. }
  565. } while (Pgd++, Address = Next, Address != End);
  566. return EFI_SUCCESS;
  567. }
  568. /**
  569. Page tables are established from memory-mapped tables.
  570. @param MemoryRegion A pointer to a memory-mapped table entry.
  571. @retval EFI_SUCCESS The page table was created successfully.
  572. @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion.
  573. **/
  574. EFI_STATUS
  575. FillTranslationTable (
  576. IN MEMORY_REGION_DESCRIPTOR *MemoryRegion
  577. )
  578. {
  579. return MemoryMapPageRange (MemoryRegion->VirtualBase,
  580. (MemoryRegion->Length + MemoryRegion->VirtualBase),
  581. MemoryRegion->Attributes);
  582. }
  583. /**
  584. write operation is performed Count times from the first element of Buffer.
  585. Convert EFI Attributes to Loongarch Attributes.
  586. @param[in] EfiAttributes Efi Attributes.
  587. @retval LoongArch Attributes.
  588. **/
  589. UINTN
  590. EfiAttributeToLoongArchAttribute (
  591. IN UINTN EfiAttributes
  592. )
  593. {
  594. UINTN LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | PLV_KERNEL | PAGE_GLOBAL;
  595. switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
  596. case EFI_MEMORY_UC:
  597. LoongArchAttributes |= CACHE_SUC;
  598. break;
  599. case EFI_MEMORY_WC:
  600. case EFI_MEMORY_WT:
  601. case EFI_MEMORY_WB:
  602. LoongArchAttributes |= CACHE_CC;
  603. break;
  604. default :
  605. LoongArchAttributes |= CACHE_CC;
  606. break;
  607. }
  608. // Write protection attributes
  609. if (((EfiAttributes & EFI_MEMORY_RO) != 0) ||
  610. ((EfiAttributes & EFI_MEMORY_WP) != 0))
  611. {
  612. LoongArchAttributes &= ~PAGE_DIRTY;
  613. }
  614. if (EfiAttributes & EFI_MEMORY_RP) {
  615. LoongArchAttributes |= PAGE_NO_READ;
  616. }
  617. //eXecute protection attribute
  618. if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
  619. LoongArchAttributes |= PAGE_NO_EXEC;
  620. }
  621. return LoongArchAttributes;
  622. }
  623. /**
  624. Finds the length and memory properties of the memory region corresponding to the specified base address.
  625. @param[in] BaseAddress To find the base address of the memory region.
  626. @param[in] EndAddress To find the end address of the memory region.
  627. @param[out] RegionLength The length of the memory region found.
  628. @param[out] RegionAttributes Properties of the memory region found.
  629. @retval EFI_SUCCESS The corresponding memory area was successfully found
  630. EFI_NOT_FOUND No memory area found
  631. **/
  632. EFI_STATUS
  633. GetLoongArchMemoryRegion (
  634. IN UINTN BaseAddress,
  635. IN UINTN EndAddress,
  636. OUT UINTN *RegionLength,
  637. OUT UINTN *RegionAttributes
  638. )
  639. {
  640. PTE *Pte;
  641. UINTN Attributes;
  642. UINTN AttributesTmp;
  643. UINTN MaxAddress;
  644. MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
  645. Pte = GetPteAddress (BaseAddress);
  646. if (!MmuIsInit ()) {
  647. return EFI_SUCCESS;
  648. }
  649. if (Pte == NULL) {
  650. return EFI_NOT_FOUND;
  651. }
  652. Attributes = GET_PAGE_ATTRIBUTES (*Pte);
  653. if (IS_HUGE_PAGE (Pte->PteVal)) {
  654. *RegionAttributes = Attributes & (~(PAGE_HUGE));
  655. *RegionLength += HUGE_PAGE_SIZE;
  656. } else {
  657. *RegionLength += EFI_PAGE_SIZE;
  658. *RegionAttributes = Attributes;
  659. }
  660. while (BaseAddress <= MaxAddress) {
  661. Pte = GetPteAddress (BaseAddress);
  662. if (Pte == NULL) {
  663. return EFI_SUCCESS;
  664. }
  665. AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
  666. if (IS_HUGE_PAGE (Pte->PteVal)) {
  667. if (AttributesTmp == Attributes) {
  668. *RegionLength += HUGE_PAGE_SIZE;
  669. }
  670. BaseAddress += HUGE_PAGE_SIZE;
  671. } else {
  672. if (AttributesTmp == Attributes) {
  673. *RegionLength += EFI_PAGE_SIZE;
  674. }
  675. BaseAddress += EFI_PAGE_SIZE;
  676. }
  677. if (BaseAddress > EndAddress) {
  678. break;
  679. }
  680. }
  681. return EFI_SUCCESS;
  682. }
  683. /**
  684. Sets the Attributes of the specified memory region
  685. @param[in] BaseAddress The base address of the memory region to set the Attributes.
  686. @param[in] Length The length of the memory region to set the Attributes.
  687. @param[in] Attributes The Attributes to be set.
  688. @retval EFI_SUCCESS The Attributes was set successfully
  689. **/
  690. EFI_STATUS
  691. LoongArchSetMemoryAttributes (
  692. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  693. IN UINTN Length,
  694. IN UINTN Attributes
  695. )
  696. {
  697. if (!MmuIsInit ()) {
  698. return EFI_SUCCESS;
  699. }
  700. Attributes = EfiAttributeToLoongArchAttribute (Attributes);
  701. DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
  702. MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
  703. DEBUG ((DEBUG_VERBOSE, "%a %d end.\n", __func__, __LINE__));
  704. return EFI_SUCCESS;
  705. }
  706. /**
  707. Sets the non-executable Attributes for the specified memory region
  708. @param[in] BaseAddress The base address of the memory region to set the Attributes.
  709. @param[in] Length The length of the memory region to set the Attributes.
  710. @retval EFI_SUCCESS The Attributes was set successfully
  711. **/
  712. EFI_STATUS
  713. LoongArchSetMemoryRegionNoExec (
  714. IN EFI_PHYSICAL_ADDRESS BaseAddress,
  715. IN UINTN Length
  716. )
  717. {
  718. if (MmuIsInit ()) {
  719. Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
  720. LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
  721. }
  722. return EFI_SUCCESS;
  723. }
  724. /**
  725. Check to see if mmu successfully initializes and saves the result.
  726. @param VOID.
  727. @retval EFI_SUCCESS Initialization succeeded.
  728. **/
  729. EFI_STATUS
  730. MmuInitialize (VOID)
  731. {
  732. if (PcdGet64 (PcdSwapPageDir) != 0) {
  733. mMmuInited = TRUE;
  734. }
  735. return EFI_SUCCESS;
  736. }