Browse Source

Lots of mx docs

master
Bottersnike 2 months ago
parent
commit
d50469adfd
  1. 7
      docs.py
  2. 14
      headers.js
  3. 36
      styles.css
  4. 186
      templates/pages/sega/software/index.html
  5. 147
      templates/pages/sega/software/mx/mxkeychip.html
  6. 51
      templates/pages/sega/software/mx/mxmaster.html
  7. 0
      templates/pages/sega/software/mx/mxprestartup.html
  8. 9
      templates/pages/sega/software/mx/mxstartup.html
  9. 23
      templates/pages/sega/software/mxmaster.html
  10. 4
      templates/pages/sega/software/security/dongle.html
  11. 4
      templates/sega.html

7
docs.py

@ -50,14 +50,13 @@ SEGA_CONTENTS = {
"drivers": ("Device drivers", None),
"security": ("Security", {
"game.html": "Game encryption",
"dongle.html": "Dongles",
"keychip.html": "Keychips",
}),
"groovemaster.html": "GrooveMaster.ini",
}),
"network": ("Networking", {
"allnet.html": "ALL.Net"
}),
# "network": ("Networking", {
# "allnet.html": "ALL.Net"
# }),
}
CONTENTS = {
"": EAMUSE_CONTENTS,

14
headers.js

@ -1,4 +1,5 @@
for (const el of document.querySelectorAll("[id]")) {
if (el.tagName === "marker") continue;
el.classList.add("haspara");
const pilcrow = document.createElement("a");
pilcrow.className = "pilcrow";
@ -13,8 +14,8 @@ const foldable = (root, children) => {
if (e.target.classList.contains("pilcrow")) state = true;
else state = !state;
children.style.height = state ? "auto" : "0";
children.style.overflow = state ? "visible" : "hidden";
if (state) children.classList.remove("closed");
else children.classList.add("closed");
if (state) root.classList.remove("closed");
else root.classList.add("closed");
});
@ -31,6 +32,7 @@ const make_foldable = (root) => {
if (!stack.root) continue;
const new_e = document.createElement("div");
new_e.classList.add("toggle-section");
for (const old_e of stack.children) {
old_e.remove();
new_e.appendChild(old_e);
@ -54,7 +56,13 @@ const make_foldable = (root) => {
}
};
let end = null;
for (const child of [...root.children]) {
if (child.tagName === "FOOTER") {
end = child;
break;
}
if (/^H\d$/.test(child.tagName)) {
const this_level = parseInt(child.tagName[1]) - 1;
@ -73,7 +81,7 @@ const make_foldable = (root) => {
}
for (let level = 9; level >= 0; level--) {
flush_header(level, null);
flush_header(level, end);
}
};
make_foldable(document.body);

36
styles.css

@ -24,6 +24,10 @@ thead {
border-bottom: 2px solid currentColor;
}
svg {
transform: translateZ(0);
}
td {
border: 1px solid #111;
padding: 2px;
@ -218,9 +222,11 @@ figure>figcaption:first-child {
span.mark {
outline: 1px solid #c7254e;
}
.client {
color: #f5417d;
}
.server {
color: #4171f5;
}
@ -238,6 +244,11 @@ mark {
cursor: pointer;
position: relative;
}
.toggle-root.closed {
user-select: none;
}
.toggle-root::before {
opacity: .5;
content: "";
@ -251,13 +262,38 @@ mark {
transform: translateY(-50%) rotate(45deg);
transition: transform 100ms ease-out, opacity 100ms ease-out;
}
.toggle-root:hover::before {
opacity: 1;
}
.toggle-root.closed::before {
transform: translateY(-50%) rotate(-45deg);
}
.toggle-section {
opacity: 1;
height: auto;
transition: opacity 50ms ease-out;
overflow: visible;
}
.toggle-section.closed {
opacity: 0;
overflow: hidden;
height: 0;
}
@keyframes height0 {
from {
height: auto;
}
to {
height: 0;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #000;

186
templates/pages/sega/software/index.html

@ -3,4 +3,190 @@
{% block body %}
<h1>Software</h1>
{{ generate_toc()|safe }}
<p>The following is a diagram of the Ring* boot process. Click on any of the programs to learn more about what they do.
</p>
<p>The entrypoint, <code>mxprestartup.exe</code>, is set as the shell for the <code>AppUser</code> user. This is
configured in the registry at <code>HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\shell</code>.</p>
<!-- mxauthdisc.exe
mxshellexecute.exe -->
<svg viewbox="-0.5 -0.5 1000 1050" style="width: 1000px">
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="8" refX="0" refY="4" orient="auto">
<polygon points="0 0, 10 4, 0 8" fill="currentColor" />
</marker>
</defs>
<a href="./mx/mxprestartup.html">
<rect x="25" y="0" width="300" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="175" y="25" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
C:\System\Execute\mxprestartup.exe
</text>
</a>
<line x1="325" y1="25" x2="340.5" y2="25" stroke="currentColor" marker-end="url(#arrowhead)"></line>
<a href="./mx/mxstartup.html">
<rect x="350" y="0" width="300" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="500" y="25" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
C:\System\Execute\mxstartup.exe
</text>
</a>
<line x1="500" y1="50" x2="500" y2="90.5" stroke="currentColor" marker-end="url(#arrowhead)"></line>
<line x1="0" y1="75" x2="1000" y2="75" stroke="currentColor" marker-end="url(#arrowhead)" stroke-dasharray="2">
</line>
<a href="./mx/mxmaster.html">
<rect x="400" y="100" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="500" y="125" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
S:\mxmaster.exe
</text>
</a>
<line x1="500" y1="150" x2="500" y2="165.5" stroke="currentColor" marker-end="url(#arrowhead)"></line>
<g>
<rect x="0" y="175" width="999" height="850" stroke-width="1px" stroke="currentColor" stroke-dasharray="4">
</rect>
<text x="15" y="200" fill="currentColor" font-family="monospace">MASTER_PROCESS::SysProcessStart</text>
<a href="./mx/mxkeychip.html">
<rect x="25" y="215" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="125" y="240" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxkeychip.exe
</text>
</a>
<rect x="275" y="215" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="375" y="240" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxnetwork.exe -p 40104
</text>7
<rect x="525" y="215" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="625" y="240" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxstorage.exe
</text>
<rect x="775" y="215" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="875" y="232" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxjvs.exe
</text>
<text x="875" y="248" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
(not present)
</text>
<rect x="25" y="275" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="250" y="300" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxinstaller.exe -cmdport 40102 -bindport 40103
</text>
<text x="15" y="360" fill="currentColor" font-family="monospace">MASTER_PROCESS::FdcProcessStart</text>
<rect x="25" y="375" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="125" y="400" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxgcatcher.exe
</text>
<rect x="275" y="375" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="375" y="400" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxgfetcher.exe
</text>
<rect x="525" y="375" width="200" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="625" y="400" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
s:\mxgdeliver.exe
</text>
<text x="15" y="460" fill="currentColor" font-family="monospace">MASTER_PROCESS::FirstFgProcessStart</text>
<text x="30" y="475" fill="currentColor" font-family="monospace">APP_LAUNCHER::CreateThread</text>
<text x="45" y="490" fill="currentColor" font-family="monospace">APP_LAUNCHER::AppThread (initial launch mode =
6)</text>
<text x="60" y="515" fill="currentColor" font-family="monospace">Launch mode 1 (system error):</text>
<rect x="25" y="525" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="250" y="550" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
c:\System\Execute\mxsegaboot.exe -r
</text>
<text x="60" y="600" fill="currentColor" font-family="monospace">Launch mode 2 (start game):</text>
<rect x="25" y="610" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="50" y="635" fill="currentColor" dominant-baseline="middle" text-anchor="left" font-family="monospace">
First found, of:
</text>
<text x="250" y="622" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.com
</text>
<text x="250" y="635" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.exe
</text>
<text x="250" y="649" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.bat
</text>
<rect x="525" y="610" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="750" y="635" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
If not found: Launch mode 1
</text>
<text x="60" y="685" fill="currentColor" font-family="monospace">Launch mode 3 (start system test menu):</text>
<rect x="25" y="695" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="250" y="720" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
c:\System\Execute\mxsegaboot.exe -t -r
</text>
<text x="60" y="770" fill="currentColor" font-family="monospace">Launch mode 4 (start game test menu):</text>
<rect x="25" y="780" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="50" y="805" fill="currentColor" dominant-baseline="middle" text-anchor="left" font-family="monospace">
First found, of:
</text>
<text x="250" y="792" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.com gametest
</text>
<text x="250" y="805" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.exe gametest
</text>
<text x="250" y="819" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
x:\game.bat gametest
</text>
<rect x="525" y="780" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="750" y="805" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
If not found: Launch mode 1
</text>
<text x="60" y="855" fill="currentColor" font-family="monospace">Launch mode 5 (???):</text>
<rect x="25" y="865" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="250" y="890" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
c:\System\Execute\mxsegaboot.exe -d
</text>
<text x="60" y="940" fill="currentColor" font-family="monospace">Launch mode 6 (boot system):</text>
<rect x="25" y="950" width="450" height="50" stroke-width="1px" stroke="currentColor"></rect>
<text x="250" y="975" fill="currentColor" dominant-baseline="middle" text-anchor="middle"
font-family="monospace">
c:\System\Execute\mxsegaboot.exe
</text>
</g>
</svg>
{% endblock %}

147
templates/pages/sega/software/mx/mxkeychip.html

@ -0,0 +1,147 @@
{% extends "sega.html" %}
{% block title %}mxkeychip{% endblock %}
{% block body %}
<h1>mxkeychip</h1>
<p>mxkeychip is responsible for interfacing between the physical keychip, and anything that needs to talk to it (the
system services and the game). It does this by means of the <a
href="{{ROOT}}/sega/software/drivers/#mxparallel">mxparallel</a> driver. I have not yet documented the parallel
protocol.</p>
<p>Owners wishing to start a system without a legitimate keychip need only replace this binary with a custom binary. <a
href="https://gitea.tendokyu.moe/Bottersnike/micetools/src/branch/master/src/micetools/micekeychip">micekeychip</a>
is an example of one such binary, making use of the official libpcp. (Contact me if you want a build.)</p>
<h2>PCP Service</h2>
<p>mxkeychip runs a PCP service on port <code>40106</code> (data port <code>40107</code>).</p>
<h3><code>keychip.version</code></h3>
<p>Return the keychip version, as two bytes. <code>0104</code> is the current keychip version, representing
<code>1.4</code>. An optional parameter <code>device</code> can be added to retrieve a specific version. The only
allowed value for this however is <code>n2</code>, and <code>0104</code> should be returned in both cases.
</p>
<h3><code>keychip.ds.compute</code></h3>
<p>Perform a query-response challenge. The query is the command argument, and the page is passed as a parameter with
name <code>page</code>. TODO: Details of how to calculate responses!</p>
<h3><code>keychip.ssd.proof</code></h3>
<p>Perform a query-response challenge. The query is the command argument, and the page is passed as a parameter with
name <code>page</code>. TODO: Details of how to calculate responses!</p>
<h3><code>keychip.ssd.hostproof</code></h3>
<h3><code>keychip.status</code></h3>
<p>Get the current keychip status. Reponses should be either <code>init</code> to indicate mxkeychip is still performing
setup, <code>available</code> to indicate the keychip is ready to use, or <code>error</code> to indicate the keychip
is not present, or unusuable.</p>
<h3><code>keychip.encrypt</code></h3>
<h3><code>keychip.decrypt</code></h3>
<h3><code>keychip.setiv</code></h3>
<h3><code>keychip.appboot.*</code></h3>
<p>Request one of a number of variables from the keychip regarding the authorised game configuration:</p>
<table>
<tr>
<td><code>formattype</code></td>
<td>Data format. <code>mxsegaboot</code> will only support version <code>1</code>.</td>
</tr>
<tr>
<td><code>platformid</code></td>
<td>The hardware platform ID. <code>AAL</code> or <code>AAM</code>. <code>___</code> is sent if this is
unavailable.</td>
</tr>
<tr>
<td><code>gameid</code></td>
<td>The four-character game ID. <code>____</code> is sent if this is unavailable.</td>
</tr>
<tr>
<td><code>systemflag</code></td>
<td>A single byte containing a number of system flags. What exactly these bits do is unknown right now, but
<code>64<sub>h</sub></code> works fine.
</td>
</tr>
<tr>
<td><code>modeltype</code></td>
<td><code>02</code></td>
</tr>
<tr>
<td><code>region</code></td>
<td>Region bitmask. 1 = Japan, 2 = USA, 4 = Export, 8 = China</td>
</tr>
<tr>
<td><code>networkaddr</code></td>
<td>The IP address for this machine</td>
</tr>
<tr>
<td><code>dvdflag</code></td>
<td><code>01</code></td>
</tr>
<tr>
<td><code>seed</code></td>
<td>A seed value that will be used for.. something? Not sure yet. It's 16 bytes.</td>
</tr>
</table>
<h3><code>keychip.billing.*</code></h3>
<p>As with appboot, billing contains a number of values stored on the keychip, however some of these are also writiable.
</p>
<table>
<tr>
<td><code>keyid</code></td>
<td>The keychip ID. For example, A72E-0123456. Read-only.</td>
</tr>
<tr>
<td><code>mainid</code></td>
<td>The hardware ID. For example, AASE-0123456. This value can be written. In this respect, it stores the
previous owner of the keychip, allowing systems to identify if they have been presented with a new keychip,
and allowing a curious owner (or curious sega) to identify who last used this keychip.</td>
</tr>
<tr>
<td><code>playcount</code></td>
<td>The number of plays that have been performed. This value can be incremented by providing <code>1</code>.
</td>
</tr>
<tr>
<td><code>playlimit</code></td>
<td>The number of plays that are allowed until the game must next check in with a billing server. This value can
be written, however a signature (128 bytes) must then be sent over a data transfer to validate that this
playlimit update was authorised by a legitimate billing server. As the private keys for the billing service
are not currently known, and likely never will be, this renders legitimate keychips useless after playcount
runs out!</td>
</tr>
<tr>
<td><code>nearful</code></td>
<td>Get the 'nearfull' value stored from the billing server. This is the number of plays remaining at which a
game is expected to pre-emptively check in with a billing server. This value is a 32-bit value, also
containing the accounting mode in the upper two bytes of the value. As with playlimit, this value can be
written, but requires a valid signature to be sent.</td>
</tr>
<tr>
<td><code>signaturepubkey</code></td>
<td>Retrieve the public key for the billing server signing service.</td>
</tr>
<tr>
<td><code>cacertification</code></td>
<td>Retrieve the authorative certiciate for the billing server. This certificate will be trusted implicitly,
regardless of the actual legitimacy of the certificate (including allowing self-signing).</td>
</tr>
</table>
<h3><code>keychip.tracedata.restore</code></h3>
<h3><code>keychip.tracedata.put</code></h3>
<h3><code>keychip.tracedata.get</code></h3>
<h3><code>keychip.tracedata.logicalerase</code></h3>
<h3><code>keychip.tracedata.sectorerase</code></h3>
<h3><code>keychip.eeprom</code></h3>
<h3><code>keychip.nvram0</code></h3>
<h3><code>keychip.nvram1</code></h3>
<h3><code>keychip.nvram2</code></h3>
<h3><code>keychip.nvram3</code></h3>
<h3><code>keychip.nvram4</code></h3>
<h3><code>keychip.nvram5</code></h3>
<h3><code>keychip.nvram6</code></h3>
<h3><code>keychip.nvram7</code></h3>
<h3><code>keychip.nvram8</code></h3>
<h3><code>keychip.nvram9</code></h3>
{% endblock %}

51
templates/pages/sega/software/mx/mxmaster.html

@ -0,0 +1,51 @@
{% extends "sega.html" %}
{% block title %}mxmaster{% endblock %}
{% block body %}
<h1>mxmaster</h1>
<p>mxmaster is the program responsible for orchastrating the entire system.</p>
<p>Before spawning any processes, it copies the following files from <code>s:\</code> into
<code>c:\System\Execute</code>:</p>
<ul>
<li><code>mxsegaboot.exe</code></li>
<li><code>mxauthdisc.exe</code></li>
<li><code>mxshellexecute.exe</code></li>
<li><code>ringmaster_pub.pem</code></li>
<li><code>develop_regset.txt</code></li>
<li><code>lockid.txt</code></li>
<li><code>d3dref9.dll</code></li>
<li><code>mxsegaboot_2052.dll</code></li>
</ul>
<p>Following this, it begins to spawn system processes as required. The full diagram can be found on the <a
href="..">software page</a>.</p>
<!-- <ul>
<li><code>s:\mxkeychip.exe</code></li>
<li><code>s:\mxnetwork.exe -p 40104</code></li>
<li><code>s:\mxstorage.exe</code></li>
<li><code>s:\mxinstaller.exe -cmdport 40102 -binport 40103</code> (sometimes with <code>-openmode any</code> appended)</li>
<li><code>s:\mxgcatcher.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>s:\mxgfetcher.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>s:\mxgdeliver.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>C:\WINDOWS\system32\regini.exe S:\default_regset.txt</code></li>
<li><code>c:\System\Execute\mxsegaboot.exe</code></li>
<!-- TODO: Investigate amDongleSetAuthConfig->FUN_00412ae0 -- >
</ul> -->
<h2>PCP Service</h2>
<p>mxmaster runs a PCP service on port <code>40100</code> (data port <code>40101</code>).</p>
<h3><code>mxmaster.reconnect.usb.device</code></h3>
<h3><code>mxmaster.erase_log</code></h3>
<h3><code>mxmaster.output_log</code></h3>
<h3><code>mxmaster.logging_available</code></h3>
<h3><code>mxmaster.develop</code></h3>
<h3><code>mxmaster.foreground.getcount</code></h3>
<h3><code>mxmaster.foreground.fault</code></h3>
<h3><code>mxmaster.foreground.next</code></h3>
<h3><code>mxmaster.foreground.active</code></h3>
<h3><code>mxmaster.foreground.current</code></h3>
{% endblock %}

0
templates/pages/sega/software/mxprestartup.html → templates/pages/sega/software/mx/mxprestartup.html

9
templates/pages/sega/software/mxstartup.html → templates/pages/sega/software/mx/mxstartup.html

@ -6,9 +6,16 @@
<p>mxstartup is responsible for some very initial system checks, loading the S: drive, and handing over to <a
href="./mxmaster.html">mxmaster.exe</a>.</p>
<p>The S: drive is a TrueCrypt partition. Its keyfile is located in an ADS at
<code>C:\System\Execute\DLL:SystemKeyFile</code>, and the password is <code>segahardpassword</code>.
</p>
<p>Micetools contains a bare-minim version of this file. <a
href="https://gitea.tendokyu.moe/Bottersnike/micetools/src/branch/master/src/micetools/miceboot/mxstartup.c">It
can be found on the micetools repository.</a> This shows, roughly, how the volume is mounted and prepared.</p>
<p>This is the first time anything other than the Windows XP boot screen will be shown.</p>
<img class="graphic" src="../../images/mxstartup.png">
<img class="graphic" src="../../../images/mxstartup.png">
<p>mxstartup is responsible for a number of error codes, listed below. This table contains every error mxstartup can
produce, to the best of my knowledge.</p>

23
templates/pages/sega/software/mxmaster.html

@ -1,23 +0,0 @@
{% extends "sega.html" %}
{% block title %}mxmaster{% endblock %}
{% block body %}
<h1>mxmaster</h1>
<p>mxmaster is the program responsible for orchastrating the entire system.</p>
<p>It first spawns the following list of programs:</p>
<ul>
<li><code>s:\mxkeychip.exe</code></li>
<li><code>s:\mxnetwork.exe -p 40104</code></li>
<li><code>s:\mxstorage.exe</code></li>
<li><code>s:\mxinstaller.exe -cmdport 40102 -binport 40103</code> (sometimes with <code>-openmode any</code> appended)</li>
<li><code>s:\mxgcatcher.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>s:\mxgfetcher.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>s:\mxgdeliver.exe {appboot.platformid} {appboot.gameid} {appboot.networkaddr} {appboot.keyid}</code></li>
<li><code>C:\WINDOWS\system32\regini.exe S:\default_regset.txt</code></li>
<li><code>c:\System\Execute\mxsegaboot.exe</code></li>
<!-- TODO: Investigate amDongleSetAuthConfig->FUN_00412ae0 -->
</ul>
{% endblock %}

4
templates/pages/sega/software/security/dongle.html

@ -1,4 +0,0 @@
{% extends "sega.html" %}
{% block title %}{% endblock %}
{% block body %}
{% endblock %}

4
templates/sega.html

@ -4,7 +4,9 @@
<table class="nav">
<tr>
<td><a href="{{ROOT}}/sega/">Contents</a></td>
<td><a href="{{ROOT}}/sega/network/allnet.html">ALL.Net</a></td>
<td><a href="{{ROOT}}/sega/intro/">Intro</a></td>
<td><a href="{{ROOT}}/sega/software/">Software</a></td>
<td><a href="{{ROOT}}/sega/hardware/">Hardware</a></td>
</tr>
</table>
{% block body %}{% endblock %}

Loading…
Cancel
Save