KMemoryManager.cs 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Common;
  3. using Ryujinx.HLE.HOS.Kernel.Common;
  4. using Ryujinx.HLE.HOS.Kernel.Process;
  5. using System;
  6. using System.Collections.Generic;
  7. namespace Ryujinx.HLE.HOS.Kernel.Memory
  8. {
  9. class KMemoryManager
  10. {
  11. public const int PageSize = 0x1000;
  12. private const int KMemoryBlockSize = 0x40;
  13. //We need 2 blocks for the case where a big block
  14. //needs to be split in 2, plus one block that will be the new one inserted.
  15. private const int MaxBlocksNeededForInsertion = 2;
  16. private LinkedList<KMemoryBlock> _blocks;
  17. private MemoryManager _cpuMemory;
  18. private Horizon _system;
  19. public ulong AddrSpaceStart { get; private set; }
  20. public ulong AddrSpaceEnd { get; private set; }
  21. public ulong CodeRegionStart { get; private set; }
  22. public ulong CodeRegionEnd { get; private set; }
  23. public ulong HeapRegionStart { get; private set; }
  24. public ulong HeapRegionEnd { get; private set; }
  25. private ulong _currentHeapAddr;
  26. public ulong AliasRegionStart { get; private set; }
  27. public ulong AliasRegionEnd { get; private set; }
  28. public ulong StackRegionStart { get; private set; }
  29. public ulong StackRegionEnd { get; private set; }
  30. public ulong TlsIoRegionStart { get; private set; }
  31. public ulong TlsIoRegionEnd { get; private set; }
  32. private ulong _heapCapacity;
  33. public ulong PhysicalMemoryUsage { get; private set; }
  34. private MemoryRegion _memRegion;
  35. private bool _aslrDisabled;
  36. public int AddrSpaceWidth { get; private set; }
  37. private bool _isKernel;
  38. private bool _aslrEnabled;
  39. private KMemoryBlockAllocator _blockAllocator;
  40. private int _contextId;
  41. private MersenneTwister _randomNumberGenerator;
  42. public KMemoryManager(Horizon system, MemoryManager cpuMemory)
  43. {
  44. _system = system;
  45. _cpuMemory = cpuMemory;
  46. _blocks = new LinkedList<KMemoryBlock>();
  47. }
  48. private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
  49. public KernelResult InitializeForProcess(
  50. AddressSpaceType addrSpaceType,
  51. bool aslrEnabled,
  52. bool aslrDisabled,
  53. MemoryRegion memRegion,
  54. ulong address,
  55. ulong size,
  56. KMemoryBlockAllocator blockAllocator)
  57. {
  58. if ((uint)addrSpaceType > (uint)AddressSpaceType.Addr39Bits)
  59. {
  60. throw new ArgumentException(nameof(addrSpaceType));
  61. }
  62. _contextId = _system.ContextIdManager.GetId();
  63. ulong addrSpaceBase = 0;
  64. ulong addrSpaceSize = 1UL << AddrSpaceSizes[(int)addrSpaceType];
  65. KernelResult result = CreateUserAddressSpace(
  66. addrSpaceType,
  67. aslrEnabled,
  68. aslrDisabled,
  69. addrSpaceBase,
  70. addrSpaceSize,
  71. memRegion,
  72. address,
  73. size,
  74. blockAllocator);
  75. if (result != KernelResult.Success)
  76. {
  77. _system.ContextIdManager.PutId(_contextId);
  78. }
  79. return result;
  80. }
  81. private class Region
  82. {
  83. public ulong Start;
  84. public ulong End;
  85. public ulong Size;
  86. public ulong AslrOffset;
  87. }
  88. private KernelResult CreateUserAddressSpace(
  89. AddressSpaceType addrSpaceType,
  90. bool aslrEnabled,
  91. bool aslrDisabled,
  92. ulong addrSpaceStart,
  93. ulong addrSpaceEnd,
  94. MemoryRegion memRegion,
  95. ulong address,
  96. ulong size,
  97. KMemoryBlockAllocator blockAllocator)
  98. {
  99. ulong endAddr = address + size;
  100. Region aliasRegion = new Region();
  101. Region heapRegion = new Region();
  102. Region stackRegion = new Region();
  103. Region tlsIoRegion = new Region();
  104. ulong codeRegionSize;
  105. ulong stackAndTlsIoStart;
  106. ulong stackAndTlsIoEnd;
  107. ulong baseAddress;
  108. switch (addrSpaceType)
  109. {
  110. case AddressSpaceType.Addr32Bits:
  111. aliasRegion.Size = 0x40000000;
  112. heapRegion.Size = 0x40000000;
  113. stackRegion.Size = 0;
  114. tlsIoRegion.Size = 0;
  115. CodeRegionStart = 0x200000;
  116. codeRegionSize = 0x3fe00000;
  117. stackAndTlsIoStart = 0x200000;
  118. stackAndTlsIoEnd = 0x40000000;
  119. baseAddress = 0x200000;
  120. AddrSpaceWidth = 32;
  121. break;
  122. case AddressSpaceType.Addr36Bits:
  123. aliasRegion.Size = 0x180000000;
  124. heapRegion.Size = 0x180000000;
  125. stackRegion.Size = 0;
  126. tlsIoRegion.Size = 0;
  127. CodeRegionStart = 0x8000000;
  128. codeRegionSize = 0x78000000;
  129. stackAndTlsIoStart = 0x8000000;
  130. stackAndTlsIoEnd = 0x80000000;
  131. baseAddress = 0x8000000;
  132. AddrSpaceWidth = 36;
  133. break;
  134. case AddressSpaceType.Addr32BitsNoMap:
  135. aliasRegion.Size = 0;
  136. heapRegion.Size = 0x80000000;
  137. stackRegion.Size = 0;
  138. tlsIoRegion.Size = 0;
  139. CodeRegionStart = 0x200000;
  140. codeRegionSize = 0x3fe00000;
  141. stackAndTlsIoStart = 0x200000;
  142. stackAndTlsIoEnd = 0x40000000;
  143. baseAddress = 0x200000;
  144. AddrSpaceWidth = 32;
  145. break;
  146. case AddressSpaceType.Addr39Bits:
  147. aliasRegion.Size = 0x1000000000;
  148. heapRegion.Size = 0x180000000;
  149. stackRegion.Size = 0x80000000;
  150. tlsIoRegion.Size = 0x1000000000;
  151. CodeRegionStart = BitUtils.AlignDown(address, 0x200000);
  152. codeRegionSize = BitUtils.AlignUp (endAddr, 0x200000) - CodeRegionStart;
  153. stackAndTlsIoStart = 0;
  154. stackAndTlsIoEnd = 0;
  155. baseAddress = 0x8000000;
  156. AddrSpaceWidth = 39;
  157. break;
  158. default: throw new ArgumentException(nameof(addrSpaceType));
  159. }
  160. CodeRegionEnd = CodeRegionStart + codeRegionSize;
  161. ulong mapBaseAddress;
  162. ulong mapAvailableSize;
  163. if (CodeRegionStart - baseAddress >= addrSpaceEnd - CodeRegionEnd)
  164. {
  165. //Has more space before the start of the code region.
  166. mapBaseAddress = baseAddress;
  167. mapAvailableSize = CodeRegionStart - baseAddress;
  168. }
  169. else
  170. {
  171. //Has more space after the end of the code region.
  172. mapBaseAddress = CodeRegionEnd;
  173. mapAvailableSize = addrSpaceEnd - CodeRegionEnd;
  174. }
  175. ulong mapTotalSize = aliasRegion.Size + heapRegion.Size + stackRegion.Size + tlsIoRegion.Size;
  176. ulong aslrMaxOffset = mapAvailableSize - mapTotalSize;
  177. _aslrEnabled = aslrEnabled;
  178. AddrSpaceStart = addrSpaceStart;
  179. AddrSpaceEnd = addrSpaceEnd;
  180. _blockAllocator = blockAllocator;
  181. if (mapAvailableSize < mapTotalSize)
  182. {
  183. return KernelResult.OutOfMemory;
  184. }
  185. if (aslrEnabled)
  186. {
  187. aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
  188. heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
  189. stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
  190. tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
  191. }
  192. //Regions are sorted based on ASLR offset.
  193. //When ASLR is disabled, the order is Map, Heap, NewMap and TlsIo.
  194. aliasRegion.Start = mapBaseAddress + aliasRegion.AslrOffset;
  195. aliasRegion.End = aliasRegion.Start + aliasRegion.Size;
  196. heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
  197. heapRegion.End = heapRegion.Start + heapRegion.Size;
  198. stackRegion.Start = mapBaseAddress + stackRegion.AslrOffset;
  199. stackRegion.End = stackRegion.Start + stackRegion.Size;
  200. tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
  201. tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
  202. SortRegion(heapRegion, aliasRegion);
  203. if (stackRegion.Size != 0)
  204. {
  205. SortRegion(stackRegion, aliasRegion);
  206. SortRegion(stackRegion, heapRegion);
  207. }
  208. else
  209. {
  210. stackRegion.Start = stackAndTlsIoStart;
  211. stackRegion.End = stackAndTlsIoEnd;
  212. }
  213. if (tlsIoRegion.Size != 0)
  214. {
  215. SortRegion(tlsIoRegion, aliasRegion);
  216. SortRegion(tlsIoRegion, heapRegion);
  217. SortRegion(tlsIoRegion, stackRegion);
  218. }
  219. else
  220. {
  221. tlsIoRegion.Start = stackAndTlsIoStart;
  222. tlsIoRegion.End = stackAndTlsIoEnd;
  223. }
  224. AliasRegionStart = aliasRegion.Start;
  225. AliasRegionEnd = aliasRegion.End;
  226. HeapRegionStart = heapRegion.Start;
  227. HeapRegionEnd = heapRegion.End;
  228. StackRegionStart = stackRegion.Start;
  229. StackRegionEnd = stackRegion.End;
  230. TlsIoRegionStart = tlsIoRegion.Start;
  231. TlsIoRegionEnd = tlsIoRegion.End;
  232. _currentHeapAddr = HeapRegionStart;
  233. _heapCapacity = 0;
  234. PhysicalMemoryUsage = 0;
  235. _memRegion = memRegion;
  236. _aslrDisabled = aslrDisabled;
  237. return InitializeBlocks(addrSpaceStart, addrSpaceEnd);
  238. }
  239. private ulong GetRandomValue(ulong min, ulong max)
  240. {
  241. return (ulong)GetRandomValue((long)min, (long)max);
  242. }
  243. private long GetRandomValue(long min, long max)
  244. {
  245. if (_randomNumberGenerator == null)
  246. {
  247. _randomNumberGenerator = new MersenneTwister(0);
  248. }
  249. return _randomNumberGenerator.GenRandomNumber(min, max);
  250. }
  251. private static void SortRegion(Region lhs, Region rhs)
  252. {
  253. if (lhs.AslrOffset < rhs.AslrOffset)
  254. {
  255. rhs.Start += lhs.Size;
  256. rhs.End += lhs.Size;
  257. }
  258. else
  259. {
  260. lhs.Start += rhs.Size;
  261. lhs.End += rhs.Size;
  262. }
  263. }
  264. private KernelResult InitializeBlocks(ulong addrSpaceStart, ulong addrSpaceEnd)
  265. {
  266. //First insertion will always need only a single block,
  267. //because there's nothing else to split.
  268. if (!_blockAllocator.CanAllocate(1))
  269. {
  270. return KernelResult.OutOfResource;
  271. }
  272. ulong addrSpacePagesCount = (addrSpaceEnd - addrSpaceStart) / PageSize;
  273. InsertBlock(addrSpaceStart, addrSpacePagesCount, MemoryState.Unmapped);
  274. return KernelResult.Success;
  275. }
  276. public KernelResult MapPages(
  277. ulong address,
  278. KPageList pageList,
  279. MemoryState state,
  280. MemoryPermission permission)
  281. {
  282. ulong pagesCount = pageList.GetPagesCount();
  283. ulong size = pagesCount * PageSize;
  284. if (!ValidateRegionForState(address, size, state))
  285. {
  286. return KernelResult.InvalidMemState;
  287. }
  288. lock (_blocks)
  289. {
  290. if (!IsUnmapped(address, pagesCount * PageSize))
  291. {
  292. return KernelResult.InvalidMemState;
  293. }
  294. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  295. {
  296. return KernelResult.OutOfResource;
  297. }
  298. KernelResult result = MapPages(address, pageList, permission);
  299. if (result == KernelResult.Success)
  300. {
  301. InsertBlock(address, pagesCount, state, permission);
  302. }
  303. return result;
  304. }
  305. }
  306. public KernelResult UnmapPages(ulong address, KPageList pageList, MemoryState stateExpected)
  307. {
  308. ulong pagesCount = pageList.GetPagesCount();
  309. ulong size = pagesCount * PageSize;
  310. ulong endAddr = address + size;
  311. ulong addrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize;
  312. if (AddrSpaceStart > address)
  313. {
  314. return KernelResult.InvalidMemState;
  315. }
  316. if (addrSpacePagesCount < pagesCount)
  317. {
  318. return KernelResult.InvalidMemState;
  319. }
  320. if (endAddr - 1 > AddrSpaceEnd - 1)
  321. {
  322. return KernelResult.InvalidMemState;
  323. }
  324. lock (_blocks)
  325. {
  326. KPageList currentPageList = new KPageList();
  327. AddVaRangeToPageList(currentPageList, address, pagesCount);
  328. if (!currentPageList.IsEqual(pageList))
  329. {
  330. return KernelResult.InvalidMemRange;
  331. }
  332. if (CheckRange(
  333. address,
  334. size,
  335. MemoryState.Mask,
  336. stateExpected,
  337. MemoryPermission.None,
  338. MemoryPermission.None,
  339. MemoryAttribute.Mask,
  340. MemoryAttribute.None,
  341. MemoryAttribute.IpcAndDeviceMapped,
  342. out MemoryState state,
  343. out _,
  344. out _))
  345. {
  346. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  347. {
  348. return KernelResult.OutOfResource;
  349. }
  350. KernelResult result = MmuUnmap(address, pagesCount);
  351. if (result == KernelResult.Success)
  352. {
  353. InsertBlock(address, pagesCount, MemoryState.Unmapped);
  354. }
  355. return result;
  356. }
  357. else
  358. {
  359. return KernelResult.InvalidMemState;
  360. }
  361. }
  362. }
  363. public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission)
  364. {
  365. //TODO.
  366. return KernelResult.Success;
  367. }
  368. public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
  369. {
  370. //TODO.
  371. return KernelResult.Success;
  372. }
  373. public KernelResult AllocateOrMapPa(
  374. ulong neededPagesCount,
  375. int alignment,
  376. ulong srcPa,
  377. bool map,
  378. ulong regionStart,
  379. ulong regionPagesCount,
  380. MemoryState state,
  381. MemoryPermission permission,
  382. out ulong address)
  383. {
  384. address = 0;
  385. ulong regionSize = regionPagesCount * PageSize;
  386. ulong regionEndAddr = regionStart + regionSize;
  387. if (!ValidateRegionForState(regionStart, regionSize, state))
  388. {
  389. return KernelResult.InvalidMemState;
  390. }
  391. if (regionPagesCount <= neededPagesCount)
  392. {
  393. return KernelResult.OutOfMemory;
  394. }
  395. ulong reservedPagesCount = _isKernel ? 1UL : 4UL;
  396. lock (_blocks)
  397. {
  398. if (_aslrEnabled)
  399. {
  400. ulong totalNeededSize = (reservedPagesCount + neededPagesCount) * PageSize;
  401. ulong remainingPages = regionPagesCount - neededPagesCount;
  402. ulong aslrMaxOffset = ((remainingPages + reservedPagesCount) * PageSize) / (ulong)alignment;
  403. for (int attempt = 0; attempt < 8; attempt++)
  404. {
  405. address = BitUtils.AlignDown(regionStart + GetRandomValue(0, aslrMaxOffset) * (ulong)alignment, alignment);
  406. ulong endAddr = address + totalNeededSize;
  407. KMemoryInfo info = FindBlock(address).GetInfo();
  408. if (info.State != MemoryState.Unmapped)
  409. {
  410. continue;
  411. }
  412. ulong currBaseAddr = info.Address + reservedPagesCount * PageSize;
  413. ulong currEndAddr = info.Address + info.Size;
  414. if (address >= regionStart &&
  415. address >= currBaseAddr &&
  416. endAddr - 1 <= regionEndAddr - 1 &&
  417. endAddr - 1 <= currEndAddr - 1)
  418. {
  419. break;
  420. }
  421. }
  422. if (address == 0)
  423. {
  424. ulong aslrPage = GetRandomValue(0, aslrMaxOffset);
  425. address = FindFirstFit(
  426. regionStart + aslrPage * PageSize,
  427. regionPagesCount - aslrPage,
  428. neededPagesCount,
  429. alignment,
  430. 0,
  431. reservedPagesCount);
  432. }
  433. }
  434. if (address == 0)
  435. {
  436. address = FindFirstFit(
  437. regionStart,
  438. regionPagesCount,
  439. neededPagesCount,
  440. alignment,
  441. 0,
  442. reservedPagesCount);
  443. }
  444. if (address == 0)
  445. {
  446. return KernelResult.OutOfMemory;
  447. }
  448. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  449. {
  450. return KernelResult.OutOfResource;
  451. }
  452. MemoryOperation operation = map
  453. ? MemoryOperation.MapPa
  454. : MemoryOperation.Allocate;
  455. KernelResult result = DoMmuOperation(
  456. address,
  457. neededPagesCount,
  458. srcPa,
  459. map,
  460. permission,
  461. operation);
  462. if (result != KernelResult.Success)
  463. {
  464. return result;
  465. }
  466. InsertBlock(address, neededPagesCount, state, permission);
  467. }
  468. return KernelResult.Success;
  469. }
  470. public KernelResult MapNewProcessCode(
  471. ulong address,
  472. ulong pagesCount,
  473. MemoryState state,
  474. MemoryPermission permission)
  475. {
  476. ulong size = pagesCount * PageSize;
  477. if (!ValidateRegionForState(address, size, state))
  478. {
  479. return KernelResult.InvalidMemState;
  480. }
  481. lock (_blocks)
  482. {
  483. if (!IsUnmapped(address, size))
  484. {
  485. return KernelResult.InvalidMemState;
  486. }
  487. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  488. {
  489. return KernelResult.OutOfResource;
  490. }
  491. KernelResult result = DoMmuOperation(
  492. address,
  493. pagesCount,
  494. 0,
  495. false,
  496. permission,
  497. MemoryOperation.Allocate);
  498. if (result == KernelResult.Success)
  499. {
  500. InsertBlock(address, pagesCount, state, permission);
  501. }
  502. return result;
  503. }
  504. }
  505. public KernelResult MapProcessCodeMemory(ulong dst, ulong src, ulong size)
  506. {
  507. ulong pagesCount = size / PageSize;
  508. lock (_blocks)
  509. {
  510. bool success = CheckRange(
  511. src,
  512. size,
  513. MemoryState.Mask,
  514. MemoryState.Heap,
  515. MemoryPermission.Mask,
  516. MemoryPermission.ReadAndWrite,
  517. MemoryAttribute.Mask,
  518. MemoryAttribute.None,
  519. MemoryAttribute.IpcAndDeviceMapped,
  520. out MemoryState state,
  521. out MemoryPermission permission,
  522. out _);
  523. success &= IsUnmapped(dst, size);
  524. if (success)
  525. {
  526. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
  527. {
  528. return KernelResult.OutOfResource;
  529. }
  530. KPageList pageList = new KPageList();
  531. AddVaRangeToPageList(pageList, src, pagesCount);
  532. KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
  533. if (result != KernelResult.Success)
  534. {
  535. return result;
  536. }
  537. result = MapPages(dst, pageList, MemoryPermission.None);
  538. if (result != KernelResult.Success)
  539. {
  540. MmuChangePermission(src, pagesCount, permission);
  541. return result;
  542. }
  543. InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed);
  544. InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
  545. return KernelResult.Success;
  546. }
  547. else
  548. {
  549. return KernelResult.InvalidMemState;
  550. }
  551. }
  552. }
  553. public KernelResult UnmapProcessCodeMemory(ulong dst, ulong src, ulong size)
  554. {
  555. ulong pagesCount = size / PageSize;
  556. lock (_blocks)
  557. {
  558. bool success = CheckRange(
  559. src,
  560. size,
  561. MemoryState.Mask,
  562. MemoryState.Heap,
  563. MemoryPermission.None,
  564. MemoryPermission.None,
  565. MemoryAttribute.Mask,
  566. MemoryAttribute.Borrowed,
  567. MemoryAttribute.IpcAndDeviceMapped,
  568. out _,
  569. out _,
  570. out _);
  571. success &= CheckRange(
  572. dst,
  573. PageSize,
  574. MemoryState.UnmapProcessCodeMemoryAllowed,
  575. MemoryState.UnmapProcessCodeMemoryAllowed,
  576. MemoryPermission.None,
  577. MemoryPermission.None,
  578. MemoryAttribute.Mask,
  579. MemoryAttribute.None,
  580. MemoryAttribute.IpcAndDeviceMapped,
  581. out MemoryState state,
  582. out _,
  583. out _);
  584. success &= CheckRange(
  585. dst,
  586. size,
  587. MemoryState.Mask,
  588. state,
  589. MemoryPermission.None,
  590. MemoryPermission.None,
  591. MemoryAttribute.Mask,
  592. MemoryAttribute.None);
  593. if (success)
  594. {
  595. KernelResult result = MmuUnmap(dst, pagesCount);
  596. if (result != KernelResult.Success)
  597. {
  598. return result;
  599. }
  600. //TODO: Missing some checks here.
  601. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
  602. {
  603. return KernelResult.OutOfResource;
  604. }
  605. InsertBlock(dst, pagesCount, MemoryState.Unmapped);
  606. InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
  607. return KernelResult.Success;
  608. }
  609. else
  610. {
  611. return KernelResult.InvalidMemState;
  612. }
  613. }
  614. }
  615. public KernelResult SetHeapSize(ulong size, out ulong address)
  616. {
  617. address = 0;
  618. if (size > HeapRegionEnd - HeapRegionStart)
  619. {
  620. return KernelResult.OutOfMemory;
  621. }
  622. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  623. ulong currentHeapSize = GetHeapSize();
  624. if (currentHeapSize <= size)
  625. {
  626. //Expand.
  627. ulong diffSize = size - currentHeapSize;
  628. lock (_blocks)
  629. {
  630. if (currentProcess.ResourceLimit != null && diffSize != 0 &&
  631. !currentProcess.ResourceLimit.Reserve(LimitableResource.Memory, diffSize))
  632. {
  633. return KernelResult.ResLimitExceeded;
  634. }
  635. ulong pagesCount = diffSize / PageSize;
  636. KMemoryRegionManager region = GetMemoryRegionManager();
  637. KernelResult result = region.AllocatePages(pagesCount, _aslrDisabled, out KPageList pageList);
  638. void CleanUpForError()
  639. {
  640. if (pageList != null)
  641. {
  642. region.FreePages(pageList);
  643. }
  644. if (currentProcess.ResourceLimit != null && diffSize != 0)
  645. {
  646. currentProcess.ResourceLimit.Release(LimitableResource.Memory, diffSize);
  647. }
  648. }
  649. if (result != KernelResult.Success)
  650. {
  651. CleanUpForError();
  652. return result;
  653. }
  654. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  655. {
  656. CleanUpForError();
  657. return KernelResult.OutOfResource;
  658. }
  659. if (!IsUnmapped(_currentHeapAddr, diffSize))
  660. {
  661. CleanUpForError();
  662. return KernelResult.InvalidMemState;
  663. }
  664. result = DoMmuOperation(
  665. _currentHeapAddr,
  666. pagesCount,
  667. pageList,
  668. MemoryPermission.ReadAndWrite,
  669. MemoryOperation.MapVa);
  670. if (result != KernelResult.Success)
  671. {
  672. CleanUpForError();
  673. return result;
  674. }
  675. InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
  676. }
  677. }
  678. else
  679. {
  680. //Shrink.
  681. ulong freeAddr = HeapRegionStart + size;
  682. ulong diffSize = currentHeapSize - size;
  683. lock (_blocks)
  684. {
  685. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  686. {
  687. return KernelResult.OutOfResource;
  688. }
  689. if (!CheckRange(
  690. freeAddr,
  691. diffSize,
  692. MemoryState.Mask,
  693. MemoryState.Heap,
  694. MemoryPermission.Mask,
  695. MemoryPermission.ReadAndWrite,
  696. MemoryAttribute.Mask,
  697. MemoryAttribute.None,
  698. MemoryAttribute.IpcAndDeviceMapped,
  699. out _,
  700. out _,
  701. out _))
  702. {
  703. return KernelResult.InvalidMemState;
  704. }
  705. ulong pagesCount = diffSize / PageSize;
  706. KernelResult result = MmuUnmap(freeAddr, pagesCount);
  707. if (result != KernelResult.Success)
  708. {
  709. return result;
  710. }
  711. currentProcess.ResourceLimit?.Release(LimitableResource.Memory, BitUtils.AlignDown(diffSize, PageSize));
  712. InsertBlock(freeAddr, pagesCount, MemoryState.Unmapped);
  713. }
  714. }
  715. _currentHeapAddr = HeapRegionStart + size;
  716. address = HeapRegionStart;
  717. return KernelResult.Success;
  718. }
  719. public ulong GetTotalHeapSize()
  720. {
  721. lock (_blocks)
  722. {
  723. return GetHeapSize() + PhysicalMemoryUsage;
  724. }
  725. }
  726. private ulong GetHeapSize()
  727. {
  728. return _currentHeapAddr - HeapRegionStart;
  729. }
  730. public KernelResult SetHeapCapacity(ulong capacity)
  731. {
  732. lock (_blocks)
  733. {
  734. _heapCapacity = capacity;
  735. }
  736. return KernelResult.Success;
  737. }
  738. public KernelResult SetMemoryAttribute(
  739. ulong address,
  740. ulong size,
  741. MemoryAttribute attributeMask,
  742. MemoryAttribute attributeValue)
  743. {
  744. lock (_blocks)
  745. {
  746. if (CheckRange(
  747. address,
  748. size,
  749. MemoryState.AttributeChangeAllowed,
  750. MemoryState.AttributeChangeAllowed,
  751. MemoryPermission.None,
  752. MemoryPermission.None,
  753. MemoryAttribute.BorrowedAndIpcMapped,
  754. MemoryAttribute.None,
  755. MemoryAttribute.DeviceMappedAndUncached,
  756. out MemoryState state,
  757. out MemoryPermission permission,
  758. out MemoryAttribute attribute))
  759. {
  760. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  761. {
  762. return KernelResult.OutOfResource;
  763. }
  764. ulong pagesCount = size / PageSize;
  765. attribute &= ~attributeMask;
  766. attribute |= attributeMask & attributeValue;
  767. InsertBlock(address, pagesCount, state, permission, attribute);
  768. return KernelResult.Success;
  769. }
  770. else
  771. {
  772. return KernelResult.InvalidMemState;
  773. }
  774. }
  775. }
  776. public KMemoryInfo QueryMemory(ulong address)
  777. {
  778. if (address >= AddrSpaceStart &&
  779. address < AddrSpaceEnd)
  780. {
  781. lock (_blocks)
  782. {
  783. return FindBlock(address).GetInfo();
  784. }
  785. }
  786. else
  787. {
  788. return new KMemoryInfo(
  789. AddrSpaceEnd,
  790. ~AddrSpaceEnd + 1,
  791. MemoryState.Reserved,
  792. MemoryPermission.None,
  793. MemoryAttribute.None,
  794. 0,
  795. 0);
  796. }
  797. }
  798. public KernelResult Map(ulong dst, ulong src, ulong size)
  799. {
  800. bool success;
  801. lock (_blocks)
  802. {
  803. success = CheckRange(
  804. src,
  805. size,
  806. MemoryState.MapAllowed,
  807. MemoryState.MapAllowed,
  808. MemoryPermission.Mask,
  809. MemoryPermission.ReadAndWrite,
  810. MemoryAttribute.Mask,
  811. MemoryAttribute.None,
  812. MemoryAttribute.IpcAndDeviceMapped,
  813. out MemoryState srcState,
  814. out _,
  815. out _);
  816. success &= IsUnmapped(dst, size);
  817. if (success)
  818. {
  819. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
  820. {
  821. return KernelResult.OutOfResource;
  822. }
  823. ulong pagesCount = size / PageSize;
  824. KPageList pageList = new KPageList();
  825. AddVaRangeToPageList(pageList, src, pagesCount);
  826. KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
  827. if (result != KernelResult.Success)
  828. {
  829. return result;
  830. }
  831. result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite);
  832. if (result != KernelResult.Success)
  833. {
  834. if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success)
  835. {
  836. throw new InvalidOperationException("Unexpected failure reverting memory permission.");
  837. }
  838. return result;
  839. }
  840. InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed);
  841. InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite);
  842. return KernelResult.Success;
  843. }
  844. else
  845. {
  846. return KernelResult.InvalidMemState;
  847. }
  848. }
  849. }
  850. public KernelResult UnmapForKernel(ulong address, ulong pagesCount, MemoryState stateExpected)
  851. {
  852. ulong size = pagesCount * PageSize;
  853. lock (_blocks)
  854. {
  855. if (CheckRange(
  856. address,
  857. size,
  858. MemoryState.Mask,
  859. stateExpected,
  860. MemoryPermission.None,
  861. MemoryPermission.None,
  862. MemoryAttribute.Mask,
  863. MemoryAttribute.None,
  864. MemoryAttribute.IpcAndDeviceMapped,
  865. out _,
  866. out _,
  867. out _))
  868. {
  869. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  870. {
  871. return KernelResult.OutOfResource;
  872. }
  873. KernelResult result = MmuUnmap(address, pagesCount);
  874. if (result == KernelResult.Success)
  875. {
  876. InsertBlock(address, pagesCount, MemoryState.Unmapped);
  877. }
  878. return KernelResult.Success;
  879. }
  880. else
  881. {
  882. return KernelResult.InvalidMemState;
  883. }
  884. }
  885. }
  886. public KernelResult Unmap(ulong dst, ulong src, ulong size)
  887. {
  888. bool success;
  889. lock (_blocks)
  890. {
  891. success = CheckRange(
  892. src,
  893. size,
  894. MemoryState.MapAllowed,
  895. MemoryState.MapAllowed,
  896. MemoryPermission.Mask,
  897. MemoryPermission.None,
  898. MemoryAttribute.Mask,
  899. MemoryAttribute.Borrowed,
  900. MemoryAttribute.IpcAndDeviceMapped,
  901. out MemoryState srcState,
  902. out _,
  903. out _);
  904. success &= CheckRange(
  905. dst,
  906. size,
  907. MemoryState.Mask,
  908. MemoryState.Stack,
  909. MemoryPermission.None,
  910. MemoryPermission.None,
  911. MemoryAttribute.Mask,
  912. MemoryAttribute.None,
  913. MemoryAttribute.IpcAndDeviceMapped,
  914. out _,
  915. out MemoryPermission dstPermission,
  916. out _);
  917. if (success)
  918. {
  919. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion * 2))
  920. {
  921. return KernelResult.OutOfResource;
  922. }
  923. ulong pagesCount = size / PageSize;
  924. KPageList srcPageList = new KPageList();
  925. KPageList dstPageList = new KPageList();
  926. AddVaRangeToPageList(srcPageList, src, pagesCount);
  927. AddVaRangeToPageList(dstPageList, dst, pagesCount);
  928. if (!dstPageList.IsEqual(srcPageList))
  929. {
  930. return KernelResult.InvalidMemRange;
  931. }
  932. KernelResult result = MmuUnmap(dst, pagesCount);
  933. if (result != KernelResult.Success)
  934. {
  935. return result;
  936. }
  937. result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite);
  938. if (result != KernelResult.Success)
  939. {
  940. MapPages(dst, dstPageList, dstPermission);
  941. return result;
  942. }
  943. InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite);
  944. InsertBlock(dst, pagesCount, MemoryState.Unmapped);
  945. return KernelResult.Success;
  946. }
  947. else
  948. {
  949. return KernelResult.InvalidMemState;
  950. }
  951. }
  952. }
  953. public KernelResult ReserveTransferMemory(ulong address, ulong size, MemoryPermission permission)
  954. {
  955. lock (_blocks)
  956. {
  957. if (CheckRange(
  958. address,
  959. size,
  960. MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
  961. MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
  962. MemoryPermission.Mask,
  963. MemoryPermission.ReadAndWrite,
  964. MemoryAttribute.Mask,
  965. MemoryAttribute.None,
  966. MemoryAttribute.IpcAndDeviceMapped,
  967. out MemoryState state,
  968. out _,
  969. out MemoryAttribute attribute))
  970. {
  971. //TODO: Missing checks.
  972. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  973. {
  974. return KernelResult.OutOfResource;
  975. }
  976. ulong pagesCount = size / PageSize;
  977. attribute |= MemoryAttribute.Borrowed;
  978. InsertBlock(address, pagesCount, state, permission, attribute);
  979. return KernelResult.Success;
  980. }
  981. else
  982. {
  983. return KernelResult.InvalidMemState;
  984. }
  985. }
  986. }
  987. public KernelResult ResetTransferMemory(ulong address, ulong size)
  988. {
  989. lock (_blocks)
  990. {
  991. if (CheckRange(
  992. address,
  993. size,
  994. MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
  995. MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
  996. MemoryPermission.None,
  997. MemoryPermission.None,
  998. MemoryAttribute.Mask,
  999. MemoryAttribute.Borrowed,
  1000. MemoryAttribute.IpcAndDeviceMapped,
  1001. out MemoryState state,
  1002. out _,
  1003. out _))
  1004. {
  1005. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  1006. {
  1007. return KernelResult.OutOfResource;
  1008. }
  1009. ulong pagesCount = size / PageSize;
  1010. InsertBlock(address, pagesCount, state, MemoryPermission.ReadAndWrite);
  1011. return KernelResult.Success;
  1012. }
  1013. else
  1014. {
  1015. return KernelResult.InvalidMemState;
  1016. }
  1017. }
  1018. }
  1019. public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
  1020. {
  1021. lock (_blocks)
  1022. {
  1023. if (CheckRange(
  1024. address,
  1025. size,
  1026. MemoryState.ProcessPermissionChangeAllowed,
  1027. MemoryState.ProcessPermissionChangeAllowed,
  1028. MemoryPermission.None,
  1029. MemoryPermission.None,
  1030. MemoryAttribute.Mask,
  1031. MemoryAttribute.None,
  1032. MemoryAttribute.IpcAndDeviceMapped,
  1033. out MemoryState oldState,
  1034. out MemoryPermission oldPermission,
  1035. out _))
  1036. {
  1037. MemoryState newState = oldState;
  1038. //If writing into the code region is allowed, then we need
  1039. //to change it to mutable.
  1040. if ((permission & MemoryPermission.Write) != 0)
  1041. {
  1042. if (oldState == MemoryState.CodeStatic)
  1043. {
  1044. newState = MemoryState.CodeMutable;
  1045. }
  1046. else if (oldState == MemoryState.ModCodeStatic)
  1047. {
  1048. newState = MemoryState.ModCodeMutable;
  1049. }
  1050. else
  1051. {
  1052. throw new InvalidOperationException($"Memory state \"{oldState}\" not valid for this operation.");
  1053. }
  1054. }
  1055. if (newState != oldState || permission != oldPermission)
  1056. {
  1057. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  1058. {
  1059. return KernelResult.OutOfResource;
  1060. }
  1061. ulong pagesCount = size / PageSize;
  1062. MemoryOperation operation = (permission & MemoryPermission.Execute) != 0
  1063. ? MemoryOperation.ChangePermsAndAttributes
  1064. : MemoryOperation.ChangePermRw;
  1065. KernelResult result = DoMmuOperation(address, pagesCount, 0, false, permission, operation);
  1066. if (result != KernelResult.Success)
  1067. {
  1068. return result;
  1069. }
  1070. InsertBlock(address, pagesCount, newState, permission);
  1071. }
  1072. return KernelResult.Success;
  1073. }
  1074. else
  1075. {
  1076. return KernelResult.InvalidMemState;
  1077. }
  1078. }
  1079. }
  1080. public KernelResult MapPhysicalMemory(ulong address, ulong size)
  1081. {
  1082. ulong endAddr = address + size;
  1083. lock (_blocks)
  1084. {
  1085. ulong mappedSize = 0;
  1086. KMemoryInfo info;
  1087. LinkedListNode<KMemoryBlock> node = FindBlockNode(address);
  1088. do
  1089. {
  1090. info = node.Value.GetInfo();
  1091. if (info.State != MemoryState.Unmapped)
  1092. {
  1093. mappedSize += GetSizeInRange(info, address, endAddr);
  1094. }
  1095. node = node.Next;
  1096. }
  1097. while (info.Address + info.Size < endAddr && node != null);
  1098. if (mappedSize == size)
  1099. {
  1100. return KernelResult.Success;
  1101. }
  1102. ulong remainingSize = size - mappedSize;
  1103. ulong remainingPages = remainingSize / PageSize;
  1104. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  1105. if (currentProcess.ResourceLimit != null &&
  1106. !currentProcess.ResourceLimit.Reserve(LimitableResource.Memory, remainingSize))
  1107. {
  1108. return KernelResult.ResLimitExceeded;
  1109. }
  1110. KMemoryRegionManager region = GetMemoryRegionManager();
  1111. KernelResult result = region.AllocatePages(remainingPages, _aslrDisabled, out KPageList pageList);
  1112. void CleanUpForError()
  1113. {
  1114. if (pageList != null)
  1115. {
  1116. region.FreePages(pageList);
  1117. }
  1118. currentProcess.ResourceLimit?.Release(LimitableResource.Memory, remainingSize);
  1119. }
  1120. if (result != KernelResult.Success)
  1121. {
  1122. CleanUpForError();
  1123. return result;
  1124. }
  1125. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  1126. {
  1127. CleanUpForError();
  1128. return KernelResult.OutOfResource;
  1129. }
  1130. MapPhysicalMemory(pageList, address, endAddr);
  1131. PhysicalMemoryUsage += remainingSize;
  1132. ulong pagesCount = size / PageSize;
  1133. InsertBlock(
  1134. address,
  1135. pagesCount,
  1136. MemoryState.Unmapped,
  1137. MemoryPermission.None,
  1138. MemoryAttribute.None,
  1139. MemoryState.Heap,
  1140. MemoryPermission.ReadAndWrite,
  1141. MemoryAttribute.None);
  1142. }
  1143. return KernelResult.Success;
  1144. }
  1145. public KernelResult UnmapPhysicalMemory(ulong address, ulong size)
  1146. {
  1147. ulong endAddr = address + size;
  1148. lock (_blocks)
  1149. {
  1150. //Scan, ensure that the region can be unmapped (all blocks are heap or
  1151. //already unmapped), fill pages list for freeing memory.
  1152. ulong heapMappedSize = 0;
  1153. KPageList pageList = new KPageList();
  1154. KMemoryInfo info;
  1155. LinkedListNode<KMemoryBlock> baseNode = FindBlockNode(address);
  1156. LinkedListNode<KMemoryBlock> node = baseNode;
  1157. do
  1158. {
  1159. info = node.Value.GetInfo();
  1160. if (info.State == MemoryState.Heap)
  1161. {
  1162. if (info.Attribute != MemoryAttribute.None)
  1163. {
  1164. return KernelResult.InvalidMemState;
  1165. }
  1166. ulong blockSize = GetSizeInRange(info, address, endAddr);
  1167. ulong blockAddress = GetAddrInRange(info, address);
  1168. AddVaRangeToPageList(pageList, blockAddress, blockSize / PageSize);
  1169. heapMappedSize += blockSize;
  1170. }
  1171. else if (info.State != MemoryState.Unmapped)
  1172. {
  1173. return KernelResult.InvalidMemState;
  1174. }
  1175. node = node.Next;
  1176. }
  1177. while (info.Address + info.Size < endAddr && node != null);
  1178. if (heapMappedSize == 0)
  1179. {
  1180. return KernelResult.Success;
  1181. }
  1182. if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
  1183. {
  1184. return KernelResult.OutOfResource;
  1185. }
  1186. //Try to unmap all the heap mapped memory inside range.
  1187. KernelResult result = KernelResult.Success;
  1188. node = baseNode;
  1189. do
  1190. {
  1191. info = node.Value.GetInfo();
  1192. if (info.State == MemoryState.Heap)
  1193. {
  1194. ulong blockSize = GetSizeInRange(info, address, endAddr);
  1195. ulong blockAddress = GetAddrInRange(info, address);
  1196. ulong blockPagesCount = blockSize / PageSize;
  1197. result = MmuUnmap(blockAddress, blockPagesCount);
  1198. if (result != KernelResult.Success)
  1199. {
  1200. //If we failed to unmap, we need to remap everything back again.
  1201. MapPhysicalMemory(pageList, address, blockAddress + blockSize);
  1202. break;
  1203. }
  1204. }
  1205. node = node.Next;
  1206. }
  1207. while (info.Address + info.Size < endAddr && node != null);
  1208. if (result == KernelResult.Success)
  1209. {
  1210. GetMemoryRegionManager().FreePages(pageList);
  1211. PhysicalMemoryUsage -= heapMappedSize;
  1212. KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
  1213. currentProcess.ResourceLimit?.Release(LimitableResource.Memory, heapMappedSize);
  1214. ulong pagesCount = size / PageSize;
  1215. InsertBlock(address, pagesCount, MemoryState.Unmapped);
  1216. }
  1217. return result;
  1218. }
  1219. }
  1220. private void MapPhysicalMemory(KPageList pageList, ulong address, ulong endAddr)
  1221. {
  1222. KMemoryInfo info;
  1223. LinkedListNode<KMemoryBlock> node = FindBlockNode(address);
  1224. LinkedListNode<KPageNode> pageListNode = pageList.Nodes.First;
  1225. KPageNode pageNode = pageListNode.Value;
  1226. ulong srcPa = pageNode.Address;
  1227. ulong srcPaPages = pageNode.PagesCount;
  1228. do
  1229. {
  1230. info = node.Value.GetInfo();
  1231. if (info.State == MemoryState.Unmapped)
  1232. {
  1233. ulong blockSize = GetSizeInRange(info, address, endAddr);
  1234. ulong dstVaPages = blockSize / PageSize;
  1235. ulong dstVa = GetAddrInRange(info, address);
  1236. while (dstVaPages > 0)
  1237. {
  1238. if (srcPaPages == 0)
  1239. {
  1240. pageListNode = pageListNode.Next;
  1241. pageNode = pageListNode.Value;
  1242. srcPa = pageNode.Address;
  1243. srcPaPages = pageNode.PagesCount;
  1244. }
  1245. ulong pagesCount = srcPaPages;
  1246. if (pagesCount > dstVaPages)
  1247. {
  1248. pagesCount = dstVaPages;
  1249. }
  1250. DoMmuOperation(
  1251. dstVa,
  1252. pagesCount,
  1253. srcPa,
  1254. true,
  1255. MemoryPermission.ReadAndWrite,
  1256. MemoryOperation.MapPa);
  1257. dstVa += pagesCount * PageSize;
  1258. srcPa += pagesCount * PageSize;
  1259. srcPaPages -= pagesCount;
  1260. dstVaPages -= pagesCount;
  1261. }
  1262. }
  1263. node = node.Next;
  1264. }
  1265. while (info.Address + info.Size < endAddr && node != null);
  1266. }
  1267. private static ulong GetSizeInRange(KMemoryInfo info, ulong start, ulong end)
  1268. {
  1269. ulong endAddr = info.Size + info.Address;
  1270. ulong size = info.Size;
  1271. if (info.Address < start)
  1272. {
  1273. size -= start - info.Address;
  1274. }
  1275. if (endAddr > end)
  1276. {
  1277. size -= endAddr - end;
  1278. }
  1279. return size;
  1280. }
  1281. private static ulong GetAddrInRange(KMemoryInfo info, ulong start)
  1282. {
  1283. if (info.Address < start)
  1284. {
  1285. return start;
  1286. }
  1287. return info.Address;
  1288. }
  1289. private void AddVaRangeToPageList(KPageList pageList, ulong start, ulong pagesCount)
  1290. {
  1291. ulong address = start;
  1292. while (address < start + pagesCount * PageSize)
  1293. {
  1294. KernelResult result = ConvertVaToPa(address, out ulong pa);
  1295. if (result != KernelResult.Success)
  1296. {
  1297. throw new InvalidOperationException("Unexpected failure translating virtual address.");
  1298. }
  1299. pageList.AddRange(pa, 1);
  1300. address += PageSize;
  1301. }
  1302. }
  1303. private bool IsUnmapped(ulong address, ulong size)
  1304. {
  1305. return CheckRange(
  1306. address,
  1307. size,
  1308. MemoryState.Mask,
  1309. MemoryState.Unmapped,
  1310. MemoryPermission.Mask,
  1311. MemoryPermission.None,
  1312. MemoryAttribute.Mask,
  1313. MemoryAttribute.None,
  1314. MemoryAttribute.IpcAndDeviceMapped,
  1315. out _,
  1316. out _,
  1317. out _);
  1318. }
  1319. private bool CheckRange(
  1320. ulong address,
  1321. ulong size,
  1322. MemoryState stateMask,
  1323. MemoryState stateExpected,
  1324. MemoryPermission permissionMask,
  1325. MemoryPermission permissionExpected,
  1326. MemoryAttribute attributeMask,
  1327. MemoryAttribute attributeExpected,
  1328. MemoryAttribute attributeIgnoreMask,
  1329. out MemoryState outState,
  1330. out MemoryPermission outPermission,
  1331. out MemoryAttribute outAttribute)
  1332. {
  1333. ulong endAddr = address + size - 1;
  1334. LinkedListNode<KMemoryBlock> node = FindBlockNode(address);
  1335. KMemoryInfo info = node.Value.GetInfo();
  1336. MemoryState firstState = info.State;
  1337. MemoryPermission firstPermission = info.Permission;
  1338. MemoryAttribute firstAttribute = info.Attribute;
  1339. do
  1340. {
  1341. info = node.Value.GetInfo();
  1342. //Check if the block state matches what we expect.
  1343. if ( firstState != info.State ||
  1344. firstPermission != info.Permission ||
  1345. (info.Attribute & attributeMask) != attributeExpected ||
  1346. (firstAttribute | attributeIgnoreMask) != (info.Attribute | attributeIgnoreMask) ||
  1347. (firstState & stateMask) != stateExpected ||
  1348. (firstPermission & permissionMask) != permissionExpected)
  1349. {
  1350. break;
  1351. }
  1352. //Check if this is the last block on the range, if so return success.
  1353. if (endAddr <= info.Address + info.Size - 1)
  1354. {
  1355. outState = firstState;
  1356. outPermission = firstPermission;
  1357. outAttribute = firstAttribute & ~attributeIgnoreMask;
  1358. return true;
  1359. }
  1360. node = node.Next;
  1361. }
  1362. while (node != null);
  1363. outState = MemoryState.Unmapped;
  1364. outPermission = MemoryPermission.None;
  1365. outAttribute = MemoryAttribute.None;
  1366. return false;
  1367. }
  1368. private bool CheckRange(
  1369. ulong address,
  1370. ulong size,
  1371. MemoryState stateMask,
  1372. MemoryState stateExpected,
  1373. MemoryPermission permissionMask,
  1374. MemoryPermission permissionExpected,
  1375. MemoryAttribute attributeMask,
  1376. MemoryAttribute attributeExpected)
  1377. {
  1378. ulong endAddr = address + size - 1;
  1379. LinkedListNode<KMemoryBlock> node = FindBlockNode(address);
  1380. do
  1381. {
  1382. KMemoryInfo info = node.Value.GetInfo();
  1383. //Check if the block state matches what we expect.
  1384. if ((info.State & stateMask) != stateExpected ||
  1385. (info.Permission & permissionMask) != permissionExpected ||
  1386. (info.Attribute & attributeMask) != attributeExpected)
  1387. {
  1388. break;
  1389. }
  1390. //Check if this is the last block on the range, if so return success.
  1391. if (endAddr <= info.Address + info.Size - 1)
  1392. {
  1393. return true;
  1394. }
  1395. node = node.Next;
  1396. }
  1397. while (node != null);
  1398. return false;
  1399. }
  1400. private void InsertBlock(
  1401. ulong baseAddress,
  1402. ulong pagesCount,
  1403. MemoryState oldState,
  1404. MemoryPermission oldPermission,
  1405. MemoryAttribute oldAttribute,
  1406. MemoryState newState,
  1407. MemoryPermission newPermission,
  1408. MemoryAttribute newAttribute)
  1409. {
  1410. //Insert new block on the list only on areas where the state
  1411. //of the block matches the state specified on the Old* state
  1412. //arguments, otherwise leave it as is.
  1413. int oldCount = _blocks.Count;
  1414. oldAttribute |= MemoryAttribute.IpcAndDeviceMapped;
  1415. ulong endAddr = pagesCount * PageSize + baseAddress;
  1416. LinkedListNode<KMemoryBlock> node = _blocks.First;
  1417. while (node != null)
  1418. {
  1419. LinkedListNode<KMemoryBlock> newNode = node;
  1420. LinkedListNode<KMemoryBlock> nextNode = node.Next;
  1421. KMemoryBlock currBlock = node.Value;
  1422. ulong currBaseAddr = currBlock.BaseAddress;
  1423. ulong currEndAddr = currBlock.PagesCount * PageSize + currBaseAddr;
  1424. if (baseAddress < currEndAddr && currBaseAddr < endAddr)
  1425. {
  1426. MemoryAttribute currBlockAttr = currBlock.Attribute | MemoryAttribute.IpcAndDeviceMapped;
  1427. if (currBlock.State != oldState ||
  1428. currBlock.Permission != oldPermission ||
  1429. currBlockAttr != oldAttribute)
  1430. {
  1431. node = nextNode;
  1432. continue;
  1433. }
  1434. if (currBaseAddr >= baseAddress && currEndAddr <= endAddr)
  1435. {
  1436. currBlock.State = newState;
  1437. currBlock.Permission = newPermission;
  1438. currBlock.Attribute &= ~MemoryAttribute.IpcAndDeviceMapped;
  1439. currBlock.Attribute |= newAttribute;
  1440. }
  1441. else if (currBaseAddr >= baseAddress)
  1442. {
  1443. currBlock.BaseAddress = endAddr;
  1444. currBlock.PagesCount = (currEndAddr - endAddr) / PageSize;
  1445. ulong newPagesCount = (endAddr - currBaseAddr) / PageSize;
  1446. newNode = _blocks.AddBefore(node, new KMemoryBlock(
  1447. currBaseAddr,
  1448. newPagesCount,
  1449. newState,
  1450. newPermission,
  1451. newAttribute));
  1452. }
  1453. else if (currEndAddr <= endAddr)
  1454. {
  1455. currBlock.PagesCount = (baseAddress - currBaseAddr) / PageSize;
  1456. ulong newPagesCount = (currEndAddr - baseAddress) / PageSize;
  1457. newNode = _blocks.AddAfter(node, new KMemoryBlock(
  1458. baseAddress,
  1459. newPagesCount,
  1460. newState,
  1461. newPermission,
  1462. newAttribute));
  1463. }
  1464. else
  1465. {
  1466. currBlock.PagesCount = (baseAddress - currBaseAddr) / PageSize;
  1467. ulong nextPagesCount = (currEndAddr - endAddr) / PageSize;
  1468. newNode = _blocks.AddAfter(node, new KMemoryBlock(
  1469. baseAddress,
  1470. pagesCount,
  1471. newState,
  1472. newPermission,
  1473. newAttribute));
  1474. _blocks.AddAfter(newNode, new KMemoryBlock(
  1475. endAddr,
  1476. nextPagesCount,
  1477. currBlock.State,
  1478. currBlock.Permission,
  1479. currBlock.Attribute));
  1480. nextNode = null;
  1481. }
  1482. MergeEqualStateNeighbours(newNode);
  1483. }
  1484. node = nextNode;
  1485. }
  1486. _blockAllocator.Count += _blocks.Count - oldCount;
  1487. }
  1488. private void InsertBlock(
  1489. ulong baseAddress,
  1490. ulong pagesCount,
  1491. MemoryState state,
  1492. MemoryPermission permission = MemoryPermission.None,
  1493. MemoryAttribute attribute = MemoryAttribute.None)
  1494. {
  1495. //Inserts new block at the list, replacing and spliting
  1496. //existing blocks as needed.
  1497. KMemoryBlock block = new KMemoryBlock(baseAddress, pagesCount, state, permission, attribute);
  1498. int oldCount = _blocks.Count;
  1499. ulong endAddr = pagesCount * PageSize + baseAddress;
  1500. LinkedListNode<KMemoryBlock> newNode = null;
  1501. LinkedListNode<KMemoryBlock> node = _blocks.First;
  1502. while (node != null)
  1503. {
  1504. KMemoryBlock currBlock = node.Value;
  1505. LinkedListNode<KMemoryBlock> nextNode = node.Next;
  1506. ulong currBaseAddr = currBlock.BaseAddress;
  1507. ulong currEndAddr = currBlock.PagesCount * PageSize + currBaseAddr;
  1508. if (baseAddress < currEndAddr && currBaseAddr < endAddr)
  1509. {
  1510. if (baseAddress >= currBaseAddr && endAddr <= currEndAddr)
  1511. {
  1512. block.Attribute |= currBlock.Attribute & MemoryAttribute.IpcAndDeviceMapped;
  1513. }
  1514. if (baseAddress > currBaseAddr && endAddr < currEndAddr)
  1515. {
  1516. currBlock.PagesCount = (baseAddress - currBaseAddr) / PageSize;
  1517. ulong nextPagesCount = (currEndAddr - endAddr) / PageSize;
  1518. newNode = _blocks.AddAfter(node, block);
  1519. _blocks.AddAfter(newNode, new KMemoryBlock(
  1520. endAddr,
  1521. nextPagesCount,
  1522. currBlock.State,
  1523. currBlock.Permission,
  1524. currBlock.Attribute));
  1525. break;
  1526. }
  1527. else if (baseAddress <= currBaseAddr && endAddr < currEndAddr)
  1528. {
  1529. currBlock.BaseAddress = endAddr;
  1530. currBlock.PagesCount = (currEndAddr - endAddr) / PageSize;
  1531. if (newNode == null)
  1532. {
  1533. newNode = _blocks.AddBefore(node, block);
  1534. }
  1535. }
  1536. else if (baseAddress > currBaseAddr && endAddr >= currEndAddr)
  1537. {
  1538. currBlock.PagesCount = (baseAddress - currBaseAddr) / PageSize;
  1539. if (newNode == null)
  1540. {
  1541. newNode = _blocks.AddAfter(node, block);
  1542. }
  1543. }
  1544. else
  1545. {
  1546. if (newNode == null)
  1547. {
  1548. newNode = _blocks.AddBefore(node, block);
  1549. }
  1550. _blocks.Remove(node);
  1551. }
  1552. }
  1553. node = nextNode;
  1554. }
  1555. if (newNode == null)
  1556. {
  1557. newNode = _blocks.AddFirst(block);
  1558. }
  1559. MergeEqualStateNeighbours(newNode);
  1560. _blockAllocator.Count += _blocks.Count - oldCount;
  1561. }
  1562. private void MergeEqualStateNeighbours(LinkedListNode<KMemoryBlock> node)
  1563. {
  1564. KMemoryBlock block = node.Value;
  1565. ulong endAddr = block.PagesCount * PageSize + block.BaseAddress;
  1566. if (node.Previous != null)
  1567. {
  1568. KMemoryBlock previous = node.Previous.Value;
  1569. if (BlockStateEquals(block, previous))
  1570. {
  1571. _blocks.Remove(node.Previous);
  1572. block.BaseAddress = previous.BaseAddress;
  1573. }
  1574. }
  1575. if (node.Next != null)
  1576. {
  1577. KMemoryBlock next = node.Next.Value;
  1578. if (BlockStateEquals(block, next))
  1579. {
  1580. _blocks.Remove(node.Next);
  1581. endAddr = next.BaseAddress + next.PagesCount * PageSize;
  1582. }
  1583. }
  1584. block.PagesCount = (endAddr - block.BaseAddress) / PageSize;
  1585. }
  1586. private static bool BlockStateEquals(KMemoryBlock lhs, KMemoryBlock rhs)
  1587. {
  1588. return lhs.State == rhs.State &&
  1589. lhs.Permission == rhs.Permission &&
  1590. lhs.Attribute == rhs.Attribute &&
  1591. lhs.DeviceRefCount == rhs.DeviceRefCount &&
  1592. lhs.IpcRefCount == rhs.IpcRefCount;
  1593. }
  1594. private ulong FindFirstFit(
  1595. ulong regionStart,
  1596. ulong regionPagesCount,
  1597. ulong neededPagesCount,
  1598. int alignment,
  1599. ulong reservedStart,
  1600. ulong reservedPagesCount)
  1601. {
  1602. ulong reservedSize = reservedPagesCount * PageSize;
  1603. ulong totalNeededSize = reservedSize + neededPagesCount * PageSize;
  1604. ulong regionEndAddr = regionStart + regionPagesCount * PageSize;
  1605. LinkedListNode<KMemoryBlock> node = FindBlockNode(regionStart);
  1606. KMemoryInfo info = node.Value.GetInfo();
  1607. while (regionEndAddr >= info.Address)
  1608. {
  1609. if (info.State == MemoryState.Unmapped)
  1610. {
  1611. ulong currBaseAddr = info.Address + reservedSize;
  1612. ulong currEndAddr = info.Address + info.Size - 1;
  1613. ulong address = BitUtils.AlignDown(currBaseAddr, alignment) + reservedStart;
  1614. if (currBaseAddr > address)
  1615. {
  1616. address += (ulong)alignment;
  1617. }
  1618. ulong allocationEndAddr = address + totalNeededSize - 1;
  1619. if (allocationEndAddr <= regionEndAddr &&
  1620. allocationEndAddr <= currEndAddr &&
  1621. address < allocationEndAddr)
  1622. {
  1623. return address;
  1624. }
  1625. }
  1626. node = node.Next;
  1627. if (node == null)
  1628. {
  1629. break;
  1630. }
  1631. info = node.Value.GetInfo();
  1632. }
  1633. return 0;
  1634. }
  1635. private KMemoryBlock FindBlock(ulong address)
  1636. {
  1637. return FindBlockNode(address)?.Value;
  1638. }
  1639. private LinkedListNode<KMemoryBlock> FindBlockNode(ulong address)
  1640. {
  1641. lock (_blocks)
  1642. {
  1643. LinkedListNode<KMemoryBlock> node = _blocks.First;
  1644. while (node != null)
  1645. {
  1646. KMemoryBlock block = node.Value;
  1647. ulong currEndAddr = block.PagesCount * PageSize + block.BaseAddress;
  1648. if (block.BaseAddress <= address && currEndAddr - 1 >= address)
  1649. {
  1650. return node;
  1651. }
  1652. node = node.Next;
  1653. }
  1654. }
  1655. return null;
  1656. }
  1657. private bool ValidateRegionForState(ulong address, ulong size, MemoryState state)
  1658. {
  1659. ulong endAddr = address + size;
  1660. ulong regionBaseAddr = GetBaseAddrForState(state);
  1661. ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
  1662. bool InsideRegion()
  1663. {
  1664. return regionBaseAddr <= address &&
  1665. endAddr > address &&
  1666. endAddr - 1 <= regionEndAddr - 1;
  1667. }
  1668. bool OutsideHeapRegion()
  1669. {
  1670. return endAddr <= HeapRegionStart ||
  1671. address >= HeapRegionEnd;
  1672. }
  1673. bool OutsideMapRegion()
  1674. {
  1675. return endAddr <= AliasRegionStart ||
  1676. address >= AliasRegionEnd;
  1677. }
  1678. switch (state)
  1679. {
  1680. case MemoryState.Io:
  1681. case MemoryState.Normal:
  1682. case MemoryState.CodeStatic:
  1683. case MemoryState.CodeMutable:
  1684. case MemoryState.SharedMemory:
  1685. case MemoryState.ModCodeStatic:
  1686. case MemoryState.ModCodeMutable:
  1687. case MemoryState.Stack:
  1688. case MemoryState.ThreadLocal:
  1689. case MemoryState.TransferMemoryIsolated:
  1690. case MemoryState.TransferMemory:
  1691. case MemoryState.ProcessMemory:
  1692. case MemoryState.CodeReadOnly:
  1693. case MemoryState.CodeWritable:
  1694. return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion();
  1695. case MemoryState.Heap:
  1696. return InsideRegion() && OutsideMapRegion();
  1697. case MemoryState.IpcBuffer0:
  1698. case MemoryState.IpcBuffer1:
  1699. case MemoryState.IpcBuffer3:
  1700. return InsideRegion() && OutsideHeapRegion();
  1701. case MemoryState.KernelStack:
  1702. return InsideRegion();
  1703. }
  1704. throw new ArgumentException($"Invalid state value \"{state}\".");
  1705. }
  1706. private ulong GetBaseAddrForState(MemoryState state)
  1707. {
  1708. switch (state)
  1709. {
  1710. case MemoryState.Io:
  1711. case MemoryState.Normal:
  1712. case MemoryState.ThreadLocal:
  1713. return TlsIoRegionStart;
  1714. case MemoryState.CodeStatic:
  1715. case MemoryState.CodeMutable:
  1716. case MemoryState.SharedMemory:
  1717. case MemoryState.ModCodeStatic:
  1718. case MemoryState.ModCodeMutable:
  1719. case MemoryState.TransferMemoryIsolated:
  1720. case MemoryState.TransferMemory:
  1721. case MemoryState.ProcessMemory:
  1722. case MemoryState.CodeReadOnly:
  1723. case MemoryState.CodeWritable:
  1724. return GetAddrSpaceBaseAddr();
  1725. case MemoryState.Heap:
  1726. return HeapRegionStart;
  1727. case MemoryState.IpcBuffer0:
  1728. case MemoryState.IpcBuffer1:
  1729. case MemoryState.IpcBuffer3:
  1730. return AliasRegionStart;
  1731. case MemoryState.Stack:
  1732. return StackRegionStart;
  1733. case MemoryState.KernelStack:
  1734. return AddrSpaceStart;
  1735. }
  1736. throw new ArgumentException($"Invalid state value \"{state}\".");
  1737. }
  1738. private ulong GetSizeForState(MemoryState state)
  1739. {
  1740. switch (state)
  1741. {
  1742. case MemoryState.Io:
  1743. case MemoryState.Normal:
  1744. case MemoryState.ThreadLocal:
  1745. return TlsIoRegionEnd - TlsIoRegionStart;
  1746. case MemoryState.CodeStatic:
  1747. case MemoryState.CodeMutable:
  1748. case MemoryState.SharedMemory:
  1749. case MemoryState.ModCodeStatic:
  1750. case MemoryState.ModCodeMutable:
  1751. case MemoryState.TransferMemoryIsolated:
  1752. case MemoryState.TransferMemory:
  1753. case MemoryState.ProcessMemory:
  1754. case MemoryState.CodeReadOnly:
  1755. case MemoryState.CodeWritable:
  1756. return GetAddrSpaceSize();
  1757. case MemoryState.Heap:
  1758. return HeapRegionEnd - HeapRegionStart;
  1759. case MemoryState.IpcBuffer0:
  1760. case MemoryState.IpcBuffer1:
  1761. case MemoryState.IpcBuffer3:
  1762. return AliasRegionEnd - AliasRegionStart;
  1763. case MemoryState.Stack:
  1764. return StackRegionEnd - StackRegionStart;
  1765. case MemoryState.KernelStack:
  1766. return AddrSpaceEnd - AddrSpaceStart;
  1767. }
  1768. throw new ArgumentException($"Invalid state value \"{state}\".");
  1769. }
  1770. public ulong GetAddrSpaceBaseAddr()
  1771. {
  1772. if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39)
  1773. {
  1774. return 0x8000000;
  1775. }
  1776. else if (AddrSpaceWidth == 32)
  1777. {
  1778. return 0x200000;
  1779. }
  1780. else
  1781. {
  1782. throw new InvalidOperationException("Invalid address space width!");
  1783. }
  1784. }
  1785. public ulong GetAddrSpaceSize()
  1786. {
  1787. if (AddrSpaceWidth == 36)
  1788. {
  1789. return 0xff8000000;
  1790. }
  1791. else if (AddrSpaceWidth == 39)
  1792. {
  1793. return 0x7ff8000000;
  1794. }
  1795. else if (AddrSpaceWidth == 32)
  1796. {
  1797. return 0xffe00000;
  1798. }
  1799. else
  1800. {
  1801. throw new InvalidOperationException("Invalid address space width!");
  1802. }
  1803. }
  1804. private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission)
  1805. {
  1806. ulong currAddr = address;
  1807. KernelResult result = KernelResult.Success;
  1808. foreach (KPageNode pageNode in pageList)
  1809. {
  1810. result = DoMmuOperation(
  1811. currAddr,
  1812. pageNode.PagesCount,
  1813. pageNode.Address,
  1814. true,
  1815. permission,
  1816. MemoryOperation.MapPa);
  1817. if (result != KernelResult.Success)
  1818. {
  1819. KMemoryInfo info = FindBlock(currAddr).GetInfo();
  1820. ulong pagesCount = (address - currAddr) / PageSize;
  1821. result = MmuUnmap(address, pagesCount);
  1822. break;
  1823. }
  1824. currAddr += pageNode.PagesCount * PageSize;
  1825. }
  1826. return result;
  1827. }
  1828. private KernelResult MmuUnmap(ulong address, ulong pagesCount)
  1829. {
  1830. return DoMmuOperation(
  1831. address,
  1832. pagesCount,
  1833. 0,
  1834. false,
  1835. MemoryPermission.None,
  1836. MemoryOperation.Unmap);
  1837. }
  1838. private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission)
  1839. {
  1840. return DoMmuOperation(
  1841. address,
  1842. pagesCount,
  1843. 0,
  1844. false,
  1845. permission,
  1846. MemoryOperation.ChangePermRw);
  1847. }
  1848. private KernelResult DoMmuOperation(
  1849. ulong dstVa,
  1850. ulong pagesCount,
  1851. ulong srcPa,
  1852. bool map,
  1853. MemoryPermission permission,
  1854. MemoryOperation operation)
  1855. {
  1856. if (map != (operation == MemoryOperation.MapPa))
  1857. {
  1858. throw new ArgumentException(nameof(map) + " value is invalid for this operation.");
  1859. }
  1860. KernelResult result;
  1861. switch (operation)
  1862. {
  1863. case MemoryOperation.MapPa:
  1864. {
  1865. ulong size = pagesCount * PageSize;
  1866. _cpuMemory.Map((long)dstVa, (long)(srcPa - DramMemoryMap.DramBase), (long)size);
  1867. result = KernelResult.Success;
  1868. break;
  1869. }
  1870. case MemoryOperation.Allocate:
  1871. {
  1872. KMemoryRegionManager region = GetMemoryRegionManager();
  1873. result = region.AllocatePages(pagesCount, _aslrDisabled, out KPageList pageList);
  1874. if (result == KernelResult.Success)
  1875. {
  1876. result = MmuMapPages(dstVa, pageList);
  1877. }
  1878. break;
  1879. }
  1880. case MemoryOperation.Unmap:
  1881. {
  1882. ulong size = pagesCount * PageSize;
  1883. _cpuMemory.Unmap((long)dstVa, (long)size);
  1884. result = KernelResult.Success;
  1885. break;
  1886. }
  1887. case MemoryOperation.ChangePermRw: result = KernelResult.Success; break;
  1888. case MemoryOperation.ChangePermsAndAttributes: result = KernelResult.Success; break;
  1889. default: throw new ArgumentException($"Invalid operation \"{operation}\".");
  1890. }
  1891. return result;
  1892. }
  1893. private KernelResult DoMmuOperation(
  1894. ulong address,
  1895. ulong pagesCount,
  1896. KPageList pageList,
  1897. MemoryPermission permission,
  1898. MemoryOperation operation)
  1899. {
  1900. if (operation != MemoryOperation.MapVa)
  1901. {
  1902. throw new ArgumentException($"Invalid memory operation \"{operation}\" specified.");
  1903. }
  1904. return MmuMapPages(address, pageList);
  1905. }
  1906. private KMemoryRegionManager GetMemoryRegionManager()
  1907. {
  1908. return _system.MemoryRegions[(int)_memRegion];
  1909. }
  1910. private KernelResult MmuMapPages(ulong address, KPageList pageList)
  1911. {
  1912. foreach (KPageNode pageNode in pageList)
  1913. {
  1914. ulong size = pageNode.PagesCount * PageSize;
  1915. _cpuMemory.Map((long)address, (long)(pageNode.Address - DramMemoryMap.DramBase), (long)size);
  1916. address += size;
  1917. }
  1918. return KernelResult.Success;
  1919. }
  1920. public KernelResult ConvertVaToPa(ulong va, out ulong pa)
  1921. {
  1922. pa = DramMemoryMap.DramBase + (ulong)_cpuMemory.GetPhysicalAddress((long)va);
  1923. return KernelResult.Success;
  1924. }
  1925. public long GetMmUsedPages()
  1926. {
  1927. lock (_blocks)
  1928. {
  1929. return BitUtils.DivRoundUp(GetMmUsedSize(), PageSize);
  1930. }
  1931. }
  1932. private long GetMmUsedSize()
  1933. {
  1934. return _blocks.Count * KMemoryBlockSize;
  1935. }
  1936. public bool IsInvalidRegion(ulong address, ulong size)
  1937. {
  1938. return address + size - 1 > GetAddrSpaceBaseAddr() + GetAddrSpaceSize() - 1;
  1939. }
  1940. public bool InsideAddrSpace(ulong address, ulong size)
  1941. {
  1942. return AddrSpaceStart <= address && address + size - 1 <= AddrSpaceEnd - 1;
  1943. }
  1944. public bool InsideAliasRegion(ulong address, ulong size)
  1945. {
  1946. return address + size > AliasRegionStart && AliasRegionEnd > address;
  1947. }
  1948. public bool InsideHeapRegion(ulong address, ulong size)
  1949. {
  1950. return address + size > HeapRegionStart && HeapRegionEnd > address;
  1951. }
  1952. public bool InsideStackRegion(ulong address, ulong size)
  1953. {
  1954. return address + size > StackRegionStart && StackRegionEnd > address;
  1955. }
  1956. public bool OutsideAliasRegion(ulong address, ulong size)
  1957. {
  1958. return AliasRegionStart > address || address + size - 1 > AliasRegionEnd - 1;
  1959. }
  1960. public bool OutsideAddrSpace(ulong address, ulong size)
  1961. {
  1962. return AddrSpaceStart > address || address + size - 1 > AddrSpaceEnd - 1;
  1963. }
  1964. public bool OutsideStackRegion(ulong address, ulong size)
  1965. {
  1966. return StackRegionStart > address || address + size - 1 > StackRegionEnd - 1;
  1967. }
  1968. }
  1969. }