templeos-info/public/Wb/Doc/MemOverview.DD.HTML

144 lines
12 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="generator" content="TempleOS V5.03">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/style/templeos.css">
<script src="/script/templeos.js"></script>
<style type="text/css">
.cF0{color:#000000;background-color:#ffffff;}
.cF1{color:#0000aa;background-color:#ffffff;}
.cF2{color:#00aa00;background-color:#ffffff;}
.cF3{color:#00aaaa;background-color:#ffffff;}
.cF4{color:#aa0000;background-color:#ffffff;}
.cF5{color:#aa00aa;background-color:#ffffff;}
.cF6{color:#aa5500;background-color:#ffffff;}
.cF7{color:#aaaaaa;background-color:#ffffff;}
.cF8{color:#555555;background-color:#ffffff;}
.cF9{color:#5555ff;background-color:#ffffff;}
.cFA{color:#55ff55;background-color:#ffffff;}
.cFB{color:#55ffff;background-color:#ffffff;}
.cFC{color:#ff5555;background-color:#ffffff;}
.cFD{color:#ff55ff;background-color:#ffffff;}
.cFE{color:#ffff55;background-color:#ffffff;}
.cFF{color:#ffffff;background-color:#ffffff;}
</style>
</head>
<body>
<pre style="font-family: courier, monospace; font-size: 10pt;">
<a name="l1"></a><span class=cF5> Memory Overview</span><span class=cF0>
<a name="l2"></a>
<a name="l3"></a>Paging is practically not used. 64-bit mode requires paging, however, so it is
<a name="l4"></a>identity-mapped -- virtual identical to physical. All tasks on all cores use
<a name="l5"></a>the same page table map, just as though all addresses are physical addresses.
<a name="l6"></a>2Meg or 1Gig page table entries are used. Nothing swaps to disk.
<a name="l7"></a>
<a name="l8"></a>In TempleOS, the lowest 2Gig of memory is called the </span><span class=cF2>code heap</span><span class=cF0>. TempleOS's
<a name="l9"></a>compiler always uses 32-bit signed relative JMP &amp; CALL insts because 64-bit
<a name="l10"></a>CALLs take two insts. With signed +/- 32-bit values, code can only call a
<a name="l11"></a>function within 2Gig distance. Therefore, TempleOS keeps all code in the lowest
<a name="l12"></a>2Gig memory addresses including what would normally be called &quot;the kernel&quot;. Two
<a name="l13"></a>Gig is plenty for code, don't worry.
<a name="l14"></a>
<a name="l15"></a>You can create new, independent heaps using </span><a href="/Wb/Kernel/Mem/HeapCtrl.HC#l1"><span class=cF4>HeapCtrlInit</span></a><span class=cF0>(). Then, use the </span><span class=cF4>
<a name="l16"></a></span><a href="/Wb/Kernel/KernelA.HH#l2863"><span class=cF4>CHeapCtrl</span></a><span class=cF0> as the 2nd arg to </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l387"><span class=cF4>MAlloc</span></a><span class=cF0>(). See </span><a href="/Wb/Adam/Opt/Utils/HeapLog.HC#l73"><span class=cF4>HeapLog</span></a><span class=cF0>() for an example.
<a name="l17"></a>
<a name="l18"></a>Memory alloced by a task will be freed when the task is killed. The </span><a href="/Wb/Doc/Glossary.DD.HTML#l171"><span class=cF4>Adam Task</span></a><span class=cF0>
<a name="l19"></a>is a task that never dies. His memory is like kernel memory in other operating
<a name="l20"></a>systems. See </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l402"><span class=cF4>ACAlloc</span></a><span class=cF0>(), </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l390"><span class=cF4>AMAlloc</span></a><span class=cF0>(), </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l418"><span class=cF4>AMAllocIdent</span></a><span class=cF0>() and </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l461"><span class=cF4>AStrNew</span></a><span class=cF0>().
<a name="l21"></a>
<a name="l22"></a>All of the regular page tables are marked, &quot;cached&quot;. When accessing hardware,
<a name="l23"></a>however, you need uncached page table. The lowest 4Gig addresses have an alias
<a name="l24"></a>to access hardware located toward the top of mapped space, </span><span class=cF2>0x10000000000</span><span class=cF0>. See </span><span class=cF4>
<a name="l25"></a></span><a href="/Wb/Kernel/KMain.HC#l69"><span class=cF4>dev.uncached_alias</span></a><span class=cF0>.
<a name="l26"></a>
<a name="l27"></a>During an extended powered-on session of TempleOS, in theory, memory will become
<a name="l28"></a>fragmented, requiring a reboot. It has never happens to me.
<a name="l29"></a>
<a name="l30"></a>See </span><a href="/Wb/Adam/Opt/Utils/MemRep.HC#l193"><span class=cF4>MemRep</span></a><span class=cF0>() and </span><a href="/Wb/Demo/MemDemo.HC#l1"><span class=cF4>::/Demo/MemDemo.HC</span></a><span class=cF0>.
<a name="l31"></a>
<a name="l32"></a>
<a name="l33"></a></span><span class=cF5> Single System-wide Mem Map
<a name="l34"></a>
<a name="l35"></a></span><span class=cF2> 0x0000007C00- 0x000003616F</span><span class=cF0>
<a name="l36"></a> Kernel module, placed here by the boot-loader, </span><a href="/Wb/Kernel/KernelA.HH#l3835"><span class=cF4>BOOT_RAM_BASE</span></a><span class=cF0>.
<a name="l37"></a>
<a name="l38"></a></span><span class=cF2> 0x0000096600- 0x0000096FFF</span><span class=cF0>
<a name="l39"></a> Boot block relocated here before loading the Kernel module, </span><a href="/Wb/Adam/Opt/Boot/BootDVD.HC#l1"><span class=cF4>BootDVD</span></a><span class=cF0> &amp; </span><a href="/Wb/Adam/Opt/Boot/BootHD.HC#l1"><span class=cF4>BootHD</span></a><span class=cF0>.
<a name="l40"></a>
<a name="l41"></a></span><span class=cF2> 0x0000097000- 0x0000097030</span><span class=cF0> Multicore start-up vect code, </span><a href="/Wb/Kernel/KernelA.HH#l525"><span class=cF4>MPN_VECT</span></a><span class=cF0>.
<a name="l42"></a></span><span class=cF2>~0x000009F000- 0x000009FFFF</span><span class=cF0> Extended BIOS data area.
<a name="l43"></a></span><span class=cF2> 0x00000A0000- 0x00000BFFFF</span><span class=cF0> VGA graphics mem with alias at </span><a href="/Wb/Kernel/KGlbls.HC#l30"><span class=cF4>text</span></a><span class=cF0>.vga_alias.
<a name="l44"></a></span><span class=cF2> 0x0000100000- 0x0000101FFF</span><span class=cF0> </span><a href="/Wb/Kernel/KernelA.HH#l3415"><span class=cF4>CSysFixedArea</span></a><span class=cF0> for misc.
<a name="l45"></a></span><span class=cF2> 0x000050A000- 0x001FFDFFFF</span><span class=cF0> Code Heap mem.
<a name="l46"></a>
<a name="l47"></a></span><span class=cF2> 0x00E0000000- 0x00FFFFFFFF</span><span class=cF0>
<a name="l48"></a> 32-bit devices could alloc memory at 0xF0000000 going up, but this is wrong,
<a name="l49"></a> since some PCs already have devices at 0xF0000000. No PCI devices are
<a name="l50"></a> supported, so </span><a href="/Wb/Kernel/Mem/MemPhysical.HC#l58"><span class=cF4>Mem32DevAlloc</span></a><span class=cF0>() flaws are not an issue.
<a name="l51"></a>
<a name="l52"></a></span><span class=cF2> 0x0080000000-~0x00DFFFFFFF</span><span class=cF0>
<a name="l53"></a></span><span class=cF2> 0x0100000000-~0xFFFFFFFFFF</span><span class=cF0>
<a name="l54"></a> Data Heap mem. (The physical memory that exists in this range is data heap.)
<a name="l55"></a>
<a name="l56"></a></span><span class=cF2> 0x10000000000- 0x100FFFFFFFF</span><span class=cF0>
<a name="l57"></a> Uncached alias of first 4Gig. (For 32-bit device access.)
<a name="l58"></a>
<a name="l59"></a></span><span class=cF2> - 0x100FFFFFFFF</span><span class=cF0>
<a name="l60"></a> 64-bit devices are alloced with </span><a href="/Wb/Kernel/Mem/MemPhysical.HC#l108"><span class=cF4>Mem64DevAlloc</span></a><span class=cF0>() counting bwd, but no PCI
<a name="l61"></a> devices are actually supported.
<a name="l62"></a>
<a name="l63"></a>
<a name="l64"></a>
<a name="l65"></a>* Note: There is a break in the data-heap block pool. This has no effect except
<a name="l66"></a>the obvious effect that fragmentation has on contiguous requests. I can </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l387"><span class=cF4>MAlloc</span></a><span class=cF0>(
<a name="l67"></a>) an 8Gig chunk on my 12Gig machine. I can </span><a href="/Wb/Kernel/Mem/MAllocFree.HC#l387"><span class=cF4>MAlloc</span></a><span class=cF0>() an 32Gig chunk on my 64Gig
<a name="l68"></a>machine.
<a name="l69"></a>
<a name="l70"></a>* Note: For systems with less than 2Gig RAM, the code and data heap block pools
<a name="l71"></a>are the same. For systems with 2-4Gig of RAM, the code heap is 1/4 of the
<a name="l72"></a>total. See </span><a href="/Wb/Kernel/Mem/BlkPool.HC#l29"><span class=cF4>BlkPoolsInit</span></a><span class=cF0>().
<a name="l73"></a>
<a name="l74"></a>
<a name="l75"></a></span><span class=cF5> History</span><span class=cF0>
<a name="l76"></a>
<a name="l77"></a>In 2003, I wanted to make a no-paging ring-0-only 64-bit operating system for
<a name="l78"></a>super speed with simplicity and full access. With paging, every memory request
<a name="l79"></a>requires 5 accesses -- it must access the address itself, 4K, 2Meg, 1Gig, and
<a name="l80"></a>512Gig page tables, but the CPU's translation look-aside buffer mostly removes
<a name="l81"></a>the penalty for using paging. So, I did not want to use paging, but long mode
<a name="l82"></a>requires it. I did the next best thing -- I identity-mapped everything and
<a name="l83"></a>achieved the simplicity I was after with subtle performance boosts, not wasting
<a name="l84"></a>time changing address maps. And, I look forward to the day I command Intel to
<a name="l85"></a>make an optimized no-paging long mode.
<a name="l86"></a>
<a name="l87"></a>I needed VGA A0000-BFFFF memory to be write-through and 0xE0000000-0xFFFFFFFF to
<a name="l88"></a>be uncached for various devices. All 64-bit computers allow stopping address
<a name="l89"></a>translation at 2Meg page size, not using 4K. I wanted to use 2Meg for
<a name="l90"></a>everything because it's faster, with one less level of page tables. I had to
<a name="l91"></a>make A0000-BFFFF write-through, though, so I could not use 2Meg size on the
<a name="l92"></a>lowest page. I did the lowest 2Meg area as 4K pages. I also unmapped the first
<a name="l93"></a>4K to cause a fault when dereferencing NULL.
<a name="l94"></a>
<a name="l95"></a>In 2016, I came-up with an alternate idea. I double mapped the lowest memory
<a name="l96"></a>with an alias that was uncached. Accessing the lowest 2Meg area directly was
<a name="l97"></a>cached but the alias I created up at the top of address space was uncached. See </span><span class=cF4>
<a name="l98"></a></span><a href="/Wb/Kernel/Mem/MemPhysical.HC#l138"><span class=cF4>UncachedAliasAlloc</span></a><span class=cF0>(). Unfortunately, I could no longer boast of the simplicity
<a name="l99"></a>of identity mapping everything. Since many of my users are familiar with
<a name="l100"></a>A0000-BFFFF, it is actually pretty seriously unfortunate that they cannot use
<a name="l101"></a>the easy-to-understand numbers of A0000-BFFFF, but must access the relocated
<a name="l102"></a>alias location. See </span><a href="/Wb/Kernel/KMain.HC#l69"><span class=cF4>text.vga_alias</span></a><span class=cF0>. I also no longer cause a fault when
<a name="l103"></a>dereferencing NULL.
<a name="l104"></a>
<a name="l105"></a>Then, I switched to 1Gig page sizes. For the lowest 4Gig, I set-up an alias up
<a name="l106"></a>at the top of address space. See </span><a href="/Wb/Kernel/Mem/MemPhysical.HC#l138"><span class=cF4>UncachedAliasAlloc</span></a><span class=cF0>(). Not all computers
<a name="l107"></a>support 1Gig page tables, however, so I also support 2Meg.
<a name="l108"></a>
<a name="l109"></a>My original plan was to allow changing the page tables as needed, so I had code
<a name="l110"></a>for taking control of 2Meg pages and marking them uncached or whatever. When I
<a name="l111"></a>did a HDAudio driver, I requested some 32-bit address space as uncached. Today,
<a name="l112"></a>all of the first 4Gig can be accessed without caching at the </span><a href="/Wb/Kernel/KMain.HC#l69"><span class=cF4>dev.uncached_alias</span></a><span class=cF0>.
</span></pre></body>
</html>