Folding regions!

This commit is contained in:
Bottersnike 2022-11-17 17:53:00 +00:00
parent b629929a48
commit df26f4613a
10 changed files with 602 additions and 14 deletions

View File

@ -1,8 +1,79 @@
for (const el of document.querySelectorAll("[id]")) {
el.classList.add("haspara")
el.classList.add("haspara");
const pilcrow = document.createElement("a");
pilcrow.className = "pilcrow"
pilcrow.className = "pilcrow";
pilcrow.href = "#" + el.id;
pilcrow.innerHTML = "¶"
el.prepend(pilcrow)
pilcrow.innerHTML = "¶";
el.prepend(pilcrow);
}
const foldable = (root, children) => {
let state = true;
root.addEventListener("click", (e) => {
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) root.classList.remove("closed");
else root.classList.add("closed");
});
root.classList.add("toggle-root");
};
const make_foldable = (root) => {
const child_stacks = new Array(10).fill(null).map(() => ({ children: [], root: null }));
const flush_header = (this_level, sibling) => {
for (let level = 9; level >= this_level; level--) {
const stack = child_stacks[level];
if (!stack.root) continue;
const new_e = document.createElement("div");
for (const old_e of stack.children) {
old_e.remove();
new_e.appendChild(old_e);
}
foldable(stack.root, new_e);
let parent_level;
for (parent_level = level - 1; parent_level > 0; parent_level--) if (child_stacks[parent_level].root) break;
if (parent_level === -1) {
if (sibling) root.insertBefore(new_e, sibling);
else root.appendChild(new_e);
} else {
stack.root.remove();
child_stacks[parent_level].children.push(stack.root);
child_stacks[parent_level].children.push(new_e);
}
stack.root = null;
stack.children.length = 0;
}
};
for (const child of [...root.children]) {
if (/^H\d$/.test(child.tagName)) {
const this_level = parseInt(child.tagName[1]) - 1;
flush_header(this_level, child);
child_stacks[this_level].root = child;
continue;
}
for (let level = 9; level >= 0; level--) {
if (child_stacks[level].root) {
child_stacks[level].children.push(child);
break;
}
}
}
for (let level = 9; level >= 0; level--) {
flush_header(level, null);
}
};
make_foldable(document.body);

BIN
images/mxstartup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -144,7 +144,7 @@ table.nav td {
.pilcrow {
position: absolute;
right: calc(100%);
padding-right: 4px;
padding-right: 24px;
top: .1em;
font-size: .9em;
text-decoration: none;
@ -234,6 +234,30 @@ mark {
text-underline-offset: 1px;
}
.toggle-root {
cursor: pointer;
position: relative;
}
.toggle-root::before {
opacity: .5;
content: "";
display: block;
border: 4px solid currentColor;
border-left-color: transparent;
border-top-color: transparent;
position: absolute;
left: -18px;
top: 50%;
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);
}
@media (prefers-color-scheme: dark) {
body {
background-color: #000;

View File

@ -50,6 +50,40 @@
<li><code><a href="#getdatalist">cardmng.getdatalist</a></code></li>
</ul>
<h4>dataid? refid?</h4>
<p>Some requests use <code>refid</code>, some use <code>dataid</code>, and some use both. What exactly you use these
values for is largely left up to the server implementer, as the game will echo them back verbatim, however here are
three suggestions:</p>
<table>
<tr>
<td><code>refid</code></td>
<td>An ID that references the user</td>
</tr>
<tr>
<td><code>data</code></td>
<td>An ID that references the game specific data for this user/game combination</td>
</tr>
</table>
<table>
<tr>
<td><code>refid</code></td>
<td>A session token issued during card auth</td>
</tr>
<tr>
<td><code>data</code></td>
<td>An ID that references the game specific data for this user/game combination</td>
</tr>
</table>
<table>
<tr>
<td><code>refid</code></td>
<td>An ID that references the user</td>
</tr>
<tr>
<td><code>data</code></td>
<td>The same as refid; we can use database joins for accessing game data</td>
</tr>
</table>
<h2 id="inquire"><code>cardmng.inquire</code></h2>
<p>Request information about a card that has been inserted or touched against a reader.</p>
@ -76,12 +110,11 @@
<table>
<tr>
<td><code>refid</code></td>
<td>A reference to this card to be used in other requests</td>
<td>See section about refid and dataid</td>
</tr>
<tr>
<td><code>dataid</code></td>
<td>Appears to be set the same as <code>refid</code>; presumably to allow different keys for game state vs
login details.</td>
<td>See section about refid and dataid</td>
</tr>
<tr>
<td><code>newflag</code></td>
@ -94,12 +127,16 @@
</tr>
<tr>
<td><code>expired</code></td>
<td>? Just set to <code>0</code>.</td>
<td>? Just set it to <code>0</code>.</td>
</tr>
<tr>
<td><code>newflag</code></td>
<td>? Just set it to <code>0</code>.</td>
</tr>
</table>
<h2 id="getrefid"><code>cardmng.getrefid</code></h2>
<p>Register a new card to this server.</p>
<p>Register a new card to this server. In the process, we're also going to create a game profile.</p>
<h3>Request:</h3>
<pre>{% highlight "cxml" %}<call ...>
<cardmng method="getrefid" cardtype="" cardid="" newflag="" passwd="" model*="" />
@ -122,20 +159,21 @@
<table>
<tr>
<td><code>refid</code></td>
<td>A reference to this card to be used in other requests</td>
<td>See section about refid and dataid</td>
</tr>
<tr>
<td><code>dataid</code></td>
<td>Appears to be set the same as <code>refid</code>; presumably to allow different keys for game state vs
login details.</td>
<td>See section about refid and dataid</td>
</tr>
<tr>
<td><code>pcode</code></td>
<td>? Not present in captured data.</td>
<td>? Just omit this</td>
</tr>
</table>
<h2 id="bindmodel"><code>cardmng.bindmodel</code></h2>
<p>Create a data profile for this card on the current game. Request and response should be fairly self-explanatory.</p>
<h3>Request:</h3>
<pre>{% highlight "cxml" %}<call ...>
<cardmng method="bindmodel" refid="" newflag="" model*="" />

View File

@ -219,5 +219,7 @@
<h2>Possible XRPC requests</h2>
<p>Of which properly documented:<br> - <code>cardmng</code></p>
{{ generate_xrpc_list()|safe }}
{% endblock %}

View File

@ -0,0 +1,269 @@
{% extends "sega.html" %}
{% block title %}SEGA Partition Structure{% endblock %}
{% block body %}
<h1>SEGA Partition Structure</h1>
<p>Games on the Ring* series use MBR partitioned drives. The core partition structure is as follows:</p>
<table>
<thead>
<tr>
<td>Partition</td>
<td>Size</td>
<td>Format</td>
<td>Content</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1.5GiB</td>
<td>NTFS</td>
<td>Windows XP Embedded 2009</td>
</tr>
<tr>
<td>2</td>
<td>1.5GiB</td>
<td>NTFS</td>
<td>Windows recovery partition</td>
</tr>
<tr>
<td>3</td>
<td><i>remaining space</i></td>
<td>Extended Partition (LBA)</td>
<td>Game data</td>
</tr>
<tr>
<td>4</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>Extended partitions are structed by a linked list of partition headers at the beginning of each partition. These
headers reserve 3F<sub>h</sub> blocks for their information, however only use a single block at the start of this
for actual data. SEGA make use of the remaining blocks in the first extended partition header for SEGA boot records.
</p>
<table>
<thead>
<tr>
<td>Partition offset (blocks)</td>
<td>Content</td>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Extended partition header</td>
</tr>
<tr>
<td>1</td>
<td>SEGA Partition Description</td>
</tr>
<tr>
<td>2</td>
<td>SEGA Boot Record (1)</td>
</tr>
<tr>
<td>3</td>
<td>SEGA Boot Record (2)</td>
</tr>
<tr>
<td>4-63</td>
<td>Additional data storage</td>
</tr>
<tr>
<td>64-...</td>
<td>Actual partition data</td>
</tr>
</tbody>
</table>
<p>Two identical copies of the SEGA Boot Record are present. This is for redundancy; if either is corrupted, an attempt
will be made to restore it from the other copy.</p>
<h2>SEGA Partition Description</h2>
<p>The SEGA Partition Description (SPD) largely echos the structure laid out by the extended partition headers, however
is the table SEGA loaders preferentially read. It takes up all 512 bytes of the block; it's structure is as follows:
</p>
<table>
<thead>
<tr>
<td></td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</thead>
<tbody>
<tr>
<td>00<sub>h</sub></td>
<td colspan="4">CRC32</td>
<td>Ver</td>
<td colspan="11"></td>
</tr>
<tr>
<td>10<sub>h</sub></td>
<td>Slot content</td>
<td>?</td>
<td colspan="2">Block size</td>
<td colspan="4">Block count</td>
<td colspan="8"></td>
</tr>
<tr>
<td>20<sub>h</sub></td>
<td>Slot content</td>
<td>?</td>
<td colspan="2">Block size</td>
<td colspan="4">Block count</td>
<td colspan="8"></td>
</tr>
<tr>
<td>30<sub>h</sub></td>
<td>Slot content</td>
<td>?</td>
<td colspan="2">Block size</td>
<td colspan="4">Block count</td>
<td colspan="8"></td>
</tr>
<tr>
<td colspan="17">...</td>
</tr>
<tr>
<td>F0<sub>h</sub></td>
<td>Slot content</td>
<td>?</td>
<td colspan="2">Block size</td>
<td colspan="4">Block count</td>
<td colspan="8"></td>
</tr>
</tbody>
</table>
<p>The slot content types are:</p>
<table>
<thead>
<tr>
<td>Value</td>
<td>Meaning</td>
</tr>
</thead>
<tbody>
<tr>
<td>10<sub>h</sub></td>
<td>original0</td>
</tr>
<tr>
<td>11<sub>h</sub></td>
<td>original1</td>
</tr>
<tr>
<td>20<sub>h</sub></td>
<td>patch0</td>
</tr>
<tr>
<td>21<sub>h</sub></td>
<td>patch1</td>
</tr>
<tr>
<td>30<sub>h</sub></td>
<td>os</td>
</tr>
<tr>
<td>40<sub>h</sub></td>
<td>app_data</td>
</tr>
</tbody>
</table>
<h2>SEGA Boot Record</h2>
<p>The SEGA Boot Record (SBR) contains detailed information about the content of each slot.</p>
<table>
<thead>
<tr>
<td></td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</thead>
<tbody>
<tr>
<td>00<sub>h</sub></td>
<td colspan="4">CRC32</td>
<td>Ver</td>
<td colspan="11"></td>
</tr>
<tr>
<td>10<sub>h</sub></td>
<td colspan="16"></td>
</tr>
<tr>
<td>20<sub>h</sub></td>
<td>Bootslot</td>
<td colspan="2"></td>
<td colspan="5">5x slot status</td>
<td colspan="8"></td>
</tr>
<tr>
<td>30<sub>h</sub></td>
<td rowspan="3" colspan="16"></td>
</tr>
<tr>
<td>...</td>
</tr>
<tr>
<td>A0<sub>h</sub></td>
</tr>
<tr>
<td>B0<sub>h</sub></td>
</tr>
<tr>
<td>C0<sub>h</sub></td>
</tr>
<tr>
<td>D0<sub>h</sub></td>
</tr>
<tr>
<td>E0<sub>h</sub></td>
</tr>
<tr>
<td>F0<sub>h</sub></td>
</tr>
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "sega.html" %}
{% block title %}Boot Sequence{% endblock %}
{% block body %}
<h1>Boot Sequence</h1>
<p>This page is a stub for now.</p>
<ol>
<li><a href="./mxprestartup.html">mxprestartup</a></li>
<li><a href="./mxstartup.html">mxstartup</a></li>
</ol>
{% endblock %}

View File

@ -0,0 +1,23 @@
{% 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>
<!-- Investigate amDongleSetAuthConfig->FUN_00412ae0 -->
</ul>
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends "sega.html" %}
{% block title %}mxprestartup{% endblock %}
{% block body %}
<h1>mxprestartup</h1>
<p>mxprestartup is the first program to run when the AppUser user logs in.</p>
<p>This program's sole job is to construct the password for SystemUser, and spawn <a
href="./mxstartup.html">mxstartup.exe</a> as SystemUser.</p>
<p>Micetools contains a full version of this program, with a few additions for ease of use. <a
href="https://gitea.tendokyu.moe/Bottersnike/micetools/src/branch/master/src/micetools/miceboot/mxprestartup.c">It
can be found on the micetools repository.</a></p>
{% endblock %}

View File

@ -0,0 +1,133 @@
{% extends "sega.html" %}
{% block title %}mxstartup{% endblock %}
{% block body %}
<h1>mxstartup</h1>
<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>This is the first time anything other than the Windows XP boot screen will be shown.</p>
<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>
<table>
<thead>
<tr>
<td>Error code</td>
<td>Message</td>
<td>Meaning</td>
</tr>
</thead>
<tbody>
<tr>
<td>0500</td>
<td>SecurityCheck error</td>
<td></td>
</tr>
<tr>
<td>0501</td>
<td>CheckEwfState error</td>
<td></td>
</tr>
<tr>
<td>0502</td>
<td>GetSystemVersion error</td>
<td></td>
</tr>
<tr>
<td>0503</td>
<td>GetsystemKeyFile</td>
<td></td>
</tr>
<tr>
<td>0504</td>
<td>SetDiskAccessPrivilege</td>
<td></td>
</tr>
<tr>
<td>0505</td>
<td>MountSystem</td>
<td></td>
</tr>
<tr>
<td>0506</td>
<td>MountUpdate error</td>
<td></td>
</tr>
<tr>
<td>0507</td>
<td>ExecuteMaMaster</td>
<td></td>
</tr>
<tr>
<td>0508</td>
<td>GetOSUpdateKeyFile error</td>
<td></td>
</tr>
<tr>
<td>0509</td>
<td>ExecuteMxOSUpdate error</td>
<td></td>
</tr>
<tr>
<td>0510</td>
<td>ChangeEWFStateEnable error</td>
<td></td>
</tr>
<tr>
<td>0511</td>
<td>GetSBRSlotOSState error</td>
<td></td>
</tr>
<tr>
<td>0512</td>
<td>Deleate Key File error</td>
<td></td>
</tr>
<tr>
<td>0513</td>
<td>MountDriver error</td>
<td></td>
</tr>
<tr>
<td>0514</td>
<td>CheckPlatform error</td>
<td></td>
</tr>
<tr>
<td>0540</td>
<td>Unmount error</td>
<td></td>
</tr>
<tr>
<td>0541</td>
<td>MountRecoveryVolume error</td>
<td></td>
</tr>
<tr>
<td>0543</td>
<td>MxChangeActivePartition error</td>
<td></td>
</tr>
<tr>
<td>0545</td>
<td>osuSystemReboot error</td>
<td></td>
</tr>
<tr>
<td>0546</td>
<td>GetSystemDiskNumber error</td>
<td></td>
</tr>
<tr>
<td>????</td>
<td>SetBackupComputerName failed</td>
<td></td>
</tr>
</tbody>
</table>
<p>These errors are also reported into the Application event log, under the source <code>mxstartup</code>.</p>
{% endblock %}