k_page_table.cpp 148 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/alignment.h"
  4. #include "common/assert.h"
  5. #include "common/literals.h"
  6. #include "common/scope_exit.h"
  7. #include "common/settings.h"
  8. #include "core/core.h"
  9. #include "core/hle/kernel/k_address_space_info.h"
  10. #include "core/hle/kernel/k_memory_block.h"
  11. #include "core/hle/kernel/k_memory_block_manager.h"
  12. #include "core/hle/kernel/k_page_group.h"
  13. #include "core/hle/kernel/k_page_table.h"
  14. #include "core/hle/kernel/k_process.h"
  15. #include "core/hle/kernel/k_resource_limit.h"
  16. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  17. #include "core/hle/kernel/k_system_control.h"
  18. #include "core/hle/kernel/k_system_resource.h"
  19. #include "core/hle/kernel/kernel.h"
  20. #include "core/hle/kernel/svc_results.h"
  21. #include "core/memory.h"
  22. namespace Kernel {
  23. namespace {
  24. class KScopedLightLockPair {
  25. YUZU_NON_COPYABLE(KScopedLightLockPair);
  26. YUZU_NON_MOVEABLE(KScopedLightLockPair);
  27. private:
  28. KLightLock* m_lower;
  29. KLightLock* m_upper;
  30. public:
  31. KScopedLightLockPair(KLightLock& lhs, KLightLock& rhs) {
  32. // Ensure our locks are in a consistent order.
  33. if (std::addressof(lhs) <= std::addressof(rhs)) {
  34. m_lower = std::addressof(lhs);
  35. m_upper = std::addressof(rhs);
  36. } else {
  37. m_lower = std::addressof(rhs);
  38. m_upper = std::addressof(lhs);
  39. }
  40. // Acquire both locks.
  41. m_lower->Lock();
  42. if (m_lower != m_upper) {
  43. m_upper->Lock();
  44. }
  45. }
  46. ~KScopedLightLockPair() {
  47. // Unlock the upper lock.
  48. if (m_upper != nullptr && m_upper != m_lower) {
  49. m_upper->Unlock();
  50. }
  51. // Unlock the lower lock.
  52. if (m_lower != nullptr) {
  53. m_lower->Unlock();
  54. }
  55. }
  56. public:
  57. // Utility.
  58. void TryUnlockHalf(KLightLock& lock) {
  59. // Only allow unlocking if the lock is half the pair.
  60. if (m_lower != m_upper) {
  61. // We want to be sure the lock is one we own.
  62. if (m_lower == std::addressof(lock)) {
  63. lock.Unlock();
  64. m_lower = nullptr;
  65. } else if (m_upper == std::addressof(lock)) {
  66. lock.Unlock();
  67. m_upper = nullptr;
  68. }
  69. }
  70. }
  71. };
  72. using namespace Common::Literals;
  73. constexpr size_t GetAddressSpaceWidthFromType(Svc::CreateProcessFlag as_type) {
  74. switch (as_type) {
  75. case Svc::CreateProcessFlag::AddressSpace32Bit:
  76. case Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias:
  77. return 32;
  78. case Svc::CreateProcessFlag::AddressSpace64BitDeprecated:
  79. return 36;
  80. case Svc::CreateProcessFlag::AddressSpace64Bit:
  81. return 39;
  82. default:
  83. ASSERT(false);
  84. return {};
  85. }
  86. }
  87. } // namespace
  88. KPageTable::KPageTable(Core::System& system_)
  89. : m_general_lock{system_.Kernel()},
  90. m_map_physical_memory_lock{system_.Kernel()}, m_system{system_}, m_kernel{system_.Kernel()} {}
  91. KPageTable::~KPageTable() = default;
  92. Result KPageTable::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr,
  93. bool enable_das_merge, bool from_back,
  94. KMemoryManager::Pool pool, KProcessAddress code_addr,
  95. size_t code_size, KSystemResource* system_resource,
  96. KResourceLimit* resource_limit,
  97. Core::Memory::Memory& memory) {
  98. const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) {
  99. return KAddressSpaceInfo::GetAddressSpaceStart(m_address_space_width, type);
  100. };
  101. const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) {
  102. return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type);
  103. };
  104. // Set the tracking memory
  105. m_memory = std::addressof(memory);
  106. // Set our width and heap/alias sizes
  107. m_address_space_width = GetAddressSpaceWidthFromType(as_type);
  108. const KProcessAddress start = 0;
  109. const KProcessAddress end{1ULL << m_address_space_width};
  110. size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)};
  111. size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)};
  112. ASSERT(code_addr < code_addr + code_size);
  113. ASSERT(code_addr + code_size - 1 <= end - 1);
  114. // Adjust heap/alias size if we don't have an alias region
  115. if (as_type == Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias) {
  116. heap_region_size += alias_region_size;
  117. alias_region_size = 0;
  118. }
  119. // Set code regions and determine remaining
  120. constexpr size_t RegionAlignment{2_MiB};
  121. KProcessAddress process_code_start{};
  122. KProcessAddress process_code_end{};
  123. size_t stack_region_size{};
  124. size_t kernel_map_region_size{};
  125. if (m_address_space_width == 39) {
  126. alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias);
  127. heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap);
  128. stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack);
  129. kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
  130. m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit);
  131. m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
  132. m_alias_code_region_start = m_code_region_start;
  133. m_alias_code_region_end = m_code_region_end;
  134. process_code_start = Common::AlignDown(GetInteger(code_addr), RegionAlignment);
  135. process_code_end = Common::AlignUp(GetInteger(code_addr) + code_size, RegionAlignment);
  136. } else {
  137. stack_region_size = 0;
  138. kernel_map_region_size = 0;
  139. m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall);
  140. m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall);
  141. m_stack_region_start = m_code_region_start;
  142. m_alias_code_region_start = m_code_region_start;
  143. m_alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) +
  144. GetSpaceSize(KAddressSpaceInfo::Type::MapLarge);
  145. m_stack_region_end = m_code_region_end;
  146. m_kernel_map_region_start = m_code_region_start;
  147. m_kernel_map_region_end = m_code_region_end;
  148. process_code_start = m_code_region_start;
  149. process_code_end = m_code_region_end;
  150. }
  151. // Set other basic fields
  152. m_enable_aslr = enable_aslr;
  153. m_enable_device_address_space_merge = enable_das_merge;
  154. m_address_space_start = start;
  155. m_address_space_end = end;
  156. m_is_kernel = false;
  157. m_memory_block_slab_manager = system_resource->GetMemoryBlockSlabManagerPointer();
  158. m_block_info_manager = system_resource->GetBlockInfoManagerPointer();
  159. m_resource_limit = resource_limit;
  160. // Determine the region we can place our undetermineds in
  161. KProcessAddress alloc_start{};
  162. size_t alloc_size{};
  163. if ((process_code_start - m_code_region_start) >= (end - process_code_end)) {
  164. alloc_start = m_code_region_start;
  165. alloc_size = process_code_start - m_code_region_start;
  166. } else {
  167. alloc_start = process_code_end;
  168. alloc_size = end - process_code_end;
  169. }
  170. const size_t needed_size =
  171. (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size);
  172. R_UNLESS(alloc_size >= needed_size, ResultOutOfMemory);
  173. const size_t remaining_size{alloc_size - needed_size};
  174. // Determine random placements for each region
  175. size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{};
  176. if (enable_aslr) {
  177. alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  178. RegionAlignment;
  179. heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  180. RegionAlignment;
  181. stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  182. RegionAlignment;
  183. kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
  184. RegionAlignment;
  185. }
  186. // Setup heap and alias regions
  187. m_alias_region_start = alloc_start + alias_rnd;
  188. m_alias_region_end = m_alias_region_start + alias_region_size;
  189. m_heap_region_start = alloc_start + heap_rnd;
  190. m_heap_region_end = m_heap_region_start + heap_region_size;
  191. if (alias_rnd <= heap_rnd) {
  192. m_heap_region_start += alias_region_size;
  193. m_heap_region_end += alias_region_size;
  194. } else {
  195. m_alias_region_start += heap_region_size;
  196. m_alias_region_end += heap_region_size;
  197. }
  198. // Setup stack region
  199. if (stack_region_size) {
  200. m_stack_region_start = alloc_start + stack_rnd;
  201. m_stack_region_end = m_stack_region_start + stack_region_size;
  202. if (alias_rnd < stack_rnd) {
  203. m_stack_region_start += alias_region_size;
  204. m_stack_region_end += alias_region_size;
  205. } else {
  206. m_alias_region_start += stack_region_size;
  207. m_alias_region_end += stack_region_size;
  208. }
  209. if (heap_rnd < stack_rnd) {
  210. m_stack_region_start += heap_region_size;
  211. m_stack_region_end += heap_region_size;
  212. } else {
  213. m_heap_region_start += stack_region_size;
  214. m_heap_region_end += stack_region_size;
  215. }
  216. }
  217. // Setup kernel map region
  218. if (kernel_map_region_size) {
  219. m_kernel_map_region_start = alloc_start + kmap_rnd;
  220. m_kernel_map_region_end = m_kernel_map_region_start + kernel_map_region_size;
  221. if (alias_rnd < kmap_rnd) {
  222. m_kernel_map_region_start += alias_region_size;
  223. m_kernel_map_region_end += alias_region_size;
  224. } else {
  225. m_alias_region_start += kernel_map_region_size;
  226. m_alias_region_end += kernel_map_region_size;
  227. }
  228. if (heap_rnd < kmap_rnd) {
  229. m_kernel_map_region_start += heap_region_size;
  230. m_kernel_map_region_end += heap_region_size;
  231. } else {
  232. m_heap_region_start += kernel_map_region_size;
  233. m_heap_region_end += kernel_map_region_size;
  234. }
  235. if (stack_region_size) {
  236. if (stack_rnd < kmap_rnd) {
  237. m_kernel_map_region_start += stack_region_size;
  238. m_kernel_map_region_end += stack_region_size;
  239. } else {
  240. m_stack_region_start += kernel_map_region_size;
  241. m_stack_region_end += kernel_map_region_size;
  242. }
  243. }
  244. }
  245. // Set heap and fill members.
  246. m_current_heap_end = m_heap_region_start;
  247. m_max_heap_size = 0;
  248. m_mapped_physical_memory_size = 0;
  249. m_mapped_unsafe_physical_memory = 0;
  250. m_mapped_insecure_memory = 0;
  251. m_mapped_ipc_server_memory = 0;
  252. m_heap_fill_value = 0;
  253. m_ipc_fill_value = 0;
  254. m_stack_fill_value = 0;
  255. // Set allocation option.
  256. m_allocate_option =
  257. KMemoryManager::EncodeOption(pool, from_back ? KMemoryManager::Direction::FromBack
  258. : KMemoryManager::Direction::FromFront);
  259. // Ensure that we regions inside our address space
  260. auto IsInAddressSpace = [&](KProcessAddress addr) {
  261. return m_address_space_start <= addr && addr <= m_address_space_end;
  262. };
  263. ASSERT(IsInAddressSpace(m_alias_region_start));
  264. ASSERT(IsInAddressSpace(m_alias_region_end));
  265. ASSERT(IsInAddressSpace(m_heap_region_start));
  266. ASSERT(IsInAddressSpace(m_heap_region_end));
  267. ASSERT(IsInAddressSpace(m_stack_region_start));
  268. ASSERT(IsInAddressSpace(m_stack_region_end));
  269. ASSERT(IsInAddressSpace(m_kernel_map_region_start));
  270. ASSERT(IsInAddressSpace(m_kernel_map_region_end));
  271. // Ensure that we selected regions that don't overlap
  272. const KProcessAddress alias_start{m_alias_region_start};
  273. const KProcessAddress alias_last{m_alias_region_end - 1};
  274. const KProcessAddress heap_start{m_heap_region_start};
  275. const KProcessAddress heap_last{m_heap_region_end - 1};
  276. const KProcessAddress stack_start{m_stack_region_start};
  277. const KProcessAddress stack_last{m_stack_region_end - 1};
  278. const KProcessAddress kmap_start{m_kernel_map_region_start};
  279. const KProcessAddress kmap_last{m_kernel_map_region_end - 1};
  280. ASSERT(alias_last < heap_start || heap_last < alias_start);
  281. ASSERT(alias_last < stack_start || stack_last < alias_start);
  282. ASSERT(alias_last < kmap_start || kmap_last < alias_start);
  283. ASSERT(heap_last < stack_start || stack_last < heap_start);
  284. ASSERT(heap_last < kmap_start || kmap_last < heap_start);
  285. m_current_heap_end = m_heap_region_start;
  286. m_max_heap_size = 0;
  287. m_mapped_physical_memory_size = 0;
  288. m_memory_pool = pool;
  289. m_page_table_impl = std::make_unique<Common::PageTable>();
  290. m_page_table_impl->Resize(m_address_space_width, PageBits);
  291. // Initialize our memory block manager.
  292. R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end,
  293. m_memory_block_slab_manager));
  294. }
  295. void KPageTable::Finalize() {
  296. auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
  297. if (Settings::IsFastmemEnabled()) {
  298. m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
  299. }
  300. };
  301. // Finalize memory blocks.
  302. m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback));
  303. // Release any insecure mapped memory.
  304. if (m_mapped_insecure_memory) {
  305. UNIMPLEMENTED();
  306. }
  307. // Release any ipc server memory.
  308. if (m_mapped_ipc_server_memory) {
  309. UNIMPLEMENTED();
  310. }
  311. // Close the backing page table, as the destructor is not called for guest objects.
  312. m_page_table_impl.reset();
  313. }
  314. Result KPageTable::MapProcessCode(KProcessAddress addr, size_t num_pages, KMemoryState state,
  315. KMemoryPermission perm) {
  316. const u64 size{num_pages * PageSize};
  317. // Validate the mapping request.
  318. R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
  319. // Lock the table.
  320. KScopedLightLock lk(m_general_lock);
  321. // Verify that the destination memory is unmapped.
  322. R_TRY(this->CheckMemoryState(addr, size, KMemoryState::All, KMemoryState::Free,
  323. KMemoryPermission::None, KMemoryPermission::None,
  324. KMemoryAttribute::None, KMemoryAttribute::None));
  325. // Create an update allocator.
  326. Result allocator_result{ResultSuccess};
  327. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  328. m_memory_block_slab_manager);
  329. // Allocate and open.
  330. KPageGroup pg{m_kernel, m_block_info_manager};
  331. R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
  332. &pg, num_pages,
  333. KMemoryManager::EncodeOption(KMemoryManager::Pool::Application, m_allocation_option)));
  334. R_TRY(Operate(addr, num_pages, pg, OperationType::MapGroup));
  335. // Update the blocks.
  336. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
  337. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
  338. KMemoryBlockDisableMergeAttribute::None);
  339. R_SUCCEED();
  340. }
  341. Result KPageTable::MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address,
  342. size_t size) {
  343. // Validate the mapping request.
  344. R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
  345. ResultInvalidMemoryRegion);
  346. // Lock the table.
  347. KScopedLightLock lk(m_general_lock);
  348. // Verify that the source memory is normal heap.
  349. KMemoryState src_state{};
  350. KMemoryPermission src_perm{};
  351. size_t num_src_allocator_blocks{};
  352. R_TRY(this->CheckMemoryState(&src_state, &src_perm, nullptr, &num_src_allocator_blocks,
  353. src_address, size, KMemoryState::All, KMemoryState::Normal,
  354. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  355. KMemoryAttribute::All, KMemoryAttribute::None));
  356. // Verify that the destination memory is unmapped.
  357. size_t num_dst_allocator_blocks{};
  358. R_TRY(this->CheckMemoryState(&num_dst_allocator_blocks, dst_address, size, KMemoryState::All,
  359. KMemoryState::Free, KMemoryPermission::None,
  360. KMemoryPermission::None, KMemoryAttribute::None,
  361. KMemoryAttribute::None));
  362. // Create an update allocator for the source.
  363. Result src_allocator_result{ResultSuccess};
  364. KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
  365. m_memory_block_slab_manager,
  366. num_src_allocator_blocks);
  367. R_TRY(src_allocator_result);
  368. // Create an update allocator for the destination.
  369. Result dst_allocator_result{ResultSuccess};
  370. KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
  371. m_memory_block_slab_manager,
  372. num_dst_allocator_blocks);
  373. R_TRY(dst_allocator_result);
  374. // Map the code memory.
  375. {
  376. // Determine the number of pages being operated on.
  377. const size_t num_pages = size / PageSize;
  378. // Create page groups for the memory being mapped.
  379. KPageGroup pg{m_kernel, m_block_info_manager};
  380. AddRegionToPages(src_address, num_pages, pg);
  381. // We're going to perform an update, so create a helper.
  382. KScopedPageTableUpdater updater(this);
  383. // Reprotect the source as kernel-read/not mapped.
  384. const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
  385. KMemoryPermission::NotMapped);
  386. R_TRY(Operate(src_address, num_pages, new_perm, OperationType::ChangePermissions));
  387. // Ensure that we unprotect the source pages on failure.
  388. auto unprot_guard = SCOPE_GUARD({
  389. ASSERT(this->Operate(src_address, num_pages, src_perm, OperationType::ChangePermissions)
  390. .IsSuccess());
  391. });
  392. // Map the alias pages.
  393. const KPageProperties dst_properties = {new_perm, false, false,
  394. DisableMergeAttribute::DisableHead};
  395. R_TRY(
  396. this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false));
  397. // We successfully mapped the alias pages, so we don't need to unprotect the src pages on
  398. // failure.
  399. unprot_guard.Cancel();
  400. // Apply the memory block updates.
  401. m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages,
  402. src_state, new_perm, KMemoryAttribute::Locked,
  403. KMemoryBlockDisableMergeAttribute::Locked,
  404. KMemoryBlockDisableMergeAttribute::None);
  405. m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
  406. KMemoryState::AliasCode, new_perm, KMemoryAttribute::None,
  407. KMemoryBlockDisableMergeAttribute::Normal,
  408. KMemoryBlockDisableMergeAttribute::None);
  409. }
  410. R_SUCCEED();
  411. }
  412. Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address,
  413. size_t size,
  414. ICacheInvalidationStrategy icache_invalidation_strategy) {
  415. // Validate the mapping request.
  416. R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
  417. ResultInvalidMemoryRegion);
  418. // Lock the table.
  419. KScopedLightLock lk(m_general_lock);
  420. // Verify that the source memory is locked normal heap.
  421. size_t num_src_allocator_blocks{};
  422. R_TRY(this->CheckMemoryState(std::addressof(num_src_allocator_blocks), src_address, size,
  423. KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None,
  424. KMemoryPermission::None, KMemoryAttribute::All,
  425. KMemoryAttribute::Locked));
  426. // Verify that the destination memory is aliasable code.
  427. size_t num_dst_allocator_blocks{};
  428. R_TRY(this->CheckMemoryStateContiguous(
  429. std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
  430. KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
  431. KMemoryAttribute::All & ~KMemoryAttribute::PermissionLocked, KMemoryAttribute::None));
  432. // Determine whether any pages being unmapped are code.
  433. bool any_code_pages = false;
  434. {
  435. KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(dst_address);
  436. while (true) {
  437. // Get the memory info.
  438. const KMemoryInfo info = it->GetMemoryInfo();
  439. // Check if the memory has code flag.
  440. if ((info.GetState() & KMemoryState::FlagCode) != KMemoryState::None) {
  441. any_code_pages = true;
  442. break;
  443. }
  444. // Check if we're done.
  445. if (dst_address + size - 1 <= info.GetLastAddress()) {
  446. break;
  447. }
  448. // Advance.
  449. ++it;
  450. }
  451. }
  452. // Ensure that we maintain the instruction cache.
  453. bool reprotected_pages = false;
  454. SCOPE_EXIT({
  455. if (reprotected_pages && any_code_pages) {
  456. if (icache_invalidation_strategy == ICacheInvalidationStrategy::InvalidateRange) {
  457. m_system.InvalidateCpuInstructionCacheRange(GetInteger(dst_address), size);
  458. } else {
  459. m_system.InvalidateCpuInstructionCaches();
  460. }
  461. }
  462. });
  463. // Unmap.
  464. {
  465. // Determine the number of pages being operated on.
  466. const size_t num_pages = size / PageSize;
  467. // Create an update allocator for the source.
  468. Result src_allocator_result{ResultSuccess};
  469. KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
  470. m_memory_block_slab_manager,
  471. num_src_allocator_blocks);
  472. R_TRY(src_allocator_result);
  473. // Create an update allocator for the destination.
  474. Result dst_allocator_result{ResultSuccess};
  475. KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
  476. m_memory_block_slab_manager,
  477. num_dst_allocator_blocks);
  478. R_TRY(dst_allocator_result);
  479. // Unmap the aliased copy of the pages.
  480. R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
  481. // Try to set the permissions for the source pages back to what they should be.
  482. R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
  483. OperationType::ChangePermissions));
  484. // Apply the memory block updates.
  485. m_memory_block_manager.Update(
  486. std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None,
  487. KMemoryPermission::None, KMemoryAttribute::None,
  488. KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal);
  489. m_memory_block_manager.Update(
  490. std::addressof(src_allocator), src_address, num_pages, KMemoryState::Normal,
  491. KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
  492. KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked);
  493. // Note that we reprotected pages.
  494. reprotected_pages = true;
  495. }
  496. R_SUCCEED();
  497. }
  498. KProcessAddress KPageTable::FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
  499. size_t num_pages, size_t alignment, size_t offset,
  500. size_t guard_pages) {
  501. KProcessAddress address = 0;
  502. if (num_pages <= region_num_pages) {
  503. if (this->IsAslrEnabled()) {
  504. UNIMPLEMENTED();
  505. }
  506. // Find the first free area.
  507. if (address == 0) {
  508. address = m_memory_block_manager.FindFreeArea(region_start, region_num_pages, num_pages,
  509. alignment, offset, guard_pages);
  510. }
  511. }
  512. return address;
  513. }
  514. Result KPageTable::MakePageGroup(KPageGroup& pg, KProcessAddress addr, size_t num_pages) {
  515. ASSERT(this->IsLockedByCurrentThread());
  516. const size_t size = num_pages * PageSize;
  517. // We're making a new group, not adding to an existing one.
  518. R_UNLESS(pg.empty(), ResultInvalidCurrentMemory);
  519. // Begin traversal.
  520. Common::PageTable::TraversalContext context;
  521. Common::PageTable::TraversalEntry next_entry;
  522. R_UNLESS(m_page_table_impl->BeginTraversal(next_entry, context, GetInteger(addr)),
  523. ResultInvalidCurrentMemory);
  524. // Prepare tracking variables.
  525. KPhysicalAddress cur_addr = next_entry.phys_addr;
  526. size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
  527. size_t tot_size = cur_size;
  528. // Iterate, adding to group as we go.
  529. const auto& memory_layout = m_system.Kernel().MemoryLayout();
  530. while (tot_size < size) {
  531. R_UNLESS(m_page_table_impl->ContinueTraversal(next_entry, context),
  532. ResultInvalidCurrentMemory);
  533. if (next_entry.phys_addr != (cur_addr + cur_size)) {
  534. const size_t cur_pages = cur_size / PageSize;
  535. R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
  536. R_TRY(pg.AddBlock(cur_addr, cur_pages));
  537. cur_addr = next_entry.phys_addr;
  538. cur_size = next_entry.block_size;
  539. } else {
  540. cur_size += next_entry.block_size;
  541. }
  542. tot_size += next_entry.block_size;
  543. }
  544. // Ensure we add the right amount for the last block.
  545. if (tot_size > size) {
  546. cur_size -= (tot_size - size);
  547. }
  548. // Add the last block.
  549. const size_t cur_pages = cur_size / PageSize;
  550. R_UNLESS(IsHeapPhysicalAddress(memory_layout, cur_addr), ResultInvalidCurrentMemory);
  551. R_TRY(pg.AddBlock(cur_addr, cur_pages));
  552. R_SUCCEED();
  553. }
  554. bool KPageTable::IsValidPageGroup(const KPageGroup& pg, KProcessAddress addr, size_t num_pages) {
  555. ASSERT(this->IsLockedByCurrentThread());
  556. const size_t size = num_pages * PageSize;
  557. const auto& memory_layout = m_system.Kernel().MemoryLayout();
  558. // Empty groups are necessarily invalid.
  559. if (pg.empty()) {
  560. return false;
  561. }
  562. // We're going to validate that the group we'd expect is the group we see.
  563. auto cur_it = pg.begin();
  564. KPhysicalAddress cur_block_address = cur_it->GetAddress();
  565. size_t cur_block_pages = cur_it->GetNumPages();
  566. auto UpdateCurrentIterator = [&]() {
  567. if (cur_block_pages == 0) {
  568. if ((++cur_it) == pg.end()) {
  569. return false;
  570. }
  571. cur_block_address = cur_it->GetAddress();
  572. cur_block_pages = cur_it->GetNumPages();
  573. }
  574. return true;
  575. };
  576. // Begin traversal.
  577. Common::PageTable::TraversalContext context;
  578. Common::PageTable::TraversalEntry next_entry;
  579. if (!m_page_table_impl->BeginTraversal(next_entry, context, GetInteger(addr))) {
  580. return false;
  581. }
  582. // Prepare tracking variables.
  583. KPhysicalAddress cur_addr = next_entry.phys_addr;
  584. size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
  585. size_t tot_size = cur_size;
  586. // Iterate, comparing expected to actual.
  587. while (tot_size < size) {
  588. if (!m_page_table_impl->ContinueTraversal(next_entry, context)) {
  589. return false;
  590. }
  591. if (next_entry.phys_addr != (cur_addr + cur_size)) {
  592. const size_t cur_pages = cur_size / PageSize;
  593. if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
  594. return false;
  595. }
  596. if (!UpdateCurrentIterator()) {
  597. return false;
  598. }
  599. if (cur_block_address != cur_addr || cur_block_pages < cur_pages) {
  600. return false;
  601. }
  602. cur_block_address += cur_size;
  603. cur_block_pages -= cur_pages;
  604. cur_addr = next_entry.phys_addr;
  605. cur_size = next_entry.block_size;
  606. } else {
  607. cur_size += next_entry.block_size;
  608. }
  609. tot_size += next_entry.block_size;
  610. }
  611. // Ensure we compare the right amount for the last block.
  612. if (tot_size > size) {
  613. cur_size -= (tot_size - size);
  614. }
  615. if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
  616. return false;
  617. }
  618. if (!UpdateCurrentIterator()) {
  619. return false;
  620. }
  621. return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize);
  622. }
  623. Result KPageTable::UnmapProcessMemory(KProcessAddress dst_addr, size_t size,
  624. KPageTable& src_page_table, KProcessAddress src_addr) {
  625. // Acquire the table locks.
  626. KScopedLightLockPair lk(src_page_table.m_general_lock, m_general_lock);
  627. const size_t num_pages{size / PageSize};
  628. // Check that the memory is mapped in the destination process.
  629. size_t num_allocator_blocks;
  630. R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All,
  631. KMemoryState::SharedCode, KMemoryPermission::UserReadWrite,
  632. KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
  633. KMemoryAttribute::None));
  634. // Check that the memory is mapped in the source process.
  635. R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess,
  636. KMemoryState::FlagCanMapProcess, KMemoryPermission::None,
  637. KMemoryPermission::None, KMemoryAttribute::All,
  638. KMemoryAttribute::None));
  639. // Create an update allocator.
  640. Result allocator_result{ResultSuccess};
  641. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  642. m_memory_block_slab_manager, num_allocator_blocks);
  643. R_TRY(allocator_result);
  644. R_TRY(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
  645. // Apply the memory block update.
  646. m_memory_block_manager.Update(std::addressof(allocator), dst_addr, num_pages,
  647. KMemoryState::Free, KMemoryPermission::None,
  648. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
  649. KMemoryBlockDisableMergeAttribute::Normal);
  650. m_system.InvalidateCpuInstructionCaches();
  651. R_SUCCEED();
  652. }
  653. Result KPageTable::SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed,
  654. KProcessAddress address, size_t size,
  655. KMemoryPermission test_perm, KMemoryState dst_state) {
  656. // Validate pre-conditions.
  657. ASSERT(this->IsLockedByCurrentThread());
  658. ASSERT(test_perm == KMemoryPermission::UserReadWrite ||
  659. test_perm == KMemoryPermission::UserRead);
  660. // Check that the address is in range.
  661. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  662. // Get the source permission.
  663. const auto src_perm = (test_perm == KMemoryPermission::UserReadWrite)
  664. ? KMemoryPermission::KernelReadWrite | KMemoryPermission::NotMapped
  665. : KMemoryPermission::UserRead;
  666. // Get aligned extents.
  667. const KProcessAddress aligned_src_start = Common::AlignDown(GetInteger(address), PageSize);
  668. const KProcessAddress aligned_src_end = Common::AlignUp(GetInteger(address) + size, PageSize);
  669. const KProcessAddress mapping_src_start = Common::AlignUp(GetInteger(address), PageSize);
  670. const KProcessAddress mapping_src_end = Common::AlignDown(GetInteger(address) + size, PageSize);
  671. const auto aligned_src_last = (aligned_src_end)-1;
  672. const auto mapping_src_last = (mapping_src_end)-1;
  673. // Get the test state and attribute mask.
  674. KMemoryState test_state;
  675. KMemoryAttribute test_attr_mask;
  676. switch (dst_state) {
  677. case KMemoryState::Ipc:
  678. test_state = KMemoryState::FlagCanUseIpc;
  679. test_attr_mask =
  680. KMemoryAttribute::Uncached | KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked;
  681. break;
  682. case KMemoryState::NonSecureIpc:
  683. test_state = KMemoryState::FlagCanUseNonSecureIpc;
  684. test_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
  685. break;
  686. case KMemoryState::NonDeviceIpc:
  687. test_state = KMemoryState::FlagCanUseNonDeviceIpc;
  688. test_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
  689. break;
  690. default:
  691. R_THROW(ResultInvalidCombination);
  692. }
  693. // Ensure that on failure, we roll back appropriately.
  694. size_t mapped_size = 0;
  695. ON_RESULT_FAILURE {
  696. if (mapped_size > 0) {
  697. this->CleanupForIpcClientOnServerSetupFailure(page_list, mapping_src_start, mapped_size,
  698. src_perm);
  699. }
  700. };
  701. size_t blocks_needed = 0;
  702. // Iterate, mapping as needed.
  703. KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(aligned_src_start);
  704. while (true) {
  705. const KMemoryInfo info = it->GetMemoryInfo();
  706. // Validate the current block.
  707. R_TRY(this->CheckMemoryState(info, test_state, test_state, test_perm, test_perm,
  708. test_attr_mask, KMemoryAttribute::None));
  709. if (mapping_src_start < mapping_src_end && (mapping_src_start) < info.GetEndAddress() &&
  710. info.GetAddress() < GetInteger(mapping_src_end)) {
  711. const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start)
  712. ? info.GetAddress()
  713. : (mapping_src_start);
  714. const auto cur_end = mapping_src_last >= info.GetLastAddress() ? info.GetEndAddress()
  715. : (mapping_src_end);
  716. const size_t cur_size = cur_end - cur_start;
  717. if (info.GetAddress() < GetInteger(mapping_src_start)) {
  718. ++blocks_needed;
  719. }
  720. if (mapping_src_last < info.GetLastAddress()) {
  721. ++blocks_needed;
  722. }
  723. // Set the permissions on the block, if we need to.
  724. if ((info.GetPermission() & KMemoryPermission::IpcLockChangeMask) != src_perm) {
  725. R_TRY(Operate(cur_start, cur_size / PageSize, src_perm,
  726. OperationType::ChangePermissions));
  727. }
  728. // Note that we mapped this part.
  729. mapped_size += cur_size;
  730. }
  731. // If the block is at the end, we're done.
  732. if (aligned_src_last <= info.GetLastAddress()) {
  733. break;
  734. }
  735. // Advance.
  736. ++it;
  737. ASSERT(it != m_memory_block_manager.end());
  738. }
  739. if (out_blocks_needed != nullptr) {
  740. ASSERT(blocks_needed <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
  741. *out_blocks_needed = blocks_needed;
  742. }
  743. R_SUCCEED();
  744. }
  745. Result KPageTable::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
  746. KProcessAddress src_addr, KMemoryPermission test_perm,
  747. KMemoryState dst_state, KPageTable& src_page_table,
  748. bool send) {
  749. ASSERT(this->IsLockedByCurrentThread());
  750. ASSERT(src_page_table.IsLockedByCurrentThread());
  751. // Check that we can theoretically map.
  752. const KProcessAddress region_start = m_alias_region_start;
  753. const size_t region_size = m_alias_region_end - m_alias_region_start;
  754. R_UNLESS(size < region_size, ResultOutOfAddressSpace);
  755. // Get aligned source extents.
  756. const KProcessAddress src_start = src_addr;
  757. const KProcessAddress src_end = src_addr + size;
  758. const KProcessAddress aligned_src_start = Common::AlignDown(GetInteger(src_start), PageSize);
  759. const KProcessAddress aligned_src_end = Common::AlignUp(GetInteger(src_start) + size, PageSize);
  760. const KProcessAddress mapping_src_start = Common::AlignUp(GetInteger(src_start), PageSize);
  761. const KProcessAddress mapping_src_end =
  762. Common::AlignDown(GetInteger(src_start) + size, PageSize);
  763. const size_t aligned_src_size = aligned_src_end - aligned_src_start;
  764. const size_t mapping_src_size =
  765. (mapping_src_start < mapping_src_end) ? (mapping_src_end - mapping_src_start) : 0;
  766. // Select a random address to map at.
  767. KProcessAddress dst_addr =
  768. this->FindFreeArea(region_start, region_size / PageSize, aligned_src_size / PageSize,
  769. PageSize, 0, this->GetNumGuardPages());
  770. R_UNLESS(dst_addr != 0, ResultOutOfAddressSpace);
  771. // Check that we can perform the operation we're about to perform.
  772. ASSERT(this->CanContain(dst_addr, aligned_src_size, dst_state));
  773. // Create an update allocator.
  774. Result allocator_result;
  775. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  776. m_memory_block_slab_manager);
  777. R_TRY(allocator_result);
  778. // We're going to perform an update, so create a helper.
  779. KScopedPageTableUpdater updater(this);
  780. // Reserve space for any partial pages we allocate.
  781. const size_t unmapped_size = aligned_src_size - mapping_src_size;
  782. KScopedResourceReservation memory_reservation(
  783. m_resource_limit, LimitableResource::PhysicalMemoryMax, unmapped_size);
  784. R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
  785. // Ensure that we manage page references correctly.
  786. KPhysicalAddress start_partial_page = 0;
  787. KPhysicalAddress end_partial_page = 0;
  788. KProcessAddress cur_mapped_addr = dst_addr;
  789. // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
  790. // free on scope exit.
  791. SCOPE_EXIT({
  792. if (start_partial_page != 0) {
  793. m_system.Kernel().MemoryManager().Close(start_partial_page, 1);
  794. }
  795. if (end_partial_page != 0) {
  796. m_system.Kernel().MemoryManager().Close(end_partial_page, 1);
  797. }
  798. });
  799. ON_RESULT_FAILURE {
  800. if (cur_mapped_addr != dst_addr) {
  801. ASSERT(Operate(dst_addr, (cur_mapped_addr - dst_addr) / PageSize,
  802. KMemoryPermission::None, OperationType::Unmap)
  803. .IsSuccess());
  804. }
  805. };
  806. // Allocate the start page as needed.
  807. if (aligned_src_start < mapping_src_start) {
  808. start_partial_page =
  809. m_system.Kernel().MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option);
  810. R_UNLESS(start_partial_page != 0, ResultOutOfMemory);
  811. }
  812. // Allocate the end page as needed.
  813. if (mapping_src_end < aligned_src_end &&
  814. (aligned_src_start < mapping_src_end || aligned_src_start == mapping_src_start)) {
  815. end_partial_page =
  816. m_system.Kernel().MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option);
  817. R_UNLESS(end_partial_page != 0, ResultOutOfMemory);
  818. }
  819. // Get the implementation.
  820. auto& src_impl = src_page_table.PageTableImpl();
  821. // Get the fill value for partial pages.
  822. const auto fill_val = m_ipc_fill_value;
  823. // Begin traversal.
  824. Common::PageTable::TraversalContext context;
  825. Common::PageTable::TraversalEntry next_entry;
  826. bool traverse_valid =
  827. src_impl.BeginTraversal(next_entry, context, GetInteger(aligned_src_start));
  828. ASSERT(traverse_valid);
  829. // Prepare tracking variables.
  830. KPhysicalAddress cur_block_addr = next_entry.phys_addr;
  831. size_t cur_block_size =
  832. next_entry.block_size - ((cur_block_addr) & (next_entry.block_size - 1));
  833. size_t tot_block_size = cur_block_size;
  834. // Map the start page, if we have one.
  835. if (start_partial_page != 0) {
  836. // Ensure the page holds correct data.
  837. const KVirtualAddress start_partial_virt =
  838. GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), start_partial_page);
  839. if (send) {
  840. const size_t partial_offset = src_start - aligned_src_start;
  841. size_t copy_size, clear_size;
  842. if (src_end < mapping_src_start) {
  843. copy_size = size;
  844. clear_size = mapping_src_start - src_end;
  845. } else {
  846. copy_size = mapping_src_start - src_start;
  847. clear_size = 0;
  848. }
  849. std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val,
  850. partial_offset);
  851. std::memcpy(
  852. m_memory->GetPointer<void>(GetInteger(start_partial_virt) + partial_offset),
  853. m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress(
  854. m_system.Kernel().MemoryLayout(), cur_block_addr)) +
  855. partial_offset),
  856. copy_size);
  857. if (clear_size > 0) {
  858. std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt) +
  859. partial_offset + copy_size),
  860. fill_val, clear_size);
  861. }
  862. } else {
  863. std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val,
  864. PageSize);
  865. }
  866. // Map the page.
  867. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, start_partial_page));
  868. // Update tracking extents.
  869. cur_mapped_addr += PageSize;
  870. cur_block_addr += PageSize;
  871. cur_block_size -= PageSize;
  872. // If the block's size was one page, we may need to continue traversal.
  873. if (cur_block_size == 0 && aligned_src_size > PageSize) {
  874. traverse_valid = src_impl.ContinueTraversal(next_entry, context);
  875. ASSERT(traverse_valid);
  876. cur_block_addr = next_entry.phys_addr;
  877. cur_block_size = next_entry.block_size;
  878. tot_block_size += next_entry.block_size;
  879. }
  880. }
  881. // Map the remaining pages.
  882. while (aligned_src_start + tot_block_size < mapping_src_end) {
  883. // Continue the traversal.
  884. traverse_valid = src_impl.ContinueTraversal(next_entry, context);
  885. ASSERT(traverse_valid);
  886. // Process the block.
  887. if (next_entry.phys_addr != cur_block_addr + cur_block_size) {
  888. // Map the block we've been processing so far.
  889. R_TRY(Operate(cur_mapped_addr, cur_block_size / PageSize, test_perm, OperationType::Map,
  890. cur_block_addr));
  891. // Update tracking extents.
  892. cur_mapped_addr += cur_block_size;
  893. cur_block_addr = next_entry.phys_addr;
  894. cur_block_size = next_entry.block_size;
  895. } else {
  896. cur_block_size += next_entry.block_size;
  897. }
  898. tot_block_size += next_entry.block_size;
  899. }
  900. // Handle the last direct-mapped page.
  901. if (const KProcessAddress mapped_block_end =
  902. aligned_src_start + tot_block_size - cur_block_size;
  903. mapped_block_end < mapping_src_end) {
  904. const size_t last_block_size = mapping_src_end - mapped_block_end;
  905. // Map the last block.
  906. R_TRY(Operate(cur_mapped_addr, last_block_size / PageSize, test_perm, OperationType::Map,
  907. cur_block_addr));
  908. // Update tracking extents.
  909. cur_mapped_addr += last_block_size;
  910. cur_block_addr += last_block_size;
  911. if (mapped_block_end + cur_block_size < aligned_src_end &&
  912. cur_block_size == last_block_size) {
  913. traverse_valid = src_impl.ContinueTraversal(next_entry, context);
  914. ASSERT(traverse_valid);
  915. cur_block_addr = next_entry.phys_addr;
  916. }
  917. }
  918. // Map the end page, if we have one.
  919. if (end_partial_page != 0) {
  920. // Ensure the page holds correct data.
  921. const KVirtualAddress end_partial_virt =
  922. GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), end_partial_page);
  923. if (send) {
  924. const size_t copy_size = src_end - mapping_src_end;
  925. std::memcpy(m_memory->GetPointer<void>(GetInteger(end_partial_virt)),
  926. m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress(
  927. m_system.Kernel().MemoryLayout(), cur_block_addr))),
  928. copy_size);
  929. std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt) + copy_size),
  930. fill_val, PageSize - copy_size);
  931. } else {
  932. std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt)), fill_val,
  933. PageSize);
  934. }
  935. // Map the page.
  936. R_TRY(Operate(cur_mapped_addr, 1, test_perm, OperationType::Map, end_partial_page));
  937. }
  938. // Update memory blocks to reflect our changes
  939. m_memory_block_manager.Update(std::addressof(allocator), dst_addr, aligned_src_size / PageSize,
  940. dst_state, test_perm, KMemoryAttribute::None,
  941. KMemoryBlockDisableMergeAttribute::Normal,
  942. KMemoryBlockDisableMergeAttribute::None);
  943. // Set the output address.
  944. *out_addr = dst_addr + (src_start - aligned_src_start);
  945. // We succeeded.
  946. memory_reservation.Commit();
  947. R_SUCCEED();
  948. }
  949. Result KPageTable::SetupForIpc(KProcessAddress* out_dst_addr, size_t size, KProcessAddress src_addr,
  950. KPageTable& src_page_table, KMemoryPermission test_perm,
  951. KMemoryState dst_state, bool send) {
  952. // For convenience, alias this.
  953. KPageTable& dst_page_table = *this;
  954. // Acquire the table locks.
  955. KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock);
  956. // We're going to perform an update, so create a helper.
  957. KScopedPageTableUpdater updater(std::addressof(src_page_table));
  958. // Perform client setup.
  959. size_t num_allocator_blocks;
  960. R_TRY(src_page_table.SetupForIpcClient(updater.GetPageList(),
  961. std::addressof(num_allocator_blocks), src_addr, size,
  962. test_perm, dst_state));
  963. // Create an update allocator.
  964. Result allocator_result;
  965. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  966. src_page_table.m_memory_block_slab_manager,
  967. num_allocator_blocks);
  968. R_TRY(allocator_result);
  969. // Get the mapped extents.
  970. const KProcessAddress src_map_start = Common::AlignUp(GetInteger(src_addr), PageSize);
  971. const KProcessAddress src_map_end = Common::AlignDown(GetInteger(src_addr) + size, PageSize);
  972. const size_t src_map_size = src_map_end - src_map_start;
  973. // Ensure that we clean up appropriately if we fail after this.
  974. const auto src_perm = (test_perm == KMemoryPermission::UserReadWrite)
  975. ? KMemoryPermission::KernelReadWrite | KMemoryPermission::NotMapped
  976. : KMemoryPermission::UserRead;
  977. ON_RESULT_FAILURE {
  978. if (src_map_end > src_map_start) {
  979. src_page_table.CleanupForIpcClientOnServerSetupFailure(
  980. updater.GetPageList(), src_map_start, src_map_size, src_perm);
  981. }
  982. };
  983. // Perform server setup.
  984. R_TRY(dst_page_table.SetupForIpcServer(out_dst_addr, size, src_addr, test_perm, dst_state,
  985. src_page_table, send));
  986. // If anything was mapped, ipc-lock the pages.
  987. if (src_map_start < src_map_end) {
  988. // Get the source permission.
  989. src_page_table.m_memory_block_manager.UpdateLock(std::addressof(allocator), src_map_start,
  990. (src_map_end - src_map_start) / PageSize,
  991. &KMemoryBlock::LockForIpc, src_perm);
  992. }
  993. R_SUCCEED();
  994. }
  995. Result KPageTable::CleanupForIpcServer(KProcessAddress address, size_t size,
  996. KMemoryState dst_state) {
  997. // Validate the address.
  998. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  999. // Lock the table.
  1000. KScopedLightLock lk(m_general_lock);
  1001. // Validate the memory state.
  1002. size_t num_allocator_blocks;
  1003. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
  1004. KMemoryState::All, dst_state, KMemoryPermission::UserRead,
  1005. KMemoryPermission::UserRead, KMemoryAttribute::All,
  1006. KMemoryAttribute::None));
  1007. // Create an update allocator.
  1008. Result allocator_result;
  1009. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1010. m_memory_block_slab_manager, num_allocator_blocks);
  1011. R_TRY(allocator_result);
  1012. // We're going to perform an update, so create a helper.
  1013. KScopedPageTableUpdater updater(this);
  1014. // Get aligned extents.
  1015. const KProcessAddress aligned_start = Common::AlignDown(GetInteger(address), PageSize);
  1016. const KProcessAddress aligned_end = Common::AlignUp(GetInteger(address) + size, PageSize);
  1017. const size_t aligned_size = aligned_end - aligned_start;
  1018. const size_t aligned_num_pages = aligned_size / PageSize;
  1019. // Unmap the pages.
  1020. R_TRY(Operate(aligned_start, aligned_num_pages, KMemoryPermission::None, OperationType::Unmap));
  1021. // Update memory blocks.
  1022. m_memory_block_manager.Update(std::addressof(allocator), aligned_start, aligned_num_pages,
  1023. KMemoryState::None, KMemoryPermission::None,
  1024. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
  1025. KMemoryBlockDisableMergeAttribute::Normal);
  1026. // Release from the resource limit as relevant.
  1027. const KProcessAddress mapping_start = Common::AlignUp(GetInteger(address), PageSize);
  1028. const KProcessAddress mapping_end = Common::AlignDown(GetInteger(address) + size, PageSize);
  1029. const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0;
  1030. m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, aligned_size - mapping_size);
  1031. R_SUCCEED();
  1032. }
  1033. Result KPageTable::CleanupForIpcClient(KProcessAddress address, size_t size,
  1034. KMemoryState dst_state) {
  1035. // Validate the address.
  1036. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  1037. // Get aligned source extents.
  1038. const KProcessAddress mapping_start = Common::AlignUp(GetInteger(address), PageSize);
  1039. const KProcessAddress mapping_end = Common::AlignDown(GetInteger(address) + size, PageSize);
  1040. const KProcessAddress mapping_last = mapping_end - 1;
  1041. const size_t mapping_size = (mapping_start < mapping_end) ? (mapping_end - mapping_start) : 0;
  1042. // If nothing was mapped, we're actually done immediately.
  1043. R_SUCCEED_IF(mapping_size == 0);
  1044. // Get the test state and attribute mask.
  1045. KMemoryState test_state;
  1046. KMemoryAttribute test_attr_mask;
  1047. switch (dst_state) {
  1048. case KMemoryState::Ipc:
  1049. test_state = KMemoryState::FlagCanUseIpc;
  1050. test_attr_mask =
  1051. KMemoryAttribute::Uncached | KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked;
  1052. break;
  1053. case KMemoryState::NonSecureIpc:
  1054. test_state = KMemoryState::FlagCanUseNonSecureIpc;
  1055. test_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
  1056. break;
  1057. case KMemoryState::NonDeviceIpc:
  1058. test_state = KMemoryState::FlagCanUseNonDeviceIpc;
  1059. test_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked;
  1060. break;
  1061. default:
  1062. R_THROW(ResultInvalidCombination);
  1063. }
  1064. // Lock the table.
  1065. // NOTE: Nintendo does this *after* creating the updater below, but this does not follow
  1066. // convention elsewhere in KPageTable.
  1067. KScopedLightLock lk(m_general_lock);
  1068. // We're going to perform an update, so create a helper.
  1069. KScopedPageTableUpdater updater(this);
  1070. // Ensure that on failure, we roll back appropriately.
  1071. size_t mapped_size = 0;
  1072. ON_RESULT_FAILURE {
  1073. if (mapped_size > 0) {
  1074. // Determine where the mapping ends.
  1075. const auto mapped_end = (mapping_start) + mapped_size;
  1076. const auto mapped_last = mapped_end - 1;
  1077. // Get current and next iterators.
  1078. KMemoryBlockManager::const_iterator start_it =
  1079. m_memory_block_manager.FindIterator(mapping_start);
  1080. KMemoryBlockManager::const_iterator next_it = start_it;
  1081. ++next_it;
  1082. // Get the current block info.
  1083. KMemoryInfo cur_info = start_it->GetMemoryInfo();
  1084. // Create tracking variables.
  1085. KProcessAddress cur_address = cur_info.GetAddress();
  1086. size_t cur_size = cur_info.GetSize();
  1087. bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
  1088. bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
  1089. bool first =
  1090. cur_info.GetIpcDisableMergeCount() == 1 &&
  1091. (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Locked) ==
  1092. KMemoryBlockDisableMergeAttribute::None;
  1093. while (((cur_address) + cur_size - 1) < mapped_last) {
  1094. // Check that we have a next block.
  1095. ASSERT(next_it != m_memory_block_manager.end());
  1096. // Get the next info.
  1097. const KMemoryInfo next_info = next_it->GetMemoryInfo();
  1098. // Check if we can consolidate the next block's permission set with the current one.
  1099. const bool next_perm_eq =
  1100. next_info.GetPermission() == next_info.GetOriginalPermission();
  1101. const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1;
  1102. if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm &&
  1103. cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) {
  1104. // We can consolidate the reprotection for the current and next block into a
  1105. // single call.
  1106. cur_size += next_info.GetSize();
  1107. } else {
  1108. // We have to operate on the current block.
  1109. if ((cur_needs_set_perm || first) && !cur_perm_eq) {
  1110. ASSERT(Operate(cur_address, cur_size / PageSize, cur_info.GetPermission(),
  1111. OperationType::ChangePermissions)
  1112. .IsSuccess());
  1113. }
  1114. // Advance.
  1115. cur_address = next_info.GetAddress();
  1116. cur_size = next_info.GetSize();
  1117. first = false;
  1118. }
  1119. // Advance.
  1120. cur_info = next_info;
  1121. cur_perm_eq = next_perm_eq;
  1122. cur_needs_set_perm = next_needs_set_perm;
  1123. ++next_it;
  1124. }
  1125. // Process the last block.
  1126. if ((first || cur_needs_set_perm) && !cur_perm_eq) {
  1127. ASSERT(Operate(cur_address, cur_size / PageSize, cur_info.GetPermission(),
  1128. OperationType::ChangePermissions)
  1129. .IsSuccess());
  1130. }
  1131. }
  1132. };
  1133. // Iterate, reprotecting as needed.
  1134. {
  1135. // Get current and next iterators.
  1136. KMemoryBlockManager::const_iterator start_it =
  1137. m_memory_block_manager.FindIterator(mapping_start);
  1138. KMemoryBlockManager::const_iterator next_it = start_it;
  1139. ++next_it;
  1140. // Validate the current block.
  1141. KMemoryInfo cur_info = start_it->GetMemoryInfo();
  1142. ASSERT(this->CheckMemoryState(cur_info, test_state, test_state, KMemoryPermission::None,
  1143. KMemoryPermission::None,
  1144. test_attr_mask | KMemoryAttribute::IpcLocked,
  1145. KMemoryAttribute::IpcLocked)
  1146. .IsSuccess());
  1147. // Create tracking variables.
  1148. KProcessAddress cur_address = cur_info.GetAddress();
  1149. size_t cur_size = cur_info.GetSize();
  1150. bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
  1151. bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
  1152. bool first =
  1153. cur_info.GetIpcDisableMergeCount() == 1 &&
  1154. (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Locked) ==
  1155. KMemoryBlockDisableMergeAttribute::None;
  1156. while ((cur_address + cur_size - 1) < mapping_last) {
  1157. // Check that we have a next block.
  1158. ASSERT(next_it != m_memory_block_manager.end());
  1159. // Get the next info.
  1160. const KMemoryInfo next_info = next_it->GetMemoryInfo();
  1161. // Validate the next block.
  1162. ASSERT(this->CheckMemoryState(next_info, test_state, test_state,
  1163. KMemoryPermission::None, KMemoryPermission::None,
  1164. test_attr_mask | KMemoryAttribute::IpcLocked,
  1165. KMemoryAttribute::IpcLocked)
  1166. .IsSuccess());
  1167. // Check if we can consolidate the next block's permission set with the current one.
  1168. const bool next_perm_eq =
  1169. next_info.GetPermission() == next_info.GetOriginalPermission();
  1170. const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1;
  1171. if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm &&
  1172. cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) {
  1173. // We can consolidate the reprotection for the current and next block into a single
  1174. // call.
  1175. cur_size += next_info.GetSize();
  1176. } else {
  1177. // We have to operate on the current block.
  1178. if ((cur_needs_set_perm || first) && !cur_perm_eq) {
  1179. R_TRY(Operate(cur_address, cur_size / PageSize,
  1180. cur_needs_set_perm ? cur_info.GetOriginalPermission()
  1181. : cur_info.GetPermission(),
  1182. OperationType::ChangePermissions));
  1183. }
  1184. // Mark that we mapped the block.
  1185. mapped_size += cur_size;
  1186. // Advance.
  1187. cur_address = next_info.GetAddress();
  1188. cur_size = next_info.GetSize();
  1189. first = false;
  1190. }
  1191. // Advance.
  1192. cur_info = next_info;
  1193. cur_perm_eq = next_perm_eq;
  1194. cur_needs_set_perm = next_needs_set_perm;
  1195. ++next_it;
  1196. }
  1197. // Process the last block.
  1198. const auto lock_count =
  1199. cur_info.GetIpcLockCount() +
  1200. (next_it != m_memory_block_manager.end()
  1201. ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount())
  1202. : 0);
  1203. if ((first || cur_needs_set_perm || (lock_count == 1)) && !cur_perm_eq) {
  1204. R_TRY(Operate(cur_address, cur_size / PageSize,
  1205. cur_needs_set_perm ? cur_info.GetOriginalPermission()
  1206. : cur_info.GetPermission(),
  1207. OperationType::ChangePermissions));
  1208. }
  1209. }
  1210. // Create an update allocator.
  1211. // NOTE: Guaranteed zero blocks needed here.
  1212. Result allocator_result;
  1213. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1214. m_memory_block_slab_manager, 0);
  1215. R_TRY(allocator_result);
  1216. // Unlock the pages.
  1217. m_memory_block_manager.UpdateLock(std::addressof(allocator), mapping_start,
  1218. mapping_size / PageSize, &KMemoryBlock::UnlockForIpc,
  1219. KMemoryPermission::None);
  1220. R_SUCCEED();
  1221. }
  1222. void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLinkedList* page_list,
  1223. KProcessAddress address, size_t size,
  1224. KMemoryPermission prot_perm) {
  1225. ASSERT(this->IsLockedByCurrentThread());
  1226. ASSERT(Common::IsAligned(GetInteger(address), PageSize));
  1227. ASSERT(Common::IsAligned(size, PageSize));
  1228. // Get the mapped extents.
  1229. const KProcessAddress src_map_start = address;
  1230. const KProcessAddress src_map_end = address + size;
  1231. const KProcessAddress src_map_last = src_map_end - 1;
  1232. // This function is only invoked when there's something to do.
  1233. ASSERT(src_map_end > src_map_start);
  1234. // Iterate over blocks, fixing permissions.
  1235. KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address);
  1236. while (true) {
  1237. const KMemoryInfo info = it->GetMemoryInfo();
  1238. const auto cur_start = info.GetAddress() >= GetInteger(src_map_start)
  1239. ? info.GetAddress()
  1240. : GetInteger(src_map_start);
  1241. const auto cur_end =
  1242. src_map_last <= info.GetLastAddress() ? src_map_end : info.GetEndAddress();
  1243. // If we can, fix the protections on the block.
  1244. if ((info.GetIpcLockCount() == 0 &&
  1245. (info.GetPermission() & KMemoryPermission::IpcLockChangeMask) != prot_perm) ||
  1246. (info.GetIpcLockCount() != 0 &&
  1247. (info.GetOriginalPermission() & KMemoryPermission::IpcLockChangeMask) != prot_perm)) {
  1248. // Check if we actually need to fix the protections on the block.
  1249. if (cur_end == src_map_end || info.GetAddress() <= GetInteger(src_map_start) ||
  1250. (info.GetPermission() & KMemoryPermission::IpcLockChangeMask) != prot_perm) {
  1251. ASSERT(Operate(cur_start, (cur_end - cur_start) / PageSize, info.GetPermission(),
  1252. OperationType::ChangePermissions)
  1253. .IsSuccess());
  1254. }
  1255. }
  1256. // If we're past the end of the region, we're done.
  1257. if (src_map_last <= info.GetLastAddress()) {
  1258. break;
  1259. }
  1260. // Advance.
  1261. ++it;
  1262. ASSERT(it != m_memory_block_manager.end());
  1263. }
  1264. }
  1265. Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
  1266. // Lock the physical memory lock.
  1267. KScopedLightLock phys_lk(m_map_physical_memory_lock);
  1268. // Calculate the last address for convenience.
  1269. const KProcessAddress last_address = address + size - 1;
  1270. // Define iteration variables.
  1271. KProcessAddress cur_address;
  1272. size_t mapped_size;
  1273. // The entire mapping process can be retried.
  1274. while (true) {
  1275. // Check if the memory is already mapped.
  1276. {
  1277. // Lock the table.
  1278. KScopedLightLock lk(m_general_lock);
  1279. // Iterate over the memory.
  1280. cur_address = address;
  1281. mapped_size = 0;
  1282. auto it = m_memory_block_manager.FindIterator(cur_address);
  1283. while (true) {
  1284. // Check that the iterator is valid.
  1285. ASSERT(it != m_memory_block_manager.end());
  1286. // Get the memory info.
  1287. const KMemoryInfo info = it->GetMemoryInfo();
  1288. // Check if we're done.
  1289. if (last_address <= info.GetLastAddress()) {
  1290. if (info.GetState() != KMemoryState::Free) {
  1291. mapped_size += (last_address + 1 - cur_address);
  1292. }
  1293. break;
  1294. }
  1295. // Track the memory if it's mapped.
  1296. if (info.GetState() != KMemoryState::Free) {
  1297. mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
  1298. }
  1299. // Advance.
  1300. cur_address = info.GetEndAddress();
  1301. ++it;
  1302. }
  1303. // If the size mapped is the size requested, we've nothing to do.
  1304. R_SUCCEED_IF(size == mapped_size);
  1305. }
  1306. // Allocate and map the memory.
  1307. {
  1308. // Reserve the memory from the process resource limit.
  1309. KScopedResourceReservation memory_reservation(
  1310. m_resource_limit, LimitableResource::PhysicalMemoryMax, size - mapped_size);
  1311. R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
  1312. // Allocate pages for the new memory.
  1313. KPageGroup pg{m_kernel, m_block_info_manager};
  1314. R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess(
  1315. &pg, (size - mapped_size) / PageSize, m_allocate_option, 0, 0));
  1316. // If we fail in the next bit (or retry), we need to cleanup the pages.
  1317. // auto pg_guard = SCOPE_GUARD {
  1318. // pg.OpenFirst();
  1319. // pg.Close();
  1320. //};
  1321. // Map the memory.
  1322. {
  1323. // Lock the table.
  1324. KScopedLightLock lk(m_general_lock);
  1325. size_t num_allocator_blocks = 0;
  1326. // Verify that nobody has mapped memory since we first checked.
  1327. {
  1328. // Iterate over the memory.
  1329. size_t checked_mapped_size = 0;
  1330. cur_address = address;
  1331. auto it = m_memory_block_manager.FindIterator(cur_address);
  1332. while (true) {
  1333. // Check that the iterator is valid.
  1334. ASSERT(it != m_memory_block_manager.end());
  1335. // Get the memory info.
  1336. const KMemoryInfo info = it->GetMemoryInfo();
  1337. const bool is_free = info.GetState() == KMemoryState::Free;
  1338. if (is_free) {
  1339. if (info.GetAddress() < GetInteger(address)) {
  1340. ++num_allocator_blocks;
  1341. }
  1342. if (last_address < info.GetLastAddress()) {
  1343. ++num_allocator_blocks;
  1344. }
  1345. }
  1346. // Check if we're done.
  1347. if (last_address <= info.GetLastAddress()) {
  1348. if (!is_free) {
  1349. checked_mapped_size += (last_address + 1 - cur_address);
  1350. }
  1351. break;
  1352. }
  1353. // Track the memory if it's mapped.
  1354. if (!is_free) {
  1355. checked_mapped_size +=
  1356. KProcessAddress(info.GetEndAddress()) - cur_address;
  1357. }
  1358. // Advance.
  1359. cur_address = info.GetEndAddress();
  1360. ++it;
  1361. }
  1362. // If the size now isn't what it was before, somebody mapped or unmapped
  1363. // concurrently. If this happened, retry.
  1364. if (mapped_size != checked_mapped_size) {
  1365. continue;
  1366. }
  1367. }
  1368. // Create an update allocator.
  1369. ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
  1370. Result allocator_result;
  1371. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1372. m_memory_block_slab_manager,
  1373. num_allocator_blocks);
  1374. R_TRY(allocator_result);
  1375. // We're going to perform an update, so create a helper.
  1376. KScopedPageTableUpdater updater(this);
  1377. // Prepare to iterate over the memory.
  1378. auto pg_it = pg.begin();
  1379. KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
  1380. size_t pg_pages = pg_it->GetNumPages();
  1381. // Reset the current tracking address, and make sure we clean up on failure.
  1382. // pg_guard.Cancel();
  1383. cur_address = address;
  1384. ON_RESULT_FAILURE {
  1385. if (cur_address > address) {
  1386. const KProcessAddress last_unmap_address = cur_address - 1;
  1387. // Iterate, unmapping the pages.
  1388. cur_address = address;
  1389. auto it = m_memory_block_manager.FindIterator(cur_address);
  1390. while (true) {
  1391. // Check that the iterator is valid.
  1392. ASSERT(it != m_memory_block_manager.end());
  1393. // Get the memory info.
  1394. const KMemoryInfo info = it->GetMemoryInfo();
  1395. // If the memory state is free, we mapped it and need to unmap it.
  1396. if (info.GetState() == KMemoryState::Free) {
  1397. // Determine the range to unmap.
  1398. const size_t cur_pages =
  1399. std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
  1400. last_unmap_address + 1 - cur_address) /
  1401. PageSize;
  1402. // Unmap.
  1403. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None,
  1404. OperationType::Unmap)
  1405. .IsSuccess());
  1406. }
  1407. // Check if we're done.
  1408. if (last_unmap_address <= info.GetLastAddress()) {
  1409. break;
  1410. }
  1411. // Advance.
  1412. cur_address = info.GetEndAddress();
  1413. ++it;
  1414. }
  1415. }
  1416. // Release any remaining unmapped memory.
  1417. m_system.Kernel().MemoryManager().OpenFirst(pg_phys_addr, pg_pages);
  1418. m_system.Kernel().MemoryManager().Close(pg_phys_addr, pg_pages);
  1419. for (++pg_it; pg_it != pg.end(); ++pg_it) {
  1420. m_system.Kernel().MemoryManager().OpenFirst(pg_it->GetAddress(),
  1421. pg_it->GetNumPages());
  1422. m_system.Kernel().MemoryManager().Close(pg_it->GetAddress(),
  1423. pg_it->GetNumPages());
  1424. }
  1425. };
  1426. auto it = m_memory_block_manager.FindIterator(cur_address);
  1427. while (true) {
  1428. // Check that the iterator is valid.
  1429. ASSERT(it != m_memory_block_manager.end());
  1430. // Get the memory info.
  1431. const KMemoryInfo info = it->GetMemoryInfo();
  1432. // If it's unmapped, we need to map it.
  1433. if (info.GetState() == KMemoryState::Free) {
  1434. // Determine the range to map.
  1435. size_t map_pages =
  1436. std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
  1437. last_address + 1 - cur_address) /
  1438. PageSize;
  1439. // While we have pages to map, map them.
  1440. {
  1441. // Create a page group for the current mapping range.
  1442. KPageGroup cur_pg(m_kernel, m_block_info_manager);
  1443. {
  1444. ON_RESULT_FAILURE_2 {
  1445. cur_pg.OpenFirst();
  1446. cur_pg.Close();
  1447. };
  1448. size_t remain_pages = map_pages;
  1449. while (remain_pages > 0) {
  1450. // Check if we're at the end of the physical block.
  1451. if (pg_pages == 0) {
  1452. // Ensure there are more pages to map.
  1453. ASSERT(pg_it != pg.end());
  1454. // Advance our physical block.
  1455. ++pg_it;
  1456. pg_phys_addr = pg_it->GetAddress();
  1457. pg_pages = pg_it->GetNumPages();
  1458. }
  1459. // Add whatever we can to the current block.
  1460. const size_t cur_pages = std::min(pg_pages, remain_pages);
  1461. R_TRY(cur_pg.AddBlock(pg_phys_addr +
  1462. ((pg_pages - cur_pages) * PageSize),
  1463. cur_pages));
  1464. // Advance.
  1465. remain_pages -= cur_pages;
  1466. pg_pages -= cur_pages;
  1467. }
  1468. }
  1469. // Map the pages.
  1470. R_TRY(this->Operate(cur_address, map_pages, cur_pg,
  1471. OperationType::MapFirstGroup));
  1472. }
  1473. }
  1474. // Check if we're done.
  1475. if (last_address <= info.GetLastAddress()) {
  1476. break;
  1477. }
  1478. // Advance.
  1479. cur_address = info.GetEndAddress();
  1480. ++it;
  1481. }
  1482. // We succeeded, so commit the memory reservation.
  1483. memory_reservation.Commit();
  1484. // Increase our tracked mapped size.
  1485. m_mapped_physical_memory_size += (size - mapped_size);
  1486. // Update the relevant memory blocks.
  1487. m_memory_block_manager.UpdateIfMatch(
  1488. std::addressof(allocator), address, size / PageSize, KMemoryState::Free,
  1489. KMemoryPermission::None, KMemoryAttribute::None, KMemoryState::Normal,
  1490. KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
  1491. address == this->GetAliasRegionStart()
  1492. ? KMemoryBlockDisableMergeAttribute::Normal
  1493. : KMemoryBlockDisableMergeAttribute::None,
  1494. KMemoryBlockDisableMergeAttribute::None);
  1495. R_SUCCEED();
  1496. }
  1497. }
  1498. }
  1499. }
  1500. Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
  1501. // Lock the physical memory lock.
  1502. KScopedLightLock phys_lk(m_map_physical_memory_lock);
  1503. // Lock the table.
  1504. KScopedLightLock lk(m_general_lock);
  1505. // Calculate the last address for convenience.
  1506. const KProcessAddress last_address = address + size - 1;
  1507. // Define iteration variables.
  1508. KProcessAddress map_start_address = 0;
  1509. KProcessAddress map_last_address = 0;
  1510. KProcessAddress cur_address;
  1511. size_t mapped_size;
  1512. size_t num_allocator_blocks = 0;
  1513. // Check if the memory is mapped.
  1514. {
  1515. // Iterate over the memory.
  1516. cur_address = address;
  1517. mapped_size = 0;
  1518. auto it = m_memory_block_manager.FindIterator(cur_address);
  1519. while (true) {
  1520. // Check that the iterator is valid.
  1521. ASSERT(it != m_memory_block_manager.end());
  1522. // Get the memory info.
  1523. const KMemoryInfo info = it->GetMemoryInfo();
  1524. // Verify the memory's state.
  1525. const bool is_normal = info.GetState() == KMemoryState::Normal &&
  1526. info.GetAttribute() == KMemoryAttribute::None;
  1527. const bool is_free = info.GetState() == KMemoryState::Free;
  1528. R_UNLESS(is_normal || is_free, ResultInvalidCurrentMemory);
  1529. if (is_normal) {
  1530. R_UNLESS(info.GetAttribute() == KMemoryAttribute::None, ResultInvalidCurrentMemory);
  1531. if (map_start_address == 0) {
  1532. map_start_address = cur_address;
  1533. }
  1534. map_last_address =
  1535. (last_address >= info.GetLastAddress()) ? info.GetLastAddress() : last_address;
  1536. if (info.GetAddress() < GetInteger(address)) {
  1537. ++num_allocator_blocks;
  1538. }
  1539. if (last_address < info.GetLastAddress()) {
  1540. ++num_allocator_blocks;
  1541. }
  1542. mapped_size += (map_last_address + 1 - cur_address);
  1543. }
  1544. // Check if we're done.
  1545. if (last_address <= info.GetLastAddress()) {
  1546. break;
  1547. }
  1548. // Advance.
  1549. cur_address = info.GetEndAddress();
  1550. ++it;
  1551. }
  1552. // If there's nothing mapped, we've nothing to do.
  1553. R_SUCCEED_IF(mapped_size == 0);
  1554. }
  1555. // Create an update allocator.
  1556. ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
  1557. Result allocator_result;
  1558. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1559. m_memory_block_slab_manager, num_allocator_blocks);
  1560. R_TRY(allocator_result);
  1561. // We're going to perform an update, so create a helper.
  1562. KScopedPageTableUpdater updater(this);
  1563. // Separate the mapping.
  1564. R_TRY(Operate(map_start_address, (map_last_address + 1 - map_start_address) / PageSize,
  1565. KMemoryPermission::None, OperationType::Separate));
  1566. // Reset the current tracking address, and make sure we clean up on failure.
  1567. cur_address = address;
  1568. // Iterate over the memory, unmapping as we go.
  1569. auto it = m_memory_block_manager.FindIterator(cur_address);
  1570. const auto clear_merge_attr =
  1571. (it->GetState() == KMemoryState::Normal &&
  1572. it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address)
  1573. ? KMemoryBlockDisableMergeAttribute::Normal
  1574. : KMemoryBlockDisableMergeAttribute::None;
  1575. while (true) {
  1576. // Check that the iterator is valid.
  1577. ASSERT(it != m_memory_block_manager.end());
  1578. // Get the memory info.
  1579. const KMemoryInfo info = it->GetMemoryInfo();
  1580. // If the memory state is normal, we need to unmap it.
  1581. if (info.GetState() == KMemoryState::Normal) {
  1582. // Determine the range to unmap.
  1583. const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
  1584. last_address + 1 - cur_address) /
  1585. PageSize;
  1586. // Unmap.
  1587. ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap)
  1588. .IsSuccess());
  1589. }
  1590. // Check if we're done.
  1591. if (last_address <= info.GetLastAddress()) {
  1592. break;
  1593. }
  1594. // Advance.
  1595. cur_address = info.GetEndAddress();
  1596. ++it;
  1597. }
  1598. // Release the memory resource.
  1599. m_mapped_physical_memory_size -= mapped_size;
  1600. m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, mapped_size);
  1601. // Update memory blocks.
  1602. m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize,
  1603. KMemoryState::Free, KMemoryPermission::None,
  1604. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
  1605. clear_merge_attr);
  1606. // We succeeded.
  1607. R_SUCCEED();
  1608. }
  1609. Result KPageTable::MapMemory(KProcessAddress dst_address, KProcessAddress src_address,
  1610. size_t size) {
  1611. // Lock the table.
  1612. KScopedLightLock lk(m_general_lock);
  1613. // Validate that the source address's state is valid.
  1614. KMemoryState src_state;
  1615. size_t num_src_allocator_blocks;
  1616. R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr,
  1617. std::addressof(num_src_allocator_blocks), src_address, size,
  1618. KMemoryState::FlagCanAlias, KMemoryState::FlagCanAlias,
  1619. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  1620. KMemoryAttribute::All, KMemoryAttribute::None));
  1621. // Validate that the dst address's state is valid.
  1622. size_t num_dst_allocator_blocks;
  1623. R_TRY(this->CheckMemoryState(std::addressof(num_dst_allocator_blocks), dst_address, size,
  1624. KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
  1625. KMemoryPermission::None, KMemoryAttribute::None,
  1626. KMemoryAttribute::None));
  1627. // Create an update allocator for the source.
  1628. Result src_allocator_result;
  1629. KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
  1630. m_memory_block_slab_manager,
  1631. num_src_allocator_blocks);
  1632. R_TRY(src_allocator_result);
  1633. // Create an update allocator for the destination.
  1634. Result dst_allocator_result;
  1635. KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
  1636. m_memory_block_slab_manager,
  1637. num_dst_allocator_blocks);
  1638. R_TRY(dst_allocator_result);
  1639. // Map the memory.
  1640. {
  1641. // Determine the number of pages being operated on.
  1642. const size_t num_pages = size / PageSize;
  1643. // Create page groups for the memory being unmapped.
  1644. KPageGroup pg{m_kernel, m_block_info_manager};
  1645. // Create the page group representing the source.
  1646. R_TRY(this->MakePageGroup(pg, src_address, num_pages));
  1647. // We're going to perform an update, so create a helper.
  1648. KScopedPageTableUpdater updater(this);
  1649. // Reprotect the source as kernel-read/not mapped.
  1650. const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
  1651. KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
  1652. const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
  1653. const KPageProperties src_properties = {new_src_perm, false, false,
  1654. DisableMergeAttribute::DisableHeadBodyTail};
  1655. R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
  1656. OperationType::ChangePermissions));
  1657. // Ensure that we unprotect the source pages on failure.
  1658. ON_RESULT_FAILURE {
  1659. const KPageProperties unprotect_properties = {
  1660. KMemoryPermission::UserReadWrite, false, false,
  1661. DisableMergeAttribute::EnableHeadBodyTail};
  1662. ASSERT(this->Operate(src_address, num_pages, unprotect_properties.perm,
  1663. OperationType::ChangePermissions) == ResultSuccess);
  1664. };
  1665. // Map the alias pages.
  1666. const KPageProperties dst_map_properties = {KMemoryPermission::UserReadWrite, false, false,
  1667. DisableMergeAttribute::DisableHead};
  1668. R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties,
  1669. false));
  1670. // Apply the memory block updates.
  1671. m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages,
  1672. src_state, new_src_perm, new_src_attr,
  1673. KMemoryBlockDisableMergeAttribute::Locked,
  1674. KMemoryBlockDisableMergeAttribute::None);
  1675. m_memory_block_manager.Update(
  1676. std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::Stack,
  1677. KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
  1678. KMemoryBlockDisableMergeAttribute::Normal, KMemoryBlockDisableMergeAttribute::None);
  1679. }
  1680. R_SUCCEED();
  1681. }
  1682. Result KPageTable::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address,
  1683. size_t size) {
  1684. // Lock the table.
  1685. KScopedLightLock lk(m_general_lock);
  1686. // Validate that the source address's state is valid.
  1687. KMemoryState src_state;
  1688. size_t num_src_allocator_blocks;
  1689. R_TRY(this->CheckMemoryState(
  1690. std::addressof(src_state), nullptr, nullptr, std::addressof(num_src_allocator_blocks),
  1691. src_address, size, KMemoryState::FlagCanAlias, KMemoryState::FlagCanAlias,
  1692. KMemoryPermission::All, KMemoryPermission::NotMapped | KMemoryPermission::KernelRead,
  1693. KMemoryAttribute::All, KMemoryAttribute::Locked));
  1694. // Validate that the dst address's state is valid.
  1695. KMemoryPermission dst_perm;
  1696. size_t num_dst_allocator_blocks;
  1697. R_TRY(this->CheckMemoryState(
  1698. nullptr, std::addressof(dst_perm), nullptr, std::addressof(num_dst_allocator_blocks),
  1699. dst_address, size, KMemoryState::All, KMemoryState::Stack, KMemoryPermission::None,
  1700. KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
  1701. // Create an update allocator for the source.
  1702. Result src_allocator_result;
  1703. KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
  1704. m_memory_block_slab_manager,
  1705. num_src_allocator_blocks);
  1706. R_TRY(src_allocator_result);
  1707. // Create an update allocator for the destination.
  1708. Result dst_allocator_result;
  1709. KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
  1710. m_memory_block_slab_manager,
  1711. num_dst_allocator_blocks);
  1712. R_TRY(dst_allocator_result);
  1713. // Unmap the memory.
  1714. {
  1715. // Determine the number of pages being operated on.
  1716. const size_t num_pages = size / PageSize;
  1717. // Create page groups for the memory being unmapped.
  1718. KPageGroup pg{m_kernel, m_block_info_manager};
  1719. // Create the page group representing the destination.
  1720. R_TRY(this->MakePageGroup(pg, dst_address, num_pages));
  1721. // Ensure the page group is the valid for the source.
  1722. R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), ResultInvalidMemoryRegion);
  1723. // We're going to perform an update, so create a helper.
  1724. KScopedPageTableUpdater updater(this);
  1725. // Unmap the aliased copy of the pages.
  1726. const KPageProperties dst_unmap_properties = {KMemoryPermission::None, false, false,
  1727. DisableMergeAttribute::None};
  1728. R_TRY(
  1729. this->Operate(dst_address, num_pages, dst_unmap_properties.perm, OperationType::Unmap));
  1730. // Ensure that we re-map the aliased pages on failure.
  1731. ON_RESULT_FAILURE {
  1732. this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg);
  1733. };
  1734. // Try to set the permissions for the source pages back to what they should be.
  1735. const KPageProperties src_properties = {KMemoryPermission::UserReadWrite, false, false,
  1736. DisableMergeAttribute::EnableAndMergeHeadBodyTail};
  1737. R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
  1738. OperationType::ChangePermissions));
  1739. // Apply the memory block updates.
  1740. m_memory_block_manager.Update(
  1741. std::addressof(src_allocator), src_address, num_pages, src_state,
  1742. KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
  1743. KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked);
  1744. m_memory_block_manager.Update(
  1745. std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None,
  1746. KMemoryPermission::None, KMemoryAttribute::None,
  1747. KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal);
  1748. }
  1749. R_SUCCEED();
  1750. }
  1751. Result KPageTable::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
  1752. size_t num_pages, KMemoryPermission perm) {
  1753. ASSERT(this->IsLockedByCurrentThread());
  1754. // Create a page group to hold the pages we allocate.
  1755. KPageGroup pg{m_kernel, m_block_info_manager};
  1756. // Allocate the pages.
  1757. R_TRY(
  1758. m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
  1759. // Ensure that the page group is closed when we're done working with it.
  1760. SCOPE_EXIT({ pg.Close(); });
  1761. // Clear all pages.
  1762. for (const auto& it : pg) {
  1763. std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
  1764. it.GetSize());
  1765. }
  1766. // Map the pages.
  1767. R_RETURN(this->Operate(address, num_pages, pg, OperationType::MapGroup));
  1768. }
  1769. Result KPageTable::MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
  1770. const KPageGroup& pg, const KPageProperties properties,
  1771. bool reuse_ll) {
  1772. ASSERT(this->IsLockedByCurrentThread());
  1773. // Note the current address, so that we can iterate.
  1774. const KProcessAddress start_address = address;
  1775. KProcessAddress cur_address = address;
  1776. // Ensure that we clean up on failure.
  1777. ON_RESULT_FAILURE {
  1778. ASSERT(!reuse_ll);
  1779. if (cur_address != start_address) {
  1780. const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
  1781. DisableMergeAttribute::None};
  1782. ASSERT(this->Operate(start_address, (cur_address - start_address) / PageSize,
  1783. unmap_properties.perm, OperationType::Unmap) == ResultSuccess);
  1784. }
  1785. };
  1786. // Iterate, mapping all pages in the group.
  1787. for (const auto& block : pg) {
  1788. // Map and advance.
  1789. const KPageProperties cur_properties =
  1790. (cur_address == start_address)
  1791. ? properties
  1792. : KPageProperties{properties.perm, properties.io, properties.uncached,
  1793. DisableMergeAttribute::None};
  1794. this->Operate(cur_address, block.GetNumPages(), cur_properties.perm, OperationType::Map,
  1795. block.GetAddress());
  1796. cur_address += block.GetSize();
  1797. }
  1798. // We succeeded!
  1799. R_SUCCEED();
  1800. }
  1801. void KPageTable::RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
  1802. const KPageGroup& pg) {
  1803. ASSERT(this->IsLockedByCurrentThread());
  1804. // Note the current address, so that we can iterate.
  1805. const KProcessAddress start_address = address;
  1806. const KProcessAddress last_address = start_address + size - 1;
  1807. const KProcessAddress end_address = last_address + 1;
  1808. // Iterate over the memory.
  1809. auto pg_it = pg.begin();
  1810. ASSERT(pg_it != pg.end());
  1811. KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
  1812. size_t pg_pages = pg_it->GetNumPages();
  1813. auto it = m_memory_block_manager.FindIterator(start_address);
  1814. while (true) {
  1815. // Check that the iterator is valid.
  1816. ASSERT(it != m_memory_block_manager.end());
  1817. // Get the memory info.
  1818. const KMemoryInfo info = it->GetMemoryInfo();
  1819. // Determine the range to map.
  1820. KProcessAddress map_address = std::max<KProcessAddress>(info.GetAddress(), start_address);
  1821. const KProcessAddress map_end_address =
  1822. std::min<KProcessAddress>(info.GetEndAddress(), end_address);
  1823. ASSERT(map_end_address != map_address);
  1824. // Determine if we should disable head merge.
  1825. const bool disable_head_merge =
  1826. info.GetAddress() >= GetInteger(start_address) &&
  1827. True(info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Normal);
  1828. const KPageProperties map_properties = {
  1829. info.GetPermission(), false, false,
  1830. disable_head_merge ? DisableMergeAttribute::DisableHead : DisableMergeAttribute::None};
  1831. // While we have pages to map, map them.
  1832. size_t map_pages = (map_end_address - map_address) / PageSize;
  1833. while (map_pages > 0) {
  1834. // Check if we're at the end of the physical block.
  1835. if (pg_pages == 0) {
  1836. // Ensure there are more pages to map.
  1837. ASSERT(pg_it != pg.end());
  1838. // Advance our physical block.
  1839. ++pg_it;
  1840. pg_phys_addr = pg_it->GetAddress();
  1841. pg_pages = pg_it->GetNumPages();
  1842. }
  1843. // Map whatever we can.
  1844. const size_t cur_pages = std::min(pg_pages, map_pages);
  1845. ASSERT(this->Operate(map_address, map_pages, map_properties.perm, OperationType::Map,
  1846. pg_phys_addr) == ResultSuccess);
  1847. // Advance.
  1848. map_address += cur_pages * PageSize;
  1849. map_pages -= cur_pages;
  1850. pg_phys_addr += cur_pages * PageSize;
  1851. pg_pages -= cur_pages;
  1852. }
  1853. // Check if we're done.
  1854. if (last_address <= info.GetLastAddress()) {
  1855. break;
  1856. }
  1857. // Advance.
  1858. ++it;
  1859. }
  1860. // Check that we re-mapped precisely the page group.
  1861. ASSERT((++pg_it) == pg.end());
  1862. }
  1863. Result KPageTable::MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
  1864. KPhysicalAddress phys_addr, bool is_pa_valid,
  1865. KProcessAddress region_start, size_t region_num_pages,
  1866. KMemoryState state, KMemoryPermission perm) {
  1867. ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
  1868. // Ensure this is a valid map request.
  1869. R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
  1870. ResultInvalidCurrentMemory);
  1871. R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
  1872. // Lock the table.
  1873. KScopedLightLock lk(m_general_lock);
  1874. // Find a random address to map at.
  1875. KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment,
  1876. 0, this->GetNumGuardPages());
  1877. R_UNLESS(addr != 0, ResultOutOfMemory);
  1878. ASSERT(Common::IsAligned(GetInteger(addr), alignment));
  1879. ASSERT(this->CanContain(addr, num_pages * PageSize, state));
  1880. ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
  1881. KMemoryPermission::None, KMemoryPermission::None,
  1882. KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
  1883. // Create an update allocator.
  1884. Result allocator_result;
  1885. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1886. m_memory_block_slab_manager);
  1887. R_TRY(allocator_result);
  1888. // We're going to perform an update, so create a helper.
  1889. KScopedPageTableUpdater updater(this);
  1890. // Perform mapping operation.
  1891. if (is_pa_valid) {
  1892. const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
  1893. R_TRY(this->Operate(addr, num_pages, properties.perm, OperationType::Map, phys_addr));
  1894. } else {
  1895. R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
  1896. }
  1897. // Update the blocks.
  1898. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
  1899. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
  1900. KMemoryBlockDisableMergeAttribute::None);
  1901. // We successfully mapped the pages.
  1902. *out_addr = addr;
  1903. R_SUCCEED();
  1904. }
  1905. Result KPageTable::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
  1906. KMemoryPermission perm) {
  1907. // Check that the map is in range.
  1908. const size_t size = num_pages * PageSize;
  1909. R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
  1910. // Lock the table.
  1911. KScopedLightLock lk(m_general_lock);
  1912. // Check the memory state.
  1913. size_t num_allocator_blocks;
  1914. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
  1915. KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
  1916. KMemoryPermission::None, KMemoryAttribute::None,
  1917. KMemoryAttribute::None));
  1918. // Create an update allocator.
  1919. Result allocator_result;
  1920. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1921. m_memory_block_slab_manager, num_allocator_blocks);
  1922. R_TRY(allocator_result);
  1923. // We're going to perform an update, so create a helper.
  1924. KScopedPageTableUpdater updater(this);
  1925. // Map the pages.
  1926. R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
  1927. // Update the blocks.
  1928. m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
  1929. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
  1930. KMemoryBlockDisableMergeAttribute::None);
  1931. R_SUCCEED();
  1932. }
  1933. Result KPageTable::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) {
  1934. // Check that the unmap is in range.
  1935. const size_t size = num_pages * PageSize;
  1936. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  1937. // Lock the table.
  1938. KScopedLightLock lk(m_general_lock);
  1939. // Check the memory state.
  1940. size_t num_allocator_blocks;
  1941. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
  1942. KMemoryState::All, state, KMemoryPermission::None,
  1943. KMemoryPermission::None, KMemoryAttribute::All,
  1944. KMemoryAttribute::None));
  1945. // Create an update allocator.
  1946. Result allocator_result;
  1947. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1948. m_memory_block_slab_manager, num_allocator_blocks);
  1949. R_TRY(allocator_result);
  1950. // We're going to perform an update, so create a helper.
  1951. KScopedPageTableUpdater updater(this);
  1952. // Perform the unmap.
  1953. const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
  1954. DisableMergeAttribute::None};
  1955. R_TRY(this->Operate(address, num_pages, unmap_properties.perm, OperationType::Unmap));
  1956. // Update the blocks.
  1957. m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
  1958. KMemoryPermission::None, KMemoryAttribute::None,
  1959. KMemoryBlockDisableMergeAttribute::None,
  1960. KMemoryBlockDisableMergeAttribute::Normal);
  1961. R_SUCCEED();
  1962. }
  1963. Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
  1964. KProcessAddress region_start, size_t region_num_pages,
  1965. KMemoryState state, KMemoryPermission perm) {
  1966. ASSERT(!this->IsLockedByCurrentThread());
  1967. // Ensure this is a valid map request.
  1968. const size_t num_pages = pg.GetNumPages();
  1969. R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
  1970. ResultInvalidCurrentMemory);
  1971. R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
  1972. // Lock the table.
  1973. KScopedLightLock lk(m_general_lock);
  1974. // Find a random address to map at.
  1975. KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize,
  1976. 0, this->GetNumGuardPages());
  1977. R_UNLESS(addr != 0, ResultOutOfMemory);
  1978. ASSERT(this->CanContain(addr, num_pages * PageSize, state));
  1979. ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
  1980. KMemoryPermission::None, KMemoryPermission::None,
  1981. KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
  1982. // Create an update allocator.
  1983. Result allocator_result;
  1984. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  1985. m_memory_block_slab_manager);
  1986. R_TRY(allocator_result);
  1987. // We're going to perform an update, so create a helper.
  1988. KScopedPageTableUpdater updater(this);
  1989. // Perform mapping operation.
  1990. const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
  1991. R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
  1992. // Update the blocks.
  1993. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
  1994. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
  1995. KMemoryBlockDisableMergeAttribute::None);
  1996. // We successfully mapped the pages.
  1997. *out_addr = addr;
  1998. R_SUCCEED();
  1999. }
  2000. Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMemoryState state,
  2001. KMemoryPermission perm) {
  2002. ASSERT(!this->IsLockedByCurrentThread());
  2003. // Ensure this is a valid map request.
  2004. const size_t num_pages = pg.GetNumPages();
  2005. const size_t size = num_pages * PageSize;
  2006. R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
  2007. // Lock the table.
  2008. KScopedLightLock lk(m_general_lock);
  2009. // Check if state allows us to map.
  2010. size_t num_allocator_blocks;
  2011. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size,
  2012. KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
  2013. KMemoryPermission::None, KMemoryAttribute::None,
  2014. KMemoryAttribute::None));
  2015. // Create an update allocator.
  2016. Result allocator_result;
  2017. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2018. m_memory_block_slab_manager, num_allocator_blocks);
  2019. R_TRY(allocator_result);
  2020. // We're going to perform an update, so create a helper.
  2021. KScopedPageTableUpdater updater(this);
  2022. // Perform mapping operation.
  2023. const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
  2024. R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
  2025. // Update the blocks.
  2026. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
  2027. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
  2028. KMemoryBlockDisableMergeAttribute::None);
  2029. // We successfully mapped the pages.
  2030. R_SUCCEED();
  2031. }
  2032. Result KPageTable::UnmapPageGroup(KProcessAddress address, const KPageGroup& pg,
  2033. KMemoryState state) {
  2034. ASSERT(!this->IsLockedByCurrentThread());
  2035. // Ensure this is a valid unmap request.
  2036. const size_t num_pages = pg.GetNumPages();
  2037. const size_t size = num_pages * PageSize;
  2038. R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
  2039. // Lock the table.
  2040. KScopedLightLock lk(m_general_lock);
  2041. // Check if state allows us to unmap.
  2042. size_t num_allocator_blocks;
  2043. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
  2044. KMemoryState::All, state, KMemoryPermission::None,
  2045. KMemoryPermission::None, KMemoryAttribute::All,
  2046. KMemoryAttribute::None));
  2047. // Check that the page group is valid.
  2048. R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), ResultInvalidCurrentMemory);
  2049. // Create an update allocator.
  2050. Result allocator_result;
  2051. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2052. m_memory_block_slab_manager, num_allocator_blocks);
  2053. R_TRY(allocator_result);
  2054. // We're going to perform an update, so create a helper.
  2055. KScopedPageTableUpdater updater(this);
  2056. // Perform unmapping operation.
  2057. const KPageProperties properties = {KMemoryPermission::None, false, false,
  2058. DisableMergeAttribute::None};
  2059. R_TRY(this->Operate(address, num_pages, properties.perm, OperationType::Unmap));
  2060. // Update the blocks.
  2061. m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
  2062. KMemoryPermission::None, KMemoryAttribute::None,
  2063. KMemoryBlockDisableMergeAttribute::None,
  2064. KMemoryBlockDisableMergeAttribute::Normal);
  2065. R_SUCCEED();
  2066. }
  2067. Result KPageTable::MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
  2068. KMemoryState state_mask, KMemoryState state,
  2069. KMemoryPermission perm_mask, KMemoryPermission perm,
  2070. KMemoryAttribute attr_mask, KMemoryAttribute attr) {
  2071. // Ensure that the page group isn't null.
  2072. ASSERT(out != nullptr);
  2073. // Make sure that the region we're mapping is valid for the table.
  2074. const size_t size = num_pages * PageSize;
  2075. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  2076. // Lock the table.
  2077. KScopedLightLock lk(m_general_lock);
  2078. // Check if state allows us to create the group.
  2079. R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState::FlagReferenceCounted,
  2080. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  2081. attr_mask, attr));
  2082. // Create a new page group for the region.
  2083. R_TRY(this->MakePageGroup(*out, address, num_pages));
  2084. R_SUCCEED();
  2085. }
  2086. Result KPageTable::SetProcessMemoryPermission(KProcessAddress addr, size_t size,
  2087. Svc::MemoryPermission svc_perm) {
  2088. const size_t num_pages = size / PageSize;
  2089. // Lock the table.
  2090. KScopedLightLock lk(m_general_lock);
  2091. // Verify we can change the memory permission.
  2092. KMemoryState old_state;
  2093. KMemoryPermission old_perm;
  2094. size_t num_allocator_blocks;
  2095. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr,
  2096. std::addressof(num_allocator_blocks), addr, size,
  2097. KMemoryState::FlagCode, KMemoryState::FlagCode,
  2098. KMemoryPermission::None, KMemoryPermission::None,
  2099. KMemoryAttribute::All, KMemoryAttribute::None));
  2100. // Determine new perm/state.
  2101. const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
  2102. KMemoryState new_state = old_state;
  2103. const bool is_w = (new_perm & KMemoryPermission::UserWrite) == KMemoryPermission::UserWrite;
  2104. const bool is_x = (new_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
  2105. const bool was_x =
  2106. (old_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
  2107. ASSERT(!(is_w && is_x));
  2108. if (is_w) {
  2109. switch (old_state) {
  2110. case KMemoryState::Code:
  2111. new_state = KMemoryState::CodeData;
  2112. break;
  2113. case KMemoryState::AliasCode:
  2114. new_state = KMemoryState::AliasCodeData;
  2115. break;
  2116. default:
  2117. ASSERT(false);
  2118. break;
  2119. }
  2120. }
  2121. // Succeed if there's nothing to do.
  2122. R_SUCCEED_IF(old_perm == new_perm && old_state == new_state);
  2123. // Create an update allocator.
  2124. Result allocator_result{ResultSuccess};
  2125. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2126. m_memory_block_slab_manager, num_allocator_blocks);
  2127. R_TRY(allocator_result);
  2128. // Perform mapping operation.
  2129. const auto operation =
  2130. was_x ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions;
  2131. R_TRY(Operate(addr, num_pages, new_perm, operation));
  2132. // Update the blocks.
  2133. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, new_state, new_perm,
  2134. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
  2135. KMemoryBlockDisableMergeAttribute::None);
  2136. // Ensure cache coherency, if we're setting pages as executable.
  2137. if (is_x) {
  2138. m_system.InvalidateCpuInstructionCacheRange(GetInteger(addr), size);
  2139. }
  2140. R_SUCCEED();
  2141. }
  2142. KMemoryInfo KPageTable::QueryInfoImpl(KProcessAddress addr) {
  2143. KScopedLightLock lk(m_general_lock);
  2144. return m_memory_block_manager.FindBlock(addr)->GetMemoryInfo();
  2145. }
  2146. KMemoryInfo KPageTable::QueryInfo(KProcessAddress addr) {
  2147. if (!Contains(addr, 1)) {
  2148. return {
  2149. .m_address = GetInteger(m_address_space_end),
  2150. .m_size = 0 - GetInteger(m_address_space_end),
  2151. .m_state = static_cast<KMemoryState>(Svc::MemoryState::Inaccessible),
  2152. .m_device_disable_merge_left_count = 0,
  2153. .m_device_disable_merge_right_count = 0,
  2154. .m_ipc_lock_count = 0,
  2155. .m_device_use_count = 0,
  2156. .m_ipc_disable_merge_count = 0,
  2157. .m_permission = KMemoryPermission::None,
  2158. .m_attribute = KMemoryAttribute::None,
  2159. .m_original_permission = KMemoryPermission::None,
  2160. .m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute::None,
  2161. };
  2162. }
  2163. return QueryInfoImpl(addr);
  2164. }
  2165. Result KPageTable::SetMemoryPermission(KProcessAddress addr, size_t size,
  2166. Svc::MemoryPermission svc_perm) {
  2167. const size_t num_pages = size / PageSize;
  2168. // Lock the table.
  2169. KScopedLightLock lk(m_general_lock);
  2170. // Verify we can change the memory permission.
  2171. KMemoryState old_state;
  2172. KMemoryPermission old_perm;
  2173. size_t num_allocator_blocks;
  2174. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr,
  2175. std::addressof(num_allocator_blocks), addr, size,
  2176. KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect,
  2177. KMemoryPermission::None, KMemoryPermission::None,
  2178. KMemoryAttribute::All, KMemoryAttribute::None));
  2179. // Determine new perm.
  2180. const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
  2181. R_SUCCEED_IF(old_perm == new_perm);
  2182. // Create an update allocator.
  2183. Result allocator_result{ResultSuccess};
  2184. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2185. m_memory_block_slab_manager, num_allocator_blocks);
  2186. R_TRY(allocator_result);
  2187. // Perform mapping operation.
  2188. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  2189. // Update the blocks.
  2190. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm,
  2191. KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
  2192. KMemoryBlockDisableMergeAttribute::None);
  2193. R_SUCCEED();
  2194. }
  2195. Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr) {
  2196. const size_t num_pages = size / PageSize;
  2197. ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) ==
  2198. KMemoryAttribute::SetMask);
  2199. // Lock the table.
  2200. KScopedLightLock lk(m_general_lock);
  2201. // Verify we can change the memory attribute.
  2202. KMemoryState old_state;
  2203. KMemoryPermission old_perm;
  2204. KMemoryAttribute old_attr;
  2205. size_t num_allocator_blocks;
  2206. constexpr auto AttributeTestMask =
  2207. ~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
  2208. const KMemoryState state_test_mask =
  2209. static_cast<KMemoryState>(((mask & static_cast<u32>(KMemoryAttribute::Uncached))
  2210. ? static_cast<u32>(KMemoryState::FlagCanChangeAttribute)
  2211. : 0) |
  2212. ((mask & static_cast<u32>(KMemoryAttribute::PermissionLocked))
  2213. ? static_cast<u32>(KMemoryState::FlagCanPermissionLock)
  2214. : 0));
  2215. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
  2216. std::addressof(old_attr), std::addressof(num_allocator_blocks),
  2217. addr, size, state_test_mask, state_test_mask,
  2218. KMemoryPermission::None, KMemoryPermission::None,
  2219. AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
  2220. // Create an update allocator.
  2221. Result allocator_result{ResultSuccess};
  2222. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2223. m_memory_block_slab_manager, num_allocator_blocks);
  2224. R_TRY(allocator_result);
  2225. // If we need to, perform a change attribute operation.
  2226. if (True(KMemoryAttribute::Uncached & static_cast<KMemoryAttribute>(mask))) {
  2227. // Perform operation.
  2228. R_TRY(this->Operate(addr, num_pages, old_perm,
  2229. OperationType::ChangePermissionsAndRefreshAndFlush, 0));
  2230. }
  2231. // Update the blocks.
  2232. m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages,
  2233. static_cast<KMemoryAttribute>(mask),
  2234. static_cast<KMemoryAttribute>(attr));
  2235. R_SUCCEED();
  2236. }
  2237. Result KPageTable::SetMaxHeapSize(size_t size) {
  2238. // Lock the table.
  2239. KScopedLightLock lk(m_general_lock);
  2240. // Only process page tables are allowed to set heap size.
  2241. ASSERT(!this->IsKernel());
  2242. m_max_heap_size = size;
  2243. R_SUCCEED();
  2244. }
  2245. Result KPageTable::SetHeapSize(u64* out, size_t size) {
  2246. // Lock the physical memory mutex.
  2247. KScopedLightLock map_phys_mem_lk(m_map_physical_memory_lock);
  2248. // Try to perform a reduction in heap, instead of an extension.
  2249. KProcessAddress cur_address{};
  2250. size_t allocation_size{};
  2251. {
  2252. // Lock the table.
  2253. KScopedLightLock lk(m_general_lock);
  2254. // Validate that setting heap size is possible at all.
  2255. R_UNLESS(!m_is_kernel, ResultOutOfMemory);
  2256. R_UNLESS(size <= static_cast<size_t>(m_heap_region_end - m_heap_region_start),
  2257. ResultOutOfMemory);
  2258. R_UNLESS(size <= m_max_heap_size, ResultOutOfMemory);
  2259. if (size < GetHeapSize()) {
  2260. // The size being requested is less than the current size, so we need to free the end of
  2261. // the heap.
  2262. // Validate memory state.
  2263. size_t num_allocator_blocks;
  2264. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
  2265. m_heap_region_start + size, GetHeapSize() - size,
  2266. KMemoryState::All, KMemoryState::Normal,
  2267. KMemoryPermission::All, KMemoryPermission::UserReadWrite,
  2268. KMemoryAttribute::All, KMemoryAttribute::None));
  2269. // Create an update allocator.
  2270. Result allocator_result{ResultSuccess};
  2271. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2272. m_memory_block_slab_manager,
  2273. num_allocator_blocks);
  2274. R_TRY(allocator_result);
  2275. // Unmap the end of the heap.
  2276. const auto num_pages = (GetHeapSize() - size) / PageSize;
  2277. R_TRY(Operate(m_heap_region_start + size, num_pages, KMemoryPermission::None,
  2278. OperationType::Unmap));
  2279. // Release the memory from the resource limit.
  2280. m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, num_pages * PageSize);
  2281. // Apply the memory block update.
  2282. m_memory_block_manager.Update(std::addressof(allocator), m_heap_region_start + size,
  2283. num_pages, KMemoryState::Free, KMemoryPermission::None,
  2284. KMemoryAttribute::None,
  2285. KMemoryBlockDisableMergeAttribute::None,
  2286. size == 0 ? KMemoryBlockDisableMergeAttribute::Normal
  2287. : KMemoryBlockDisableMergeAttribute::None);
  2288. // Update the current heap end.
  2289. m_current_heap_end = m_heap_region_start + size;
  2290. // Set the output.
  2291. *out = GetInteger(m_heap_region_start);
  2292. R_SUCCEED();
  2293. } else if (size == GetHeapSize()) {
  2294. // The size requested is exactly the current size.
  2295. *out = GetInteger(m_heap_region_start);
  2296. R_SUCCEED();
  2297. } else {
  2298. // We have to allocate memory. Determine how much to allocate and where while the table
  2299. // is locked.
  2300. cur_address = m_current_heap_end;
  2301. allocation_size = size - GetHeapSize();
  2302. }
  2303. }
  2304. // Reserve memory for the heap extension.
  2305. KScopedResourceReservation memory_reservation(
  2306. m_resource_limit, LimitableResource::PhysicalMemoryMax, allocation_size);
  2307. R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
  2308. // Allocate pages for the heap extension.
  2309. KPageGroup pg{m_kernel, m_block_info_manager};
  2310. R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
  2311. &pg, allocation_size / PageSize,
  2312. KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
  2313. // Clear all the newly allocated pages.
  2314. for (const auto& it : pg) {
  2315. std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
  2316. it.GetSize());
  2317. }
  2318. // Map the pages.
  2319. {
  2320. // Lock the table.
  2321. KScopedLightLock lk(m_general_lock);
  2322. // Ensure that the heap hasn't changed since we began executing.
  2323. ASSERT(cur_address == m_current_heap_end);
  2324. // Check the memory state.
  2325. size_t num_allocator_blocks{};
  2326. R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), m_current_heap_end,
  2327. allocation_size, KMemoryState::All, KMemoryState::Free,
  2328. KMemoryPermission::None, KMemoryPermission::None,
  2329. KMemoryAttribute::None, KMemoryAttribute::None));
  2330. // Create an update allocator.
  2331. Result allocator_result{ResultSuccess};
  2332. KMemoryBlockManagerUpdateAllocator allocator(
  2333. std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks);
  2334. R_TRY(allocator_result);
  2335. // Map the pages.
  2336. const auto num_pages = allocation_size / PageSize;
  2337. R_TRY(Operate(m_current_heap_end, num_pages, pg, OperationType::MapGroup));
  2338. // Clear all the newly allocated pages.
  2339. for (size_t cur_page = 0; cur_page < num_pages; ++cur_page) {
  2340. std::memset(m_memory->GetPointer(m_current_heap_end + (cur_page * PageSize)), 0,
  2341. PageSize);
  2342. }
  2343. // We succeeded, so commit our memory reservation.
  2344. memory_reservation.Commit();
  2345. // Apply the memory block update.
  2346. m_memory_block_manager.Update(
  2347. std::addressof(allocator), m_current_heap_end, num_pages, KMemoryState::Normal,
  2348. KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
  2349. m_heap_region_start == m_current_heap_end ? KMemoryBlockDisableMergeAttribute::Normal
  2350. : KMemoryBlockDisableMergeAttribute::None,
  2351. KMemoryBlockDisableMergeAttribute::None);
  2352. // Update the current heap end.
  2353. m_current_heap_end = m_heap_region_start + size;
  2354. // Set the output.
  2355. *out = GetInteger(m_heap_region_start);
  2356. R_SUCCEED();
  2357. }
  2358. }
  2359. Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress address,
  2360. size_t size, KMemoryPermission perm,
  2361. bool is_aligned, bool check_heap) {
  2362. // Lightly validate the range before doing anything else.
  2363. const size_t num_pages = size / PageSize;
  2364. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  2365. // Lock the table.
  2366. KScopedLightLock lk(m_general_lock);
  2367. // Check the memory state.
  2368. const auto test_state =
  2369. (is_aligned ? KMemoryState::FlagCanAlignedDeviceMap : KMemoryState::FlagCanDeviceMap) |
  2370. (check_heap ? KMemoryState::FlagReferenceCounted : KMemoryState::None);
  2371. size_t num_allocator_blocks;
  2372. KMemoryState old_state;
  2373. R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr,
  2374. std::addressof(num_allocator_blocks), address, size, test_state,
  2375. test_state, perm, perm,
  2376. KMemoryAttribute::IpcLocked | KMemoryAttribute::Locked,
  2377. KMemoryAttribute::None, KMemoryAttribute::DeviceShared));
  2378. // Create an update allocator.
  2379. Result allocator_result;
  2380. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2381. m_memory_block_slab_manager, num_allocator_blocks);
  2382. R_TRY(allocator_result);
  2383. // Update the memory blocks.
  2384. m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages,
  2385. &KMemoryBlock::ShareToDevice, KMemoryPermission::None);
  2386. // Set whether the locked memory was io.
  2387. *out_is_io =
  2388. static_cast<Svc::MemoryState>(old_state & KMemoryState::Mask) == Svc::MemoryState::Io;
  2389. R_SUCCEED();
  2390. }
  2391. Result KPageTable::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size,
  2392. bool check_heap) {
  2393. // Lightly validate the range before doing anything else.
  2394. const size_t num_pages = size / PageSize;
  2395. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  2396. // Lock the table.
  2397. KScopedLightLock lk(m_general_lock);
  2398. // Check the memory state.
  2399. const auto test_state = KMemoryState::FlagCanDeviceMap |
  2400. (check_heap ? KMemoryState::FlagReferenceCounted : KMemoryState::None);
  2401. size_t num_allocator_blocks;
  2402. R_TRY(this->CheckMemoryStateContiguous(
  2403. std::addressof(num_allocator_blocks), address, size, test_state, test_state,
  2404. KMemoryPermission::None, KMemoryPermission::None,
  2405. KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked, KMemoryAttribute::DeviceShared));
  2406. // Create an update allocator.
  2407. Result allocator_result;
  2408. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2409. m_memory_block_slab_manager, num_allocator_blocks);
  2410. R_TRY(allocator_result);
  2411. // Update the memory blocks.
  2412. const KMemoryBlockManager::MemoryBlockLockFunction lock_func =
  2413. m_enable_device_address_space_merge
  2414. ? &KMemoryBlock::UpdateDeviceDisableMergeStateForShare
  2415. : &KMemoryBlock::UpdateDeviceDisableMergeStateForShareRight;
  2416. m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, lock_func,
  2417. KMemoryPermission::None);
  2418. R_SUCCEED();
  2419. }
  2420. Result KPageTable::UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
  2421. // Lightly validate the range before doing anything else.
  2422. const size_t num_pages = size / PageSize;
  2423. R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
  2424. // Lock the table.
  2425. KScopedLightLock lk(m_general_lock);
  2426. // Check the memory state.
  2427. size_t num_allocator_blocks;
  2428. R_TRY(this->CheckMemoryStateContiguous(
  2429. std::addressof(num_allocator_blocks), address, size, KMemoryState::FlagCanDeviceMap,
  2430. KMemoryState::FlagCanDeviceMap, KMemoryPermission::None, KMemoryPermission::None,
  2431. KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked, KMemoryAttribute::DeviceShared));
  2432. // Create an update allocator.
  2433. Result allocator_result{ResultSuccess};
  2434. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2435. m_memory_block_slab_manager, num_allocator_blocks);
  2436. R_TRY(allocator_result);
  2437. // Update the memory blocks.
  2438. m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages,
  2439. &KMemoryBlock::UnshareToDevice, KMemoryPermission::None);
  2440. R_SUCCEED();
  2441. }
  2442. Result KPageTable::LockForIpcUserBuffer(KPhysicalAddress* out, KProcessAddress address,
  2443. size_t size) {
  2444. R_RETURN(this->LockMemoryAndOpen(
  2445. nullptr, out, address, size, KMemoryState::FlagCanIpcUserBuffer,
  2446. KMemoryState::FlagCanIpcUserBuffer, KMemoryPermission::All,
  2447. KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None,
  2448. KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite,
  2449. KMemoryAttribute::Locked));
  2450. }
  2451. Result KPageTable::UnlockForIpcUserBuffer(KProcessAddress address, size_t size) {
  2452. R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanIpcUserBuffer,
  2453. KMemoryState::FlagCanIpcUserBuffer, KMemoryPermission::None,
  2454. KMemoryPermission::None, KMemoryAttribute::All,
  2455. KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
  2456. KMemoryAttribute::Locked, nullptr));
  2457. }
  2458. Result KPageTable::LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
  2459. KMemoryPermission perm) {
  2460. R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState::FlagCanTransfer,
  2461. KMemoryState::FlagCanTransfer, KMemoryPermission::All,
  2462. KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
  2463. KMemoryAttribute::None, perm, KMemoryAttribute::Locked));
  2464. }
  2465. Result KPageTable::UnlockForTransferMemory(KProcessAddress address, size_t size,
  2466. const KPageGroup& pg) {
  2467. R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanTransfer,
  2468. KMemoryState::FlagCanTransfer, KMemoryPermission::None,
  2469. KMemoryPermission::None, KMemoryAttribute::All,
  2470. KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
  2471. KMemoryAttribute::Locked, std::addressof(pg)));
  2472. }
  2473. Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) {
  2474. R_RETURN(this->LockMemoryAndOpen(
  2475. out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
  2476. KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
  2477. KMemoryAttribute::None, KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite,
  2478. KMemoryAttribute::Locked));
  2479. }
  2480. Result KPageTable::UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg) {
  2481. R_RETURN(this->UnlockMemory(
  2482. addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
  2483. KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All,
  2484. KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg));
  2485. }
  2486. bool KPageTable::IsRegionContiguous(KProcessAddress addr, u64 size) const {
  2487. auto start_ptr = m_system.DeviceMemory().GetPointer<u8>(GetInteger(addr));
  2488. for (u64 offset{}; offset < size; offset += PageSize) {
  2489. if (start_ptr != m_system.DeviceMemory().GetPointer<u8>(GetInteger(addr) + offset)) {
  2490. return false;
  2491. }
  2492. start_ptr += PageSize;
  2493. }
  2494. return true;
  2495. }
  2496. void KPageTable::AddRegionToPages(KProcessAddress start, size_t num_pages,
  2497. KPageGroup& page_linked_list) {
  2498. KProcessAddress addr{start};
  2499. while (addr < start + (num_pages * PageSize)) {
  2500. const KPhysicalAddress paddr{GetPhysicalAddr(addr)};
  2501. ASSERT(paddr != 0);
  2502. page_linked_list.AddBlock(paddr, 1);
  2503. addr += PageSize;
  2504. }
  2505. }
  2506. KProcessAddress KPageTable::AllocateVirtualMemory(KProcessAddress start, size_t region_num_pages,
  2507. u64 needed_num_pages, size_t align) {
  2508. if (m_enable_aslr) {
  2509. UNIMPLEMENTED();
  2510. }
  2511. return m_memory_block_manager.FindFreeArea(start, region_num_pages, needed_num_pages, align, 0,
  2512. IsKernel() ? 1 : 4);
  2513. }
  2514. Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGroup& page_group,
  2515. OperationType operation) {
  2516. ASSERT(this->IsLockedByCurrentThread());
  2517. ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
  2518. ASSERT(num_pages > 0);
  2519. ASSERT(num_pages == page_group.GetNumPages());
  2520. switch (operation) {
  2521. case OperationType::MapGroup:
  2522. case OperationType::MapFirstGroup: {
  2523. // We want to maintain a new reference to every page in the group.
  2524. KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
  2525. for (const auto& node : page_group) {
  2526. const size_t size{node.GetNumPages() * PageSize};
  2527. // Map the pages.
  2528. m_memory->MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress());
  2529. addr += size;
  2530. }
  2531. // We succeeded! We want to persist the reference to the pages.
  2532. spg.CancelClose();
  2533. break;
  2534. }
  2535. default:
  2536. ASSERT(false);
  2537. break;
  2538. }
  2539. R_SUCCEED();
  2540. }
  2541. Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
  2542. OperationType operation, KPhysicalAddress map_addr) {
  2543. ASSERT(this->IsLockedByCurrentThread());
  2544. ASSERT(num_pages > 0);
  2545. ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
  2546. ASSERT(ContainsPages(addr, num_pages));
  2547. switch (operation) {
  2548. case OperationType::Unmap: {
  2549. // Ensure that any pages we track close on exit.
  2550. KPageGroup pages_to_close{m_kernel, this->GetBlockInfoManager()};
  2551. SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
  2552. this->AddRegionToPages(addr, num_pages, pages_to_close);
  2553. m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
  2554. break;
  2555. }
  2556. case OperationType::Map: {
  2557. ASSERT(map_addr);
  2558. ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize));
  2559. m_memory->MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr);
  2560. // Open references to pages, if we should.
  2561. if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
  2562. m_kernel.MemoryManager().Open(map_addr, num_pages);
  2563. }
  2564. break;
  2565. }
  2566. case OperationType::Separate: {
  2567. // HACK: Unimplemented.
  2568. break;
  2569. }
  2570. case OperationType::ChangePermissions:
  2571. case OperationType::ChangePermissionsAndRefresh:
  2572. case OperationType::ChangePermissionsAndRefreshAndFlush:
  2573. break;
  2574. default:
  2575. ASSERT(false);
  2576. break;
  2577. }
  2578. R_SUCCEED();
  2579. }
  2580. void KPageTable::FinalizeUpdate(PageLinkedList* page_list) {
  2581. while (page_list->Peek()) {
  2582. [[maybe_unused]] auto page = page_list->Pop();
  2583. // TODO(bunnei): Free pages once they are allocated in guest memory
  2584. // ASSERT(this->GetPageTableManager().IsInPageTableHeap(page));
  2585. // ASSERT(this->GetPageTableManager().GetRefCount(page) == 0);
  2586. // this->GetPageTableManager().Free(page);
  2587. }
  2588. }
  2589. KProcessAddress KPageTable::GetRegionAddress(Svc::MemoryState state) const {
  2590. switch (state) {
  2591. case Svc::MemoryState::Free:
  2592. case Svc::MemoryState::Kernel:
  2593. return m_address_space_start;
  2594. case Svc::MemoryState::Normal:
  2595. return m_heap_region_start;
  2596. case Svc::MemoryState::Ipc:
  2597. case Svc::MemoryState::NonSecureIpc:
  2598. case Svc::MemoryState::NonDeviceIpc:
  2599. return m_alias_region_start;
  2600. case Svc::MemoryState::Stack:
  2601. return m_stack_region_start;
  2602. case Svc::MemoryState::Static:
  2603. case Svc::MemoryState::ThreadLocal:
  2604. return m_kernel_map_region_start;
  2605. case Svc::MemoryState::Io:
  2606. case Svc::MemoryState::Shared:
  2607. case Svc::MemoryState::AliasCode:
  2608. case Svc::MemoryState::AliasCodeData:
  2609. case Svc::MemoryState::Transfered:
  2610. case Svc::MemoryState::SharedTransfered:
  2611. case Svc::MemoryState::SharedCode:
  2612. case Svc::MemoryState::GeneratedCode:
  2613. case Svc::MemoryState::CodeOut:
  2614. case Svc::MemoryState::Coverage:
  2615. case Svc::MemoryState::Insecure:
  2616. return m_alias_code_region_start;
  2617. case Svc::MemoryState::Code:
  2618. case Svc::MemoryState::CodeData:
  2619. return m_code_region_start;
  2620. default:
  2621. UNREACHABLE();
  2622. }
  2623. }
  2624. size_t KPageTable::GetRegionSize(Svc::MemoryState state) const {
  2625. switch (state) {
  2626. case Svc::MemoryState::Free:
  2627. case Svc::MemoryState::Kernel:
  2628. return m_address_space_end - m_address_space_start;
  2629. case Svc::MemoryState::Normal:
  2630. return m_heap_region_end - m_heap_region_start;
  2631. case Svc::MemoryState::Ipc:
  2632. case Svc::MemoryState::NonSecureIpc:
  2633. case Svc::MemoryState::NonDeviceIpc:
  2634. return m_alias_region_end - m_alias_region_start;
  2635. case Svc::MemoryState::Stack:
  2636. return m_stack_region_end - m_stack_region_start;
  2637. case Svc::MemoryState::Static:
  2638. case Svc::MemoryState::ThreadLocal:
  2639. return m_kernel_map_region_end - m_kernel_map_region_start;
  2640. case Svc::MemoryState::Io:
  2641. case Svc::MemoryState::Shared:
  2642. case Svc::MemoryState::AliasCode:
  2643. case Svc::MemoryState::AliasCodeData:
  2644. case Svc::MemoryState::Transfered:
  2645. case Svc::MemoryState::SharedTransfered:
  2646. case Svc::MemoryState::SharedCode:
  2647. case Svc::MemoryState::GeneratedCode:
  2648. case Svc::MemoryState::CodeOut:
  2649. case Svc::MemoryState::Coverage:
  2650. case Svc::MemoryState::Insecure:
  2651. return m_alias_code_region_end - m_alias_code_region_start;
  2652. case Svc::MemoryState::Code:
  2653. case Svc::MemoryState::CodeData:
  2654. return m_code_region_end - m_code_region_start;
  2655. default:
  2656. UNREACHABLE();
  2657. }
  2658. }
  2659. bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const {
  2660. const KProcessAddress end = addr + size;
  2661. const KProcessAddress last = end - 1;
  2662. const KProcessAddress region_start = this->GetRegionAddress(state);
  2663. const size_t region_size = this->GetRegionSize(state);
  2664. const bool is_in_region =
  2665. region_start <= addr && addr < end && last <= region_start + region_size - 1;
  2666. const bool is_in_heap = !(end <= m_heap_region_start || m_heap_region_end <= addr ||
  2667. m_heap_region_start == m_heap_region_end);
  2668. const bool is_in_alias = !(end <= m_alias_region_start || m_alias_region_end <= addr ||
  2669. m_alias_region_start == m_alias_region_end);
  2670. switch (state) {
  2671. case Svc::MemoryState::Free:
  2672. case Svc::MemoryState::Kernel:
  2673. return is_in_region;
  2674. case Svc::MemoryState::Io:
  2675. case Svc::MemoryState::Static:
  2676. case Svc::MemoryState::Code:
  2677. case Svc::MemoryState::CodeData:
  2678. case Svc::MemoryState::Shared:
  2679. case Svc::MemoryState::AliasCode:
  2680. case Svc::MemoryState::AliasCodeData:
  2681. case Svc::MemoryState::Stack:
  2682. case Svc::MemoryState::ThreadLocal:
  2683. case Svc::MemoryState::Transfered:
  2684. case Svc::MemoryState::SharedTransfered:
  2685. case Svc::MemoryState::SharedCode:
  2686. case Svc::MemoryState::GeneratedCode:
  2687. case Svc::MemoryState::CodeOut:
  2688. case Svc::MemoryState::Coverage:
  2689. case Svc::MemoryState::Insecure:
  2690. return is_in_region && !is_in_heap && !is_in_alias;
  2691. case Svc::MemoryState::Normal:
  2692. ASSERT(is_in_heap);
  2693. return is_in_region && !is_in_alias;
  2694. case Svc::MemoryState::Ipc:
  2695. case Svc::MemoryState::NonSecureIpc:
  2696. case Svc::MemoryState::NonDeviceIpc:
  2697. ASSERT(is_in_alias);
  2698. return is_in_region && !is_in_heap;
  2699. default:
  2700. return false;
  2701. }
  2702. }
  2703. Result KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
  2704. KMemoryState state, KMemoryPermission perm_mask,
  2705. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2706. KMemoryAttribute attr) const {
  2707. // Validate the states match expectation.
  2708. R_UNLESS((info.m_state & state_mask) == state, ResultInvalidCurrentMemory);
  2709. R_UNLESS((info.m_permission & perm_mask) == perm, ResultInvalidCurrentMemory);
  2710. R_UNLESS((info.m_attribute & attr_mask) == attr, ResultInvalidCurrentMemory);
  2711. R_SUCCEED();
  2712. }
  2713. Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, KProcessAddress addr,
  2714. size_t size, KMemoryState state_mask,
  2715. KMemoryState state, KMemoryPermission perm_mask,
  2716. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2717. KMemoryAttribute attr) const {
  2718. ASSERT(this->IsLockedByCurrentThread());
  2719. // Get information about the first block.
  2720. const KProcessAddress last_addr = addr + size - 1;
  2721. KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
  2722. KMemoryInfo info = it->GetMemoryInfo();
  2723. // If the start address isn't aligned, we need a block.
  2724. const size_t blocks_for_start_align =
  2725. (Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
  2726. while (true) {
  2727. // Validate against the provided masks.
  2728. R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
  2729. // Break once we're done.
  2730. if (last_addr <= info.GetLastAddress()) {
  2731. break;
  2732. }
  2733. // Advance our iterator.
  2734. it++;
  2735. ASSERT(it != m_memory_block_manager.cend());
  2736. info = it->GetMemoryInfo();
  2737. }
  2738. // If the end address isn't aligned, we need a block.
  2739. const size_t blocks_for_end_align =
  2740. (Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
  2741. if (out_blocks_needed != nullptr) {
  2742. *out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
  2743. }
  2744. R_SUCCEED();
  2745. }
  2746. Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
  2747. KMemoryAttribute* out_attr, size_t* out_blocks_needed,
  2748. KMemoryBlockManager::const_iterator it,
  2749. KProcessAddress last_addr, KMemoryState state_mask,
  2750. KMemoryState state, KMemoryPermission perm_mask,
  2751. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2752. KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
  2753. ASSERT(this->IsLockedByCurrentThread());
  2754. // Get information about the first block.
  2755. KMemoryInfo info = it->GetMemoryInfo();
  2756. // Validate all blocks in the range have correct state.
  2757. const KMemoryState first_state = info.m_state;
  2758. const KMemoryPermission first_perm = info.m_permission;
  2759. const KMemoryAttribute first_attr = info.m_attribute;
  2760. while (true) {
  2761. // Validate the current block.
  2762. R_UNLESS(info.m_state == first_state, ResultInvalidCurrentMemory);
  2763. R_UNLESS(info.m_permission == first_perm, ResultInvalidCurrentMemory);
  2764. R_UNLESS((info.m_attribute | ignore_attr) == (first_attr | ignore_attr),
  2765. ResultInvalidCurrentMemory);
  2766. // Validate against the provided masks.
  2767. R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
  2768. // Break once we're done.
  2769. if (last_addr <= info.GetLastAddress()) {
  2770. break;
  2771. }
  2772. // Advance our iterator.
  2773. it++;
  2774. ASSERT(it != m_memory_block_manager.cend());
  2775. info = it->GetMemoryInfo();
  2776. }
  2777. // Write output state.
  2778. if (out_state != nullptr) {
  2779. *out_state = first_state;
  2780. }
  2781. if (out_perm != nullptr) {
  2782. *out_perm = first_perm;
  2783. }
  2784. if (out_attr != nullptr) {
  2785. *out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
  2786. }
  2787. // If the end address isn't aligned, we need a block.
  2788. if (out_blocks_needed != nullptr) {
  2789. const size_t blocks_for_end_align =
  2790. (Common::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress())
  2791. ? 1
  2792. : 0;
  2793. *out_blocks_needed = blocks_for_end_align;
  2794. }
  2795. R_SUCCEED();
  2796. }
  2797. Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
  2798. KMemoryAttribute* out_attr, size_t* out_blocks_needed,
  2799. KProcessAddress addr, size_t size, KMemoryState state_mask,
  2800. KMemoryState state, KMemoryPermission perm_mask,
  2801. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2802. KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
  2803. ASSERT(this->IsLockedByCurrentThread());
  2804. // Check memory state.
  2805. const KProcessAddress last_addr = addr + size - 1;
  2806. KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
  2807. R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr,
  2808. state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
  2809. // If the start address isn't aligned, we need a block.
  2810. if (out_blocks_needed != nullptr &&
  2811. Common::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) {
  2812. ++(*out_blocks_needed);
  2813. }
  2814. R_SUCCEED();
  2815. }
  2816. Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_KPhysicalAddress,
  2817. KProcessAddress addr, size_t size, KMemoryState state_mask,
  2818. KMemoryState state, KMemoryPermission perm_mask,
  2819. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2820. KMemoryAttribute attr, KMemoryPermission new_perm,
  2821. KMemoryAttribute lock_attr) {
  2822. // Validate basic preconditions.
  2823. ASSERT((lock_attr & attr) == KMemoryAttribute::None);
  2824. ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
  2825. KMemoryAttribute::None);
  2826. // Validate the lock request.
  2827. const size_t num_pages = size / PageSize;
  2828. R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
  2829. // Lock the table.
  2830. KScopedLightLock lk(m_general_lock);
  2831. // Check that the output page group is empty, if it exists.
  2832. if (out_pg) {
  2833. ASSERT(out_pg->GetNumPages() == 0);
  2834. }
  2835. // Check the state.
  2836. KMemoryState old_state{};
  2837. KMemoryPermission old_perm{};
  2838. KMemoryAttribute old_attr{};
  2839. size_t num_allocator_blocks{};
  2840. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
  2841. std::addressof(old_attr), std::addressof(num_allocator_blocks),
  2842. addr, size, state_mask | KMemoryState::FlagReferenceCounted,
  2843. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  2844. attr_mask, attr));
  2845. // Get the physical address, if we're supposed to.
  2846. if (out_KPhysicalAddress != nullptr) {
  2847. ASSERT(this->GetPhysicalAddressLocked(out_KPhysicalAddress, addr));
  2848. }
  2849. // Make the page group, if we're supposed to.
  2850. if (out_pg != nullptr) {
  2851. R_TRY(this->MakePageGroup(*out_pg, addr, num_pages));
  2852. }
  2853. // Create an update allocator.
  2854. Result allocator_result{ResultSuccess};
  2855. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2856. m_memory_block_slab_manager, num_allocator_blocks);
  2857. R_TRY(allocator_result);
  2858. // Decide on new perm and attr.
  2859. new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
  2860. KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr | lock_attr);
  2861. // Update permission, if we need to.
  2862. if (new_perm != old_perm) {
  2863. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  2864. }
  2865. // Apply the memory block updates.
  2866. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm,
  2867. new_attr, KMemoryBlockDisableMergeAttribute::Locked,
  2868. KMemoryBlockDisableMergeAttribute::None);
  2869. // If we have an output page group, open.
  2870. if (out_pg) {
  2871. out_pg->Open();
  2872. }
  2873. R_SUCCEED();
  2874. }
  2875. Result KPageTable::UnlockMemory(KProcessAddress addr, size_t size, KMemoryState state_mask,
  2876. KMemoryState state, KMemoryPermission perm_mask,
  2877. KMemoryPermission perm, KMemoryAttribute attr_mask,
  2878. KMemoryAttribute attr, KMemoryPermission new_perm,
  2879. KMemoryAttribute lock_attr, const KPageGroup* pg) {
  2880. // Validate basic preconditions.
  2881. ASSERT((attr_mask & lock_attr) == lock_attr);
  2882. ASSERT((attr & lock_attr) == lock_attr);
  2883. // Validate the unlock request.
  2884. const size_t num_pages = size / PageSize;
  2885. R_UNLESS(this->Contains(addr, size), ResultInvalidCurrentMemory);
  2886. // Lock the table.
  2887. KScopedLightLock lk(m_general_lock);
  2888. // Check the state.
  2889. KMemoryState old_state{};
  2890. KMemoryPermission old_perm{};
  2891. KMemoryAttribute old_attr{};
  2892. size_t num_allocator_blocks{};
  2893. R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
  2894. std::addressof(old_attr), std::addressof(num_allocator_blocks),
  2895. addr, size, state_mask | KMemoryState::FlagReferenceCounted,
  2896. state | KMemoryState::FlagReferenceCounted, perm_mask, perm,
  2897. attr_mask, attr));
  2898. // Check the page group.
  2899. if (pg != nullptr) {
  2900. R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion);
  2901. }
  2902. // Decide on new perm and attr.
  2903. new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
  2904. KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr);
  2905. // Create an update allocator.
  2906. Result allocator_result{ResultSuccess};
  2907. KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
  2908. m_memory_block_slab_manager, num_allocator_blocks);
  2909. R_TRY(allocator_result);
  2910. // Update permission, if we need to.
  2911. if (new_perm != old_perm) {
  2912. R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
  2913. }
  2914. // Apply the memory block updates.
  2915. m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm,
  2916. new_attr, KMemoryBlockDisableMergeAttribute::None,
  2917. KMemoryBlockDisableMergeAttribute::Locked);
  2918. R_SUCCEED();
  2919. }
  2920. } // namespace Kernel