<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Ron Popov</title>
    <link rel="self" type="application/atom+xml" href="https://ronpopov.me/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://ronpopov.me"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-07-29T00:00:00+00:00</updated>
    <id>https://ronpopov.me/atom.xml</id>
    <entry xml:lang="en">
        <title>Debugging GPU Memory Access</title>
        <published>2026-07-29T00:00:00+00:00</published>
        <updated>2026-07-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ronpopov.me/gpu-memory-transfers/"/>
        <id>https://ronpopov.me/gpu-memory-transfers/</id>
        
        <content type="html" xml:base="https://ronpopov.me/gpu-memory-transfers/">&lt;section class=&quot;alert note&quot; role=&quot;note&quot; aria-labelledby=&quot;uzzKAqJk&quot;&gt;
    &lt;div class=&quot;alert-icon alert-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;alert-content&quot; role=&quot;presentation&quot;&gt;
        &lt;strong id=&quot;uzzKAqJk&quot; class=&quot;alert-title&quot; aria-hidden=&quot;true&quot;&gt;Disclaimer&lt;&#x2F;strong&gt;
        &lt;p&gt;This blog contains a lot of content, and i don&#x27;t feel like splitting it into multiple parts, it might be a bit long, there will be a TL;DR at the end&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;section&gt;
&lt;h1 id=&quot;what-s-now&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;What&#x27;s now?&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;If you have been following my previous blogs, you will know i am building pomelo, an open source alternative to the stock homemenu.
And since the homemenu, is a &lt;strong&gt;pretty&lt;&#x2F;strong&gt; critical part of the 3ds console, it&#x27;s kinda harsh.&lt;&#x2F;p&gt;
&lt;p&gt;In the previous 3 blogs, i was talking about a low level issue. When a 3ds process starts, it requests from the kernel a memory region it can use as heap, and one it can use as linear heap - heap for storing textures and GPU stuff.
The unique part about linear heap, is that it&#x27;s continous in the physical memory as well. This is very important when storing buffers that the GPU will access, as the GPU doesn&#x27;t have an MMU and works mostly with physical addresses.&lt;&#x2F;p&gt;
&lt;p&gt;For regular apps, libctru (open source 3ds SDK) just takes care of it, but when you are building a homemenu, it&#x27;s not that simple...&lt;&#x2F;p&gt;
&lt;p&gt;After i fixed the linear heap allocation, i started having other issues, in mikage everything was working just fine.
However on real hardware, the rendering failed and after some basic debugging, it&#x27;s seems like the rendering process simply hangs :(&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;3ds-gpu-rendering-process&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;3ds GPU Rendering Process&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Before we talk about what is the issue that i experienced with pomelo, we need to learn a bit about the 3ds rendering process.&lt;&#x2F;p&gt;
&lt;p&gt;The 3ds has the PICA200 GPU that we will be talking about today. And a sysmodule called the &lt;code&gt;GSP&lt;&#x2F;code&gt; module that acts as a driver for communicating with the GPU.
We also have &lt;code&gt;citro3d&lt;&#x2F;code&gt;, which is a usermode sdk, meaning the it&#x27;s part of the app that wants to render stuff, that we will be using as an abstraction layer.&lt;&#x2F;p&gt;
&lt;p&gt;Assuming we have already initialized everything required for rendering, let&#x27;s look at what happens every frame we render :)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frame-init&quot;&gt;Frame Init&lt;&#x2F;h2&gt;
&lt;p&gt;One of the most important parts of the rendering process is the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt;, it contains all the render instructions for the GPU, including textures to render, text, vectors (lines, rectangles). It also includes the physical addresses that point to the location of these textures, vectors in physical memory. Again, the GPU doesn&#x27;t really know what virtaul memory is.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; is initialized by citro3d, and allocated in the linear heap of pomele, you should already know what is a linear heap from the previous blog :)&lt;&#x2F;p&gt;
&lt;p&gt;We start by zeroing out the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt;, as we don&#x27;t want any garbage or leftovers in that buffer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;adding-textures-and-vectors&quot;&gt;Adding Textures and Vectors&lt;&#x2F;h2&gt;
&lt;p&gt;Now is the time for us to get creative :)&lt;&#x2F;p&gt;
&lt;p&gt;Pomelo now can draw the background, draw the game icons, add the game name and publisher to the frame, basically all the interesting stuff.
All these actions are transformed into commands that are added to the command buffer. They are not actually rendered, only stored in a temporary buffer, waiting to be flushed to the GPU.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frame-end&quot;&gt;Frame End&lt;&#x2F;h2&gt;
&lt;p&gt;Now is the Interesting part...&lt;&#x2F;p&gt;
&lt;p&gt;After pomelo added all the textures and everything it wants to render, we have a &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; that is filled with instructions for the GPU to process and make the magic happen.&lt;&#x2F;p&gt;
&lt;p&gt;Now there are 3 different calls to the GSP module to do in order to render the frame:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-memoryfill&quot;&gt;1. MemoryFill&lt;&#x2F;h3&gt;
&lt;p&gt;This tells the GPU to clean the VRAM memory. It is used to clear the previous frame before starting to render new stuff on top of it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-processcommandlist&quot;&gt;2. ProcessCommandList&lt;&#x2F;h3&gt;
&lt;p&gt;This call is the most complicated by far, so i want to focus on it a bit more. Also (spoiler alert), this is the call that caused pomelo to hang, we will talk more about it very soon.&lt;&#x2F;p&gt;
&lt;p&gt;It tells the GSP module to render the beautiful &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; that we have built.&lt;&#x2F;p&gt;
&lt;p&gt;We give the &lt;strong&gt;GSP module&lt;&#x2F;strong&gt; the Virtual Address of the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; and it&#x27;s size. The GSP module translates this virtual address into a physical address, that the GPU can actually use and access.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike other common operating systems, on the 3ds translating the virtual address to a physical address is fairly easy, in most cases it&#x27;s simply a hardcoded offset between the two addresses.&lt;&#x2F;p&gt;
&lt;p&gt;Then the GSP module is giving the GPU the physical address of the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; and it&#x27;s size, and the GPU does it&#x27;s magic.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-displaytransfer&quot;&gt;3. DisplayTransfer&lt;&#x2F;h3&gt;
&lt;p&gt;This call tells the GSP module to tell the GPU to start rendering all the processing it just did.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;waiting-for-a-return-signal&quot;&gt;Waiting for a Return Signal&lt;&#x2F;h2&gt;
&lt;p&gt;We will know that the GPU finished what the GSP module asked for, by receiving signals from the GPU that indicate it&#x27;s status.
Each such GSP call has a signal of it&#x27;s own that indicates the action finished:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;PSC0 - Indicates the MemoryFill finished&lt;&#x2F;li&gt;
&lt;li&gt;P3D - Indicates the ProcessCommandList finished&lt;&#x2F;li&gt;
&lt;li&gt;PPF - Indicates the DisplayTransfer finished&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Once we have received all 3 signals we can be sure that the GPU did it&#x27;s job and the image should now show up on the console :)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;diagram&quot;&gt;Diagram!&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;gpu_crash&#x2F;gpu_processing_diag.png&quot; alt=&quot;GPU ProcessCommandList Diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;debugging-the-issue&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;Debugging The Issue&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;After we transfered Pomelo to use the System region in FCRAM, instead of the APP region, which you can read more about in the previous blogs.
I suddenly noticed that pomelo started hanging shortly after booting...&lt;&#x2F;p&gt;
&lt;p&gt;I would get some text on the top screen, but the bottom screen, where i actually rendered textures and pretty stuff, was empty.
So i started adding print statements, and i very quickly learned that the part that was hanging pomelo was FrameEnd.&lt;&#x2F;p&gt;
&lt;p&gt;So i continued debugging, and the issue was that we were waiting for a signal that the GPU never sent, but which signal is the missing one?&lt;&#x2F;p&gt;
&lt;p&gt;I printed all the signals and stubbed each of the calls to the GSP module, to identify the GSP call that was causing the hang, and i learned that the &lt;strong&gt;culprit was &lt;code&gt;ProcessCommandList&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;virtual-addr-to-physical-addr-translation&quot;&gt;Virtual Addr to Physical Addr Translation&lt;&#x2F;h3&gt;
&lt;p&gt;I wanted to test if the issue could be in the translation between virtual addr to physical addr by the GSP module.&lt;&#x2F;p&gt;
&lt;p&gt;There were some changes to the address of VADDR in kernel version 2.44 of the 3ds kernel, and that was my first suspect.&lt;&#x2F;p&gt;
&lt;p&gt;I did all sorts of random stuff to test it, but the final test was editing the GSP module itself to crash when sending the physical addr to the GPU. The crash would give us the register dump, which would contain the physical addr that was passed to the GPU.&lt;&#x2F;p&gt;
&lt;p&gt;I used claude to find the exact point in the GSP module that we need to replace with svcBreak, and build me a patch file.
Because this is a sysmodule and not a regular title, we can&#x27;t use &quot;Game Patching&quot; like we did in the previous blog, we need to use &quot;sysmodule patching&quot;, that works by giving Luma3ds a patch file to patch the real GSP module.&lt;&#x2F;p&gt;
&lt;p&gt;This gave us two crash dumps, one for pomelo, and one for the real homemenu&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Pomelo GSP Module Crash&lt;&#x2F;strong&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;gpu_crash&#x2F;screenshot_27-Jul-2026_18-04-40.png&quot; alt=&quot;Pomelo GSP Crash&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Stock Homemenu GSP Module Crash&lt;&#x2F;strong&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;gpu_crash&#x2F;screenshot_27-Jul-2026_18-04-54.png&quot; alt=&quot;Stock Homemenu GSP Crash&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The relevant register is R1, which contains the physical memory (after translation from virtual) of the gpuCmdBuffer that is transfered to the GPU by the GSP module.
As you can see in the crash dumps, the physical address of the buffer that pomelo allocated is &lt;code&gt;0x280BBC00&lt;&#x2F;code&gt;. The physical address of the stock homemenu buffer is &lt;code&gt;0x28005AA0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Hmmmm, it&#x27;s not that same, but they are in the same region of memory, with a diff of around 0xB0000 bytes (~700KB), it&#x27;s probably not substantial enough to be the reason for the hang :(&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-commands-are-being-passed-to-the-gpu&quot;&gt;What commands are being passed to the GPU?&lt;&#x2F;h3&gt;
&lt;p&gt;I was trying to get claude to fix the hanging GPU issue, not with much success :(&lt;&#x2F;p&gt;
&lt;p&gt;But it did raise an interesting point. He saw i am using the stock font that comes with the console. Claude was thinking that the font was in some shared memory region that could be unreachable to the GPU.
I was able to disprove this fairly quickly but this led to an interesting thought.&lt;&#x2F;p&gt;
&lt;p&gt;If the ProcessCommandList call hangs the GPU, the reason could be one of that commands that the GPU tries to process?
Maybe one of them tries to access some weird memory region and this hangs the GPU? Maybe one of the textures &#x2F; vectors &#x2F; whatever is passed to the GPU, is mapped in some weird memory region, that the GPU cannot access?&lt;&#x2F;p&gt;
&lt;p&gt;There is only one way to find out!&lt;&#x2F;p&gt;
&lt;p&gt;So we dumped the commands from the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt; by going over the buffer and parsing the commands in the buffer. In practice, they are all GPU Register Writes, as this is how most of the interaction between the GPU and the CPU works, by writing to GPU registers.&lt;&#x2F;p&gt;
&lt;p&gt;One of them popped up right as i dumped the commands from the &lt;code&gt;gpuCmdBuffer&lt;&#x2F;code&gt;, and it was the GPU Register called &lt;strong&gt;&lt;code&gt;GPUREG_ATTRIBBUFFERS_LOC&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;
This register is used as a base address for passing addresses of vertex buffer. When we want to point the GPU at the addr of a certain vertex buffer, we only need to give the GPU the offset from the base address, and that way we can save a couple of bytes :)&lt;&#x2F;p&gt;
&lt;p&gt;When the GPU renders vertices (triangles and such, NOT TEXTURES), pomelo is expected to store all the data about the vertices in a buffer in it&#x27;s own memory, and give the GPU the address of that buffer, which should be allocated in the linear heap. Access to the vertices buffers works by giving the GPU a base address + offset.&lt;&#x2F;p&gt;
&lt;p&gt;But that is an important BUT - &lt;strong&gt;the GPU can only access the first 256MB from the base address&lt;&#x2F;strong&gt;, meaning the physical addresses that can be accesses are, base address -&amp;gt; base address + 256MB.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s look at the numbers, shall we?&lt;&#x2F;p&gt;
&lt;p&gt;The default base address in citro3d is &lt;code&gt;0x18000000&lt;&#x2F;code&gt;, The application region of FCRAM starts at &lt;code&gt;0x20000000&lt;&#x2F;code&gt;, &lt;strong&gt;The system region of FCRAM start at &lt;code&gt;0x28000000&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(FCRAM System Region Start) - (Citro3d base address) = 0x28000000 - 0x18000000 = 0x10000000 = Exactly 256MB!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Meaning, &lt;strong&gt;THE GPU CANNOT ACCESS THE SYSTEM REGION OF FCRAM!&lt;&#x2F;strong&gt;
The border of the region which the GPU can access is exactly where the System Region of FCRAM starts!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;gpu_crash&#x2F;memory_layout_diag.png&quot; alt=&quot;GPU Base Address Diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;the-fix&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;The Fix&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;The fix is as easy as bumping the value up to 0x20000000, and it fixes the issues.
The obvious caveate is that we cannot store the vertices buffer in the address range between 0x18000000 - 0x20000000, now that region doesn&#x27;t contain FCRAM, it contains VRAM and QTM Memory. I wasn&#x27;t planning to use them anytime soon (and not really even sure how to do so), but this is something to be aware of.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;what-this-means-for-pomelo&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;What This Means For Pomelo?&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Now that pomelo is using the SYSTEM region of FCRAM, a lot of games that didn&#x27;t previously boot, boot just fine now. Even big titles like Mario Kart 7, and the Pokemon games!&lt;&#x2F;p&gt;
&lt;p&gt;This is one of the bigggest challenges i have faced when building Pomelo, and i think it&#x27;s safe to say that we have solved most of the hard R&amp;amp;D parts in pomelo.
Now, what we have left is making it more usable and actually a good UX, with things such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Better shutdown sequence&lt;&#x2F;li&gt;
&lt;li&gt;Improve the return to menu sequence&lt;&#x2F;li&gt;
&lt;li&gt;Better UI&lt;&#x2F;li&gt;
&lt;li&gt;Show system stats&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And much more...&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;tl-dr&quot;&gt;&lt;h1 style=&quot;text-align: center;&quot;&gt;TL;DR&lt;&#x2F;h1&gt;&lt;&#x2F;h1&gt;
&lt;ol&gt;
&lt;li&gt;We changed pomelo to use SYSTEM region of FCRAM, instead of APPLICATION region of FCRAM.&lt;&#x2F;li&gt;
&lt;li&gt;When drawing a frame we give the GPU a vertices buffer that is stored in the linear heap. The access is done by specifying a base address, that is hardcoded in the SDK we are using, and also an offset from the base address.&lt;&#x2F;li&gt;
&lt;li&gt;The GPU can only access the 256MB of memory after the base address.&lt;&#x2F;li&gt;
&lt;li&gt;The new SYSTEM region is not part of those 256MB of memory that the GPU can access&lt;&#x2F;li&gt;
&lt;li&gt;We need to change the value of the base address in the SDK we are using.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Homemenu Memory Shenanigans - Part 3 - Finalle!</title>
        <published>2026-07-19T00:00:00+00:00</published>
        <updated>2026-07-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ronpopov.me/homemenu-memory-shenanigans-part3/"/>
        <id>https://ronpopov.me/homemenu-memory-shenanigans-part3/</id>
        
        <content type="html" xml:base="https://ronpopov.me/homemenu-memory-shenanigans-part3/">&lt;h1 id=&quot;where-we-left-off&quot;&gt;Where we left off&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;homemenu-memory-shenanigans-part1&#x2F;&quot;&gt;If you missed the first part&lt;&#x2F;a&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;homemenu-memory-shenanigans-part2&#x2F;&quot;&gt;If you missed the second part&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;tl;dr&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I wanted to know how much memory the real homemenu is requesting &lt;strong&gt;on real hardware&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;I patched the relevant svcControlMemory call to crash instead, which would dump the stack and register values - that contain the args passed to svcControlMemory, including size and etc...&lt;&#x2F;li&gt;
&lt;li&gt;The real homemenu is requesting ~13MB of linear heap, i can&#x27;t even allocate 4MB&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h1 id=&quot;external-guidance&quot;&gt;External Guidance&lt;&#x2F;h1&gt;
&lt;p&gt;I asked about my issue in a couple of forums, and @neobrain (one of the authors of mikage), suggested something interesting.&lt;&#x2F;p&gt;
&lt;p&gt;At this point in time i wasn&#x27;t sure if my issue was the &lt;strong&gt;program state&lt;&#x2F;strong&gt;, or the &lt;strong&gt;program settings&lt;&#x2F;strong&gt;, i will explain.&lt;&#x2F;p&gt;
&lt;p&gt;When i say program state, i mean that i might have to setup the 3ds state in a different way to be able to allocate the linear heap. Maybe call some other IPC call, change the order of the IPC calls that i am performing, or something of that sort.&lt;&#x2F;p&gt;
&lt;p&gt;Or it could be an issue with the &lt;strong&gt;program settings&lt;&#x2F;strong&gt;, aka, the headers of the homemenu that i am building. So @neobrain suggested i do an experiment to check if the issue is with the program itself, or maybe the headers.&lt;&#x2F;p&gt;
&lt;p&gt;To explain that, we need to talk a bit about exheaders!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;exheaders&quot;&gt;ExHeaders&lt;&#x2F;h3&gt;
&lt;p&gt;Most 3ds titles are packaged into CXI files, also known as NCCH files.
Those files contains multiple important pieces, but we will focus on 2 of them.&lt;&#x2F;p&gt;
&lt;p&gt;The first of which is the &lt;code&gt;code.bin&lt;&#x2F;code&gt; file, this is the executable itself. It&#x27;s a file that contains the compiled instructions without any wrapper format (ELF or PE) at all, simply compiled instructions.&lt;&#x2F;p&gt;
&lt;p&gt;The second interesting piece are the ExHeaders, these headers are signed by nintendo, and contain everything the 3ds system needs to know about the title to execute it. It contains a wide range of details such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Section Sizes - the size of the TEXT section, BSS section and etc...&lt;&#x2F;li&gt;
&lt;li&gt;IPC &amp;amp; Syscall Access - to which services can i perform IPC calls? which syscalls can i call?&lt;&#x2F;li&gt;
&lt;li&gt;FCRAM Memory Region - in which region we would allocate your requested memory? This is the field i changed in the first part&lt;&#x2F;li&gt;
&lt;li&gt;A lot more random stuff - TitleId, Title Dependencies, FS Access...&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;the-experiment&quot;&gt;The Experiment&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s build a code.bin file that 1 thing exactly, allocate a linear heap using svcControlMemory. Then run that code using the real homemenu exheaders, and using pomelo exheaders. That should tell us if the issue is in the code or in the exheaders.&lt;&#x2F;p&gt;
&lt;section class=&quot;alert note&quot; role=&quot;note&quot; aria-labelledby=&quot;s+FCbQtX&quot;&gt;
    &lt;div class=&quot;alert-icon alert-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;alert-content&quot; role=&quot;presentation&quot;&gt;
        &lt;strong id=&quot;s+FCbQtX&quot; class=&quot;alert-title&quot; aria-hidden=&quot;true&quot;&gt;Side Note&lt;&#x2F;strong&gt;
        &lt;p&gt;I am using Luma3ds &quot;game patching&quot; for replacing the real homemenu &lt;code&gt;code.bin&lt;&#x2F;code&gt; and &lt;code&gt;exheader.bin&lt;&#x2F;code&gt; files with pomelo ones.
Luma3ds does something &lt;em&gt;interesting&lt;&#x2F;em&gt; when replacing the original &lt;code&gt;code.bin&lt;&#x2F;code&gt; and &lt;code&gt;exheader.bin&lt;&#x2F;code&gt; files with the custom ones, and it is patching them in some cases. For examples when loading the homemenu &lt;code&gt;code.bin&lt;&#x2F;code&gt; file (doesn&#x27;t matter if the original or a patched one), it patches out some of the security checks that the homemenu performs, such as region checks, or DS flashcart whitelists.
You can see the patching that luma3ds performs in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;LumaTeam&#x2F;Luma3DS&#x2F;blob&#x2F;master&#x2F;sysmodules&#x2F;loader&#x2F;source&#x2F;patcher.c&quot;&gt;patcher.c&lt;&#x2F;a&gt;, specifically in the function &lt;code&gt;patchCode&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Since the code.bin i am building doesn&#x27;t have the original region check logic, or the DS flashcart whitelist, the loader fails to patch the &lt;code&gt;code.bin&lt;&#x2F;code&gt; file and crashes the system as a result. This is something i also encountered when building pomelo, and i fixed it in pomelo by injecting fake code that looks like the logic that luma3ds is trying to patch but is never actually executed, just so luma3ds would think that it was able to patch the homemenu.&lt;&#x2F;p&gt;
&lt;p&gt;Since i wanted to keep this payload as simple as possible, in this case i rebuild luma3ds without the security checks, just for running the test payload.&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;section&gt;
&lt;h2 id=&quot;code-snippet&quot;&gt;Code snippet&lt;&#x2F;h2&gt;
&lt;p&gt;I ran the following code that does 3 things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Call &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; and tells it to allocate a 4MB linear heap&lt;&#x2F;li&gt;
&lt;li&gt;Copy the return code to R12&lt;&#x2F;li&gt;
&lt;li&gt;Crash the system using &lt;code&gt;svcBreak&lt;&#x2F;code&gt;, so we could read the return code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.arm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.global _start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;equ&lt;&#x2F;span&gt;&lt;span&gt; MEMOP_ALLOC_LINEAR, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x10003&lt;&#x2F;span&gt;&lt;span&gt;   @ MEMOP_LINEAR (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x10000&lt;&#x2F;span&gt;&lt;span&gt;) | MEMOP_ALLOC (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;equ&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_RW,         &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x3&lt;&#x2F;span&gt;&lt;span&gt;       @ MEMPERM_READ (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) | MEMPERM_WRITE (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #66D9EF;&quot;&gt;equ&lt;&#x2F;span&gt;&lt;span&gt; ALLOC_SIZE,         &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x400000&lt;&#x2F;span&gt;&lt;span&gt;  @ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt; MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;_start:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ldr r0, =MEMOP_ALLOC_LINEAR @ op&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    mov&lt;&#x2F;span&gt;&lt;span&gt; r1, #&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;                  @ addr0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    mov&lt;&#x2F;span&gt;&lt;span&gt; r2, #&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;                  @ addr1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ldr r3, =ALLOC_SIZE         @ size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ldr r4, =MEMPERM_RW         @ perm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    svc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x01&lt;&#x2F;span&gt;&lt;span&gt;                    @ svcControlMemory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    mov&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; r12&lt;&#x2F;span&gt;&lt;span&gt;, r0                 @ stash result code where the crash screen shows it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;    mov&lt;&#x2F;span&gt;&lt;span&gt; r0, #&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;                  @ breakReason = BREAKREASON_PANIC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    svc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0x3C&lt;&#x2F;span&gt;&lt;span&gt;                    @ svcBreak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;results&quot;&gt;Results&lt;&#x2F;h2&gt;
&lt;p&gt;I ran the code using the original homemenu exheaders, and using pomelo exheaders, and here is what i got&lt;&#x2F;p&gt;
&lt;h3 id=&quot;original-homemenu-exheaders&quot;&gt;Original Homemenu ExHeaders&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_19-Jul-2026_17-01-58.png&quot; alt=&quot;Original Homemenu ExHeaders&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pomelo-exheaders&quot;&gt;Pomelo ExHeaders&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_19-Jul-2026_17-01-52.png&quot; alt=&quot;Pomelo ExHeaders&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aha&quot;&gt;AHA!&lt;&#x2F;h2&gt;
&lt;p&gt;We got our answer! &lt;strong&gt;The issue is in the ExHeaders!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can see in the crash dump of the original homemenu exheaders that the &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; call succeeded, indicated by the value 0 in R12. And you can see that when i used pomelo ExHeaders, the value in R12 was &lt;code&gt;0xD86007F3&lt;&#x2F;code&gt;, which means the &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; FAILED when using pomelo ExHeaders files.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-now&quot;&gt;What Now?&lt;&#x2F;h1&gt;
&lt;p&gt;This really narrows down the root cause of our issue. Now i know i just need to make the ExHeaders of pomelo closer to the real ones and finally the heap allocation should work.&lt;&#x2F;p&gt;
&lt;p&gt;I am using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;3DSGuy&#x2F;Project_CTR&#x2F;tree&#x2F;e8f5f529c54ff9b22a2491a480ffa69206bf7b19&#x2F;makerom&quot;&gt;makerom&lt;&#x2F;a&gt; to build the exheaders of pomelo. And i am using a &lt;code&gt;template.rsf&lt;&#x2F;code&gt; file to tell makerom which values to put in the pomelo exheaders.&lt;&#x2F;p&gt;
&lt;p&gt;I dumped the CXI file of the original homemenu from my own console, and ran &lt;code&gt;ctrtool&lt;&#x2F;code&gt; on it to extract the headers.
I gave claude my current &lt;code&gt;template.rsf&lt;&#x2F;code&gt; file and the desired homemenu exheaders, and told it to make my headers as close as possible to the real ones.&lt;&#x2F;p&gt;
&lt;p&gt;Then, A couple of claude prompts later, &lt;strong&gt;I finally found the culprit!&lt;&#x2F;strong&gt;
The culprit was the &lt;code&gt;KernelVersion&lt;&#x2F;code&gt; value, which indicates for which kernel version that title was built and tested against.
After setting the kernel version to &lt;code&gt;2.50&lt;&#x2F;code&gt;, the linear heap allocation worked!&lt;&#x2F;p&gt;
&lt;p&gt;I started having other issues related to copying buffers from the linear heap to VRAM, but i think that is a story for another time :)&lt;&#x2F;p&gt;
&lt;p&gt;The reason the kernelversion even makes a difference is that there were some changes to the virtual memory allocation in kernel version 2.44.
The virtual address to which the physical memory was mapped, was changed in kernel version 2.44. Before 2.44, the virtual address to which heaps were mapped was &lt;code&gt;0x14000000&lt;&#x2F;code&gt;, and after 2.44 it was &lt;code&gt;0x30000000&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even after understanding the connection between the kernel version and why it affects linear heap allocations, i am still not entirely sure why not setting a kernel version causes the allocation to fail. I would expect the OS to be backwards compatible with old games, taht were built for older kernels.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;That was a pretty fun research, even tho it was pretty frustrating at times, but i think the most interesting part to take from there is the research itself, and hopefully you learned something new about 3ds heap allocation :)&lt;&#x2F;p&gt;
&lt;p&gt;Like i said, i am now having other issues related to linear memory and VRAM, so i might write some more pretty soon :)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Homemenu Memory Shenanigans - Part 2</title>
        <published>2026-07-16T00:00:00+00:00</published>
        <updated>2026-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ronpopov.me/homemenu-memory-shenanigans-part2/"/>
        <id>https://ronpopov.me/homemenu-memory-shenanigans-part2/</id>
        
        <content type="html" xml:base="https://ronpopov.me/homemenu-memory-shenanigans-part2/">&lt;h1 id=&quot;where-we-left-off&quot;&gt;Where we left off&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;homemenu-memory-shenanigans-part1&#x2F;&quot;&gt;If you missed the first part&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;tl;dr&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Some games are crashing as soon as they are launched, because they don&#x27;t have enough RAM&lt;&#x2F;li&gt;
&lt;li&gt;I need to allocate my heaps in a different region of memory, dedicated for system apps, instead of the APPLICATION memory region&lt;&#x2F;li&gt;
&lt;li&gt;Pomelo fails to allocate a linear heap in the new memory region and crashes on boot :(&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h1 id=&quot;what-is-the-linear-heap&quot;&gt;What is the linear heap?&lt;&#x2F;h1&gt;
&lt;p&gt;Linear is a heap that is used for GFX operations, such as storing textures and 3d models. The only thing that is special about it is that it&#x27;s a single consecutive section in memory, unlike a regular heap allocation. In regular heaps the memory might be spread out across multiple sections in the physical memory.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;3ds-error-codes&quot;&gt;3ds Error Codes&lt;&#x2F;h1&gt;
&lt;p&gt;Using the same technique that i used to pinpoint the exact svcBreak call that crashes the system, i can use it to also leak the returnCode from the &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; (syscall that is used to allocate memory on the 3ds console). Now the code looks like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Allocate the linear heap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcControlMemory&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;__ctru_linear_heap&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	__ctru_linear_heap_size, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMOP_ALLOC_LINEAR, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMPERM_READ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_WRITE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;	asm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; volatile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;mov r11, %0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;(rc));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;	asm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; volatile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;mov r12, %0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;EEEE0003&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_16-Jul-2026_15-17-46.png&quot; alt=&quot;Crash Dump&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can see in R11 that the error code &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; returns is &lt;code&gt;0xD86007F3&lt;&#x2F;code&gt;!
Something you should know about 3ds status code is that they are actually built from 4 different values that can be used to debug the crash:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Description&lt;&#x2F;li&gt;
&lt;li&gt;Module&lt;&#x2F;li&gt;
&lt;li&gt;Summary&lt;&#x2F;li&gt;
&lt;li&gt;Level&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;After decoding the error code using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.3dbrew.org&#x2F;wiki&#x2F;Error_codes&quot;&gt;3dbrew docs&lt;&#x2F;a&gt;, i got the following values and their meaning&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description : 0x3f3 (1011) - Out of memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Module : 0x1 (1) - Kernel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary : 0x3 (3) - Out of resource&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Level : 0x1b (27) - Permanent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Out of memory? That&#x27;s weird...&lt;&#x2F;strong&gt;
I am requesting the same amount of memory that the real homemenu is requesting. I got that number by running the real homemenu in mikage and searching for the &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; the real homemenu is calling. Operation &lt;code&gt;0x3&lt;&#x2F;code&gt; is MEMOP_ALLOC, and operation &lt;code&gt;0x10003&lt;&#x2F;code&gt; is MEMOP_ALLOC_LINEAR.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Regular heap allocation - Around 3MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SVCControlMemory: addr0=0x08000000, addr1=0x00000000, size=0x304000, op=0x3, perm=0x3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Linear heap allocation - Around 11MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SVCControlMemory: addr0=0x00000000, addr1=0x00000000, size=0xb64000, op=0x10003, perm=0x3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude suggested the reason the linear heap allocation fails is because a linear heap requires a continuous section of memory, let&#x27;s see how much memory i have available and if that makes sense
Well, i have quite a lot of memory...
Overall the system has around 255mb of ram, with 248mb available, however we are more interested specifically in the SYSTEM memory region, as only there we can allocate memory.
This region has around 100mb of ram, with 95mb of ram available for allocation, so how could that be???&lt;&#x2F;p&gt;
&lt;h1 id=&quot;how-much-memory-does-the-real-homemenu-allocate&quot;&gt;How much memory does the real homemenu allocate?&lt;&#x2F;h1&gt;
&lt;p&gt;When running the real homemenu in mikage it told me that the real homemenu is requesting around 11mb of linear heap memory, however when i request 11mb of linear heap memory using pomelo on real hardware, it crashes.
I assume there&#x27;s some diff between the way the homemenu does that on a real console and in mikage, and it&#x27;s not farfetched that the console allocated more &#x2F; less memory, based on the 3ds model (some models have more RAM than others).
I tried to reverse engineer the real homemenu and attempt to find how much linear heap it requests and i couldn&#x27;t find anything, so i really wanted to get this value somehow from the real hardware.&lt;&#x2F;p&gt;
&lt;p&gt;Now, getting those numbers is a bit hard, we want to capture the homemenu performing a syscall (which is handled by the kernel). Even tho there are debuggers for physical consoles, i&#x27;m not really sure how i could go for debugging the homemenu or the kernel itself.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t really want to invest in using, or maybe even building something like this for a super specific use case (getting the amount of ram that the real homemenu is requesting). So i decided to do something super hacky, that worked!&lt;&#x2F;p&gt;
&lt;p&gt;I dumped the &lt;code&gt;code.bin&lt;&#x2F;code&gt; file from the stock homemenu to disassemble it and get its logic, as i said i found the linear heap &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; call, but i couldn&#x27;t find what is the value that is being passed to it, it seems like it is never initialized.
So i decided to do the following, &lt;strong&gt;i patched the function call to &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; with &lt;code&gt;int 0x3C&lt;&#x2F;code&gt;, or in human language - &lt;code&gt;svcBreak&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;.
That means that instead of calling &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt;, the console will crash, and show me the registers and stack state when the call to &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; was supposed to take place, from which i could extract the different variables that are passed to it, including how much memory is requested.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00146dac 00 20 a0 e3     mov        r2,#0x0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00146db0 08 00 8d e2     add        currentSize,sp,#0x8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00146db4 24 fb ff eb     bl         ctr::svcControlMemory &amp;lt;-- replace this opcode with &amp;quot;int 0x3C&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00146db8 02 11 10 e2     ands       svcResult,currentSize,#0x80000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00146dbc 00 f0 20 e3     nop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So i patched the homemenu code.bin file, and used Luma3ds game patching to tell my console to use the patched code.bin file instead of the original homemenu, booted it up, aaaannnnnnddddddd
&lt;strong&gt;I got this beautiful crash screen :)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_16-Jul-2026_16-28-13.png&quot; alt=&quot;Crash Dump&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From here i could extract the total size that is requested for the linear heap from R4 - 0x00D00000, which is 13MB???
How does that make sense??? That&#x27;s more than what we request in mikage, and i can&#x27;t even get 4MB allocated, oof :(&lt;&#x2F;p&gt;
&lt;p&gt;I then also patched the instruction after the call to &lt;code&gt;svcControlMemory&lt;&#x2F;code&gt; to make sure the call succeeded, and it did.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;temp-summary&quot;&gt;Temp Summary&lt;&#x2F;h1&gt;
&lt;p&gt;So what did we have here?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The real homemenu is allocating 11MB when running in mikage&lt;&#x2F;li&gt;
&lt;li&gt;It allocates 13MB when running on real hardware&lt;&#x2F;li&gt;
&lt;li&gt;I can&#x27;t allocate 4MB in the same memory region :(&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;More in the next one!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Homemenu Memory Shenanigans - Part 1</title>
        <published>2026-07-13T00:00:00+00:00</published>
        <updated>2026-07-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ronpopov.me/homemenu-memory-shenanigans-part1/"/>
        <id>https://ronpopov.me/homemenu-memory-shenanigans-part1/</id>
        
        <content type="html" xml:base="https://ronpopov.me/homemenu-memory-shenanigans-part1/">&lt;h1 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h1&gt;
&lt;p&gt;While building Pomelo (which you can read more about in my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;introducing-pomelo&#x2F;&quot;&gt;previous blog&lt;&#x2F;a&gt;), i noticed that some games that pomelo tried to boot, would crash very quickly after they started - usually the more serious ones such as the mario and legend of zelda series. I assumed that i didn&#x27;t initialize &#x2F; handle something correctly, which caused some games to crash.&lt;&#x2F;p&gt;
&lt;p&gt;One such game was &quot;Super Mario 3D World&quot;, so i decided to take this one as an example, and assumed that getting it to boot, should fix the same issues that a lot of games had.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;how&quot;&gt;How?&lt;&#x2F;h1&gt;
&lt;p&gt;I dumped the game from my console, and put it into ghidra to try and understand why the game was crashing. I would also mention that i got a pretty detailed stack dump from my 3ds console, including the state of all the registers, and the stack.&lt;&#x2F;p&gt;
&lt;p&gt;I loaded the game binary into ghidra, and used the modern marvel of Artificial Intelligence to my help. I connected claude code to the ghidra MCP server, gave it the crash dump, and very quickly it gave me the answer i was looking for.
The reason &quot;Super Mario 3D World&quot; was crashing, when the game boots, it checks how much RAM is has available for use, and if it doesn&#x27;t have enough, it crashes :(&lt;&#x2F;p&gt;
&lt;p&gt;But in that case, how does the game boot at all? After all pomelo uses much less memory than the stock homemenu, so what is the issue?
And that&#x27;s when i learned about 3ds FCRAM memory regions.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;fcram-memory-regions&quot;&gt;FCRAM Memory Regions&lt;&#x2F;h1&gt;
&lt;p&gt;As you can see in this super useful &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;wwylele&#x2F;misc-3ds-diagram&#x2F;master&#x2F;memory.svg&quot;&gt;diagram&lt;&#x2F;a&gt;, the 3ds FCRAM is where the heaps of all the different processes in the 3ds are allocated.
The FCRAM is split into 3 sections:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;APPLICATION - For Games and Applications running on the 3ds system, such as &quot;Mario Kart 7&quot;, &quot;Super Mario 3D World&quot; and etc...&lt;&#x2F;li&gt;
&lt;li&gt;BASE - Used by some of the sysmodules, and also the kernel itself.&lt;&#x2F;li&gt;
&lt;li&gt;SYSTEM - Used by the NS module, some system applets (system apps such as camera or settings menu), and most importantly &lt;strong&gt;the homemenu is using this section&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;aha&quot;&gt;AHA!&lt;&#x2F;h1&gt;
&lt;p&gt;The memory region that the title is using, is defined by the title itself. Titles will usually use the APPLICATION system region, and since titles are signed by Nintendo, this is not something that the author of the app can change.
However on modded consoles, we can practically do whatever we want.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of pomelo, it is using the APPLICATION memory region, as you can see defined in the &lt;code&gt;template.rsf&lt;&#x2F;code&gt; file that is used the build the CXI section&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;MemoryType&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; Application&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;AHA! Now everything makes sense! Because Pomelo is using the &lt;code&gt;APPLICATION&lt;&#x2F;code&gt; system region, it&#x27;s using some of the memory that is reserved for actual 3ds games, and when &quot;Super Mario 3D World&quot; is booting, it doesn&#x27;t have the amount of memory that it expected.
So the fix should be as simple as changing that to &lt;code&gt;SYSTEM&lt;&#x2F;code&gt;, right? Sadly, it&#x27;s not that simple..&lt;&#x2F;p&gt;
&lt;h1 id=&quot;something-is-crashing&quot;&gt;Something is crashing :(&lt;&#x2F;h1&gt;
&lt;p&gt;Re-building Pomelo and running it on my modded console, i immediately got a crash :(&lt;&#x2F;p&gt;
&lt;p&gt;The crash dump we got looked like this. As you can see we can see the state of each register, we also have the state of the stack in the bottom screen, however that is not relevant at the moment.
The first interesting thing you can see here, is that the Exception Type is &lt;code&gt;svcBreak&lt;&#x2F;code&gt;, which is a syscall that has a single purpose - crash the system.
This means that some code somewhere, reached a state where it just couldn&#x27;t continue and had no other choice, but to crash.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_12-Jul-2026_23-56-14.png&quot; alt=&quot;Our First Crash Dump&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The PC register pointed to the &lt;code&gt;svcBreak&lt;&#x2F;code&gt; function, luckily we can use the LR register to see which function called &lt;code&gt;svcBreak&lt;&#x2F;code&gt;,
The LR function pointed to a function called &lt;code&gt;__system_allocateHeaps&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The function &lt;code&gt;__system_allocateHeaps&lt;&#x2F;code&gt; is a function that runs at a very early stage of the title boot, even before the &lt;code&gt;main&lt;&#x2F;code&gt; function is executed.
It kinda makes sense that by playing with the memory region in which the heap is allocated, we broke something related to heap allocations. Let&#x27;s dig into this function and understand which specific section is crashing!&lt;&#x2F;p&gt;
&lt;p&gt;The relevant function looked something like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Retrieve handle to the resource limit object for our process&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;Handle&lt;&#x2F;span&gt;&lt;span&gt; reslimit &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcGetResourceLimit&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;reslimit&lt;&#x2F;span&gt;&lt;span&gt;, CUR_PROCESS_HANDLE);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Retrieve information about total&#x2F;used memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; and calculate how much memory we can allocate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Allocate the application heap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcControlMemory&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;__ctru_heap&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	OS_HEAP_AREA_BEGIN,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	__ctru_heap_size, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMOP_ALLOC, MEMPERM_READ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_WRITE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Allocate the linear heap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcControlMemory&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;__ctru_linear_heap&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	__ctru_linear_heap_size, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMOP_ALLOC_LINEAR, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMPERM_READ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_WRITE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, we have 3 svcBreak calls in this function, but how can we know which one is the relevant one?
I used R12 as an error code register, in which i set a hardcoded value, just before the call to svcBreak. As svcBreak doesn&#x27;t really change the value of the registers, that value would later show up in the register state dump i get when the console crashes.&lt;&#x2F;p&gt;
&lt;p&gt;The updated code looked something like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Retrieve handle to the resource limit object for our process&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;Handle&lt;&#x2F;span&gt;&lt;span&gt; reslimit &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcGetResourceLimit&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;reslimit&lt;&#x2F;span&gt;&lt;span&gt;, CUR_PROCESS_HANDLE);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;	asm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; volatile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;mov r12, %0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;EEEE0001&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Retrieve information about total&#x2F;used memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; and calculate how much memory we can allocate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Allocate the application heap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcControlMemory&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;__ctru_heap&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	OS_HEAP_AREA_BEGIN,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	__ctru_heap_size, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMOP_ALLOC, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMPERM_READ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_WRITE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;	asm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; volatile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;mov r12, %0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;EEEE0002&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88846F;&quot;&gt;&#x2F;&#x2F; Allocate the linear heap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rc &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt; svcControlMemory&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FD971F;font-style: italic;&quot;&gt;__ctru_linear_heap&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;	0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	__ctru_linear_heap_size, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMOP_ALLOC_LINEAR, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	MEMPERM_READ &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt; MEMPERM_WRITE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;R_FAILED&lt;&#x2F;span&gt;&lt;span&gt;(rc)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #66D9EF;font-style: italic;&quot;&gt;	asm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt; volatile&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;mov r12, %0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; : :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E6DB74;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F92672;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #AE81FF;&quot;&gt;EEEE0003&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6E22E;&quot;&gt;	svcBreak&lt;&#x2F;span&gt;&lt;span&gt;(USERBREAK_PANIC);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now i could pinpoint the exact svc call that failed and causes the system to crash! After running the code on my console, R12 had the value &lt;code&gt;0xEEEE0003&lt;&#x2F;code&gt;, which means that Pomelo fails to allocate the linear heap.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;homemenu_memory_shenanigans&#x2F;screenshot_13-Jul-2026_00-12-04.png&quot; alt=&quot;Our Second Crash Dump&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;&#x2F;h1&gt;
&lt;p&gt;I feel like this is already kinda long, and i have quite a lot more to cover, so i have to split this blog into (hopefuly) 2 parts :)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Introducing Pomelo</title>
        <published>2026-07-09T00:00:00+00:00</published>
        <updated>2026-07-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ronpopov.me/introducing-pomelo/"/>
        <id>https://ronpopov.me/introducing-pomelo/</id>
        
        <content type="html" xml:base="https://ronpopov.me/introducing-pomelo/">&lt;h1 id=&quot;pomelo-an-alternative-3ds-homemenu&quot;&gt;Pomelo - An Alternative 3DS Homemenu!&lt;&#x2F;h1&gt;
&lt;p&gt;Hi Everyone, I am happy to share a project i was working on for the last couple of months called &quot;&lt;strong&gt;Pomelo&lt;&#x2F;strong&gt;&quot;, which is an &lt;strong&gt;open-source alternative for the stock 3ds homemenu!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;When i got my first 3ds console, a couple of months ago, i wanted to customize the homemenu UI of my console.
I was quite surprised to see that the only customization mechanism was themes, and there was no alternative for the stock nintendo homemenu.&lt;&#x2F;p&gt;
&lt;p&gt;Being in a time of my life where i had quite a lot of spare time, writing a homemenu for a console i know nothing about sounded like quite a cool project, that i really fell in love with over time.
I started learning about 3ds hacking and very quickly learned of a very supportive community that has TON of knowledge about anything 3ds related. Which made the entire experience a lot more fun :)&lt;&#x2F;p&gt;
&lt;p&gt;My goal with this project is to build an open source alternative to the stock nintendo homemenu, that would allow the community to customize and easily redesign.
Currently Pomelo has a very limited set of features and changing the design requires writing C code :(
I am hoping to implement a themes mechanism in the future, similar to the one nintendo has, but more flexible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;features&quot;&gt;Features&lt;&#x2F;h2&gt;
&lt;p&gt;The homemenu is a very integral part of the 3ds console, doing really, a TON of stuff behind the scenes. I don&#x27;t think Pomelo would ever be able to have the full set of features that the stock homemenu has, however i do think that it is very close to having the important features, that will allow most users to use Pomelo as a daily driver.&lt;&#x2F;p&gt;
&lt;p&gt;Currently Pomelo is still in development, the features i was focusing on are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Game Enumeration - Get a list of all the installed titles&lt;&#x2F;li&gt;
&lt;li&gt;Game Metadata - Show the name and icon of all the installed games&lt;&#x2F;li&gt;
&lt;li&gt;Game Launching - Launch one of the games that are installed on your console. This feature is pretty buggy, a lot of games crash very quickly or even don&#x27;t boot at all.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;design&quot;&gt;Design&lt;&#x2F;h2&gt;
&lt;p&gt;As you can see in the screenshots below, i am still playing around with the design until i find something i like.
Currently, my vibe is something retro, right now i&#x27;m trying to make it look like a NDS.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plans-for-the-future&quot;&gt;Plans for the future&lt;&#x2F;h2&gt;
&lt;p&gt;First of all i want to focus on improving the Game Launching part, i understand this is one of the most important features of the 3ds homemenu.
I want to get Pomelo to a state where users can actually use this as their daily driver. And then start with all the random QoL improvements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;&#x2F;h2&gt;
&lt;p&gt;Pomelo is using Luma3ds &quot;Game Patching&quot; to replace the stock nintendo homemenu, note that &quot;Game Patching&quot; is an optional feature, that has to be enabled. Currently i only tested it on my console which is a New 3DS US.
Currently the project is still in &lt;strong&gt;very early development&lt;&#x2F;strong&gt;, the source code is available for those who wish to run it on their own consoles.&lt;&#x2F;p&gt;
&lt;p&gt;For more details on installation, see the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ron-popov&#x2F;3ds-Pomelo&quot;&gt;Github Repo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;feedback&quot;&gt;Feedback&lt;&#x2F;h2&gt;
&lt;p&gt;I would love to hear your feedback and thoughts on this project, however, please note that this is a side project of mine and i am working on it in my spare time, so please be patient &amp;lt;3&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;p&gt;Pomelo is using Luma3ds Game Patching to load itself, instead of the stock homemenu, in case something goes wrong, simply remove the Pomelo &lt;code&gt;code.bin&lt;&#x2F;code&gt; and &lt;code&gt;exheader.bin&lt;&#x2F;code&gt; files from the SDCard and the stock homemenu should boot as normal.
However POMELO HAS NOT BEEN THOROUGHLY TESTED, &lt;strong&gt;USE AT YOUR OWN RISK&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;screenshots&quot;&gt;Screenshots!&lt;&#x2F;h2&gt;
&lt;p&gt;Pomelo running on real New 3DS hardware:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;introducing_pomelo&#x2F;screenshot_09-Jul-2026_14-11-00.png&quot; alt=&quot;Pomelo running on a New 3DS console, showing the game grid&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pomelo running in Mikage emulator:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;introducing_pomelo&#x2F;screenshot_12-Jun-2026_13-55-28.png&quot; alt=&quot;Pomelo running in the Mikage emulator, showing the game grid&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;introducing_pomelo&#x2F;screenshot_09-Jul-2026_19-20-03.png&quot; alt=&quot;Pomelo running in the Mikage emulator, NDS style&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ronpopov.me&#x2F;images&#x2F;introducing_pomelo&#x2F;screenshot_10-Jul-2026_14-23-26.png&quot; alt=&quot;Pomelo running in the Mikage emulator, NDS style&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
