<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>pagetable.com</title>
	<atom:link href="http://www.pagetable.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.pagetable.com</link>
	<description>Some Assembly Required</description>
	<lastBuildDate>Tue, 07 Sep 2010 08:19:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Playstation 3 Hacking &#8211; Linux Is Inevitable</title>
		<link>http://www.pagetable.com/?p=376</link>
		<comments>http://www.pagetable.com/?p=376#comments</comments>
		<pubDate>Tue, 07 Sep 2010 07:45:02 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=376</guid>
		<description><![CDATA[In the talk &#8220;Why Silicon Security is still that hard&#8221; by Felix Domke at the 24th Chaos Communication Congress in 2007 (in which he described how he hacked the Xbox 360, and bushing had a cameo at the end explaining how they hacked the Wii), I had a little part, in which I argued that [...]]]></description>
			<content:encoded><![CDATA[<p>In the talk <a href="http://www.youtube.com/watch?v=XtDTNnEvlf8">&#8220;Why Silicon Security is still that hard&#8221;</a> by <a href="http://debugmo.de/">Felix Domke</a> at the 24th Chaos Communication Congress in 2007 (in which he described how he hacked the Xbox 360, and <a href="http://hackmii.com/">bushing</a> had a cameo at the end explaining how they hacked the Wii), I had a little part, in which I argued that &#8220;Linux Is Inevitable&#8221;: If you lock down a system, it will eventually get hacked. In the light of the recent events happening with PlayStation 3 hacking, let&#8217;s revisit them.</p>
<p>This is the original slide from 2007:</p>
<style type="text/css">
  p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; min-height: 14.0px}
  p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; color: #ffffff}
  p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; color: #ffffff}
  p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; color: #ffffff}
  p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; text-align: center}
  span.s1 {letter-spacing: 0.0px}
  table.t1 {border-collapse: collapse}
  td.td1 {width: 122.5px; height: 36.8px; background-color: #929292}
  td.td2 {width: 36.5px; height: 36.8px; background-color: #929292}
  td.td3 {width: 317.0px; height: 36.8px; background-color: #929292}
  td.td4 {width: 98.0px; height: 36.8px; background-color: #929292}
  td.td5 {width: 70.0px; height: 36.8px; background-color: #929292}
  td.td6 {width: 91.0px; height: 36.8px; background-color: #929292}
  td.td7 {width: 36.5px; height: 36.8px; background-color: #000000}
  td.td8 {width: 70.0px; height: 36.8px; background-color: #f91d18}
  td.td9 {width: 91.0px; height: 36.8px; background-color: #f91d18}
  td.td10 {width: 317.0px; height: 36.8px; background-color: #fa9213}
  td.td11 {width: 98.0px; height: 36.8px; background-color: #fbd00b}
  td.td12 {width: 70.0px; height: 36.8px; background-color: #ffffff}
  td.td13 {width: 317.0px; height: 36.8px; background-color: #fbca0c}
  td.td14 {width: 98.0px; height: 36.8px; background-color: #f94317}
  td.td15 {width: 317.0px; height: 36.8px; background-color: #f96d15}
  td.td16 {width: 98.0px; height: 36.8px; background-color: #fabd0e}
  td.td17 {width: 317.0px; height: 36.8px; background-color: #fbfd01}
  td.td18 {width: 98.0px; height: 36.8px; background-color: #fa9013}
  td.td19 {width: 91.0px; height: 36.8px; background-color: #000000}
  td.td20 {width: 317.0px; height: 36.8px; background-color: #fa9f12}
  td.td21 {width: 317.0px; height: 36.8px; background-color: #fa8614}
  td.td22 {width: 317.0px; height: 36.8px; background-color: #f91d18}
  td.td23 {width: 98.0px; height: 36.8px; background-color: #8d0b08}
  td.td24 {width: 70.0px; height: 36.8px; background-color: #000000}
  td.td25 {width: 317.0px; height: 36.8px; background-color: #fbcd0c}
  td.td26 {width: 98.0px; height: 36.8px; background-color: #fbef04}
  td.td27 {width: 98.0px; height: 36.8px; background-color: #fbfd01}
  td.td28 {width: 70.0px; height: 36.8px; background-color: #929292}
</style>
<table cellspacing="0" cellpadding="3" class="t1" border="1" bordercolor="#0000">
<tbody>
<tr>
<td valign="middle" class="td1">
<p class="p2"><span class="s1"><b>device</b></span></p>
</td>
<td valign="middle" class="td2">
<p class="p2"><span class="s1"><b>y</b></span></p>
</td>
<td valign="middle" class="td3">
<p class="p2"><span class="s1"><b>security</b></span></p>
</td>
<td valign="middle" class="td4">
<p class="p2"><span class="s1"><b>hacked</b></span></p>
</td>
<td valign="middle" class="td5">
<p class="p2"><span class="s1"><b>for</b></span></p>
</td>
<td valign="middle" class="td6">
<p class="p2"><span class="s1"><b>effect</b></span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PS2</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">1999</span></p>
</td>
<td valign="middle" class="td3">
<p class="p4"><span class="s1">?</span></p>
</td>
<td valign="middle" class="td4">
<p class="p4"><span class="s1">?</span></p>
</td>
<td valign="middle" class="td8">
<p class="p4"><span class="s1">piracy</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>dbox2</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2000</span></p>
</td>
<td valign="middle" class="td10">
<p class="p5"><span class="s1">signed kernel</span></p>
</td>
<td valign="middle" class="td11">
<p class="p5"><span class="s1">3 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">pay TV decoding</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>GameCube</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td13">
<p class="p5"><span class="s1">encrypted boot</span></p>
</td>
<td valign="middle" class="td14">
<p class="p5"><span class="s1">12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Xbox</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td15">
<p class="p5"><span class="s1">encrypted/signed bootup, signed executables</span></p>
</td>
<td valign="middle" class="td16">
<p class="p5"><span class="s1">4 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>iPod</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td17">
<p class="p5"><span class="s1">checksum</span></p>
</td>
<td valign="middle" class="td18">
<p class="p5"><span class="s1">&lt;12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td19">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>DS</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2004</span></p>
</td>
<td valign="middle" class="td20">
<p class="p5"><span class="s1">signed/encrypted executables</span></p>
</td>
<td valign="middle" class="td16">
<p class="p5"><span class="s1">6 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PSP</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2004</span></p>
</td>
<td valign="middle" class="td21">
<p class="p5"><span class="s1">signed bootup/executables</span></p>
</td>
<td valign="middle" class="td11">
<p class="p5"><span class="s1">2 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Xbox 360</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2005</span></p>
</td>
<td valign="middle" class="td22">
<p class="p5"><span class="s1">encrypted/signed bootup,encrypted/signed executables, encrypted RAM, hypervisor, eFuses</span></p>
</td>
<td valign="middle" class="td14">
<p class="p5"><span class="s1">12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">leaked keys</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PS3</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2006</span></p>
</td>
<td valign="middle" class="td22">
<p class="p5"><span class="s1">encrypted/signed bootup,encrypted/signed executables, hypervisor, eFuses, isolated SPU</span></p>
</td>
<td valign="middle" class="td23">
<p class="p4"><span class="s1">not yet</span></p>
</td>
<td valign="middle" class="td24">
<p class="p4"><span class="s1">-</span></p>
</td>
<td valign="middle" class="td19">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Wii</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2006</span></p>
</td>
<td valign="middle" class="td25">
<p class="p5"><span class="s1">encrypted bootup</span></p>
</td>
<td valign="middle" class="td26">
<p class="p5"><span class="s1">1 month</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>AppleTV</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2007</span></p>
</td>
<td valign="middle" class="td17">
<p class="p5"><span class="s1">signed bootloader</span></p>
</td>
<td valign="middle" class="td27">
<p class="p5"><span class="s1">2 weeks</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">Front Row piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>iPhone</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2007</span></p>
</td>
<td valign="middle" class="td3">
<p class="p4"><span class="s1">?</span></p>
</td>
<td valign="middle" class="td27">
<p class="p5"><span class="s1">1 month</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
<p class="p5"><span class="s1">international</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">SIM-Lock revenue</span></p>
</td>
</tr>
</tbody>
</table>
<p>The table shows the relationship between the quality of a device&#8217;s security system and the time it took to hack it, as well as the original motivation for hacking and the side effects (collateral damage) it caused.</p>
<h2>Correlation security/time to hack</h2>
<p>There is a pretty clear correlation betwen the quality of the security system and the time required for hacking it &#8211; with the notable exception being the GameCube, which had rather weak security, but since its release coincided with the much more powerful Xbox, much of the hacker community neglected the GameCube until the Xbox was done. What can also be seen is that recently, devices tend to get hacked more quickly; probably simply because there are more and more people interested in hacking.</p>
<h2>Correlation Linux/time to hack</h2>
<p>The other exception is the PlayStation 3, which was not hacked until about three and a half years after its introduction. I argued that this was because there was only very little motivation to hack it: Sony shipped the devices with the &#8220;Other OS&#8221; option and even sponsored a port of Linux to it, allowing any user to install Linux if they wanted. Although Linux was running on top of a hypervisor and did not have access to all of the features of the device, it seems to have been enough to take the enough motivation to hack it out of the hacker community.</p>
<h2>Linux/homebrew is the primary motivation</h2>
<p>This is supported by the by the fact that the motivation for hacking every system in the table was either homebrew (i.e. running unautorized hobbyist applications) or Linux. Hackers seem to love to convert their devices into Linux computers to run a big library of existing software, or to hack the device to make it possible to run versions of existing emulators and games on the native OS.</p>
<h2>Piracy is a side effect</h2>
<p>None of the hacks in the table was done with the motivation to allow running copied games &#8211; but whenever the point of the security system was to prevent piracy, hacking it inevitably enabled piracy as a side effect. Some security systems protected other things like pay TV keys and SIM-locks; these also fell as side effects.</p>
<h2>2010 update</h2>
<p>In September 2009, Sony started shipping the &#8220;slim&#8221; model of the PlayStation 3, with the &#8220;Other OS&#8221; feature removed. With firmware 3.21 in April 2010, the feature was also <a href="http://blog.us.playstation.com/2009/08/27/it-only-does-everything/">removed</a> from existing original models that users chose to upgrade &#8211; which was required for using any of the online features. The missing &#8220;Other OS&#8221; feature on the slim model motivated George Hotz (geohot) to hack into hypervisor mode (Jan 2010), but this approach did not lead to a working hack of the security system. In August 2010, the Australian company OzMods announced the commercial &#8220;PSJailbreak&#8221; USB dongle that hacks into non-hypervisor mode, allowing piracy and homebrew (&#8220;Backup Manager&#8221; says &#8220;backups and homebrew&#8221;).</p>
<p>Although this is the first time that a commercial company is first to hack a system, and the first time that piracy seems to have been a key motivation, removal of &#8220;Other OS&#8221; might have been another motivation, and geohot&#8217;s previous attempts might have helped as an entry point for this hack.</p>
<p>Usually, an open hacker community develops a hack, and commercial companies convert them into modchips. This time, a company developed a hack and a modchip, and the community reverse engineered it and ported the exploit code onto several other devices, allowing people to hack the PlayStation 3 without a dedicated device. And I&#8217;m sure Linux will be adapted soon to run in the new environment.</p>
<h2>Conclusion</h2>
<p>What do we learn from this? Linux is inevitable. Or maybe it should be &#8220;Homebrew is inevitable&#8221;. In the history of mankind, there has yet to be a popular system that is locked down to only allow certain software to run, but does not get hacked to run arbitrary code. I still dare to say that if Sony had not removed &#8220;Other OS&#8221;, the PlayStation 3 would have been the first system to not get hacked. At all.</p>
<p>(Here is an updated 2010 version of the table:)</p>
<table cellspacing="0" cellpadding="3" class="t1" border="1" bordercolor="#0000">
<tbody>
<tr>
<td valign="middle" class="td1">
<p class="p2"><span class="s1"><b>device</b></span></p>
</td>
<td valign="middle" class="td2">
<p class="p2"><span class="s1"><b>y</b></span></p>
</td>
<td valign="middle" class="td3">
<p class="p2"><span class="s1"><b>security</b></span></p>
</td>
<td valign="middle" class="td4">
<p class="p2"><span class="s1"><b>hacked</b></span></p>
</td>
<td valign="middle" class="td5">
<p class="p2"><span class="s1"><b>for</b></span></p>
</td>
<td valign="middle" class="td6">
<p class="p2"><span class="s1"><b>effect</b></span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PS2</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">1999</span></p>
</td>
<td valign="middle" class="td3">
<p class="p4"><span class="s1">?</span></p>
</td>
<td valign="middle" class="td4">
<p class="p4"><span class="s1">?</span></p>
</td>
<td valign="middle" class="td8">
<p class="p4"><span class="s1">piracy</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>dbox2</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2000</span></p>
</td>
<td valign="middle" class="td10">
<p class="p5"><span class="s1">signed kernel</span></p>
</td>
<td valign="middle" class="td11">
<p class="p5"><span class="s1">3 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">pay TV decoding</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>GameCube</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td13">
<p class="p5"><span class="s1">encrypted boot</span></p>
</td>
<td valign="middle" class="td14">
<p class="p5"><span class="s1">12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Xbox</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td15">
<p class="p5"><span class="s1">encrypted/signed bootup, signed executables</span></p>
</td>
<td valign="middle" class="td16">
<p class="p5"><span class="s1">4 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>iPod</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2001</span></p>
</td>
<td valign="middle" class="td17">
<p class="p5"><span class="s1">checksum</span></p>
</td>
<td valign="middle" class="td18">
<p class="p5"><span class="s1">&lt;12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td19">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>DS</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2004</span></p>
</td>
<td valign="middle" class="td20">
<p class="p5"><span class="s1">signed/encrypted executables</span></p>
</td>
<td valign="middle" class="td16">
<p class="p5"><span class="s1">6 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PSP</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2004</span></p>
</td>
<td valign="middle" class="td21">
<p class="p5"><span class="s1">signed bootup/executables</span></p>
</td>
<td valign="middle" class="td11">
<p class="p5"><span class="s1">2 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Xbox 360</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2005</span></p>
</td>
<td valign="middle" class="td22">
<p class="p5"><span class="s1">encrypted/signed bootup,encrypted/signed executables, encrypted RAM, hypervisor, eFuses</span></p>
</td>
<td valign="middle" class="td14">
<p class="p5"><span class="s1">12 months</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
<p class="p5"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">leaked keys</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>PS3</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2006</span></p>
</td>
<td valign="middle" class="td22">
<p class="p5"><span class="s1">encrypted/signed bootup,encrypted/signed executables, hypervisor, eFuses, isolated SPU</span></p>
</td>
<td valign="middle" class="td23">
<p class="p4"><span class="s1">4 years</span></p>
</td>
<td valign="middle" class="td28">
<p class="p4"><span class="s1">Piracy</span></p>
<p class="p4"><span class="s1">Homebrew</span></p>
</td>
<td valign="middle" class="td19">
<p class="p4"><span class="s1">-</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>Wii</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2006</span></p>
</td>
<td valign="middle" class="td25">
<p class="p5"><span class="s1">encrypted bootup</span></p>
</td>
<td valign="middle" class="td26">
<p class="p5"><span class="s1">1 month</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>AppleTV</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2007</span></p>
</td>
<td valign="middle" class="td17">
<p class="p5"><span class="s1">signed bootloader</span></p>
</td>
<td valign="middle" class="td27">
<p class="p5"><span class="s1">2 weeks</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Linux</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">Front Row piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>iPhone</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2007</span></p>
</td>
<td valign="middle" class="td21">
<p class="p5"><span class="s1">signed/encrypted bootup/executables</span></p>
</td>
<td valign="middle" class="td27">
<p class="p5"><span class="s1">11 days</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
<p class="p5"><span class="s1">SIM-Lock</span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
<tr>
<td valign="middle" class="td1">
<p class="p3"><span class="s1"><b>iPad</b></span></p>
</td>
<td valign="middle" class="td7">
<p class="p4"><span class="s1">2010</span></p>
</td>
<td valign="middle" class="td21">
<p class="p5"><span class="s1">signed/encrypted bootup/executables</span></p>
</td>
<td valign="middle" class="td27">
<p class="p5"><span class="s1">1 day</span></p>
</td>
<td valign="middle" class="td12">
<p class="p5"><span class="s1">Homebrew</span></p>
<p class="p5"><span class="s1"></span></p>
</td>
<td valign="middle" class="td9">
<p class="p4"><span class="s1">piracy</span></p>
</td>
</tr>
</tbody>
</table>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=376&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=376</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Why is there no CR1 &#8211; and why are control registers such a mess anyway?</title>
		<link>http://www.pagetable.com/?p=364</link>
		<comments>http://www.pagetable.com/?p=364#comments</comments>
		<pubDate>Sat, 03 Jul 2010 05:43:40 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[trivia]]></category>
		<category><![CDATA[whines]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=364</guid>
		<description><![CDATA[If you want to enable protected mode or paging on the i386/x86_64 architecture, you use CR0, which is short for control register 0. Makes sense. These are important system settings. But if you want to switch the pagetable format, you have to change a bit in CR4 (CR1 does not exist and CR2 and CR3 [...]]]></description>
			<content:encoded><![CDATA[<p>If you want to enable protected mode or paging on the i386/x86_64 architecture, you use CR0, which is short for control register 0. Makes sense. These are important system settings. But if you want to switch the pagetable format, you have to change a bit in CR4 (CR1 does not exist and CR2 and CR3 don&#8217;t hold control bits), if you want to switch to 64 bit mode, you have to change a bit in an MSR, oh, and if you want to turn on single stepping, that&#8217;s actually in your FLAGS. Also, have I mentioned that CR5 through CR15 don&#8217;t exist &#8211; except for CR8, of course?</p>
<p>Like many (but unfortunately not all) quirks of the i386/x86_64 architecture, this mess can be explained with history.</p>
<h2>8086 &#8211; FLAGS</h2>
<p>x86 history typically starts with the 16 bit 8086, but although it was not binary compatible with its predecessor, it was nevertheless a rather straightforward assembly-level compatible 16 bit extension of the 8 bit Intel 8080 with some ideas of the Zilog Z80. The 8086 is still a classic &#8220;home computer class&#8221; CPU, which was not meant for modern operating systems: It had no MMU of any kind, and no concept of privileged and unpriviliged modes. Therefore, control bits that we see as system state today were encoded into the 16 bit FLAGS register: The interrupt enable bit and the trap flag (which will cause a software interrupt after the next instruction and thus lets you single-step) are encoded into FLAGS right next to the ALU&#8217;s flags like Zero and Carry.</p>
<h2>80286 &#8211; Machine Status Word</h2>
<p>The 80286 then came with a simple form of memory management that allowed more sophisticated (but not yet &#8220;modern&#8221;) operating systems to run &#8211; like the original versions of OS/2. The 16 bit &#8220;Machine Status Word&#8221; was created to host the big switch between legacy mode (real mode) and the new memory-managed mode (protected mode) and a program could access it using the new instructions &#8220;lmsw&#8221; and &#8220;smsw&#8221;. The 80286 had more system state than just this bit: The GDT, the IDT and the TSS had its own registers and dedicated instructions to access them (&#8220;lgdt&#8221;/&#8221;sgdt&#8221;, &#8220;lidt&#8221;/&#8221;sidt&#8221;, &#8220;ltr&#8221;/&#8221;str&#8221;)</p>
<h2>i386 &#8211; Control Registers</h2>
<p>The i386 finally had a real MMU that allowed paging and thus modern operating systems. The MMU required two more registers in the system state, one for the base address of the pagetables, and one to read a fault address from. Intel decided against adding more special purpose registers with dedicated accessor instructions, but instead introduced eight indexed 32 bit wide &#8220;control registers&#8221; CR0 to CR7. The new accessors &#8220;mov cr<i>n</i>, <i>r32</i>&#8220;/&#8221;mov <i>r32</i>, cr<i>n</i>&#8221; allowed copying between registers and control registers and had the 3 bit CR index encoded in the opcode.</p>
<p>The old MSW was also wired into the lower 16 bits of CR0; but CR0 was also extended with new bits like the switch to turn on paging. CR1 was kept reserved, presumably as a second control register for miscellaneous control bits, and CR2 and CR3 were used for the aforementioned fault address and pagetable base pointer. The opcodes to access reserved control registers generated an &#8220;invalid opcode&#8221; fault, making it possible for Intel to reuse the opcodes later if they don&#8217;t use the control registers.</p>
<h2>i486 &#8211; CR4</h2>
<p>The i486 added a few more control bits, and some of them went into CR0. But instead of overflowing the new bits into CR1, Intel decided to skip it and open up CR4 instead &#8211; for unknown reasons.</p>
<h2>Pentium &#8211; MSRs</h2>
<p>On the Pentium, Intel added for the first time control bits that were a property of the implementation as opposed to the architecture, i.e. bits that are microarchitecture-specific and will therefore only work on certain CPUs and not necessarily be supported on later CPUs &#8211; like caching details and debug settings. In order not to waste the valuable CR space with throw-away control bits, Intel introduced the Model-specific Registers (MSRs). The MSR address space is 32 bits, and every MSR is 64 bits wide. The two new instructions &#8220;rdmsr&#8221; and &#8220;wrmsr&#8221; copy between an EDX-indexed MSR and the EAX register.</p>
<h2>Pentium II &#8211; SYSENTER MSR</h2>
<p>The SYSENTER instruction that got introduced on the on the Pentium II is a fast way to switch between unprivileged and privileged mode. Instead of looking up the destination segment, instruction pointer and stack pointer in memory, the CPU holds this information in three special-purpose system registers. CR space is valuable, so Intel decided against filling up CR5, CR6 and CR7, so they put it into the MSR address space instead &#8211; at 0&#215;174 through 0&#215;176. This was practically an abuse of the MSR concept.</p>
<h2>AMD K6 &#8211; EFER MSR</h2>
<p>Who can blame AMD for doing similar things then? With the K6, which was introduced at the same time as the Pentium II, AMD diverged from just copying Intel for the first time and actually added features of their own: They added the SYSCALL instruction, and with it, a control bit that turns it on and off, and an extra control register with the target location. Being afraid to collide with Intel extensions they they didn&#8217;t know about, they put the extra system registers into the MSR space: the control register &#8220;EFER&#8221; (Extended Feature Enable Register) at 0xC000_0080 and the Syscall Target Register (STAR) at 0xC000_0081. Intel had been nicely lining up MSRs counting up from 0, so AMD decided to start counting at 0xC000_0080. Understandable as this is, it is basically the same abuse of the MSR concept as Intel&#8217;s with SYSENTER.</p>
<p>A very similar thing happened in the CPUID space, by the way: While Intel encoded all its feature bits in leaf 0x0000_0001, AMD defined leaf 0x8000_0001 for its features.</p>
<h2>x86_64 &#8211; Chaos!</h2>
<p>So far everything looked like it was getting a little more controlled. Both Intel and AMD are only adding new control registers in the MSR space, and since this is a big address space and AMD and Intel extend it on rather opposite locations, it all looks nicer. But then came x86_64: For the first time, Intel was copying a feature that AMD introduced, and it needed to be compatible with all its details. AMD had encoded the availibility of x86_64 in its own CPUID leaf in 0x8000_0001, so Intel had to support this leaf as well. And since Long Mode was turned on in the EFER MSR, Intel had to support an MSR in the AMD space of 0xC000_0000. Long mode also required supporting SYSCALL, so Intel also supported the STAR MSR.</p>
<p>Since x86_64 introduced the REX prefix to double the number of available general-purpose registers, AMD decided to allow this prefix also for &#8220;mov cr&#8221;, doubling the number of control registers and therefore introducing CR8 through CR15 &#8211; also doubling their width. And since AMD introduced them, they owned them, and decided to use CR8 for the &#8220;Task Priority Register&#8221; feature.</p>
<h2>VMX and SVM</h2>
<p>The architecture is messy, sure, but does it matter? Maybe not&#8230; as long as CPUs didn&#8217;t have virtualization extensions! Both Intel VMX and AMD SVM are designed so that they can automatically switch the complete privileged machine state including control registers and certain MSRs. Intel for example special cases CR0, CR3, CR4 and CR8, leaves CR2 to the user. AMD on the other hand has 16 fields for all CRs in its switcher. And because of the two different starting points of the MSR space, Intel VMX required a whitelist bitmap for 8192 MSRs starting at 0x0000_0000 and for another 8192 MSRs starting at 0xC000_0000 &#8211; and of course SYSENTER_CS, EFER, STAR and friends are special-cased. If you want to have a lot of fun, read the VMCS layout reference of Intel&#8217;s manual 3B!</p>
<h2>Future?</h2>
<ul>
<li>CR1 and CR5 to CR7 are still &#8220;owned&#8221; by Intel. AMD has shown that they don&#8217;t want to use them &#8211; and even Intel has not added a control register since 1989.</li>
<li>CR9 through CR15 are technically owned by AMD, since they introduced them with x86_64 and decided to use CR8. Intel adopted the reserved ones when adopting x86_64, but it is unlikely that Intel will ever adopt smaller changes to the architecture from AMD, and AMD is unlikely to use them if they won&#8217;t be part of the architecture, so these will probably never be used either. On the other hand, AMD added these to the auto-switcher list of their SVM Virtual Machine Control Block (VMCB), showing that they haven&#8217;t given up on them yet.</li>
<li>The MSR space is properly de-facto partitioned. Intel continues adding MSRs at 0 and AMD at 0xC000_0000 &#8211; but MSR have already lost their model-specificness in 1997. MSRs are the new CRs.</li>
</ul>
<p>Dear Intel, dear AMD: I like the control registers, and I hate to see them wasted. Why don&#8217;t you finally define CR1 and give it a few control bits in the future? If you&#8217;re scared about collisions, I will be happy to be the arbiter. Ah, whatever: Intel, you get to define all even bits in CR1, and AMD, you get to define all odd bits. Okay? Cool.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=364&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=364</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>High-Res Pictures of a MOS KIM-1</title>
		<link>http://www.pagetable.com/?p=359</link>
		<comments>http://www.pagetable.com/?p=359#comments</comments>
		<pubDate>Tue, 29 Jun 2010 06:10:25 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=359</guid>
		<description><![CDATA[The MOS KIM-1 is a quite rare collectorâs item today. So if you hold one in your hands, you better take some high resolution pictures of the board. Here they are: Note that this is the original revision of the board (pre-Rev A), and the 6502 CPU is from week 51 of the year 1975 [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://en.wikipedia.org/wiki/KIM-1">MOS KIM-1</a> is a quite rare collectorâs item today. So if you hold one in your hands, you better take some high resolution pictures of the board. Here they are:</p>
<p><a href="docs/kim1_board/kim1_front.jpg"><img src="docs/kim1_board/small_kim1_front.jpg"></a><a href="docs/kim1_board/kim1_back.jpg"><img src="docs/kim1_board/small_kim1_back.jpg"></a></p>
<p>Note that this is the original revision of the board (pre-Rev A), and the 6502 CPU is from week 51 of the year 1975 &#8211; so it has the <a href="http://www.pagetable.com/?p=45">ROR bug</a>!</p>
<p>Does anyone know what the three digit numbers 002 and 003 on the 6530 RIOTs mean? Are these the indexes of the ROM images? If so, what is ROM #001 and was there a #000? Also, the back has the number &#8220;0372&#8243; on it &#8211; is this a serial number? Looking at the dates of the chips, this seems to be the oldest KIM-1 of all those I could find on the internet.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=359&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=359</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How much change is in a vending machine?</title>
		<link>http://www.pagetable.com/?p=353</link>
		<comments>http://www.pagetable.com/?p=353#comments</comments>
		<pubDate>Thu, 24 Jun 2010 03:56:25 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=353</guid>
		<description><![CDATA[There is only one way to find out &#8211; all you need is a giant pile of money and a vending machine that sells soda for $1.25: If you put in a dollar note and press the &#8220;return change&#8221; button, you will get the dollar note back directly. If you put in two dollar notes [...]]]></description>
			<content:encoded><![CDATA[<p>There is only one way to find out &#8211; all you need is <a href="http://www.pagetable.com/?p=149">a giant pile of money</a> and a vending machine that sells soda for $1.25: If you put in a dollar note and press the &#8220;return change&#8221; button, you will get the dollar note back directly. If you put in two dollar notes (the maximum it takes) at a time, it will give you change for the two dollars.</p>
<p>Our machine had $29 of change. It started out with 25&cent; coins, and after a while returned a combination of different coins (25&cent; &amp; 10&cent;, then 10&cent; &amp; 5&cent;), finally switching to all 5&cent; coins at the end.</p>
<p>In total, it had</p>
<ul>
<li>25&cent; x 57 = $14.25</li>
<li>10&cent; x 114 = $11.40</li>
<li>5&cent; x 67= $3.35</li>
</ul>
<p>After this, the machine refused to take bills, so it was either full with bills or, more likely, out of change.</p>
<p>But actually, it might still contain up to 95&cent; of change &#8211; today&#8217;s homework is to find out how to measure the remaining change in the machine!</p>
<p><img src="/docs/change/change.jpg"></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=353&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=353</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Intel VT VMCS Layout</title>
		<link>http://www.pagetable.com/?p=348</link>
		<comments>http://www.pagetable.com/?p=348#comments</comments>
		<pubDate>Mon, 24 May 2010 21:58:24 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[whines]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=348</guid>
		<description><![CDATA[I understand that there might be a good reason for Intel to add virtualization extensions to their CPU architecture. Instead of fixing the x86 architecture to (optionally) make it Popek-Goldberg compliant and have all critial instructions trap if not run in Ring 0, they added non-root mode, a very big hammer that allows me to [...]]]></description>
			<content:encoded><![CDATA[<p>I understand that there might be a good reason for Intel to add virtualization extensions to their CPU architecture. Instead of fixing the x86 architecture to (optionally) make it Popek-Goldberg compliant and have all critial instructions trap if not run in Ring 0, they added non-root mode, a very big hammer that allows me to switch my CPU state completely to that of the guest and switches back to my original host state on a certain event in the guest. Well, it&#8217;s a great toy for people who want to play with CPU internals.</p>
<p>Therefore Intel had to add the VMCS, a 4 KB block in memory that holds the complete CPU state of both the host and the guest (segment registers, GDT and IDT pointer, certain MSRs etc.) as well as some control bits (for example, when to exit).</p>
<p>I also understand that Intel doesn&#8217;t allow me to just read and write memory in the VMCS, but abstracts accessing the virtualization state using a vmread/vmwrite interface. This way, the actual layout of this 4 KB page is an implementation detail and can be changed on later CPUs. It also allows for field indexes that are more spread out and encode what kind of field it is.</p>
<p>So I understand very well why Intel encodes into the VMCS field index whether it&#8217;s a control field (0), a read-only field (1), part of the guest state (2) or part of the host state (3), and whether it&#8217;s a 16 bit (0), 32 bit (2), 64 bit (1) or native-sized (3) field. This way, for example, all 16 bit guest state fields (like the guest&#8217;s CS) have indexes starting at 0&#215;0800, and all 64 bit host state fields (like the hosts&#8217;s EFER MSR) start at 0x2C00.</p>
<p>Now what I don&#8217;t understand is what is so hard to be consistent with this convention (Intel Manual 3B, Appendix H).</p>
<ul>
<li><b>VMCS Link Pointer</b> (0&#215;2800): In the first revision of VT, it had already been already decided that there should be a mechanism for having a second 4 KB page in case later versions of VT need more than 4 KB of state. For this, there is there &#8220;VMCS Link Pointer&#8221;, which is a 64 bit physical address. Guess what category this belongs to? Guest state.</li>
<li><b>&#8220;Guest Address Space Size&#8221; bit in the &#8220;VM Entry Controls&#8221; Field</b> (0&#215;4012): This is clearly guest state and not a control field.</li>
<li><b>&#8220;Host Address Space Size&#8221; bit in the &#8220;VM Exit Controls&#8221; Field</b> (0x400C): This is clearly host state and not a control field.</li>
<li><b>VMX-preemption timer value</b> (0x482E): This timer controls after how many ticks execution of the guest should end and control should be returned to the hypervisor. Intel put this into the &#8220;guest state&#8221; bucket: All other guest state fields are properties of the i386/x86_64 architecture that need to be switched, but not this one. This should really be a control field.</li>
</ul>
<p>And here is another favorite of mine: the &#8220;Primary Execution Controls&#8221; field. The 32 bits specify which events in the guest will exit guest execution and trap into the hypervisor (Table 21-6). These events are, among others:</p>
<ul>
<li>exit on HLT</li>
<li>exit on INVLPG</li>
<li>exit on MOV CR3</li>
<li>exit on PAUSE</li>
</ul>
<p>Setting these bits to 1 enables the traps. So if you set all bits to 0, you basically have an unrestricted guest, and if you set all bits to 1, you have the most controlled guest, and you get a notification about every event in the guest. Or so you might think. Actually, there are two bits in the field that don&#8217;t work like this:</p>
<ul>
<li>Use MSR bitmaps</li>
<li>Use I/O bitmaps</li>
</ul>
<p>If these bits are set to 1, it checks a whitelist whether a certain MSR or I/O access is possible. If they are set to 0, all MSR and I/O accesses trap. Compared to all other bits, that&#8217;s backwards. Oh great.</p>
<p>Since Steve Jobs seems to be happy to explain his personal opinion on everything lately, I wrote him an email asking him about this, and he replied:</p>
<pre>
Return-path: &lt;sjobs@apple.com&gt;
Received: from bulkin002-bge351000.mac.com ([unknown] [10.150.69.129])
 by ms231.mac.com
 (Sun Java(tm) System Messaging Server 7u3-12.01 64bit (built Oct 15 2009))
 with ESMTP id &lt;0L2X00HTAZ3Q6GF1@ms231.mac.com&gt; for XXX@mac.com; Mon,
 24 May 2010 13:47:50 -0700 (PDT)
Original-recipient: rfc822;XXX@mac.com
Received: from relay13.apple.com ([17.128.113.29])
 by bulkin002.mac.com (Sun Java(tm) System Messaging Server 6.3-7.02 (built Jun
 27 2008; 32bit)) with ESMTP id &lt;0L2X001EVZ3QKED0@bulkin002.mac.com&gt; for
 XXX@mac.com (ORCPT XXX@mac.com); Mon, 24 May 2010 13:47:50 -0700 (PDT)
X-AuditID: 1180721d-b7c17fe00000693e-19-4bfae5f6545a
Received: from [17.201.27.84]
	(using TLS with cipher AES128-SHA (AES128-SHA/128 bits))
	(Client did not present a certificate)	by relay13.apple.com (Apple SCV relay)
 with SMTP id DB.14.26942.6F6EAFB4; Mon, 24 May 2010 13:47:50 -0700 (PDT)
From: Steve Jobs &lt;sjobs@apple.com&gt;
Content-type: text/plain
Content-transfer-encoding: 7bit
Subject: Re: Intel VT VMCS Layout
Date: Mon, 24 May 2010 13:47:48 -0700
Message-id: &lt;3E789F1B-7E13-FFD2-80F6-8E8D4CDDE7FB@apple.com&gt;
To: Michael Steil &lt;XXX@mac.com&gt;
MIME-version: 1.0 (Apple Message framework v1077)
X-Mailer: Apple Mail (2.1077)
X-Brightmail-Tracker: AAAAAQAAAZE=

The whole VMCS is a big mess, I hate it.

&gt; Hi Steve, what do you think about the ordering of the VMCS fields in
&gt; Intel's VT extenions?
&gt;
&gt;   Michael
</pre>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=348&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=348</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Michael Steil rocks</title>
		<link>http://www.pagetable.com/?p=340</link>
		<comments>http://www.pagetable.com/?p=340#comments</comments>
		<pubDate>Wed, 05 May 2010 04:19:37 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=340</guid>
		<description><![CDATA[Google is always right. Exercise for the reader: Change it.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.google.com/search?q=michael+steil+rocks">Google</a> is always right.</p>
<p><img src="/docs/michael_steil_rocks/michael_steil_rocks.png"></p>
<p>Exercise for the reader: Change it.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=340&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=340</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Microsoft vs. Standards</title>
		<link>http://www.pagetable.com/?p=333</link>
		<comments>http://www.pagetable.com/?p=333#comments</comments>
		<pubDate>Fri, 23 Apr 2010 03:04:29 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=333</guid>
		<description><![CDATA[Here is a fun game for long car rides: One person names a respected standard implemented by dozens of IT companies, and the other person names Microsoft&#8217;s competing technology. Example: MPEG Audio (MP3/AAC) &#8211; Windows Media Audio. (When you have run out of examples, you can try this game with other major players in the [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a fun game for long car rides: One person names a respected standard implemented by dozens of IT companies, and the other person names Microsoft&#8217;s competing technology. Example: MPEG Audio (MP3/AAC) &#8211; Windows Media Audio.</p>
<p>(When you have run out of examples, you can try this game with other major players in the IT business.)</p>
<p>Let&#8217;s play this game in the comments to this blog entry: Just add as many of these pairs that you can think of &#8211; extra points if Microsoft&#8217;s technology has a closed specification.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=333&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=333</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Who invented the computer?</title>
		<link>http://www.pagetable.com/?p=330</link>
		<comments>http://www.pagetable.com/?p=330#comments</comments>
		<pubDate>Tue, 20 Apr 2010 19:24:02 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[trivia]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=330</guid>
		<description><![CDATA[In 1837, Charles Babbage designed a general purpose computer, the Analytical Engine, but never built it. Between 1934 and 1937, Church, Turing et al. defined the general purpose computer, but didn&#8217;t design one. In 1941, Konrad Zuse built the first general purpose computer, the Z3, but didn&#8217;t know it was general purpose and didn&#8217;t use [...]]]></description>
			<content:encoded><![CDATA[<ul>
<li>In 1837, Charles Babbage designed a general purpose computer, the <a href="http://en.wikipedia.org/wiki/Analytical_engine">Analytical Engine</a>, but never built it.</li>
<li>Between 1934 and 1937, Church, Turing et al. <a href="http://en.wikipedia.org/wiki/Church-Turing_thesis">defined</a> the general purpose computer, but didn&#8217;t design one.</li>
<li>In 1941, Konrad Zuse built the first general purpose computer, the <a href="http://en.wikipedia.org/wiki/Z3_(computer)">Z3</a>, but <a href="http://www.zib.de/zuse/Inhalt/Kommentare/Html/0684/universal2.html">didn&#8217;t know</a> it was general purpose and didn&#8217;t use it that way.</li>
<li>From 1943 to 1946, Mauchly and Eckert finally built a computer, <a href="http://en.wikipedia.org/wiki/ENIAC">ENIAC</a>, that was designed to be general-purpose.</li>
</ul>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=330&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=330</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Standards and Intellectual Property</title>
		<link>http://www.pagetable.com/?p=327</link>
		<comments>http://www.pagetable.com/?p=327#comments</comments>
		<pubDate>Sat, 10 Apr 2010 00:32:19 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[default]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=327</guid>
		<description><![CDATA[I am sitting here, working with my PC: My keyboard and my mouse are connected wirelessly via Bluetooth and my monitor is hooked up through DVI. The graphics card is sitting in a PCI slot, main memory is DDR-SDRAM, and my optical drive can do CDs and DVDs. While my internal hard disk speaks the [...]]]></description>
			<content:encoded><![CDATA[<p>I am sitting here, working with my PC: My keyboard and my mouse are connected wirelessly via <a href="http://www.bluetooth.com/English/Technology/Building/Pages/Qualifications.aspx">Bluetooth</a> and my monitor is hooked up through <a href="http://www.ddwg.org/downloads.asp">DVI</a>. The graphics card is sitting in a <a href="http://www.pcisig.com/developers/procedures/">PCI</a> slot, main memory is <a href="http://www.jedec.org/sites/default/files/JM21N.pdf">DDR-SDRAM</a>, and my optical drive can do <a href="https://www.ip.philips.com/services/?module=IpsLicenseProgram&#038;command=View&#038;id=15&#038;part=2">CDs</a> and <a href="http://www.dvd6cla.com/">DVDs</a>. While my internal hard disk speaks the <a href="https://www.sata-io.org/developers/purchase_spec.asp">SATA</a> protocol, my home directory is actually sitting on an <a href="http://www.sdcard.org/developers/howto/">SD</a> card that is connected through a <a href="http://www.usb.org/developers/docs/">USB</a> reader. My internet connection is done through <a href="http://broadband-forum.org/technical/ipdeclarations.php">DSL</a>. On the software side, I am using GNU/Linux and browsing the internet with Firefox. No way I would ever watch a video in <a href="http://www.mpegla.com/">H.264</a> format.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=327&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=327</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Buggy Drivers</title>
		<link>http://www.pagetable.com/?p=324</link>
		<comments>http://www.pagetable.com/?p=324#comments</comments>
		<pubDate>Thu, 01 Apr 2010 22:21:56 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[default]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=324</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><a href="/docs/buggy_drivers/buggy_drivers.jpg"><img src="/docs/buggy_drivers/buggy_drivers.jpg" width="440" height="330"></a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=324&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=324</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Announcement: &#8216;libcpu&#8217; Binary Translator</title>
		<link>http://www.pagetable.com/?p=317</link>
		<comments>http://www.pagetable.com/?p=317#comments</comments>
		<pubDate>Tue, 29 Dec 2009 19:47:09 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[default]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=317</guid>
		<description><![CDATA[I just did a Lightning Talk at the 26th Chaos Communication Congress 26C3 about our new project &#8220;libcpu&#8221;, and it has already been picked up by Golem.de and reddit.com, so I might as well announce it here: &#8220;libcpu&#8221; is an open source library that emulates several CPU architectures, allowing itself to be used as the [...]]]></description>
			<content:encoded><![CDATA[<p>I just did a <a href="http://events.ccc.de/congress/2009/wiki/Lightning_Talks_Schedule">Lightning Talk</a> at the <a href="http://events.ccc.de/congress/2009/wiki/Main_Page">26th Chaos Communication Congress 26C3</a> about our new project <a href="http://www.libcpu.org/wiki/index.php/Main_Page">&#8220;libcpu&#8221;</a>, and it has already been picked up by <a href="http://www.golem.de/0912/72116.html">Golem.de</a> and <a href="http://www.reddit.com/r/programming/comments/ajjlz/libcpu_is_an_open_source_library_that_emulates/">reddit.com</a>, so I might as well announce it here:</p>
<p><cite>&#8220;libcpu&#8221; is an open source library that emulates several CPU architectures, allowing itself to be used as the CPU core for different kinds of emulator projects. It uses its own frontends for the different CPU types, and uses LLVM for the backend. libcpu is supposed to be able to do user mode and system emulation, and dynamic as well as static recompilation.</cite></p>
<p>Here are my slides: <a href="/docs/libcpu/26C3-libcpu.pdf">26C3-libcpu.pdf</a></p>
<p>Here is the video recording: <a href="/docs/libcpu/26C3-libcpu.mp4">26C3-libcpu.mp4</a></p>
<p>Read more at <a href="http://www.libcpu.org/wiki/">http://www.libcpu.org/</a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=317&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=317</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Having Fun with Branch Delay Slots</title>
		<link>http://www.pagetable.com/?p=313</link>
		<comments>http://www.pagetable.com/?p=313#comments</comments>
		<pubDate>Mon, 23 Nov 2009 02:56:08 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[tricks]]></category>
		<category><![CDATA[trivia]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=313</guid>
		<description><![CDATA[Branch Delay Slots are one of the awkward features of RISC architectures. RISC CPUs are pipelined by definition, so while the current instruction is in execution, the following instruction(s) will be in the pipeline already. If there is for example a conditional branch in the instruction stream, the CPU cannot know whether the next instruction [...]]]></description>
			<content:encoded><![CDATA[<p>Branch Delay Slots are one of the awkward features of RISC architectures. RISC CPUs are pipelined by definition, so while the current instruction is in execution, the following instruction(s) will be in the pipeline already. If there is for example a conditional branch in the instruction stream, the CPU cannot know whether the next instruction is the one following the branch or the instruction at the target location until it has evaluated the branch. This would cause a bubble in the pipeline; therefore some RISC architectures have a branch delay slot: The instruction after the branch will always be executed, no matter whether the branch is taken or not.</p>
<p>So in practice, you can put the instruction that would be before the branch right after the branch, if this instruction is independent of the branch instruction, i.e. doesn&#8217;t access the same registers. Otherwise, you can fill it with a NOP. Out-of-order architectures can do this reordering at runtime, so there would be no need for a delay slot. Nevertheless, the delay slot is a feature of the architecture, not the implementation.</p>
<p>Some RISCs like PowerPC and ARM do not have a delay slot, but for example MIPS, SPARC, PA-RISC have it. But there are some variations: MIPS and PA-RISC have an annihilation/nullify/likely bit in the instruction, so the programmer can choose that the instruction in the delay slot only gets executed if the branch is taken.</p>
<p>Other CPUs, like SPARC, PA-RISC or the ill-fated Motorola M88K have optional delay slots: The programmer can set a bit in the opcode if he cannot come up with a good instruction for the delay slot, and save the wasted NOP in the program code this way &#8211; the CPU will put a bubble into the pipeline.</p>
<p>Now the interesting question is what happens if the branch and the delay instruction are not independent. What if the delay instruction writes r5 and the branch jumps to r5? What if it&#8217;s a branch-and-link, and the delay instruction modifies the link register? On MIPS, this is illegal, and undefined.</p>
<p>In practice, MIPS won&#8217;t halt and catch fire though. As you would expect from the design of a CPU pipeline, the CPU basically executes the branch and the delay instruction in order, as they are stored in the instruction stream, and it only delays the write to PC, i.e. the actual jump until after the delay instruction. So, for example, if you modify a register that the branch depends on, it will not influence the branch, but be in effect after the jump. </p>
<p>On the aforementioned Motorola M88K, this behaviour is documented, and GCC even makes use of it:</p>
<pre>
820:   7d ad 00 08   cmp   r13,r13,0x08    ; compare

824:   d4 6d 00 05   bb0.n 0x03,r13,0x834  ; cond. branch
828:   63 df 00 00   addu  r30,r31,0       ; delay slot

82c:   cc 00 00 7f   bsr.n 0xa28           ; function call
830:   60 21 01 ac   addu  r1,r1,0x1ac     ; delay slot: fix up link

834:   00 00 00 00   nop
</pre>
<p>The first three instructions are a compare/branch sequence. If the branch is taken, execution will continue at 0&#215;834, otherwise at 0x82c, after the delay slot. The delay instruction is independent of the branch, nothing special here yet.</p>
<p>But now look at the following two instructions: 0x82c and 0&#215;830 are not independent. r1 is the M88K&#8217;s link register, so the &#8220;bsr&#8221; writes the addres of the following instruction after the delay slot (0&#215;834) into r1. The delay slot also writes into r1: It adds 0x1ac to it. These instructions are executed in order, but the actual branch to 0xa28 will only be done after the delay instruction.</p>
<p>So what these two instructions effectively do is call a function, but set up the return address to skip the next 0x1ac bytes (107 instructions) after return. If the conditional branch at 0&#215;824 is taken, the code at 0&#215;834 will be executed, otherwise, 0xa28 is called, and the &#8220;taken&#8221; case of the conditional branch is skipped. This trick can be used whenever you have C code with an &#8220;if&#8221; statement of which one case is a single function call:</p>
<pre>
if (...) {
    call_something();
} else {
    [...]
}
</pre>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=313&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=313</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PCEPTPDPTE</title>
		<link>http://www.pagetable.com/?p=308</link>
		<comments>http://www.pagetable.com/?p=308#comments</comments>
		<pubDate>Sat, 31 Oct 2009 16:05:14 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[trivia]]></category>
		<category><![CDATA[whines]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=308</guid>
		<description><![CDATA[Here is a new pagetable entry. I like Intel. I told you before how Intel messed up the x86 register nomenclature by extending A to AX (A extended) and then to EAX (extended A extended). Then AMD came and extended the register once more, giving it a more sane name: RAX. I also told you [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a new pagetable entry.</p>
<p>I like Intel. I told you before <a href="http://www.pagetable.com/?p=14">how Intel messed up the x86 register nomenclature</a> by extending A to AX (A extended) and then to EAX (extended A extended). Then AMD came and extended the register once more, giving it a more sane name: RAX.</p>
<p>I also told you before how Intel messed up the x86 pagetable nomenclature: There were pagetables (PT, level 1) and page directories (PD, level 2) on the i386, and for the Pentium Pro, they added page directory pointers (PDP, level 3). Then AMD came and extended it once more, giving it a more sane name: page map level 4 (PML4).</p>
<p>With the advent of virtualization, both Intel and AMD added a feature to get rid of the slow software shadow pagetables, and added hardware support for nested pagetables, i.e. the guest has 4 levels of pagetables, and the host has another 4 levels.</p>
<p>AMD called these &#8211; surprise, surprise! &#8211; nested pagetables, NPT. Intel was more creative. With a history of extending architectures, they went with the big E: extended pagetables, EPT.</p>
<p>Let&#8217;s practice a bit: A PD is a page directory, a PDE is a page directory entry. You can also call it a PDPTE, a page directory pagetable entry (level 2 PTE), because after all, all these entries on all levels are PTEs, because they share the same format. A PDPPTE is a page directory pointer pagetable entry, aka level 3 entry.</p>
<p>If we use nested paging &#8211; excuse me &#8211; extended paging on Intel, we need to prepend EPT to our nice little abbreviations. An EPTPTE is a level 1 entry, an EPTPDPTE is level 2 not to be confused with an EPTPDPPTE, which is level 3, and a level 4 entry is EPTPML4PTE.</p>
<p>It get even better. Oracle/Sun/Innotek <a href="http://www.virtualbox.org/">VirtualBox</a> uses Hungarian Notation for its variable names, so it prepends &#8220;P&#8221; for pointer and &#8220;C&#8221; for constant. So what would you call a variable, which is a pointer to a constant level 2 EPT entry?</p>
<p>Of course, <a href="http://www.virtualbox.org/svn/vbox/trunk/include/VBox/hwacc_vmx.h">PCEPTPDPTE</a>.</p>
<pre>
/** Pointer to a const EPT Page Directory Pointer Entry. */
typedef const EPTPDPTE *PCEPTPDPTE;
</pre>
<p>I thought about this for a while, and considered patenting this brilliant idea of mine, but here it is, free of patents and free for everyone to use: Michael&#8217;s nomenclature for Intel/AMD pagetables:</p>
<table border="1">
<tr>
<th>new name</th>
<th>description</th>
<th>old name</th>
<tr>
<td>P4</td>
<td>pagetable level 4 page</td>
<td>PML4</td>
<tr>
<td>P3</td>
<td>pagetable level 3 page</td>
<td>PDP</td>
<tr>
<td>P2</td>
<td>pagetable level 2 page</td>
<td>PD</td>
<tr>
<td>P1</td>
<td>pagetable level 1 page</td>
<td>PT</td>
<tr>
<td>P4E</td>
<td>pagetable level 4 entry</td>
<td>PML4E/PML4PTE</td>
<tr>
<td>P3E</td>
<td>pagetable level 3 entry</td>
<td>PDPE/PDPPTE</td>
<tr>
<td>P2E</td>
<td>pagetable level 2 entry</td>
<td>PDE/PDPTE</td>
<tr>
<td>P1E</td>
<td>pagetable level 1 entry</td>
<td>PTE</td>
<tr>
<td>NP4</td>
<td>nested pagetable level 4 page</td>
<td>EPTPML4</td>
<tr>
<td>NP3</td>
<td>nested pagetable level 3 page</td>
<td>EPTPDP</td>
<tr>
<td>NP2</td>
<td>nested pagetable level 2 page</td>
<td>EPTPD</td>
<tr>
<td>NP1</td>
<td>nested pagetable level 1 page</td>
<td>EPTPT</td>
<tr>
<td>NP4E</td>
<td>nested pagetable level 4 entry</td>
<td>EPTPML4E/EPTPML4PTE</td>
<tr>
<td>NP3E</td>
<td>nested pagetable level 3 entry</td>
<td>EPTPDPE/EPTPDPPTE</td>
<tr>
<td>NP2E</td>
<td>nested pagetable level 2 entry</td>
<td>EPTPDE/EPTPDPTE</td>
<tr>
<td>NP1E</td>
<td>nested pagetable level 1 entry</td>
<td>EPTPTE</td>
</table>
<p>You are welcome.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=308&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=308</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>A Standalone printf() for Early Bootup</title>
		<link>http://www.pagetable.com/?p=298</link>
		<comments>http://www.pagetable.com/?p=298#comments</comments>
		<pubDate>Tue, 08 Sep 2009 02:15:20 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=298</guid>
		<description><![CDATA[A while ago, I complained about operating systems with overly complicated startup code that spends too much time in assembly and does hot have printf() or framebuffer access until very late. This second post is about printf(): Many systems use POST codes (on i386/x86_64, i.e. writes to port 0&#215;80) or debug LED for debugging, or [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago, I complained about operating systems with overly complicated startup code that <a href="http://www.pagetable.com/?p=276">spends too much time in assembly</a> and does hot have printf() or framebuffer access until very late.</p>
<p>This second post is about printf(): Many systems use POST codes (on i386/x86_64, i.e. writes to port 0&#215;80) or debug LED for debugging, or have complicated and cumbersome implementations for puts() and print_hex() &#8211; and printf() is only available very late, because it has some special requirement, like console channels being set up. But printf() is not rocket science: Al it needs is C and a stack. Whatever system you are bringing up on whatever platform: Having printf() as early as possible will prove very useful.</p>
<p>Today, I am presenting a full-featured standalone version of printf() that can be added to arbitrary 32 or 64 bit C code. The code has been taken from FreeBSD (<a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/subr_prf.c">sys/kern/subr_prf.c</a>) and is therefore BSD-licensed. Unnecessary functions have been removed and all typedefs required have been added.</p>
<pre>
/*-
 * Copyright (c) 1986, 1988, 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 * (c) UNIX System Laboratories, Inc.
 * All or some portions of this file are derived from material licensed
 * to the University of California by American Telephone and Telegraph
 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
 * the permission of UNIX System Laboratories, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
 */

typedef unsigned long size_t;
typedef long ssize_t;
#ifdef __64BIT__
typedef unsigned long long uintmax_t;
typedef long long intmax_t;
#else
typedef unsigned int uintmax_t;
typedef int intmax_t;
#endif
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef unsigned short u_short;
typedef unsigned long long u_quad_t;
typedef long long quad_t;
typedef unsigned long uintptr_t;
typedef long ptrdiff_t;
#define NULL ((void*)0)
#define NBBY    8               /* number of bits in a byte */
char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define hex2ascii(hex)  (hex2ascii_data[hex])
#define va_list __builtin_va_list
#define va_start __builtin_va_start
#define va_arg __builtin_va_arg
#define va_end __builtin_va_end
#define toupper(c)      ((c) - 0x20 * (((c) >= 'a') &#038;&#038; ((c) <= 'z')))
static size_t
strlen(const char *s)
{
	size_t l = 0;
	while (*s++)
		l++;
	return l;
}

/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)

/*
 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
 * order; return an optional length and a pointer to the last character
 * written in the buffer (i.e., the first character of the string).
 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
 */
static char *
ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
	char *p, c;

	p = nbuf;
	*p = '\0';
	do {
		c = hex2ascii(num % base);
		*++p = upper ? toupper(c) : c;
	} while (num /= base);
	if (lenp)
		*lenp = p - nbuf;
	return (p);
}

/*
 * Scaled down version of printf(3).
 *
 * Two additional formats:
 *
 * The format %b is supported to decode error registers.
 * Its usage is:
 *
 *	printf("reg=%b\n", regval, "<base><arg>*");
 *
 * where <base> is the output base expressed as a control character, e.g.
 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
 * the first of which gives the bit number to be inspected (origin 1), and
 * the next characters (up to a control character, i.e. a character <= 32),
 * give the name of the register.  Thus:
 *
 *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
 *
 * would produce output:
 *
 *	reg=3<BITTWO,BITONE>
 *
 * XXX:  %D  -- Hexdump, takes pointer and separator string:
 *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
 *		("%*D", len, ptr, " " -> XX XX XX XX ...
 */
int
kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
{
#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
	char nbuf[MAXNBUF];
	char *d;
	const char *p, *percent, *q;
	u_char *up;
	int ch, n;
	uintmax_t num;
	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
	int cflag, hflag, jflag, tflag, zflag;
	int dwidth, upper;
	char padc;
	int stop = 0, retval = 0;

	num = 0;
	if (!func)
		d = (char *) arg;
	else
		d = NULL;

	if (fmt == NULL)
		fmt = "(fmt null)\n";

	if (radix < 2 || radix > 36)
		radix = 10;

	for (;;) {
		padc = ' ';
		width = 0;
		while ((ch = (u_char)*fmt++) != '%' || stop) {
			if (ch == '\0')
				return (retval);
			PCHAR(ch);
		}
		percent = fmt - 1;
		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
		sign = 0; dot = 0; dwidth = 0; upper = 0;
		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
reswitch:	switch (ch = (u_char)*fmt++) {
		case '.':
			dot = 1;
			goto reswitch;
		case '#':
			sharpflag = 1;
			goto reswitch;
		case '+':
			sign = 1;
			goto reswitch;
		case '-':
			ladjust = 1;
			goto reswitch;
		case '%':
			PCHAR(ch);
			break;
		case '*':
			if (!dot) {
				width = va_arg(ap, int);
				if (width < 0) {
					ladjust = !ladjust;
					width = -width;
				}
			} else {
				dwidth = va_arg(ap, int);
			}
			goto reswitch;
		case '0':
			if (!dot) {
				padc = '0';
				goto reswitch;
			}
		case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
				for (n = 0;; ++fmt) {
					n = n * 10 + ch - '0';
					ch = *fmt;
					if (ch < '0' || ch > '9')
						break;
				}
			if (dot)
				dwidth = n;
			else
				width = n;
			goto reswitch;
		case 'b':
			num = (u_int)va_arg(ap, int);
			p = va_arg(ap, char *);
			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
				PCHAR(*q--);

			if (num == 0)
				break;

			for (tmp = 0; *p;) {
				n = *p++;
				if (num &#038; (1 << (n - 1))) {
					PCHAR(tmp ? ',' : '<');
					for (; (n = *p) > ' '; ++p)
						PCHAR(n);
					tmp = 1;
				} else
					for (; *p > ' '; ++p)
						continue;
			}
			if (tmp)
				PCHAR('>');
			break;
		case 'c':
			PCHAR(va_arg(ap, int));
			break;
		case 'D':
			up = va_arg(ap, u_char *);
			p = va_arg(ap, char *);
			if (!width)
				width = 16;
			while(width--) {
				PCHAR(hex2ascii(*up >> 4));
				PCHAR(hex2ascii(*up &#038; 0x0f));
				up++;
				if (width)
					for (q=p;*q;q++)
						PCHAR(*q);
			}
			break;
		case 'd':
		case 'i':
			base = 10;
			sign = 1;
			goto handle_sign;
		case 'h':
			if (hflag) {
				hflag = 0;
				cflag = 1;
			} else
				hflag = 1;
			goto reswitch;
		case 'j':
			jflag = 1;
			goto reswitch;
		case 'l':
			if (lflag) {
				lflag = 0;
				qflag = 1;
			} else
				lflag = 1;
			goto reswitch;
		case 'n':
			if (jflag)
				*(va_arg(ap, intmax_t *)) = retval;
			else if (qflag)
				*(va_arg(ap, quad_t *)) = retval;
			else if (lflag)
				*(va_arg(ap, long *)) = retval;
			else if (zflag)
				*(va_arg(ap, size_t *)) = retval;
			else if (hflag)
				*(va_arg(ap, short *)) = retval;
			else if (cflag)
				*(va_arg(ap, char *)) = retval;
			else
				*(va_arg(ap, int *)) = retval;
			break;
		case 'o':
			base = 8;
			goto handle_nosign;
		case 'p':
			base = 16;
			sharpflag = (width == 0);
			sign = 0;
			num = (uintptr_t)va_arg(ap, void *);
			goto number;
		case 'q':
			qflag = 1;
			goto reswitch;
		case 'r':
			base = radix;
			if (sign)
				goto handle_sign;
			goto handle_nosign;
		case 's':
			p = va_arg(ap, char *);
			if (p == NULL)
				p = "(null)";
			if (!dot)
				n = strlen (p);
			else
				for (n = 0; n < dwidth &#038;&#038; p[n]; n++)
					continue;

			width -= n;

			if (!ladjust &#038;&#038; width > 0)
				while (width--)
					PCHAR(padc);
			while (n--)
				PCHAR(*p++);
			if (ladjust &#038;&#038; width > 0)
				while (width--)
					PCHAR(padc);
			break;
		case 't':
			tflag = 1;
			goto reswitch;
		case 'u':
			base = 10;
			goto handle_nosign;
		case 'X':
			upper = 1;
		case 'x':
			base = 16;
			goto handle_nosign;
		case 'y':
			base = 16;
			sign = 1;
			goto handle_sign;
		case 'z':
			zflag = 1;
			goto reswitch;
handle_nosign:
			sign = 0;
			if (jflag)
				num = va_arg(ap, uintmax_t);
			else if (qflag)
				num = va_arg(ap, u_quad_t);
			else if (tflag)
				num = va_arg(ap, ptrdiff_t);
			else if (lflag)
				num = va_arg(ap, u_long);
			else if (zflag)
				num = va_arg(ap, size_t);
			else if (hflag)
				num = (u_short)va_arg(ap, int);
			else if (cflag)
				num = (u_char)va_arg(ap, int);
			else
				num = va_arg(ap, u_int);
			goto number;
handle_sign:
			if (jflag)
				num = va_arg(ap, intmax_t);
			else if (qflag)
				num = va_arg(ap, quad_t);
			else if (tflag)
				num = va_arg(ap, ptrdiff_t);
			else if (lflag)
				num = va_arg(ap, long);
			else if (zflag)
				num = va_arg(ap, ssize_t);
			else if (hflag)
				num = (short)va_arg(ap, int);
			else if (cflag)
				num = (char)va_arg(ap, int);
			else
				num = va_arg(ap, int);
number:
			if (sign &#038;&#038; (intmax_t)num < 0) {
				neg = 1;
				num = -(intmax_t)num;
			}
			p = ksprintn(nbuf, num, base, &#038;tmp, upper);
			if (sharpflag &#038;&#038; num != 0) {
				if (base == 8)
					tmp++;
				else if (base == 16)
					tmp += 2;
			}
			if (neg)
				tmp++;

			if (!ladjust &#038;&#038; padc != '0' &#038;&#038; width
			    &#038;&#038; (width -= tmp) > 0)
				while (width--)
					PCHAR(padc);
			if (neg)
				PCHAR('-');
			if (sharpflag &#038;&#038; num != 0) {
				if (base == 8) {
					PCHAR('0');
				} else if (base == 16) {
					PCHAR('0');
					PCHAR('x');
				}
			}
			if (!ladjust &#038;&#038; width &#038;&#038; (width -= tmp) > 0)
				while (width--)
					PCHAR(padc);

			while (*p)
				PCHAR(*p--);

			if (ladjust &#038;&#038; width &#038;&#038; (width -= tmp) > 0)
				while (width--)
					PCHAR(padc);

			break;
		default:
			while (percent < fmt)
				PCHAR(*percent++);
			/*
			 * Since we ignore an formatting argument it is no
			 * longer safe to obey the remaining formatting
			 * arguments as the arguments will no longer match
			 * the format specs.
			 */
			stop = 1;
			break;
		}
	}
#undef PCHAR
}

static void
putchar(int c, void *arg)
{
	/* add your putchar here */
}

void
printf(const char *fmt, ...)
{
	/* http://www.pagetable.com/?p=298 */
	va_list ap;

	va_start(ap, fmt);
	kvprintf(fmt, putchar, NULL, 10, ap);
	va_end(ap);
}
</pre>
<p>One thing you will have to do is #define or #undef __64__BIT to enable or disable support for printing 64 bit values. If you are on a 64 bit architecture, you will need this to print addresses properly. If you are on 32 bit, this support will require external library functions to do 64 bit arithmetic, so you probably want to turn this off.</p>
<p>On ARM, which doesn't have an assembly statement for division, will always need a library routine. You can use FreeBSD's at <a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/libkern/arm/divsi3.S">sys/libkern/arm/divsi3.S</a>, if you to add the following #defines to make the file compile:</p>
<pre>
#define __FBSDID(a)
#define RET bx lr
#define ENTRY_NP(a) _##a: .global _##a
#define _KERNEL
</pre>
<p>All you need to do now to get printf() working is to fill the putchar() function, for example with a call to a serial_putc() implementation, if you have a serial port. On a PC, serial_putc() could look like this:</p>
<pre>
static void outb(short p, unsigned char a)
{
        asm volatile("outb %b0, %w1" : : "a" (a), "Nd" (p));
}
static unsigned char inb(short p)
{
        unsigned char a;
        asm volatile("inb %w1, %b0" : "=a" (a) : "Nd" (p));
        return a;
}
#define SERIAL_PORT 0x3f8
static void
serial_putc(unsigned char c) {
	while (!(inb(SERIAL_PORT + 5) &#038; 0x20));
	outb(SERIAL_PORT, c);
}
</pre>
<p>On an "ARM Integrator/CP" board, the default for <a href="http://www.qemu.org/">QEMU</a> emulating ARM, the follwing serial_putc() would apply (make sure you are running the MMU off, or with the serial port MMIO region mapped):</p>
<pre>
#define SERIAL_PORT 0x16000000
static void
serial_putc(unsigned char c) {
	while ((*(volatile unsigned int *)(SERIAL_PORT + 0x18)) &#038; 0x20);
	*(volatile unsigned int *)(SERIAL_PORT) = (c);
}
</pre>
<p>Unfortunately, sometimes you are bringing up or debugging a system that does not have a serial port - or at least you haven't found one: Apple Macintosh and various game systems come to mind. In this case, you might be able to set up a framebuffer and print to that. In a later post, I will present a small standalone framebuffer library.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=298&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=298</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Pictures of Apple Lisa 2 Boards</title>
		<link>http://www.pagetable.com/?p=230</link>
		<comments>http://www.pagetable.com/?p=230#comments</comments>
		<pubDate>Tue, 01 Sep 2009 08:01:14 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=230</guid>
		<description><![CDATA[The Apple Lisa is a quite rare collector&#8217;s item today. So if you hold one in your hands, you better take some high resolution pictures of the boards. Here they are: CPU Board I/O Board Memory Board]]></description>
			<content:encoded><![CDATA[<p>The Apple Lisa is a quite rare collector&#8217;s item today. So if you hold one in your hands, you better take some high resolution pictures of the boards. Here they are:</p>
<h3>CPU Board</h3>
<p><a href="docs/lisa_boards/cpu_front.jpg"><img src="docs/lisa_boards/small_cpu_front.jpg"></a><a href="docs/lisa_boards/cpu_back.jpg"><img src="docs/lisa_boards/small_cpu_back.jpg"></a></p>
<h3>I/O Board</h3>
<p><a href="docs/lisa_boards/io_front.jpg"><img src="docs/lisa_boards/small_io_front.jpg"></a><a href="docs/lisa_boards/io_back.jpg"><img src="docs/lisa_boards/small_io_back.jpg"></a></p>
<h3>Memory Board</h3>
<p><a href="docs/lisa_boards/mem_front.jpg"><img src="docs/lisa_boards/small_mem_front.jpg"></a><a href="docs/lisa_boards/mem_back.jpg"><img src="docs/lisa_boards/small_mem_back.jpg"></a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=230&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=230</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>TI-99/4A BASIC as a Scripting Language</title>
		<link>http://www.pagetable.com/?p=288</link>
		<comments>http://www.pagetable.com/?p=288#comments</comments>
		<pubDate>Tue, 25 Aug 2009 03:28:09 +0000</pubDate>
		<dc:creator>James Abbatiello</dc:creator>
				<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=288</guid>
		<description><![CDATA[It is a good time for statically recompiled versions of BASIC from old computers.Â  First there was Apple I BASIC.Â  Then came Commodore BASIC.Â  Now, due to overwhelming demand, we&#8217;re proud to release TI-99/4A BASIC. For those unfamiliar the TI-99/4A was a home computer by Texas Instruments released in 1981. Unusually for the time it [...]]]></description>
			<content:encoded><![CDATA[<p>It is a good time for statically recompiled versions of BASIC from old computers.Â  First there was <a href="/?p=35">Apple I BASIC</a>.Â  Then came <a href="/?p=48">Commodore BASIC</a>.Â  Now, due to overwhelming demand, we&#8217;re proud to release <a href="http://ti99basic.sourceforge.net/">TI-99/4A BASIC</a>.  For those unfamiliar the <a href="http://en.wikipedia.org/wiki/Texas_Instruments_TI-99/4A">TI-99/4A</a> was a home computer by Texas Instruments released in 1981.  Unusually for the time it had a 16-bit CPU: the <a href="http://en.wikipedia.org/wiki/Texas_Instruments_TMS9900">TMS9900</a>.</p>
<p>Download the program from the <a href="http://sourceforge.net/projects/ti99basic/">project page on SourceForge</a>.  Binaries for Windows and Mac OS X are available and the source should compile on most POSIX-like systems.  If you port it to a new platform please drop us a line; we&#8217;d love hear about it.</p>
<p>It supports the same interfaces as the previous projects.Â  You can use it interactively in direct mode:</p>
<pre>$ tibasic
TI BASIC READY
&gt;print 4*atn(1)
 3.141592654

&gt;bye</pre>
<p>Or you can write a line-numbered program:</p>
<pre>$ tibasic
&gt;10 FOR I=1 TO 10
&gt;20 PRINT TAB(I);"Hello, world!"
&gt;30 NEXT I
&gt;RUN
Hello, world!
 Hello, world!
  Hello, world!
   Hello, world!
    Hello, world!
     Hello, world!
      Hello, world!
       Hello, world!
        Hello, world!
         Hello, world!

** DONE **

&gt;BYE</pre>
<p>You can also run programs from a file:</p>
<pre>$ cat name.bas
10 INPUT "What is your name? ":N$
20 PRINT "Hello, ";N$;"!"

$ tibasic.exe name.bas
What is your name? James
Hello, James!</pre>
<p>There are a few sample programs available on the <a href="http://ti99basic.sourceforge.net/">homepage</a> that you can run in this manner.</p>
<h3>How it works</h3>
<p>This program works much like the already mentioned Commodore BASIC project.  The original program is statically recompiled to produce a new native binary.  The recompiler is the work of Michael Steil and theÂ  support for the TI-99/4A is by James Abbatiello.</p>
<p>The output of the recompiler is tibasic.c which is platform independent.  The support functions are in runtime_functions.c and it is this file that you would edit to port to a new system or to add new features.</p>
<p>There are a couple quirks of the TI-99/4A which made this a bit trickier to support than the C64 version:</p>
<ul>
<li>The BASIC interpreter was not written in assembly language as you might expect.  Instead it was programmed in something called Graphics Programming Language (GPL).  GPL was much like an assembly language with some high-level primitives for commonly needed functions.  A program written in GPL would be assembled to bytecode and then run on an interpreter that was written in TMS9900 assembly language.  This made BASIC programs on the machine rather slow.  The CPU would execute the GPL interpreter.  The GPL interpreter would run the BASIC interpreter.  Finally, the BASIC interpreter would run your program.  Only the TMS9900 code is statically recompiled in this program.  The GPL still runs interpreted just as it did on the original machine.  While it would theoretically be possible to statically recompile the GPL code as well this would be significantly more difficult since GPL was never officially documented by TI.  The only definitive reference is the original interpreter.</li>
<li>C64 BASIC outputs characters to the screen via one function (CHROUT) which was easy to trap.  TI-99/4A BASIC outputs to the screen with direct writes to video memory from multiple different places in the code.  This requires some ugly hacks to get anything approximating reasonable on stdout.</li>
</ul>
<h3>Limitations</h3>
<p>The Cassette, Disk, and Sound devices are not currently emulated.  Contributions in these areas are most welcome.</p>
<h3>Links</h3>
<ul>
<li><a href="ftp://ftp.whtech.com/datasheets%20and%20manuals/99-4A%20Computer/99-4A%20User%20Reference%20Guide.pdf">User Reference Guide</a> (The original TI-99/4A manual)</li>
<li><a href="http://www.nouspikel.com/ti99/titech.htm">The TI-99/4A Tech Pages</a></li>
<li><a href="http://www.99er.net/download2/index.php?act=view&amp;id=102">TI-99/4A Intern</a> contains a commented listing of the TI-99/4A ROM and GROM</li>
</ul>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=288&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=288</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Amiga intern (PDF)</title>
		<link>http://www.pagetable.com/?p=201</link>
		<comments>http://www.pagetable.com/?p=201#comments</comments>
		<pubDate>Tue, 18 Aug 2009 08:01:30 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[literature]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=201</guid>
		<description><![CDATA[(German) Die QualitĂ¤t dieses Scans ist furchtbar, aber wenigstens ist die PDF durchsuchbar. Dittrich, S., Gelfand, R., &#038; Schemmel, J. (1988). Amiga intern. DĂźsseldorf: Data Becker. (PDF, 718 S., 11 MB) DAS STEHT DRIN: In der dritten Ăźberarbeiteten Auflage finden Sie alles von der Hardware Ăźber den Betriebssystemkern EXEC bis zum DOS, alle entscheidenden Informationen [...]]]></description>
			<content:encoded><![CDATA[<p>(<i>German</i>) Die QualitĂ¤t dieses Scans ist furchtbar, aber wenigstens ist die PDF durchsuchbar.</p>
<p><a href="docs/amiga_intern/amiga_intern.pdf">Dittrich, S., Gelfand, R., &#038; Schemmel, J. (1988). <i>Amiga intern</i>. DĂźsseldorf: Data Becker.</a> (PDF, 718 S., 11 MB)</p>
<table border="1">
<tr>
<td>
<p><b>DAS STEHT DRIN:</b></p>
<p>In der dritten Ăźberarbeiteten Auflage finden Sie alles von der Hardware Ăźber den Betriebssystemkern EXEC bis zum DOS, alle entscheidenden Informationen zum Amiga. Und zwar so verstĂ¤ndlich, daĂ auch die Nicht-Profis unter Ihnen die Arbeitsweise des Amiga-Betriebssystems schnell verstehen werden.</p>
<p>Aus dem Inhalt:</p>
<ul>
<li>Die Chips des Amiga (68000, CIA, Gary, Agnus, Denise, Paula)</li>
<li>Die Schnittstellen (Video, Audio, RGB, Centronics, seriell, Floppy, Gameport, Expansionsport, Zorro-Bus, Tastatur)</li>
<li>Programmierung der Hardware (Speicherbelegung, Interrupts, Copper, Blitter, Disk-Controller)</li>
<li>Strukturen des EXEC (Node, List, Libraries, Tasks)</li>
<li>Funktion des Multitasking (Task-Switching, Kommunikation zwischen Tasks, Exceptions, Traps, Semaphoren, Speicherverwaltung)</li>
<li>I/O-Handhabung beim Amiga durch Devices und I/O-Request Interrupt-Handhabung und Verwaltung der Ressources</li>
<li>RESET-feste Programme und Strukturen, Dokumentation der RESET-Routine Programmierung eigener Handler, Devices und Libraries</li>
<li>EXEC-Base (Dokumentation und Nutzung der Systemvariablen) DOS-Bibliothek (Funktionen, Parameter, Fehlermeldungen)</li>
<li>Disketten (Boot-Vorgang, Datenstrukturen, Programmaufbau) Fast-Filing-System auf Diskette und Festplatte</li>
<li>Programmstart, Parameter, Aufruf von CU und Workbench, detaillierte Beschreibung des internen Aufbaus der CU-Befehle (Interne DOS-Bibliothek) Ein-/Ausgaben (Tastatur, Bildschirm, Diskette, parallele und serielle Schnittstelle)</li>
</ul>
<p><b>UND GESCHRIEBEN HABEN DIESES BUCH:</b></p>
<p>Johannes Schemmel ist Hardware-Spezialist mit der FĂ¤higkeit, GesamtzusammenhĂ¤nge verstĂ¤ndlich darzustellen. Stefan Dittrich als 68000-Spezialist hat schon mit seinem Buch &#8220;Amiga Maschinensprache&#8221; dem interessierten AmigaAnwender gezeigt, welche FĂ¤higkeiten in dem Rechner stecken. Ralf Gelfand ist ausgefuchster Amiga-Programmierer, der spĂ¤testens seit dem groĂen Floppy-Buch zum Amiga ein Begriff ist.</p>
<p>ISBN 3-89011-104-1
</td>
</tr>
</table>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=201&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=201</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Dangerous Xbox 360 Update Killing Homebrew</title>
		<link>http://www.pagetable.com/?p=278</link>
		<comments>http://www.pagetable.com/?p=278#comments</comments>
		<pubDate>Tue, 11 Aug 2009 17:24:28 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=278</guid>
		<description><![CDATA[On Tuesday, Microsoft has released an Xbox 360 software update that overwrites the first stage bootloader of the system. Although there have been numerous software updates for Microsoft&#8217;s gaming console in the past, this is the first one to overwrite the vital boot block. Any failure while updating this will break the Xbox 360 beyond [...]]]></description>
			<content:encoded><![CDATA[<p>On Tuesday, Microsoft has released an Xbox 360 software update that overwrites the first stage bootloader of the system. Although there have been numerous software updates for Microsoft&#8217;s gaming console in the past, this is the first one to overwrite the vital boot block. Any failure while updating this will break the Xbox 360 beyond repair. Statistics from other systems have shown that about one in a thousand bootloader updates goes wrong, and unless Microsoft has a novel solution to this problem, this puts tens of thousands of Xboxes at risk.</p>
<p>It seems that this update is being done to fix a vulnerability already known to the Free60 Project. This vulnerability has been successfully exploited to run arbitrary code, and a complete end user compatible hack has been in development for some time and is planned to be released on <a href="http://free60.org/ ">free60.org</a> shortly. It will allow users to take back control of their Xboxes and run arbitrary code like homebrew applications or Linux right after turning on the console and without the need of a modchip, finally opening up the Xbox 360 to a level of hacking as the original Xbox.</p>
<p>Because of the dangerousness of the update and the homebrew lockout, <b>the Free60 Project advises all Xbox 360 users to not update their systems to the latest software version</b>. The Project website at <a href="http://free60.org/ ">http://free60.org/</a> will provide the latest information on this ongoing topic, including the final hack software.</p>
<p>Free60 (<a href="http://free60.org/ ">www.free60.org</a>) is a project that aims to enable Xbox 360 users to run homebrew applications and operating systems like Linux on their consoles. The effort is headed by Felix Domke and Michael Steil, who have a background in dbox2, Xbox and GameCube hacking, and who have spoken at various conferences about their findings. Two years ago, Free60 released a hack that allowed arbitrary code execution using a game (&#8220;King Kong Hack&#8221;) as well as an adapted version of Linux, but this possibility has been disabled by Microsoft in subsequent updates of the Xbox 360 software.</p>
<p>Felix and Michael have repeatedly argued that game console manufacturers should open up their platforms to Linux and homebrew, similar to what Sony has done with the PlayStation 3.</p>
<p>(<a href="http://debugmo.de/">Felix Domke</a>, <a href="http://www.pagetable.com/">Michael Steil</a>, <a href="http://www.free60.org/">Free60 Project</a>; 11 August 2009)</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=278&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=278</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Minimizing the Assembly needed for Machine Initialization</title>
		<link>http://www.pagetable.com/?p=276</link>
		<comments>http://www.pagetable.com/?p=276#comments</comments>
		<pubDate>Tue, 11 Aug 2009 05:47:12 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=276</guid>
		<description><![CDATA[In many operating systems, I have seen overly complicated startup code. Too much is done in assembly, and printf() and framebuffer access is only available very late. In the next three blog posts, I will show how this can be avoided. In this post, I am showing how little assembly code is needed for startup. [...]]]></description>
			<content:encoded><![CDATA[<p>In many operating systems, I have seen overly complicated startup code. Too much is done in assembly, and <a href="http://www.pagetable.com/?p=298">printf()</a> and framebuffer access is only available very late. In the next three blog posts, I will show how this can be avoided.</p>
<p>In this post, I am showing how little assembly code is needed for startup. Minimizing the assembly makes your code significantly more maintainable. Everything that really needs to be done is setting up the CPU state to support 64 bit (or 32 bit) C code running at physical addresses, and everything else, including setting up the final machine state, can be done in C with a little inline assembly. The following example switches from 16 bit (real mode) or 32 bit mode (flat protected mode) into 64 bit mode on an x86_64 CPU (NASM syntax):</p>
<pre>
PAGE_SIZE	equ	0x1000
STACK_SIZE	equ	16*1024

PML2		equ	0x1000
PML3		equ	PML2+PAGE_SIZE
PML4		equ	PML3+PAGE_SIZE

STACK_BOTTOM	equ	PML4+PAGE_SIZE
STACK_TOP	equ	STACK_BOTTOM+STACK_SIZE

CODE_START	equ	STACK_TOP

	org CODE_START

	[BITS 16]
	cli

	; clear 3 pages of pagetables
	mov edi, PML2
	xor eax, eax
	mov ecx, 3*4096/4
	rep stosd

	; set up pagetables
	mov dword [PML2], 0x87		; single 4 MB id mapping PML2
	mov dword [PML3], PML2 | 7	; single entry at PML3
	mov dword [PML4], PML3 | 7	; single entry at PML4

	; load the GDT
	lgdt [gdt_desc]

	; set PSE,  PAE
	mov eax, 0x30
	mov cr4, eax

	; long mode
	mov ecx, 0xc0000080
	rdmsr
	or eax, 0x100
	wrmsr

	; enable pagetables
	mov eax, PML4
	mov cr3, eax

	; turn on long mode and paging
	mov eax, 0x80010001
	mov cr0, eax

	jmp SEL_CS:code64

code64:
	[BITS 64]
	mov ax, SEL_DS
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	mov sp, STACK_TOP
	call start

inf:	jmp inf

gdt_desc:
	dw  GDT_LEN-1
	dd  gdt
	align 8
gdt	db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 0x00 dummy
gdt_cs	db 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xaf, 0x00 ; 0x08 code64
gdt_ds	db 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xaf, 0x00 ; 0x18 data64

GDT_LEN equ $ - gdt
SEL_CS equ gdt_cs - gdt
SEL_DS equ gdt_ds - gdt
</pre>
<p>While switching into 32 bit flat mode is trivial, switching into 64 bit mode requires setting up pagetables. This code sets up 4 MB of identity-mapped memory starting at address 0.</p>
<p>The code is designed to switch from 16 bit mode into 64 bit mode, but since 16 and 32 bit flat mode on i386 are assembly source compatible, you can replace &#8220;[BITS 16]&#8221; with &#8220;[BITS 32]&#8220;, and the code will switch from 32 bit to 64 bit mode. (Yes, it is possible to switch from real mode directly into 64 bit mode: <a href="http://forum.osdev.org/viewtopic.php?t=11093">osdev.org Forums</a>)</p>
<p>If you use this code, be careful about the memory layout. The example leaves the first page in memory untouched (in case you need the original real mode BIOS IDT for something later), and occupies the next few pages for the pagetables and the stack. Your code should be above that, but, on a BIOS system, not be between 640 KB and 1 MB (this might be device memory and ROM), and also not above 1 MB before you have enabled the A20 gate.</p>
<p>While this code is enough to support 64 bit C code, this is not enough to set up the machine to support all aspects of an operating system. You probably want to set up your own GDT that has entries for 32 bit code and data too, you want to set up an IDT in order to be able to catch exceptions and interrupts, and you will need real pagetables to support virtual memory. Also, you will have to move your stack pointer once you have your final memory layout.</p>
<p>But it is possible to construct the overly complicated GDT, IDT and pagetable structures using readable C code, and the &#8220;lidt&#8221;, &#8220;lgdt&#8221; etc. instructions can be done in inline assembly. While this is not portable C code, it is possible to reuse large parts of the machine initialization for a 32 bit (i386) and a 64 bit (x86_64) version of the operating system, which is not as easy to get right in assembly.</p>
<p>In my next post, I am going to show how easy it is to get printf() working as soon as you reach C, so you don&#8217;t have to mess around with puts()- and print_hex()-like functions in early machine initialization.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=276&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=276</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Aggressive Tail Call Optimization</title>
		<link>http://www.pagetable.com/?p=206</link>
		<comments>http://www.pagetable.com/?p=206#comments</comments>
		<pubDate>Tue, 04 Aug 2009 08:01:33 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=206</guid>
		<description><![CDATA[In some i386/x86_64 assembly code my coworker was working on, there was a macro like this: #define ENDFUNC leave \ ret Having forgotten about the exact implementation of the macro, he then wrote a function that ended like this: leave ENDFUNC Now this obviously ended the function with leave leave ret and he got very [...]]]></description>
			<content:encoded><![CDATA[<p>In some i386/x86_64 assembly code my coworker was working on, there was a macro like this:</p>
<pre>
#define ENDFUNC leave \
                ret
</pre>
<p>Having forgotten about the exact implementation of the macro, he then wrote a function that ended like this:</p>
<pre>
        leave
        ENDFUNC
</pre>
<p>Now this obviously ended the function with</p>
<pre>
        leave
        leave
        ret
</pre>
<p>and he got very interesting results. What was happening?</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=206&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=206</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>LOAD&#8221;$&#8221;,8</title>
		<link>http://www.pagetable.com/?p=273</link>
		<comments>http://www.pagetable.com/?p=273#comments</comments>
		<pubDate>Tue, 28 Jul 2009 08:01:47 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=273</guid>
		<description><![CDATA[Commodore computers up to BASIC 2.0 (like the Commodore 64, the VIC-20 and the PET 2001) only had a very basic understanding of mass storage: There were physical device numbers that were mapped to the different busses, and the &#8220;KERNAL&#8221; library had &#8220;open&#8221;, &#8220;read&#8221;, &#8220;write&#8221; and &#8220;close&#8221; functions that worked on these devices. There were [...]]]></description>
			<content:encoded><![CDATA[<p>Commodore computers up to BASIC 2.0 (like the Commodore 64, the VIC-20 and the PET 2001) only had a very basic understanding of mass storage: There were physical device numbers that were mapped to the different busses, and the &#8220;KERNAL&#8221; library had &#8220;open&#8221;, &#8220;read&#8221;, &#8220;write&#8221; and &#8220;close&#8221; functions that worked on these devices. There were also higher-level &#8220;load&#8221; and &#8220;save&#8221; functions that could load and save arbitrary regions of memory: The first two bytes of the file would be the (little endian) start address of the memory block.</p>
<p>With no special knowledge of &#8220;block storage&#8221; devices like disk drives, BASIC 2.0, which was not only a programming laguage but basically the shell of Commodore computers, could not express commands like &#8220;format a disk&#8221;, &#8220;delete a file&#8221; or &#8220;show the directory&#8221;. All this functionality, as well as the file system implementation, was part of the firmware of the disk drives.</p>
<h3>Sending a Command</h3>
<p>Sending commands to the drive was done by using the &#8220;open&#8221; call with a &#8220;secondary address&#8221; of 15: The computer&#8217;s KERNAL just sent the file name and the secondary address over the IEC bus as if it were to open a file, but the floppy drive understood secondary address 15 as the command channel. So for example, deleting a file from BASIC looked like this:</p>
<pre>
OPEN 1,8,15,"S:FOO": CLOSE 1
</pre>
<p>&#8220;1&#8243; is the KERNAL&#8217;s file descriptor, &#8220;8&#8243; the device number and &#8220;15&#8243; the secondary address. Experts omitted the close, because it blocked on the completion of the operation.</p>
<h3>Getting Data Back</h3>
<p>While the &#8220;OPEN&#8221; line for disk commands was pretty verbose, it was still doable. Getting the error message of the last operation back was more tricky: It required a loop in BASIC that read bytes from channel 15 until EOF was reached.</p>
<p>Getting a directory listing would be in the same class of problem, since it requires the computer to send a command (and a file name mask) to the floppy and receive the data. Neither BASIC nor KERNAL knew how to do this, and since this was such a common operation, it wouldn&#8217;t have been possible to have the user type in a 4 line BASIC program just to dump the directory contents.</p>
<h3>The BASIC Program Hack</h3>
<p>Here comes the trick: If the program to load started with a &#8220;$&#8221; (followed by an optional mask), the floppy drive just returned the directory listing &#8211; formatted as a BASIC program. The user could then just &#8220;LOAD&#8221; the directory and &#8220;LIST&#8221; it if it were a BASIC program:</p>
<pre>
LOAD"$",8

SEARCHING FOR $
LOADING
READY.
LIST

0 "TEST DISK       " 23 2A
20   "FOO"               PRG
3    "BAR"               PRG
641 BLOCKS FREE.
</pre>
<p>In this example, &#8220;TEST DISK&#8221; is the disk name, &#8220;23&#8243; the disk ID and &#8220;2A&#8221; the filesystem format/version (always 2A on 1540/1541/1551/1570/1571 &#8211; but this was only a redundant copy of the version information which was never read and could be changed). There are two files, 20 and 3 blocks in size respecively (a block is a 256 byte allocation unit on disk &#8211; since blocks are stored as linked lists there are only 254 bytes of payload), and both are of the &#8220;PRG&#8221; type.</p>
<h3>Encoding of Commodore BASIC Programs</h3>
<p>The floppy was aware of the encoding that Commodore BASIC (a derivative of Microsoft BASIC for 6502) used and prepared the directory listing in that way. A BASIC program in memory is a linked list of lines. Every line starts with a 2-byte pointer to the next line. A 0-pointer marks the end of the program. The next two bytes are the line number, followed by the zero-terminated encoded line contents.</p>
<p>The LIST command decodes a BASIC program in memory by following the linked list from the start of BASIC RAM. It prints the line number, a space, and the line contents. These contents have BASIC keywords encoded as 1-byte tokens starting at 0&#215;80. Character below 0&#215;80 are printed verbatim. Here is what <tt>10 PRINT"HELLO WORLD!"</tt> would look like:</p>
<pre>
0801  0E 08    - next line starts at 0x080E
0803  0A 00    - line number 10
0805  99       - token for PRINT
0806  "HELLO!" - ASCII text of line
080D  00       - end of line
080E  00 00    - end of program
</pre>
<p>The example directory listing from above would be encoded by the floppy like this:</p>
<pre>
0801  21 08    - next line starts at 0x0821
0803  00 00    - line number 0
0805  '"TEST DISK       " 23 2A '
0820  00       - end of line
0821  21 08    - next line starts at 0x0821
0823  14 00    - line number 20
0825  '  "FOO"               PRG '
0840  00       - end of line
[...]
</pre>
<p>A couple of things are interesting here:</p>
<ul>
<li>The line with the disk name and the ID is actually printed in inverted letters, which is done by having the &#8220;revert&#8221; character code as the first character of the first line, i.e. the floppy makes the assumption that the computer understands this convention.</li>
<li>BASIC will print the file sizes as variable-with line numbers, so the floppy adds extra spaces to the beginning of the line contents to have all file names aligned.</li>
<li>The floppy needs to populate the next line pointers for the linked list.</li>
</ul>
<h3>The Link Pointer</h3>
<p>The obvious question here is: How can the floppy know where in the computer&#8217;s memory the BASIC program will live? The answer is: It doesn&#8217;t. The BASIC interpreter supports having its program anywhere in memory, and loading programs that were saved from other locations on memory &#8211; or possibly other Microsoft BASIC compatible computers with a different memory layout. The VIC-20 had BASIC RAM at 0&#215;0401, the C64 at 0&#215;0801 and the C128 at 0x1C01. Therefore, BASIC &#8220;rebinds&#8221; a program on load, searching for the zero-terminator of the lines and filling the (redundant) link pointers.</p>
<p>The floppy therefore only has to send non-zero values as the link pointers for BASIC to accept the directory listing as a program. In fact, a 1541 sends the directory with a 0&#215;0401-base, which would be valid on a VIC-20. The reason for this is that the 1541 is only a 1540 with minor timing fixes for C64 support, and the 1540 is the floppy drive that was designed for the VIC-20.</p>
<p>Therefore, if you do <tt>LOAD"$",8,1</tt> on a C64, the extra &#8220;,1&#8243; will be interpreted by the KERNAL LOAD code to load the file at its original address (as opposed to the beginning of BASIC RAM), and since there is screen RAM at 0&#215;0400 on the C64, garbage will appear on the screen, because the character encoding of screen ram is incompatible with BASIC character encoding.</p>
<h3>Directory Code in 61 Bytes</h3>
<p>There are two problems with this &#8220;directory listing is a BASIC program&#8221; hack: Listing the directory overwrites a BASIC program in RAM, and listing the directory from inside an application is non-trivial.</p>
<p>Therefore, many many implementations to show a directory listing exist on the C64 &#8211; and I want to present my own one here, which is, to my knowledge, the shortest existing (and maybe shorted possible?) version. It is based on a 70 byte version published in &#8220;64&#8242;er Magazin&#8221; some time in the 80s, and I managed to get it down to 61 bytes.</p>
<pre>
,C000:  A9 01     LDA #$01     ; filename length
,C002:  AA        TAX
,C003:  A0 E8     LDY #$E8     ; there is a "$" at $E801 in ROM
,C005:  20 BD FF  JSR $FFBD    ; set filename
,C008:  A9 60     LDA #$60
,C00A:  85 B9     STA $B9      ; set secondary address
,C00C:  20 D5 F3  JSR $F3D5    ; OPEN (IEC bus version)
,C00F:  20 19 F2  JSR $F219    ; set default input device
,C012:  A0 04     LDY #$04     ; skip 4 bytes (load address and link pointer)
,C014:  20 13 EE  JSR $EE13    ; read byte
,C017:  88        DEY
,C018:  D0 FA     BNE $C014    ; loop
,C01A:  A5 90     LDA $90
,C01C:  D0 19     BNE $C037    ; check end of file
,C01E:  20 13 EE  JSR $EE13    ; read byte (block count low)
,C021:  AA        TAX
,C022:  20 13 EE  JSR $EE13    ; read byte (block count high)
,C025:  20 CD BD  JSR $BDCD    ; print 16 bit integer
,C028:  20 13 EE  JSR $EE13    ; read character
,C02B:  20 D2 FF  JSR $FFD2    ; print character to stdout
,C02E:  D0 F8     BNE $C028    ; loop until zero
,C030:  20 D7 AA  JSR $AAD7    ; print carriage return character
,C033:  A0 02     LDY #$02
,C035:  D0 DD     BNE $C014    ; skip 2 bytes next time (link pointer)
,C037:  20 42 F6  JSR $F642    ; CLOSE
,C03A:  4C F3 F6  JMP $F6F3    ; reset default input device
</pre>
<p>(There is a similar implementation <a href="http://noname.c64.org/csdb/forums/?roomid=11&#038;topicid=17487">here</a>.)</p>
<p>There are two limitations of this code though: It omits the extra space between the block number and the filename, leading to a slightly different output, and it cannot be interrupted.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=273&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=273</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>The Infinite Loop Mystery</title>
		<link>http://www.pagetable.com/?p=267</link>
		<comments>http://www.pagetable.com/?p=267#comments</comments>
		<pubDate>Tue, 21 Jul 2009 04:08:41 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=267</guid>
		<description><![CDATA[Today&#8217;s puzzle is about some code behaving horribly wrong. Recently, I was working on some operating system project and hacking on the code to switch between privileged and non-privileged mode. I could switch modes successfully and intercept traps when in non-privileged mode. Then I wanted to check whether I could handle timer interrupts correctly, so [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s puzzle is about some code behaving horribly wrong.</p>
<p>Recently, I was working on some operating system project and hacking on the code to switch between privileged and non-privileged mode. I could switch modes successfully and intercept traps when in non-privileged mode.</p>
<p>Then I wanted to check whether I could handle timer interrupts correctly, so I added this to my non-privileged code, to give the timer interrupt a chance to fire:</p>
<pre>
    volatile int i;
    for (i=0; i&lt;10000; i++);
</pre>
<p>Timer interrupts were handled correctly and eventually returned to the non-privileged code &#8211; but the delay code turned into an infinite loop!</p>
<p>I changed to loop to count only to 10, and I changed it to count down instead of up, but the result remained the same. I looked at the generated assembly. It looked like this:</p>
<pre>
    movl    $10, 0xfc(%ebp)	// i = 10
    jmp     1f			// goto 1
2:
    movl    0xfc(%ebp), %eax	// %eax = i
    decl    %eax		// %eax--
    movl    %eax,0xfc(%ebp)	// i = %eax
1:
    movl    0xfc(%ebp), %eax	// %eax = i
    testl   %eax, %eax		// if (%eax > 0)
    jg      2b			// goto 2
</pre>
<p>It looked fine. On every timer interrupt, I dumped %eax, and it was stuck at 10. I debugged my pusha/popa code to save and restore registers between modes, and it was okay. I debugged my flag handing code, and flags were fine.</p>
<p>Then I replaced my C code with the generated assembly code and added instructions that copied the value of %eax before the &#8220;decl&#8221; into %ebx, and after the &#8220;decl&#8221; into %ecx and added a trap instruction right after that to have privileged mode print out the values of the three registers.</p>
<pre>
    movl    $10, 0xfc(%ebp)	// i = 10
    jmp     1f			// goto 1
2:
    movl    0xfc(%ebp), %eax	// %eax = i
<font color="red">    movl    %eax, %ebx          // value before</font>
    decl    %eax		// %eax--
<font color="red">    movl    %eax, %ecx          // value after</font>
<font color="red">    TRAP</font>
    movl    %eax,0xfc(%ebp)	// i = %eax
1:
    movl    0xfc(%ebp), %eax	// %eax = i
    testl   %eax, %eax		// if (%eax > 0)
    jg      2b			// goto 2
</pre>
<p>The result was %eax = %ebx = %ecx = 10. This is when I understood what was going on.</p>
<p>Please share your comments below. :-)</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=267&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=267</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>This is Copyright 1983 Microsoft &#8211; NOT!</title>
		<link>http://www.pagetable.com/?p=150</link>
		<comments>http://www.pagetable.com/?p=150#comments</comments>
		<pubDate>Tue, 14 Jul 2009 08:01:08 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=150</guid>
		<description><![CDATA[If you look at a hexdump of any version of the Logitech mouse driver for MS-DOS, you will see the following: *** This is Copyright 1983 Microsoft *** 000007c0 2a 2a 2a 20 &#124; *** &#124; 000007d0 54 68 69 73 20 69 73 20 43 6f 70 79 72 69 67 68 &#124;This is [...]]]></description>
			<content:encoded><![CDATA[<p>If you look at a hexdump of any version of the Logitech mouse driver for MS-DOS, you will see the following:</p>
<p><cite>*** This is Copyright 1983 Microsoft ***</cite></p>
<pre>
000007c0                                       2a 2a 2a 20  |            *** |
000007d0  54 68 69 73 20 69 73 20  43 6f 70 79 72 69 67 68  |This is Copyrigh|
000007e0  74 20 31 39 38 33 20 4d  69 63 72 6f 73 6f 66 74  |t 1983 Microsoft|
000007f0  20 2a 2a 2a                                       | ***            |
</pre>
<p>Microsoft introduced the mouse to MS-DOS, and they specified the mouse driver interface and implemented the first MS-DOS mouse driver. Did Logitech license their code? Or did they steal it? Let&#8217;s look closer:</p>
<p><cite>This is a LOGITECH mouse driver, but some software expect here the following string:*** This is Copyright 1983 Microsoft ***</cite></p>
<pre>
00000770                           54 68 69 73 20 69 73 20  |        This is |
00000780  61 20 4c 4f 47 49 54 45  43 48 20 6d 6f 75 73 65  |a LOGITECH mouse|
00000790  20 64 72 69 76 65 72 2c  20 62 75 74 20 73 6f 6d  | driver, but som|
000007a0  65 20 73 6f 66 74 77 61  72 65 20 65 78 70 65 63  |e software expec|
000007b0  74 20 68 65 72 65 20 74  68 65 20 66 6f 6c 6c 6f  |t here the follo|
000007c0  77 69 6e 67 20 73 74 72  69 6e 67 3a 2a 2a 2a 20  |wing string:*** |
000007d0  54 68 69 73 20 69 73 20  43 6f 70 79 72 69 67 68  |This is Copyrigh|
000007e0  74 20 31 39 38 33 20 4d  69 63 72 6f 73 6f 66 74  |t 1983 Microsoft|
000007f0  20 2a 2a 2a                                       | ***            |
</pre>
<p>This string is located directly before the INT 0&#215;33 API entry point, so it is easy to check for it. There&#8217;s a sucker born every minute, but this still makes you wonder what kind of programmer would really check for a string like this, even if some Microsoft API reference indeed suggested to do so. Maybe it was only Microsoft software to compare the string.</p>
<p>In either case, this is a very bad and unfair practice. If you define an interface, don&#8217;t add a call to ask for the version (or even the vendor!), but add feature bits instead, so that an alternative implementation can choose to be compatible with parts of it (or extend the interface independently). And if you are a developer that uses an interface, use feature bits if they are there, and resist the temptation to check for the vendor, even if the API documentation tells you to do so.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=150&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=150</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>The Giant Pile of Money in My Office</title>
		<link>http://www.pagetable.com/?p=149</link>
		<comments>http://www.pagetable.com/?p=149#comments</comments>
		<pubDate>Wed, 08 Jul 2009 05:39:24 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=149</guid>
		<description><![CDATA[Corporate security thought it wasn&#8217;t the best idea: (1:06 min, 176 KB)]]></description>
			<content:encoded><![CDATA[<p><img src="docs/giant_pile_of_money/giant_pile_of_money.jpg"></p>
<p>Corporate security thought it wasn&#8217;t the best idea:</p>
<p align="center"><a href="docs/giant_pile_of_money/giant_pile_of_money.mp3"><img src="docs/mp3.png"><br />(1:06 min, 176 KB)</a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=149&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=149</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Apple Copland Reference Documentation</title>
		<link>http://www.pagetable.com/?p=211</link>
		<comments>http://www.pagetable.com/?p=211#comments</comments>
		<pubDate>Wed, 01 Jul 2009 06:39:07 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[literature]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=211</guid>
		<description><![CDATA[The Copland project was Apple&#8217;s ill-fated attempt in the mid 1990s to replace the aging classic Mac OS with a more modern operating system that had a microkernel, virtual memory and preemptive multitasking. Information on Copland is scarce, therefore I have compiled 20 hard to find Copland reference documents, as well as the 359 page [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.pagetable.com/?p=52">Copland project</a> was Apple&#8217;s ill-fated attempt in the mid 1990s to replace the aging classic Mac OS with a more modern operating system that had a microkernel, virtual memory and preemptive multitasking. Information on Copland is scarce, therefore I have compiled 20 hard to find Copland reference documents, as well as the 359 page book &#8220;Mac OS 8 Revealed&#8221;.</p>
<p>Note that Copland was supposed to be the next major OS release after System 7, so the while the first two beta releases D7E1 and D9 were called &#8220;Copland&#8221;, the final beta D11E4 was called &#8220;Mac OS 8&#8243; everywhere. After the cancellation of the Copland project, Apple reused the term &#8220;Mac OS 8&#8243; for a System 7 update.</p>
<h3>Copland D9 (Copland Developer Release &#8211; Tools Edition)</h3>
<p><i>November 1995</i></p>
<table border="1">
<tr>
<td>
<p><b>An Introduction to Copland</b>. The Mac OS Foundation for the Next Generation of Personal Computers</p>
</td>
<td><a href="docs/copland_docs/D9/An Introduction to Copland_B.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Glossary of Copland Terminology</b>. This Acrobat file contains the document âGlossary of Copland Terminology,â which defines many of the terms used throughout Copland developer documentation. Note, however, that the terms defined in this glossary are preliminary and subject to change.</p>
</td>
<td><a href="docs/copland_docs/D9/Glossary of Copland Terminology.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>The Copland Toolbox</b>. This Acrobat file contains the two-chapter book <i>The Copland Toolbox</i>. The first chapter introduces the event-handling model and human interface elements supported by the Copland Toolbox, and it describes the programming concepts necessary to use the Toolbox in applications. This will help you plan frameworks and tools that take full advantage of Coplandâs Toolbox features. The second chapter compares the System 7 Toolbox with the equivalent Copland managers and capabilities, and this chapter includes information on backward compatibility with System 7 applications and requirements for Copland-savvy applications. This is especially useful for helping you adapt your existing System 7-based frameworks to work in Copland.</p>
</td>
<td><a href="docs/copland_docs/D9/The Copland Toolbox.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Software Extensibility</b>. This Acrobat file contains the document âSoftware Extensibility and the System Object Model (SOM),â which describes where and why Copland uses SOM classes, dynamically linked libraries, and other mechanisms to support extension and modification of system software, and how you can use these to add extensibility to your own software.</p>
</td>
<td><a href="docs/copland_docs/D9/Software Extensibility.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Intro to Kernel and OS Services</b>. This Acrobat file contains the document âIntroduction to Kernel and Operating System Services,â which provides conceptual information about how and when to use services provided by the microkernel and related portions of the Copland operating system. This document will help you plan frameworks and tools that take full advantage of Coplandâs operating-system features.</p>
</td>
<td><a href="docs/copland_docs/D9/Intro to Kernel and OS Services.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Microkernel White Paper</b>. Containing the document âMicrokernel White Paper,â this file gives a conceptual overview of the Copland microkernel. This document discusses tasks, hardware and software interrupts, and privileged software execution; it describes address space management, including such topics as areas and memory reservations; and it describes messaging, such as how to use message objects, how to send and receive them, and how reply or cancel them. This version of the âMicrokernel White Paperâ differs only slightly from that delivered at the 1995 Worldwide Developerâs Conference.</p>
</td>
<td><a href="docs/copland_docs/D9/Microkernel White Paper.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Patch Manager</b>. The document âPatch Managerâ contained in this Acrobat files describes the new Copland mechanism for patching the Mac OS. This will help you plan how to create patch-type system extensions for your development environment and to produce code that creates or uses extensions that patch Copland. The Patch Manager defines an application programming interface (API) that enables software to patch the system in a consistent, more easily supported manner. This is the only documentation provided for this release of Copland that describes an application programming interface. Note, however, that as with the rest of this release, all of the Patch Managerâs programming interfaces are subject to change.</p>
</td>
<td><a href="docs/copland_docs/D9/Patch Manager.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>I/O Architecture</b>. This Acrobat file contains the document âAbout the Copland I/O Architecture,â which provides an overview of the architecture and features of Coplandâs new I/O system. This document will help you with any driver development that you might be planning for Copland, and will help you design or adapt software that writes to or otherwise directly manipulates devices. This document is identical to the chapter supplied in the <i>Copland Technical Overview</i> delivered at the 1995 Worldwide Developerâs Conference.</p>
</td>
<td><a href="docs/copland_docs/D9/I_O Architecture.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>About the Copland file System</b>. This Acrobat file contains the document âAbout the Copland file System,â which introduces the features of the new file system available with Copland. It describes the various components of the file system, including the file Manager, the Navigation Services API, and the file systems API. This document also describes how to get your program ready to use the new file Manager. finally, the Documentation for MPW folder contains information describing the Macintosh Programmerâs Workshop.</p>
</td>
<td><a href="docs/copland_docs/D9/About the Copland File System.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p><b>Copland Desktop</b>. The Copland Desktop Picture is a very high quality version of the CD cover art.  To use this as your desktop picture, place it on your Copland Drive.  While running Copland, you can open the picture from the Appearance Control Panel.</p>
</td>
<td><a href="docs/copland_docs/D9/Copland Desktop.png"><img src="docs/copland_docs/D9/Copland Desktop (32x24).png" width="32" height="32"></a></td>
</tr>
</table>
<h3>Copland D11E4 (Mac OS 8 DDK 0.4)</h3>
<p><i>June 1996 (WWDC)</i></p>
<table border="1">
<tr>
<td>
<p>This <b>Inside Macintosh for Mac OS 8 Read Me</b> provides a road map to the chapters within this folder, provides information on viewing the Acrobat files contained within this folder, and lists the methods you can use to give us your feedback on the Inside Macintosh documentation.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Inside Mac for Mac OS 8 Read Me.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For an overview of new features supported by the Toolbox, such as human interface objects, panels, window groups, imaging objects, and themes, see the chapter &#8220;Introduction to the Mac OS 8 Toolbox&#8221; in <b>Human Interface Toolbox</b>. For reference information on human interface objects, see the chapter &#8220;HIObject Class Reference&#8221; in Human Interface Toolbox.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Human Interface Toolbox.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For an overview of how Apple events are used pervasively throughout Mac OS 8 by system services as well as other programs, see the chapters &#8220;Introduction to the Mac OS 8 Event Model&#8221; and &#8220;Event Model Reference&#8221; in <b>Apple Events in Mac OS 8</b>. For information on how Apple events are processed by the Toolbox, see &#8220;Toolbox Event Routing&#8221; and &#8220;Toolbox Events Reference&#8221; in Human Interface Toolbox.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Apple Events in Mac OS 8.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For information on the Mac OS 8 File Manager, Navigation Services, and other file services, as well as reference information on the Mac OS 8 File Manager, see <b>File Navigation and Access</b>.</p>
</td>
<td><a href="docs/copland_docs/D11E4/File Navigation&#038;Access.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For information on the extensive support for text handling that enables you to develop your application for a worldwide market, such as support for Unicode, locales, and the use of text objects, see &#8220;Introduction to Text Handling and Internationalization&#8221; in <b>Text Handling and Internationalization</b>.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Text Handling&#038;Internationalization.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For information on the use of the System Object Model (SOM) in Mac OS 8, see <b>Software Extensibility</b>.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Software Extensibility.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For information on creating resources that are new in Mac OS 8, see <b>ResEdit 3.0 User&#8217;s Guide</b>.</p>
</td>
<td><a href="docs/copland_docs/D11E4/ResEdit 3.0 User's Guide.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For an overview of the Mac OS 8 microkernel, including information on tasks, processes, scheduling, preemption, multithreading, allocation of memory, and other services, see the chapter &#8220;About Mac OS 8&#8243; in <b>Microkernel and Core System Services</b>. See subsequent chapters in Microkernel and Core System Services for reference information on many of these topics.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Microkernel&#038;Core Sys Services.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For information on the Mac OS 8 I/O architecture, including information on families, plug-ins, and I/O services, see &#8220;About the I/O Architecture&#8221; in <b>Modular I/O</b>. For information on families for specific hardware devices, see subsequent chapters in Modular I/O.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Modular I_O.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>For updated information on Open Transport, see <b>Open Transport</b>.</p>
</td>
<td><a href="docs/copland_docs/D11E4/Open Transport.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
<tr>
<td>
<p>Please note that all <b>presentations</b> in this folder were created using Aldus Persuasion; an application we have not included on the DDK. (Displays Presentation, Keyboard Family Presentation, Mac OS 8 I/O Overview, OT General Presentation, OT Serial Presentation)</p>
</td>
<td><a href="docs/copland_docs/D11E4/D11E4 Presentations.zip"><img src="docs/zip.png" width="32" height="32"></a></td>
</tr>
</table>
<h3>Tony Francis: Mac OS 8 Revealed</h3>
<p><i>July 1996</i></p>
<table border="1">
<tr>
<td>
<p>With the next release of the Macintosh operating system, Apple will provide a state-of=the-art platform for developers to create new software products. At the core of Mac as 8 is a redesigned operating system foundation based on microkernel technology that will dramatically increase user productivity.</p>
<p>Author Tony Francis worked closely with the Mac as 8 engineering team to provide the inside story of the design and development of this innovative technology. The book describes the technical geography of Mac as 8 and illustrates how the system&#8217;s user benefits can be implemented in software and hardware products.</p>
<p>Written for developers, system administrators, and information systems professionals, <b>Mac OS 8 Revealed</b> explains the key technologies of Mac as 8:</p>
<ul>
<li>How Mac as 8 exploits preemptive multitasking to perform many operations concurrently;</li>
<li>How the new memory protection model insulates the microkernel and other operating system services to provide system stability;</li>
<li>How to provide automatic, intelligent assistance to users;</li>
<li>How to allow the user to customize and scale the human interface.</li>
</ul>
<p>The accompanying CD-ROM contains an electronic version of the book with animated illustrations that demonstrate the capabilities of Mac as 8. Simply click on a screen shot marked with a film strip in the book and see how a new feature in the operating system works.</p>
<p><b>Tony Francis</b> has been with Apple for over 10 years as a lead writer on the Inside Macintosh team.</p>
<p>ISBN 0-201-47955-9</p>
</p>
</td>
<td><a href="docs/copland_docs/book/Mac OS 8 Revealed.pdf"><img src="docs/pdf.png" width="32" height="32"></a></td>
</tr>
</table>
<p><i>I publish these files for educational purposes, especially for all computer archeology enthusiasts like me. This data is copyrighted, but since the project has been canceled ~13 years ago, nobody should still care about it. If you disagree, contact me. Thanks to all the people who have worked on Copland and written these interesting documents!</i></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=211&amp;ts=1284078727" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=211</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Readable and Maintainable Bitfields in C</title>
		<link>http://www.pagetable.com/?p=250</link>
		<comments>http://www.pagetable.com/?p=250#comments</comments>
		<pubDate>Tue, 23 Jun 2009 08:01:46 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[puzzle]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=250</guid>
		<description><![CDATA[Bitfields are very common in low level C programming. You can use them for efficient storage of a data structure with lots of flags, or to pass a set of flags between functions. Let us look at the different ways of doing this. The straightforward way to deal with bitfields is to do the Boolean [...]]]></description>
			<content:encoded><![CDATA[<p>Bitfields are very common in low level C programming. You can use them for efficient storage of a data structure with lots of flags, or to pass a set of flags between functions. Let us look at the different ways of doing this.</p>
<p>The straightforward way to deal with bitfields is to do the Boolean logic by hand:</p>
<h3>Boolean Magic</h3>
<pre>
#define FLAG_USER   (1 << 0)
#define FLAG_ZERO   (1 << 1)
#define FLAG_FORCE  (1 << 2)
/* bits 3-30 reserved */
#define FLAG_COMPAT (1 << 31)

int
create_object(int flags)
{
        int is_compat = (flags &#038; FLAG_COMPAT);

        if (is_compat)
                flags &#038;= ~FLAGS_FORCE;

        if (flags &#038; FLAG_FORCE) {
                [...]
        }
        [...]
}

int
create_object_zero(int flags)
{
	create_object(flags | FLAGS_ZERO);
}

void
caller()
{
        create_object(FLAG_FORCE | FLAG_COMPAT);
}
</pre>
<p>You can see code like this everywhere, so most C programmers can probably read and understand this quite easily. But unfortunately, this method is very error-prone. Mixing up "&#038;" and "&#038;&#038;" and omitting the "~" when doing "&#038;=" are common oversights, and since the compiler only sees "int" types, this also doesn't give you any kind of type-safety.</p>
<h3>Bitfields</h3>
<p>Let us look at the same code using bitfields instead:</p>
<pre>
typedef unsigned int boolean_t;
#define FALSE 0
#define TRUE !FALSE
typedef union {
        struct {
                boolean_t user:1;
                boolean_t zero:1;
                boolean_t force:1;
                int :28;                /* unused */
                boolean_t compat:1;     /* bit 31 */
        };
        int raw;
} flags_t;

int
create_object(flags_t flags)
{
        boolean_t is_compat = flags.compat;

        if (is_compat)
                flags.force = FALSE;

        if (flags.force) {
                [...]
        }
        [...]
}

int
create_object_zero(flags_t flags)
{
	flags.zero = TRUE;
	create_object(flags);
}

void
caller()
{
        create_object((flags_t) { { .force = TRUE, .compat = TRUE } });
}
</pre>
<p>Flags can just be used like any variables. The compiler abstracts the Boolean logic away. The only downside is that the code with the static initializer requires some advanced syntax.</p>
<h3>Endianness</h3>
<p>Bitfields in C always start at bit 0. While this is the least significant bit (LSB) on Little Endian (bit 0 has a weight of 2^0), most compilers on Big Endian systems inconveniently consider the most significant bit (MSB) bit 0 (bit 0 has a weight of 2^31, 2^63 etc. depending on the word size), so in case your bitfield needs to be binary-compatible across machines with different endianness, you will need to define two versions of the bitfield.</p>
<h3>The Raw Bitfield</h3>
<p>Did you notice the "int raw" in the union? It lets us conveniently (and type-safely) export the raw bit value without having to use a cast.</p>
<pre>
	printf("raw flags: 0x%x\n", flags.raw);
</pre>
<p>We can use this to reconstruct the FLAG_* constants in the original example, in case some code needs it:</p>
<pre>
#define FLAG_USER   (((flags_t) { { .user   = TRUE } }).raw)
#define FLAG_ZERO   (((flags_t) { { .zero   = TRUE } }).raw)
#define FLAG_FORCE  (((flags_t) { { .force  = TRUE } }).raw)
#define FLAG_COMPAT (((flags_t) { { .compat = TRUE } }).raw)
</pre>
<p>This code constructs a temporary instance of the bitfield, sets one bit, and converts it into a raw integer - all at compile time.</p>
<h3>Bitfield Access from Assembly</h3>
<p>With the same trick, you can also access your bitfield from assembly, for example if the bitfield is part of the Thread Control Block in your operating system kernel, and the low level context switch code needs to access one of the bits. The "int raw" can be used to statically convert a flag into the corresponding raw mask:</p>
<pre>
typedef unsigned int boolean_t;

typedef union {
	struct {
		boolean_t bit0:1;
		boolean_t bit1:1;
		int :19;
		boolean_t bit31:1;
	};
	int raw;
} bitfield_t;

int test()
{
	int param = -1;
	int result;

	__asm__ volatile (
		"test    %2, %1    \n"
		"xor     %0, %0    \n"
		"setcc   %0        \n"
		: "=r" (result)
		: "r" (param),
		  "i" (((bitfield_t) { { .bit31 = TRUE } }).raw)
	);
	return result;
}
</pre>
<p>The corresponding x86 assembly code looks like this:</p>
<pre>
	.text
	.align	4,0x90
	.globl	_test
_test:
	pushl	%ebp
	movl	%esp, %ebp
	movl	$-1, %eax
	## InlineAsm Start
	test	$0x80000000, %eax
	xor	%eax, %eax
	setcc	%eax
	## InlineAsm End
	popl	%ebp
	ret

	.subsections_via_symbols
</pre>
<p>This works fine with LLVM, but unfortunately GCC (4.2.1) has problems detecting that the raw value is available at compile time, so the "i" has to be replaced with an "r": GCC will then pre-assign a register with the raw value instead of being able to use an immediate with the "test" instruction.</p>
<h3>How to <i>Not</i> Do It</h3>
<p>I have seen C++ code doing this:</p>
<pre>
enum {
	FLAG_USER,
	FLAG_ZERO,
	FLAG_FORCE,
	FLAG_COMPAT = 31
}

int
create_object(bitfield_t flags)
{
        bool is_compat = flags.is_set(FLAG_COMPAT);

        if (is_compat)
                flags -= FLAGS_FORCE;

        if (flags.is_set(FLAG_FORCE)) {
                [...]
        }
        [...]
}

int
create_object_zero(int flags)
{
	create_object(flags + FLAGS_ZERO);
}

void
caller()
{
        create_object(((bitfield_t)FLAG_FORCE) + FLAG_COMPAT);
}
</pre>
<p>This all looks quite weird. The constants are bit index values, and they are added and subtracted. The reason is C++ operator overloading:</p>
<pre>
class bitmask_t
{
    word_t      maskvalue;

public:
    [...]
    inline bitmask_t operator -= (int n)
        {
            maskvalue = maskvalue &#038; ~(1UL << n);
            return (bitmask_t) maskvalue;
        }
    [...]
}
</pre>
<p>This is horrible. The code that uses this class makes no sense unless you read and understand the implementation of the class. And you have to be very careful: While it is possible to "add" a flag to an existing bitfield, you cannot just add two flags - it would do the arithmetic and add the two values.</p>
<p>Mapping the setting and clearing of bits onto the addition and subtraction operators is clearly wrong in the first place: Flags in a bitfield are equivalent to elements in a set. Setting a flag is equivalent to the "union" operation, which even in Mathematics has its own symbol instead of overloading the "+" operator.</p>
<h3>Question</h3>
<p>If you compile code that does something like "((bitfield_t) { { .bit31 = TRUE } }).raw" with GCC in C++ mode, it fails. Why?</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=250&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=250</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>A Lot of Security</title>
		<link>http://www.pagetable.com/?p=259</link>
		<comments>http://www.pagetable.com/?p=259#comments</comments>
		<pubDate>Tue, 16 Jun 2009 08:01:31 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[puzzle]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=259</guid>
		<description><![CDATA[I happened to drive through Cupertino, CA, USA last Wednesday and ended up in this situation: Oh-oh, they got me. But they were not after me, they escorted two vans onto some company&#8217;s campus. Five police cars, two police motorcycles, and lots of people with suits and sunglasses. For some reason, this outfit doesn&#8217;t have [...]]]></description>
			<content:encoded><![CDATA[<p>I happened to drive through Cupertino, CA, USA last Wednesday and ended up in this situation:</p>
<p><a href="docs/a_lot_of_security/a_lot_of_security_1.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_1.jpg"></a></p>
<p>Oh-oh, they got me. But they were not after me, they escorted two vans onto some company&#8217;s campus.</p>
<p><a href="docs/a_lot_of_security/a_lot_of_security_2.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_2.jpg"></a><br /><a href="docs/a_lot_of_security/a_lot_of_security_3.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_3.jpg"></a></p>
<p>Five police cars, two police motorcycles, and lots of people with suits and sunglasses. For some reason, this outfit doesn&#8217;t have the same effect on me any more since &#8220;The Matrix&#8221;.</p>
<p><img src="docs/a_lot_of_security/a_lot_of_security_detail_1.jpg"><img src="docs/a_lot_of_security/a_lot_of_security_detail_2.jpg"><br /><img src="docs/a_lot_of_security/a_lot_of_security_detail_3.jpg"><img src="docs/a_lot_of_security/a_lot_of_security_detail_4.jpg"><br /><img src="docs/a_lot_of_security/a_lot_of_security_detail_5.jpg"></p>
<p>The people in the vans went into the building through a side door:</p>
<p><a href="docs/a_lot_of_security/a_lot_of_security_4.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_4.jpg"></a><br /><a href="docs/a_lot_of_security/a_lot_of_security_5.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_5.jpg"></a><br /><a href="docs/a_lot_of_security/a_lot_of_security_6.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_6.jpg"></a><br /><a href="docs/a_lot_of_security/a_lot_of_security_7.jpg"><img src="docs/a_lot_of_security/small_a_lot_of_security_7.jpg"></a></p>
<p>Here are some details:</p>
<p><img src="docs/a_lot_of_security/a_lot_of_security_detail_6.jpg"><br /><img src="docs/a_lot_of_security/a_lot_of_security_detail_7.jpg"><br /><img src="docs/a_lot_of_security/a_lot_of_security_detail_8.jpg"></p>
<p>A blonde woman in white, a woman with a red dress, a man in a brown uniform with a suitcase, and lots of more men in suits. The vans had license places from Maryland.</p>
<p>The question of today&#8217;s security puzzle is: Who is the very important person?</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=259&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=259</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Stamp Vending Machine DoS</title>
		<link>http://www.pagetable.com/?p=101</link>
		<comments>http://www.pagetable.com/?p=101#comments</comments>
		<pubDate>Tue, 09 Jun 2009 08:01:00 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=101</guid>
		<description><![CDATA[It makes sense for a stamp vending machine to have some limits and not print any amount of stamps or stamps of any value. The vending machines from the Deutsche Post are a little weird though: You can only buy stamps worth 100 EUR at a time. Makes sense. The maximum face value for a [...]]]></description>
			<content:encoded><![CDATA[<p>It makes sense for a stamp vending machine to have some limits and not print any amount of stamps or stamps of any value. The vending machines from the Deutsche Post are a little weird though:</p>
<p><img src="docs/stamps/stamps_max_total.jpg" width="440"><br />You can only buy stamps worth 100 EUR at a time. Makes sense.</p>
<p><img src="docs/stamps/stamps_max_face.jpg" width="440"><br />The maximum face value for a stamp is 36.75 EUR. Hmmm&#8230;</p>
<p><img src="docs/stamps/stamps_max_count.jpg" width="440"><br />You can buy up to 100 stamps at a time, and the minimum face value is 1 cent. The poor machine will print worthless stamps for five minutes. The obvious question now is: What is the minimum amount of money that I have to invest to make it run out of paper.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=101&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=101</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Feed in Rogue Signal Here</title>
		<link>http://www.pagetable.com/?p=135</link>
		<comments>http://www.pagetable.com/?p=135#comments</comments>
		<pubDate>Tue, 02 Jun 2009 08:01:53 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=135</guid>
		<description><![CDATA[Sometimes it makes sense to label a surveillance camera. But it rarely makes sense to label the cables that lead to a surveillance camera in a public area of Parking Garage A at the San Francisco airport. This just invites you to do the &#8220;Splice and Dice&#8221; attack:]]></description>
			<content:encoded><![CDATA[<p>Sometimes it makes sense to label a surveillance camera.</p>
<p><img width="440" height="330" src="docs/cctv/cctv1.jpg" border="1"></p>
<p>But it rarely makes sense to label the cables that lead to a surveillance camera in a public area of Parking Garage A at the San Francisco airport.</p>
<p><img width="440" height="587" src="docs/cctv/cctv2.jpg" border="1"></p>
<p>This just invites you to do the &#8220;<a href="http://tvtropes.org/pmwiki/pmwiki.php/Main/CameraSpoofing">Splice and Dice</a>&#8221; attack:</p>
<p><a href="http://en.wikipedia.org/wiki/The_Springfield_Files"><img width="220" height="165" src="docs/cctv/cctv3a.jpg" border="1"><img width="220" height="165" src="docs/cctv/cctv3b.jpg" border="1"><img width="220" height="165" src="docs/cctv/cctv3c.jpg" border="1"><img width="220" height="165" src="docs/cctv/cctv3d.jpg" border="1"></a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=135&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=135</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Apple Lisa Operating System Reference Manual (PDF, 1983)</title>
		<link>http://www.pagetable.com/?p=241</link>
		<comments>http://www.pagetable.com/?p=241#comments</comments>
		<pubDate>Wed, 27 May 2009 07:32:33 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[literature]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=241</guid>
		<description><![CDATA[The Apple Lisa from 1983 was the first consumer-class computer with a graphical user interface and significantly more advanced than the 1984 Macintosh, which had a similar UI, but a comparatively primitive underlying OS. Here, I present a searchable PDF of the rare &#8220;Operating System Reference Manual for the Lisa&#8221; (1983), as well as a [...]]]></description>
			<content:encoded><![CDATA[<p>The Apple Lisa from 1983 was the first consumer-class computer with a graphical user interface and significantly more advanced than the 1984 Macintosh, which had a similar UI, but a comparatively primitive underlying OS. Here, I present a searchable PDF of the rare &#8220;Operating System Reference Manual for the Lisa&#8221; (1983), as well as a quick overview of the OS and how it compares to UNIX.</p>
<p><center><a href="docs/lisa_os/Operating System Reference Manual for the Lisa (1983).pdf"><img src="docs/pdf.png" width="32" height="32"><br />&#8220;Operating System Reference Manual for the Lisa&#8221; (1983)</a><br />(PDF, 188 pages, 6.2 MB)</center></p>
<p>The OS Reference Manual is actually volume 3 of 3 of the Lisa Pascal documentation. As the last page states, the book was typeset on a Lisa and printed on a dot matrix printer.</p>
<p><center><img src="docs/lisa_os/lisa_dogfood.png"></center></p>
<p>I also converted the typewriter-written draft version from <a href="http://lisa.sunder.net/cgi-bin/bookview2.cgi?zoom=-2?image=0?book=21">lisa.sunder.net</a> into a searchable PDF:</p>
<p><center><a href="docs/lisa_os/Lisa Operating System Reference Manual (Draft March 1982).pdf"><img src="docs/pdf.png" width="32" height="32"><br />&#8220;Lisa Operating System Reference Manual&#8221; (Draft March 1982)</a><br />(PDF, 113 pages, 1.2 MB)</center></p>
<p>In its spirit, the Lisa Operating System resembles UNIX a lot, and its features and details were pretty much on par with UNIX systems from that time.</p>
<p><b>Scheduling</b>: Executable files are statically linked with the Pascal runtime, and they make syscalls into the kernel. The system manages processes (with a single thread of execution) with their own address spaces that are cooperatively scheduled (255 levels of priorities). A syscall or a code segment switch can yield the CPU. Processes are managed in a tree, and the death of a parent will kill its children.</p>
<p><b>Memory Management</b>: There is no paging, but segmented memory (up to 106 code segments and 16 data segments), and explicit swapping of code and data pages. It is possible to write protect data segments.</p>
<p><b>Inter-Process Communication</b>: Two processes can communicate through shared files on the filesystem, named pipes, event channels (blocking or callback messaging with typed data) and shared data segments. Exceptions are delivered as events.</p>
<p><b>Filesystem</b>: The filesystem supports 32 character filenames and allows all ASCII characters except for &#8220;-&#8221;, which is the path separator. A path can be up to 255 characters; absolute paths start with &#8220;-&#8221; (processes have a working directory). There are no enforced extensions, but the convention is to use extensions for file types. Volumes can be mounted and unmounted, and accessed at the top level by using their device name or their volume name, if they are mounted. The serial (RS232A/RS323B) and parallel (PARAPORT) ports, stdio (MAINCONSOLE) and /dev/null (BITBKT) are<br />
like character-devices and also accessible at the top level that also provide an ioctl-like interface (DEVICE_CONTROL).</p>
<p>File access goes through open/read/write/close. A file is associated with cdate, mdate, adate, a delete protection flag and an up to 128 character label. Apart from regular files, there are pipes, disk-mapped data segments and event channel files.</p>
<p>For safety, the on-disk data structures are very redundant. Every block contains context data like a size, name, filesize, forward/backward link, inode and position in file. Directories (catalogs) and the &#8220;medium descriptor data file&#8221; are managed just like regular files.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=241&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=241</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Tripos, the Roots of AmigaDOS</title>
		<link>http://www.pagetable.com/?p=193</link>
		<comments>http://www.pagetable.com/?p=193#comments</comments>
		<pubDate>Tue, 19 May 2009 11:31:46 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=193</guid>
		<description><![CDATA[The core of the Amiga Operating systems consists of the three major components Exec (scheduling, memory management, IPC), Intuition (GUI library) and AmigaDOS (process and file management). AmigaDOS is based on the Tripos operating system which Commodore bought because development of their own DOS subsystem failed to meet deadlines. In this article, I am presenting [...]]]></description>
			<content:encoded><![CDATA[<p>The core of the Amiga Operating systems consists of the three major components Exec (scheduling, memory management, IPC), Intuition (GUI library) and AmigaDOS (process and file management). AmigaDOS is based on the Tripos operating system which Commodore bought because development of their own DOS subsystem failed to meet deadlines. In this article, I am presenting searchable PDFs of the very rare Tripos manuals (638 pages) as well as the AmigaDOS manual (304 pages). Comparing the two documents will share some insight in the relationship between Tripos and Amiga OS.</p>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><a href="docs/amigados_tripos/tripos_manuals.pdf"><img src="docs/amigados_tripos/tripos_manuals.png"><br/>Tripos Manuals<br /></a>(PDF, 638 p., 20MB)</td>
<td><a href="docs/amigados_tripos/amigados_manual.pdf"><img src="docs/amigados_tripos/amigados_manual.jpg"><br/>The AmigaDOS Manual<br /></a>(PDF, 304 p., 14MB)</td>
</tr>
<table>
<p>These are the tables of contents of the two documents:</p>
<table border="1">
<tr>
<td bgcolor="#000000"><font color="#ffffff"><b>Introduction to Tripos</b></font></td>
<td bgcolor="#000000"><font color="#ffffff"><b>AmigaDOS User&#8217;s Manual</b></font></td>
</tr>
<tr>
<td bgcolor="#eeeeee">1. Simple Use of Tripos</td>
<td bgcolor="#eeeeee">1. Introducing AmigaDOS</td>
</tr>
<tr>
<td bgcolor="#ffdddd">2. Editing Files</td>
<td></td>
</tr>
<tr>
<td bgcolor="#ffdddd">3. Further Use of Tripos</td>
<td></td>
</tr>
<tr>
<td bgcolor="#000000"><font color="#ffffff"><b>Tripos User&#8217;s Reference Manual</b></font></td>
<td></td>
</tr>
<tr>
<td bgcolor="#eeeeee">1. Tripos Commands</td>
<td bgcolor="#eeeeee">2. AmigaDOS Commands</td>
</tr>
<tr>
<td bgcolor="#eeeeee">2. ED &#8211; The Screen Editor</td>
<td bgcolor="#eeeeee">3. ED &#8211; The Screen Editor</td>
</tr>
<tr>
<td bgcolor="#eeeeee">3. EDIT &#8211; The Line Editor</td>
<td bgcolor="#eeeeee">4. EDIT &#8211; The Line Editor</td>
</tr>
<tr>
<td bgcolor="#eeeeee"> Appendix A: Error Codes and Messages</td>
<td bgcolor="#eeeeee"> Appendix: Error Codes and Messages</td>
</tr>
<tr>
<td bgcolor="#000000"><font color="#ffffff"><b>Tripos Programmer&#8217;s Reference Manual</b></font></td>
<td bgcolor="#000000"><font color="#ffffff"><b>AmigaDOS Developer&#8217;s Manual</b></font></td>
</tr>
<tr>
<td bgcolor="#eeeeee">1. Introduction to Programming</td>
<td bgcolor="#eeeeee">1. Programming on the Amiga</td>
</tr>
<tr>
<td bgcolor="#ffdddd">2. Calling the Kernel</td>
<td></td>
</tr>
<tr>
<td bgcolor="#eeeeee">3. Calling the DOS</td>
<td bgcolor="#eeeeee">2. Calling AmigaDOS</td>
</tr>
<tr>
<td bgcolor="#eeeeee">4. The Macro Assembler</td>
<td bgcolor="#eeeeee">3. The Macro Assembler</td>
</tr>
<tr>
<td bgcolor="#eeeeee">5. The Linker</td>
<td bgcolor="#eeeeee">4. The Linker</td>
</tr>
<tr>
<td bgcolor="#ffdddd">6. The System Debugger &#8211; DEBUG</td>
<td></td>
</tr>
<tr>
<td bgcolor="#ffdddd">7. Full Screen Support</td>
<td></td>
</tr>
<tr>
<td bgcolor="#ffdddd">8. Floating Point</td>
<td></td>
</tr>
<tr>
<td></td>
<td bgcolor="#ddffdd"> Appendix: Console Input and Output on the Amiga</td>
</tr>
<tr>
<td bgcolor="#000000"><font color="#ffffff"><b>Tripos Technical Reference Manual</b></font></td>
<td bgcolor="#000000"><font color="#ffffff"><b>AmigaDOS Technical Reference Manual</b></font></td>
</tr>
<tr>
<td bgcolor="#eeeeee">1. The Filing System</td>
<td bgcolor="#eeeeee">1. The Filing System</td>
</tr>
<tr>
<td bgcolor="#eeeeee">2. Binary File Structure</td>
<td bgcolor="#eeeeee">2. Amiga Binary File Structure</td>
</tr>
<tr>
<td bgcolor="#eeeeee">3. Tripos Data Structures</td>
<td bgcolor="#eeeeee">3. AmigaDOS Data Structures</td>
</tr>
<tr>
<td bgcolor="#ffdddd">4. Installation</td>
<td></td>
</tr>
<tr>
<td></td>
<td bgcolor="#ddffdd">4. AmigaDOS Additional Information for the Advanced Developer
</td>
</tr>
</table>
<h3>The Original DOS Module of AmigaOS</h3>
<p>AmigaOS was architected in a very modular way. &#8220;Exec&#8221;, the operating system kernel, was responsible for tasks (and therefore scheduling), memory management and the messaging infrastructure. It knew nothing about filesystems or user I/O. The graphics library &#8220;Intuition&#8221; built on Exec, just like the DOS module, but they were independent of each other. But the <a href="http://www.thule.no/haynie/caos.html">DOS module <a href="http://www.amigahistory.co.uk/caos.html">fell behind schedule</a>, so Commodore <a href="http://web.archive.org/web/20030711160927/http://os.amiga.com/cam/index.php?i=5&#038;p=4">decided to license</a> &#8220;<a href="http://www.cl.cam.ac.uk/~mr10/Cintpos.html">Tripos</a>&#8220;.<br />
<h3>Tripos</h3>
<p>Tripos is, according to &#8220;Introduction to Tripos&#8221;, &#8220;<cite>a multi-processing operating system designed for 68000 computers. Although you can use it as a multi-user system, you normally run Tripos for a single user. The multi-processing facility lets many jobs take place simultaneously. You can also use the multi-processing facility to suspend one job while you run another.</cite>&#8220;</p>
<p>Tripos was very similar to the Amiga OS design and therefore fit well. Tripos consisted of a kernel, a DOS library and a collection of user mode tools. Since the &#8220;Exec&#8221; was already working well, and Intuition depended on it, there was no sense in replacing it with the Tripos kernel. Instead, only the DOS part of Tripos (including the tools) was integrated into AmigaOS.</p>
<p>So the DOS API, the command line interface with its commands, the executable format (&#8220;hunk&#8221;) as well as the <a href="http://www.pagetable.com/?p=34">original Amiga filesystem</a> were all basically identical to Tripos.</p>
<h3>Comparing the Manuals</h3>
<p>Commodore published a number of reference manuals about the Amiga operating system:</p>
<ul>
<li>AMIGA ROM Kernel Reference Manual: Exec</li>
<li>Amiga ROM Kernel Reference Manual: Libraries and Devices</li>
<li>Amiga ROM Kernel Reference Manual: Includes and Autodocs</li>
<li>Amiga Intuition Reference Manual</li>
<li>The AmigaDOS Manual</li>
</ul>
<p>While the former four books were all written from stratch describing new Amiga technology, the AmigaDOS Manual was basically just the Tripos manual set with &#8220;Tripos&#8221; replaced with &#8220;AmigaDOS&#8221; and all references to technologies that didn&#8217;t make it into the Amiga removed.</p>
<p>You can see from the tables of contents of the two books that The AmigaDOS User&#8217;s Manual omitted the chapters about the Tripos kernel (AmigaOS used &#8220;Exec&#8221;), the debugger (AmigaOS had &#8220;ROMWack&#8221;), full screen support (everything above simple character I/O was done by Intuition), floating point (Amiga OS contained Motorola&#8217;s &#8220;<a href="http://www.programmersheaven.com/download/3650/download.aspx">MC68343 FLOATING POINT FIRMWARE</a>&#8221; instead) and Installation.</p>
<p>What is interesting about the AmigaDOS Manual is that very limited adaption to the Amiga has been performed. The previously quoted definition of Tripos can be found in the AmigaDOS manual as well: &#8220;<cite>AmigaDOS a multi-processing operating system designed for 68000 computers. [...]</cite>&#8221; While this would be true for Amiga<b>OS</b>, Amiga<b>DOS</b> was only a library and in no way a &#8220;multi-processing operating system&#8221;.</p>
<p>There are not many real differences between the two documents: The AmigaDOS Manual replaced references to &#8220;screen&#8221; with &#8220;current window&#8221; and mentions the new logical devices &#8220;LIBS:&#8221;, &#8220;DEVS:&#8221; and &#8220;FONTS:&#8221; when talking about the filesystem layout. There are also some smaller differences on the command line: There is no MOUNT command (AmigaOS detects disks and automounts), the &#8220;C&#8221; command has been renamed to &#8220;EXECUTE&#8221; as well as the &#8220;PAR:&#8221; device to &#8220;PRT:&#8221;. The AmigaDOS Manual also contains a section about cross-development on a Sun or MS-DOS machine.</p>
<p><i>Now I am looking forward to your comments: Did you any other interesting differences? In what way were Exec and the Tripos kernel different? Any other input? Thanks!<i></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=193&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=193</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Reverse-Engineering DOS 1.0 &#8211; Part 2: IBMBIO.COM</title>
		<link>http://www.pagetable.com/?p=184</link>
		<comments>http://www.pagetable.com/?p=184#comments</comments>
		<pubDate>Tue, 12 May 2009 08:01:13 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=184</guid>
		<description><![CDATA[My last post was about the internals of the DOS 1.0 bootsector. This time, let&#8217;s look at the next stage of the DOS 1.0 boot process, the hardware abstraction library IBMBIO.COM. CP/M and DOS History Let us first look at the historical background: CP/M was an 8 bit operating system that existed for virtually every [...]]]></description>
			<content:encoded><![CDATA[<p>My last post was about the <a href="http://www.pagetable.com/?p=165">internals of the DOS 1.0 bootsector</a>. This time, let&#8217;s look at the next stage of the DOS 1.0 boot process, the hardware abstraction library IBMBIO.COM.</p>
<h3>CP/M and DOS History</h3>
<p>Let us first look at the historical background: CP/M was an 8 bit operating system that existed for virtually every computer with an 8080/Z80 CPU. It consisted of the three core components: <a href="http://www.seasip.demon.co.uk/Cpm/bios.html">BIOS</a>, BDOS and CCP. BIOS was the machine abstraction layer that allowed CP/M work on different platforms. BDOS was the platform agnostic core library code, and CCP the command line interpreter.</p>
<p><a href="http://www.86dos.org/">86-DOS</a> by Seattle Computer Products was a clone of CP/M intended for 8086 computers. It shared the architecture of CP/M, having a separate machine abstraction layer (&#8220;DOSIO&#8221;). When Microsoft bought 86-DOS and ported it to the upcoming IBM PC (model 5150), they kept this architecture, although there was no need to implement custom drivers, since the IBM PC had all its drivers in its &#8220;BIOS&#8221; firmware. But IBM&#8217;s BIOS did not have the same interface as 86-DOS DOSIO, so PC-DOS 1.0 included a very small DOSIO which would just sit on top of BIOS and using its driver library (and work around some bugs).</p>
<p>So DOS 1.0 for the IBM PC consisted of the three parts IBMBIO.COM (machine abstraction), IBMDOS.COM (DOS library) and COMMAND.COM (command line).</p>
<p>Microsoft soon started licensing MS-DOS to other computer manufacturers that wanted to make IBM PC compatibles. Back then, IBM PC compatible meant being able to run DOS applications and not necessarily sharing the whole system design with the IBM PC, so for MS-DOS to run on other 8086-based systems, it was enough to adapt the hardware abstraction layer to these machines, and therefore Microsoft provided the source code of this part of MS-DOS to hardware vendors. In MS-DOS, the system files are called IO.SYS and MSDOS.SYS.</p>
<p>But since MS-DOS only provided a rather narrow API that did not include, for example, access to bitmap graphics, soon many DOS programs accesses hardware directly, forcing clone makers to make their PC compatibles more and more similar to the IBM PC, eventually using the same support chips and a binary compatible firmware interface. The separation of the kernel in two parts was less and less necessary, so that starting with MS-DOS 5.0, Microsoft only provided a single version of IO.SYS, and in MS-DOS 7.0 (Windows 95), IO.SYS and MSDOS.SYS were merged into IO.SYS.</p>
<h3>IBMBIO</h3>
<p>On DOS 1.0, IBMBIO.COM provides the following library functions to DOS (names taken from 86-DOS DOSIO source):</p>
<table border="1">
<tr>
<td>STATUS</td>
<td>check for keypress</td>
</tr>
<tr>
<td>INP</td>
<td>get key from keyboard</td>
</tr>
<tr>
<td>OUTP</td>
<td>send character to screen</td>
</tr>
<tr>
<td>PRINT</td>
<td>send character to printer</td>
</tr>
<tr>
<td>AUXIN</td>
<td>get character from serial</td>
</tr>
<tr>
<td>AUXOUT</td>
<td>send character to serial</td>
</tr>
<tr>
<td>READ</td>
<td>read sector(s) from disk</td>
</tr>
<tr>
<td>WRITE</td>
<td>write sector(s) to disk</td>
</tr>
<tr>
<td>DSKCHG</td>
<td>check for disk change</td>
</tr>
</table>
<p>(READ and WRITE will be directly hooked up by DOS into the INT 0&#215;25/0&#215;26 direct disk I/O API later.)</p>
<p>In addition to this, IBMBIO is the next step in the boot process after the bootloader and responsible for</p>
<ul>
<li>initializing the serial and printer ports</li>
<li>building a list of floppy drives and its capabilities</li>
<li>setting up exception vectors (division by zero etc.)</li>
<li>call the IBMDOS init code (already in memory)</li>
<li>load and run COMMAND.COM</li>
</ul>
<p>Let us now look at the library calls it provides:</p>
<h3>Serial and Printer</h3>
<p>The code to talk to the serial and printer ports is rather straightforward. There is support for a single serial port and a single printer port. IBMBIO sets up the port to 2400 8N1 and has no function to change this setting. I/O will just be passed to the respective BIOS functions, but errors will be evaluated and error messages will be printed in the error case.</p>
<h3>Keyboard and Screen</h3>
<p>While printing a character just passes the character to BIOS, character input is quite interesting: When reading a character, BIOS returns the ASCII code as well as the raw keyboard scancode. For keys that have no ASCII equivalent like the function or cursor keys, this returns zero as the ASCII code. IBMBIO always returns the ASCII code, but for special keys, it returns two bytes: A zero, indicating that it is a special key, and the BIOS scancode. Therefore in case of a special key, it caches the scancode, returns the zero, and will return the scancode the next time a character is read.</p>
<p>The Control+C/Control+Break handler uses this infrastructure to inject the code &#8220;3&#8243; into the input stream.</p>
<h3>Disk I/O: Virtual Disks</h3>
<p>The library code for Disk I/O is the most interesting part, since it can simulate a virtual disk drive, and it works around two issues of the BIOS function.</p>
<p>DOS supports up to four disk drives, A:, B:, C: and D:, but in case there is only a single drive, it will present two drives to DOS. Since all disk access goes through the READ and WRITE functions of IBMBIO, it can compare the requested disk drive with the disk drive last used, and if it&#8217;s the other drive, it will print:</p>
<pre>Insert diskette for driveÂ A: and strike
any key when ready</pre>
<p>After pressing a key, the actual I/O access is performed. This way, DOS can be completely agnostic about whether there are two physical drives, or a physical and a virtual drive, and &#8220;COPY A:FOO B:BAR&#8221; will just work. Note that without this feature, it would be impossible to get data from one disk onto another with standard DOS tools.</p>
<h3>Disk I/O: Multiple Tracks</h3>
<p>The first IBM PC BIOS issue IBMBIO works around is the fact that the original version of BIOS did not support a read or write of sectors across multiple heads. A track always had 8 sectors, and if your read starting at sector 1 of a track, it is possible to read up to 8 sectors, but starting at sector 8, only one sector can be read &#8211; if you want to continue reading sectors from the next track, you have to call BIOS again explicitly. The IBMBIO driver therefore breaks up longer reads if they span tracks.</p>
<h3>Disk I/O: 8237 DMA Controller Bug</h3>
<p>The second problem is actually a design issue with the Intel 8237 DMA controller in the PC. Although the Intel 8088 CPU was internally 16 bits, had 16 bit registers and could support up to 1 MB of RAM, it was the low cost version that was meant to interface to 8 bit support chips. The 8237 is such a support chip intended for 8 bit systems, and therefore only supports 64 KB of memory. Since this would have meant that data from the disk drive can only be read into the lower 64 KB of the PC, IBM extended the DMA controller by adding an external latch per channel to it: You set up the lower 16 bits of the DMA address in the DMA controller, and the upper 4 bits (20 bits correspond to 1 MB) in an external latch, and the upper four address lines will be provided by the latch when the DMA controller accesses memory.</p>
<p>Unfortunately, the 8237 had no &#8220;carry out&#8221;, so if you set up a DMA to 0x0FFFF (latch: 0&#215;0, DMA controller: 0xFFFF), the address inside the DMA controller will wrap around to 0&#215;0000, but it will not update the upper four bits of the address in the latch. So DMA that spans a 64 KB boundary will end up at the wrong location.</p>
<p>The idea of a device driver is to abstract away details of a device and work around device bugs, but the BIOS in the first PC failed to work around this quirk in the DMA hardware. Therefore IBMBIO works around it by detecting I/O that spans a 64 KB boundary and performing it in a temporary buffer inside IBMBIO.</p>
<p>What is interesting about these workarounds is that DOS 1.0 was the default operating system for the disk-equipped version of the IBM PC, and IBM shipped it with its first machines, so it should have been possible to include these workarounds in BIOS already. In fact, later versions of BIOS did not have these issues any more, but DOS kept supporting the workarounds for a long time.</p>
<h3>Source</h3>
<p>Here is the assembly source of IBMBIO 1.0. It can be compiled with NASM and produces a binary which is not 100% identical, because of variations in the instruction encoding of different assemblers. The original assembler wasted a few bytes in the encoding, so NOPs have been added to keep the layout identical. The binary is only 1920 bytes. IBMDOS.COM is 6400 bytes, and I might be looking into that one in the future as well.</p>
<pre>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; DOS 1.0 IBMBIO.COM (disk image MD5 73c919cecadf002a7124b7e8bfe3b5ba)</font>
<font color="#0e0eff"><font color="#007400">; Â  <a href="http://www.pagetable.com/"><font color="#0e0eff">http://www.pagetable.com/</font></a></font></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">SECTOR_SIZE Â  Â  equ Â  Â  <font color="#1c00cf">0x0200</font>Â  Â  Â  Â  Â  <font color="#007400">; size of a sector</font></font>
<font color="#000000">DOS_SIZEÂ  Â  Â  Â  equ Â  Â  <font color="#1c00cf">10000</font> Â  Â  Â  Â  Â  <font color="#007400">; max size of IBMDOS.COM in bytes</font></font>
<font color="#007400"><font color="#000000">PAUSE_KEY Â  Â  Â  equ Â  Â  </font><font color="#1c00cf">0x7200</font><font color="#000000">Â  Â  Â  Â  Â  </font>; scancode + charcode of PAUSE key</font>
<font color="#007400"><font color="#000000">KEYBUF_NEXT Â  Â  equ Â  Â  </font><font color="#1c00cf">0x041A</font><font color="#000000">Â  Â  Â  Â  Â  </font>; next character in keyboard buffer</font>
<font color="#007400"><font color="#000000">KEYBUF_FREE Â  Â  equ Â  Â  </font><font color="#1c00cf">0x041C</font><font color="#000000">Â  Â  Â  Â  Â  </font>; next free slot in keyboard buffer</font>
<font color="#000000">KEYBUFÂ  Â  Â  Â  Â  equ Â  Â  <font color="#1c00cf">0x041E</font>Â  Â  Â  Â  Â  <font color="#007400">; keyboard buffer data</font></font>
<font color="#007400"><font color="#000000">LOGICAL_DRIVE Â  equ Â  Â  </font><font color="#1c00cf">0x0504</font><font color="#000000">Â  Â  Â  Â  Â  </font>; linear address of logical drive byte</font>
<font color="#000000">SEG_DOS_TEMPÂ  Â  equ Â  Â  <font color="#1c00cf">0xE0</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; segment in which DOS was loaded</font></font>
<font color="#000000">SEG_DOS Â  Â  Â  Â  equ Â  Â  <font color="#1c00cf">0xB1</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; segment in which DOS will run</font></font>
<font color="#000000">SEG_BIO Â  Â  Â  Â  equ Â  Â  <font color="#1c00cf">0x60</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; segment in which BIO is running</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  org <font color="#1c00cf">0x0000</font>Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; segment 0x0060</font></font>
<font color="#000000"></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  INITÂ  Â  Â  Â  Â  Â  <font color="#007400">; 0x0060:0x0000 entry point</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  STATUSÂ  Â  Â  Â  Â  <font color="#007400">; 0x0060:0x0003 check for keypress</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  INP Â  Â  Â  Â  Â  Â  <font color="#007400">; 0x0060:0x0006 get key from keyboard</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  OUTPÂ  Â  Â  Â  Â  Â  </font>; 0x0060:0x0009 send character to screen</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  PRINT Â  Â  Â  Â  Â  </font>; 0x0060:0x000C send character to printer</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  AUXIN Â  Â  Â  Â  Â  </font>; 0x0060:0x000F get character from serial</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  AUXOUTÂ  Â  Â  Â  Â  </font>; 0x0060:0x0012 send character to serial</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  READÂ  Â  Â  Â  Â  Â  </font>; 0x0060:0x0015 read sector(s) from disk (INT 0x25)</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  WRITE Â  Â  Â  Â  Â  </font>; 0x0060:0x0018 write sector(s) to diskÂ  (INT 0x26)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  DSKCHGÂ  Â  Â  Â  Â  <font color="#007400">; 0x0060:0x001B check for disk change</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw SEG_DOSÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; ???</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw TXT_VERSIONÂ  Â  Â  Â  Â  <font color="#007400">; ???</font></font>
<font color="#000000">TXT_VERSION Â  Â  db <font color="#1c00cf">'BIOS Version 1.00'</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">' '</font>+<font color="#1c00cf">0x80</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">'22-Jul-81'</font>,<font color="#1c00cf">0</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#1c00cf"><font color="#000000">ERR_PAPER Â  Â  Â  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Out of pape'<font color="#000000">,</font>'r'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#1c00cf"><font color="#000000">ERR_PRINTER Â  Â  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Printer faul'<font color="#000000">,</font>'t'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#1c00cf"><font color="#000000">ERR_AUX Â  Â  Â  Â  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Aux I/O erro'<font color="#000000">,</font>'r'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; check for keypress</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  ZÂ  = set if no character</font>
<font color="#007400">;Â  all other registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">STATUSÂ  Â  Â  Â  Â  mov Â  Â  al, [cs:next_char]<font color="#007400">; check for waiting character</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  al, al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  char_availÂ  Â  Â  <font color="#007400">; yes, return it</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  ax, dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x16</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; otherwise get key (don't clear)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  status_exit Â  Â  <font color="#007400">; no key</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  ax, PAUSE_KEY Â  <font color="#007400">; PAUSE key?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  status_exit</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, <font color="#1c00cf">0x10</font>Â  Â  Â  Â  <font color="#007400">; convert into Ctrl+P</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  al, al</font>
<font color="#000000"></font>
<font color="#000000">status_exit Â  Â  mov Â  Â  ah, dhÂ  Â  Â  Â  Â  <font color="#007400">; restore original AH</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">char_availÂ  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; Interrupt 0x1B handler: Control+Break handler</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">int_1BÂ  Â  Â  Â  Â  mov Â  Â  byte [cs:next_char], <font color="#1c00cf">3</font><font color="#007400">; put code for Ctrl+C</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  iretÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; into keyboard queue</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; Interrupt 0x00 handler: Division by Zero</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">int_00Â  Â  Â  Â  Â  sti</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, ERR_DIVIDE</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  print_string</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x23</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; exit program through Ctrl+C path</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; Interrupt 0x00 handler: Single Step</font>
<font color="#007400">; Interrupt 0x03 handler: Breakpoint</font>
<font color="#007400">; Interrupt 0x04 handler: Overflow</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">iret1 Â  Â  Â  Â  Â  iretÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; empty interrupt handler</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#1c00cf"><font color="#000000">ERR_DIVIDEÂ  Â  Â  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Divide overflo'<font color="#000000">,</font>'w'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; get key from keyboard</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  all other registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">again Â  Â  Â  Â  Â  xchgÂ  Â  ax, dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">INP Â  Â  Â  Â  Â  Â  mov Â  Â  al, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  al, [cs:next_char]<font color="#007400">; get and clear waiting character</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  al, al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  inp_exitÂ  Â  Â  Â  <font color="#007400">; there is no character waiting</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  ax, dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x16</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; then read character from keyboard</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  ax, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  again</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  ax, PAUSE_KEY</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  not_pause2</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, <font color="#1c00cf">0x10</font>Â  Â  Â  Â  <font color="#007400">; Ctrl+P</font></font>
<font color="#000000">not_pause2Â  Â  Â  cmp Â  Â  al, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  skip1 Â  Â  Â  Â  Â  <font color="#007400">; key with ASCII representation</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [cs:next_char], ah<font color="#007400">; return scancode next time</font></font>
<font color="#000000">skip1 Â  Â  Â  Â  Â  mov Â  Â  ah, dhÂ  Â  Â  Â  Â  <font color="#007400">; restore AH</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">inp_exitÂ  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; send character to screen</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  all registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">OUTPÂ  Â  Â  Â  Â  Â  pushÂ  Â  bp</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  si</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  di</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x0E</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  csÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; XXX makes no sense</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  bx, <font color="#1c00cf">7</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x10</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; print character</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  di</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  si</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  bp</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; send character to printer</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  all registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">PRINT Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  byte [cs:printer_retry], <font color="#1c00cf">0</font></font>
<font color="#000000">printer_again Â  mov Â  Â  dx, <font color="#1c00cf">0</font> Â  Â  Â  Â  Â  <font color="#007400">; printer port #0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x17</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; send character to printer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, ERR_PAPER</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  testÂ  Â  ah, <font color="#1c00cf">0x20</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  printer_error Â  <font color="#007400">; out of paper error</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, ERR_PRINTER</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  testÂ  Â  ah, <font color="#1c00cf">5</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  pop_dx_ax_retfÂ  <font color="#007400">; no timeout error, return</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  byte [cs:printer_retry], <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  printer_again Â  <font color="#007400">; on a timeout, try twice</font></font>
<font color="#000000">printer_error Â  callÂ  Â  print_string</font>
<font color="#000000">pop_dx_ax_retfÂ  pop Â  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; print zero-terminated string at DS:DX</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">print_stringÂ  Â  xchgÂ  Â  si, dx</font>
<font color="#000000">prints1 Â  Â  Â  Â  cs lodsb</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  and Â  Â  al, <font color="#1c00cf">0x7F</font>Â  Â  Â  Â  <font color="#007400">; clear bit 7 (XXX why?)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  prints2 Â  Â  Â  Â  <font color="#007400">; zero-terminated</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  SEG_BIO:OUTPÂ  Â  <font color="#007400">; print character</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  prints1 Â  Â  Â  Â  <font color="#007400">; loop</font></font>
<font color="#000000">prints2 Â  Â  Â  Â  xchgÂ  Â  si, dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retn</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; get character from serial</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  all other registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">AUXIN Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, <font color="#1c00cf">0</font> Â  Â  Â  Â  Â  <font color="#007400">; serial port #0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x14</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; get character from serial port</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, ERR_AUX</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  testÂ  Â  ah, <font color="#1c00cf">0x0E</font>Â  Â  Â  Â  <font color="#007400">; framing, parity or overrun?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  aux_noerr Â  Â  Â  <font color="#007400">; no error</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  print_string</font>
<font color="#000000">aux_noerr Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, dhÂ  Â  Â  Â  Â  <font color="#007400">; restore AH</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; send character to serial</font>
<font color="#007400">;Â  AL = character</font>
<font color="#007400">;Â  all registers preserved</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">AUXOUTÂ  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x14</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; send character to serial port</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  testÂ  Â  ah, <font color="#1c00cf">0x80</font>Â  Â  Â  Â  <font color="#007400">; timeout error?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  pop_dx_ax_retfÂ  <font color="#007400">; no all fine</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, ERR_AUX</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  printer_error</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; check for disk change</font>
<font color="#007400">;Â  AH = flag (1=changed)</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">DSKCHGÂ  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0</font> Â  Â  Â  Â  Â  <font color="#007400">; the IBM PC can't detect disk change</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#000000">temp_sector:</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; entry point from boot sector</font>
<font color="#007400">;Â  assumes DX = 0</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">INITÂ  Â  Â  Â  Â  Â  cli</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ss, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  sp, temp_sector_end<font color="#007400">; set stack used during init</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sti</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  ah, ah</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x13</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; reset disk 0 (DX = 0)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, <font color="#1c00cf">0xA3</font>Â  Â  Â  Â  <font color="#007400">; 2400 8N1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x14</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; initialize serial port</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x17</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; initialize printer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x11</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; get system info</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  and Â  Â  ax, </font><font color="#1c00cf">0xC0</font><font color="#000000">Â  Â  Â  Â  </font>; number of floppies in bits 6 and 7</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, <font color="#1c00cf">5</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shr Â  Â  ax, clÂ  Â  Â  Â  Â  <font color="#007400">; (floppies-1) * 2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  ax, <font color="#1c00cf">2</font> Â  Â  Â  Â  Â  <font color="#007400">; floppies * 2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  and Â  Â  ax, <font color="#1c00cf">6</font> Â  Â  Â  Â  Â  <font color="#007400">; will become 0 for 4 floppies</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  four_floppies Â  </font>; 4 floppies (num_floppies pre-assigned with 4)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  al, <font color="#1c00cf">2</font> Â  Â  Â  Â  Â  <font color="#007400">; one floppy?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  multi_floppyÂ  Â  <font color="#007400">; no</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  ax, </font><font color="#1c00cf">1</font><font color="#000000"> Â  Â  Â  Â  Â  </font>; pretend we have two, we'll emulate one</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  byte [single_floppy], <font color="#1c00cf">1</font></font>
<font color="#000000">multi_floppyÂ  Â  mov Â  Â  bx, floppy_list</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  bx, axÂ  Â  Â  Â  Â  <font color="#007400">; + floppies * 2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [bx], <font color="#1c00cf">0</font>Â  Â  <font color="#007400">; terminate list with 2 zero words</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [bx+<font color="#1c00cf">2</font>], <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  nop Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; XXX original assembler wasted a byte</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shr Â  Â  ax, <font color="#1c00cf">1</font> Â  Â  Â  Â  Â  <font color="#007400">; =floppies</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [num_floppies], al</font>
<font color="#000000">four_floppies Â  pushÂ  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, axÂ  Â  Â  Â  Â  <font color="#007400">; DS := 0x0000</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, SEG_BIO Â  Â  <font color="#007400">; target segment for interrupt vectors</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x6E</font>], axÂ  Â  Â  <font color="#007400">; set INT 1Bh segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [<font color="#1c00cf">0x6C</font>], int_1B<font color="#007400">; set INT 1Bh offset</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [<font color="#1c00cf">0x00</font>], int_00<font color="#007400">; set INT 00h offset</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x02</font>], axÂ  Â  Â  <font color="#007400">; set INT 00h segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  bx, iret1 Â  Â  Â  <font color="#007400">; set INT 00h offset</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x04</font>], bxÂ  Â  Â  <font color="#007400">; set INT 01h offset (empty)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x06</font>], axÂ  Â  Â  <font color="#007400">; set INT 01h segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x0C</font>], bxÂ  Â  Â  <font color="#007400">; set INT 03h offset (empty)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x0E</font>], axÂ  Â  Â  <font color="#007400">; set INT 03h segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x10</font>], bxÂ  Â  Â  <font color="#007400">; set INT 04h offset (empty)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [<font color="#1c00cf">0x12</font>], axÂ  Â  Â  <font color="#007400">; set INT 04h segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, <font color="#1c00cf">0x50</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, axÂ  Â  Â  Â  Â  <font color="#007400">; DS := 0x0050</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [</font><font color="#1c00cf">0x0</font><font color="#000000">], </font><font color="#1c00cf">0</font><font color="#000000"> Â  </font>; clear 0x0500 in DOS Comm. Area (???)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, SEG_DOS Â  Â  <font color="#007400">; target segment for IBMDOS.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  es, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, DOS_SIZE/<font color="#1c00cf">2</font>Â  <font color="#007400">; size/2 of IBMDOS.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cld</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, SEG_DOS_TEMP<font color="#007400">; source segment of IBMDOS.COM</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, axÂ  Â  Â  Â  Â  </font>; the booloader read whole sectors and puts</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  di, diÂ  Â  Â  Â  Â  </font>; the IBMDOS.COM image right after this;</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  si, diÂ  Â  Â  Â  Â  <font color="#007400">; so move it down a little</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  rep movsw Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; copy 10 000 bytes from 0xE00 to 0xB10</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  si, num_floppies<font color="#007400">; pass in pointer to structure</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  SEG_DOS:</font><font color="#1c00cf">0</font><font color="#000000"> Â  Â  Â  </font>; init DOS (returns DS = memory for COMMAND.COM)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sti</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, <font color="#1c00cf">0x0100</font>Â  Â  Â  <font color="#007400">; 0x0100 in COMMAND.COM segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x1A</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x21</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; set disk transfer area address</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, [<font color="#1c00cf">0x06</font>]Â  Â  Â  <font color="#007400">; remaining memory size</font></font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  cx, </font><font color="#1c00cf">0x0100</font><font color="#000000">Â  Â  Â  </font>; - Program Segment Prefix = bytes to read</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  bx, ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, FCB_command_com<font color="#007400">; File Control Block</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x0F</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x21</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; DOS: open COMMAND.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  al, al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  error_command Â  <font color="#007400">; error opening COMMAND.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [FCB_command_com+<font color="#1c00cf">0x21</font>], <font color="#1c00cf">0</font><font color="#007400">; random record field</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [FCB_command_com+<font color="#1c00cf">0x23</font>], <font color="#1c00cf">0</font><font color="#007400">;Â  := 0x00000000</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  word [FCB_command_com+<font color="#1c00cf">0x0E</font>], <font color="#1c00cf">1</font><font color="#007400">; record length = 1 byte</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x27</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x21</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; DOS: read</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jcxzÂ  Â  error_command Â  <font color="#007400">; read 0 bytes -&gt; error</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  al, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  error_command Â  <font color="#007400">; end of file not reached -&gt; error</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  es, bxÂ  Â  Â  Â  Â  <font color="#007400">; DS := ES := SS := COMMAND.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ss, bx</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  sp, </font><font color="#1c00cf">0x40</font><font color="#000000">Â  Â  Â  Â  </font>; 64 byte stack in PSP (XXX interrupts are on!)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  ax, ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  axÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; push return address 0x0000 (int 0x20)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, [<font color="#1c00cf">0x80</font>]Â  Â  Â  <font color="#007400">; get new DTA address</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x1A</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x21</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; set disk transfer area address</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  bxÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; segment of COMMAND.COM</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, <font color="#1c00cf">0x0100</font>Â  Â  Â  <font color="#007400">; offset of COMMAND.COM entry</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retfÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; run COMMAND.COM</font></font>
<font color="#000000"></font>
<font color="#000000">error_command:Â  mov Â  Â  dx, ERR_COMMANDCOM <font color="#007400">; "\r\nBad or missing Command Interprete"</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  print_string</font>
<font color="#000000">haltÂ  Â  Â  Â  Â  Â  jpÂ  Â  Â  haltÂ  Â  <font color="#007400">; XXX jp instead of jmp</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">FCB_command_com db <font color="#1c00cf">1</font>, <font color="#1c00cf">'COMMAND CO'</font>,<font color="#1c00cf">'M'</font>+<font color="#1c00cf">0x80</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  times <font color="#1c00cf">19</font>h db <font color="#1c00cf">0</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#1c00cf"><font color="#000000">ERR_COMMANDCOMÂ  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Bad or missing Command Interprete'<font color="#000000">,</font>'r'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#007400">; this is passed to IBMDOS.COM</font>
<font color="#007400"><font color="#000000">num_floppiesÂ  Â  db </font><font color="#1c00cf">4</font><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  </font>; if there's 1 physical drive, this says 2</font>
<font color="#007400"><font color="#000000">floppy_list Â  Â  dw parameters Â  Â  Â  Â  Â  </font>; point to params for every floppy installed; 0-terminated</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw parameters</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw parameters</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw parameters</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw <font color="#1c00cf">0</font>,<font color="#1c00cf">0</font></font>
<font color="#000000"></font>
<font color="#000000">parametersÂ  Â  Â  dw SECTOR_SIZE</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">1</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; will be decremented by 1, then used</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw <font color="#1c00cf">0x0040</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dw <font color="#1c00cf">320</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; number of total sectors</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  times <font color="#1c00cf">512</font>-($-temp_sector) db <font color="#1c00cf">0</font></font>
<font color="#000000">temp_sector_end:</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">printer_retry Â  db <font color="#1c00cf">0</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; count for printer retries</font></font>
<font color="#000000">next_char Â  Â  Â  db <font color="#1c00cf">0</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; extra character in keyboard queue</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">0</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; XXX unused</font></font>
<font color="#007400"><font color="#000000">single_floppy Â  db </font><font color="#1c00cf">0</font><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  </font>; true if we emulate a second logical floppy</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; READÂ  - read sector(s) from disk</font>
<font color="#007400">; WRITE - write sector(s) to disk</font>
<font color="#007400">;Â  al Â  Â  drive number (0-3)</font>
<font color="#007400">;Â  ds:bxÂ  buffer</font>
<font color="#007400">;Â  cx Â  Â  count</font>
<font color="#007400">;Â  dx Â  Â  logical block number</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">READÂ  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">2</font> Â  Â  Â  Â  Â  <font color="#007400">; BIOS code "read"</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  short read_write</font>
<font color="#000000">WRITE Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">3</font> Â  Â  Â  Â  Â  <font color="#007400">; BIOS code "write"</font></font>
<font color="#000000">read_writeÂ  Â  Â  pushÂ  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  esÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; ES := DS</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dsÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; DS := CS</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [temp_sp], sp Â  <font color="#007400">; save sp for function abort</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [int_13_cmd], ah<font color="#007400">; save whether it was read or write</font></font>
<font color="#007400">; logic to emulate a "logical" drive B: by prompting the user to change disk</font>
<font color="#007400">; when the currently used drive is changed</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  byte [single_floppy], <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jnz Â  Â  multi_drive Â  Â  <font color="#007400">; more than one drive</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  si, si</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, siÂ  Â  Â  Â  Â  <font color="#007400">; DS := 0x0000</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  ah, [LOGICAL_DRIVE]<font color="#007400">; current logical drive</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  al, ah</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  drive_unchanged</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dxÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; save block number</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  al, <font color="#1c00cf">'A'</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [TXT_DRIVE], al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dx, TXT_INSERTDISK</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  print_stringÂ  Â  <font color="#007400">; prompt for disk change</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xor Â  Â  bp, bp</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ds, bp</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  byte [KEYBUF_NEXT], KEYBUF &amp; <font color="#1c00cf">0xFF</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  byte [KEYBUF_FREE], KEYBUF &amp; <font color="#1c00cf">0xFF</font><font color="#007400">; clear keyboard buffer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x16</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; wait for any key</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  dxÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; block number</font></font>
<font color="#007400"><font color="#000000">drive_unchanged mov Â  Â  al, </font><font color="#1c00cf">0</font><font color="#000000"> Â  Â  Â  Â  Â  </font>; for both logical A: or B: use drive A:</font>
<font color="#000000">multi_drive Â  Â  xchgÂ  Â  ax, dx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dh, <font color="#1c00cf">8</font> Â  Â  Â  Â  Â  <font color="#007400">; convert LBA to CHS</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  div Â  Â  dhÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; al = track (starts at 0)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  inc Â  Â  ahÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; ah = sector (starts at 1)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  al, ahÂ  Â  Â  Â  Â  <font color="#007400">; track and sector</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  ax, cxÂ  Â  Â  Â  Â  <font color="#007400">; cx = t/s, ax = count</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  [num_sectors], ax<font color="#007400">; count</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  dh, <font color="#1c00cf">0</font></font>
<font color="#007400">; work around DMA hardware bug in case I/O spans a 64 KB boundary</font>
<font color="#007400">; by using a temporary buffer</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  di, esÂ  Â  Â  Â  Â  <font color="#007400">; destination segment</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  di, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  di, <font color="#1c00cf">1</font> Â  Â  Â  Â  Â  <font color="#007400">; make es:bx a linear address</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  di, <font color="#1c00cf">1</font> Â  Â  Â  Â  Â  <font color="#007400">; (discard upper bits)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  di, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  di, bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  di, SECTOR_SIZE-<font color="#1c00cf">1</font><font color="#007400">; last byte of sector (linear)</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  across_64kÂ  Â  Â  <font color="#007400">; sector overflows it</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  xchgÂ  Â  bx, diÂ  Â  Â  Â  Â  <font color="#007400">; bx = last byte, di = buffer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shr Â  Â  bh, <font color="#1c00cf">1</font> Â  Â  Â  Â  Â  <font color="#007400">; sector index in memory</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0x80</font>Â  Â  Â  Â  <font color="#007400">; 0x80 sectors fit into 64 KB</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  ah, bhÂ  Â  Â  Â  Â  <font color="#007400">; sectors until 64 KB boundary</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  bx, diÂ  Â  Â  Â  Â  <font color="#007400">; bx = buffer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  ah, alÂ  Â  Â  Â  Â  <font color="#007400">; compare to number of sectors</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jbe Â  Â  skip2 Â  Â  Â  Â  Â  <font color="#007400">; they fit into 64 KB, cap num</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, alÂ  Â  Â  Â  Â  <font color="#007400">; don't cap number of sectors</font></font>
<font color="#000000">skip2 Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, ahÂ  Â  Â  Â  Â  <font color="#007400">; al = count</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  rw_tracks</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  al, ahÂ  Â  Â  Â  Â  <font color="#007400">; requested = done?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  rw_done Â  Â  Â  Â  <font color="#007400">; yes, exit</font></font>
<font color="#000000">across_64kÂ  Â  Â  dec Â  Â  alÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; one sector less</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cld</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  esÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; save data pointer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  byte [int_13_cmd], <font color="#1c00cf">2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  across_64k_read <font color="#007400">; write case follows</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  si, bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, SECTOR_SIZE/<font color="#1c00cf">2</font><font color="#007400">; copy first sector</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  di, temp_sector</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  bx, di</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  rep movsw Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; copy into IBMBIO local data</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  cx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  rw_one_sector Â  <font color="#007400">; write last sector</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  short across_64k_end</font>
<font color="#000000">across_64k_read mov Â  Â  bx, temp_sector</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  rw_one_sector Â  <font color="#007400">; read last sector into temp buffer</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  si, bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  di, bx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cx</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, SECTOR_SIZE/<font color="#1c00cf">2</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  rep movsw Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; copy out</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  cx</font>
<font color="#000000">across_64k_endÂ  add Â  Â  bh, <font color="#1c00cf">2</font> Â  Â  Â  Â  Â  <font color="#007400">; continue 0x0200 after that</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  rw_tracks</font>
<font color="#000000">rw_done Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  clc Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; success</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#007400">; read/write an arbirtary number of sectors</font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000">rw_tracks Â  Â  Â  orÂ  Â  Â  al, al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  ret2Â  Â  Â  Â  Â  Â  <font color="#007400">; nothing to read</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">9</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  ah, cl</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  ah, alÂ  Â  Â  Â  Â  <font color="#007400">; more sectors than left in track?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jbe Â  Â  skip3 Â  Â  Â  Â  Â  <font color="#007400">; no</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, alÂ  Â  Â  Â  Â  <font color="#007400">; otherwise, read up to end of track</font></font>
<font color="#000000">skip3 Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, ah</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  near rw_sectors <font color="#007400">; reads/writes up to 8 sectors</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  al, ahÂ  Â  Â  Â  Â  <font color="#007400">; decrease sectors to read</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  shl Â  Â  ah, <font color="#1c00cf">1</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  bh, ahÂ  Â  Â  Â  Â  <font color="#007400">; advance pointer by sectors * 0x0200</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  rw_tracks Â  Â  Â  <font color="#007400">; continue</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">int_13_errÂ  Â  Â  xchgÂ  Â  ax, di</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x13</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; disk reset</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  dec Â  Â  si</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  translate Â  Â  Â  <font color="#007400">; retries exhausted</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, di</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  ah, </font><font color="#1c00cf">0x80</font><font color="#000000">Â  Â  Â  Â  </font>; in the "timeout (not ready)" case,</font>
<font color="#007400"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  translate Â  Â  Â  </font>; we don't retry (this would take forever)</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jmp Â  Â  short retry</font>
<font color="#000000">translate Â  Â  Â  pushÂ  Â  cs</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ax, di</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, ahÂ  Â  Â  Â  Â  <font color="#007400">; status</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, <font color="#1c00cf">0x0A</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  di, conv_status</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  repne scasb</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  al, [di+<font color="#1c00cf">9</font>]</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  nop Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; XXX original assembler wasted a byte</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cx, [num_sectors]</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  sp, [temp_sp] Â  <font color="#007400">; clean up stack</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ds</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  es</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  stc Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color="#007400">; error</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  retf</font>
<font color="#000000"></font>
<font color="#000000">rw_one_sector Â  mov Â  Â  al, <font color="#1c00cf">1</font></font>
<font color="#000000"></font>
<font color="#007400">; reads/writes one or more sectors that are on the same track</font>
<font color="#000000">rw_sectorsÂ  Â  Â  mov Â  Â  si, <font color="#1c00cf">5</font> Â  Â  Â  Â  Â  <font color="#007400">; number of retries</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  ah, [int_13_cmd]</font>
<font color="#000000">retry Â  Â  Â  Â  Â  pushÂ  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  int Â  Â  <font color="#1c00cf">0x13</font>Â  Â  Â  Â  Â  Â  <font color="#007400">; perform the read/write</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  int_13_err</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  pop Â  Â  ax</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  sub Â  Â  [num_sectors], al</font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  add Â  Â  cl, alÂ  Â  Â  Â  Â  <font color="#007400">; calculate next sector number</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  cmp Â  Â  cl, <font color="#1c00cf">8</font> Â  Â  Â  Â  Â  <font color="#007400">; exceeds track?</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  jbe Â  Â  ret2Â  Â  Â  Â  Â  Â  <font color="#007400">; no</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  inc Â  Â  chÂ  Â  Â  Â  Â  Â  Â  <font color="#007400">; next track</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  mov Â  Â  cl, <font color="#1c00cf">1</font> Â  Â  Â  Â  Â  <font color="#007400">; sector 1</font></font>
<font color="#000000">ret2Â  Â  Â  Â  Â  Â  retn</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#1c00cf"><font color="#000000">TXT_INSERTDISKÂ  db </font>13<font color="#000000">,</font>10<font color="#000000">,</font>'Insert diskette for drive'<font color="#000000">,</font>' '<font color="#000000">+</font>0x80</font>
<font color="#1c00cf"><font color="#000000">TXT_DRIVE Â  Â  Â  db </font>'A: and strik'<font color="#000000">,</font>'e'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10</font>
<font color="#1c00cf"><font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db </font>'any key when read'<font color="#000000">,</font>'y'<font color="#000000">+</font>0x80<font color="#000000">,</font>13<font color="#000000">,</font>10<font color="#000000">,</font>10<font color="#000000">,</font>0</font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">conv_status Â  Â  db <font color="#1c00cf">0x80</font>,<font color="#1c00cf">0x40</font>,<font color="#1c00cf">0x20</font>,<font color="#1c00cf">0x10</font>,<font color="#1c00cf">9</font>,<font color="#1c00cf">8</font>,<font color="#1c00cf">4</font>,<font color="#1c00cf">3</font>,<font color="#1c00cf">2</font><font color="#007400">; BIOS error codes</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">1</font>,<font color="#1c00cf">2</font>,<font color="#1c00cf">6</font>,<font color="#1c00cf">0x0C</font>,<font color="#1c00cf">4</font>,<font color="#1c00cf">0x0C</font>,<font color="#1c00cf">4</font>,<font color="#1c00cf">8</font>,<font color="#1c00cf">0</font>,<font color="#1c00cf">0x0C</font>,<font color="#1c00cf">0x0C</font><font color="#007400">; IBMBIO error codes</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">int_13_cmdÂ  Â  Â  db <font color="#1c00cf">2</font> Â  Â </font>
<font color="#000000">temp_sp Â  Â  Â  Â  dw <font color="#1c00cf">0</font> Â  Â </font>
<font color="#000000">num_sectors Â  Â  db <font color="#1c00cf">0</font> Â  Â </font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  times <font color="#1c00cf">513</font> db <font color="#1c00cf">0</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  db <font color="#1c00cf">0xC9</font></font>
<font color="#000000">Â  Â  Â  Â  Â  Â  Â  Â  times <font color="#1c00cf">126</font> db <font color="#1c00cf">0</font></font>
<font color="#000000"></font>
<font color="#007400">;-----------------------------------------------------------------------------</font>
<font color="#000000"></font>
</pre>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=184&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=184</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Reverse-Engineering DOS 1.0 &#8211; Part 1: The Boot Sector</title>
		<link>http://www.pagetable.com/?p=165</link>
		<comments>http://www.pagetable.com/?p=165#comments</comments>
		<pubDate>Thu, 07 May 2009 08:01:25 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=165</guid>
		<description><![CDATA[The bootsector of DOS 1.0 is celebtaring its 28th birthday today (it contains the timestamp &#8220;7-May-81&#8243;), so let&#8217;s look at it more closely. Here it is: 00000000 eb 2f 14 00 00 00 60 00 20 37 2d 4d 61 79 2d 38 &#124;........ 7-May-8&#124; 00000010 31 00 00 00 00 00 00 00 00 [...]]]></description>
			<content:encoded><![CDATA[<p>The bootsector of DOS 1.0 is celebtaring its 28th birthday today (it contains the timestamp &#8220;7-May-81&#8243;), so let&#8217;s look at it more closely.</p>
<p>Here it is:</p>
<pre>
00000000  eb 2f 14 00 00 00 60 00  20 37 2d 4d 61 79 2d 38  |........ 7-May-8|
00000010  31 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |1...............|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 fa 8c c8 8e d8 ba 00  00 8e d2 bc 00 7c fb a1  |................|
00000040  06 7c 8e d8 8e c0 ba 00  00 8b c2 cd 13 72 41 e8  |................|
00000050  58 00 72 fb 2e 8b 0e 02  7c 51 bb 00 00 33 d2 b9  |................|
00000060  08 00 be 01 00 56 b0 01  b4 02 cd 13 72 22 5e 58  |................|
00000070  e8 e7 00 2b c6 74 14 fe  c5 b1 01 be 08 00 3b c6  |................|
00000080  73 04 8b f0 eb 01 96 56  50 eb dd 2e ff 2e 04 7c  |................|
00000090  be 44 7d b8 42 7d 50 32  ff ac 24 7f 74 0b 56 b4  |................|
000000a0  0e bb 07 00 cd 10 5e eb  f0 c3 bb 00 00 b9 04 00  |................|
000000b0  b8 01 02 cd 13 1e 72 34  8c c8 8e d8 bf 00 00 b9  |................|
000000c0  0b 00 26 80 0d 20 26 80  8d 20 00 20 47 e2 f3 bf  |................|
000000d0  00 00 be 76 7d b9 0b 00  fc f3 a6 75 0f bf 20 00  |................|
000000e0  be 82 7d b9 0b 00 f3 a6  75 02 1f c3 be f9 7c e8  |................|
000000f0  a5 ff b4 00 cd 16 1f f9  c3 0d 0a 4e 6f 6e 2d 53  |...........Non-S|
00000100  79 73 74 65 6d 20 64 69  73 6b 20 6f 72 20 64 69  |ystem disk or di|
00000110  73 6b 20 65 72 72 6f f2  0d 0a 52 65 70 6c 61 63  |sk erro?..Replac|
00000120  65 20 61 6e 64 20 73 74  72 69 6b 65 20 61 6e 79  |e and strike any|
00000130  20 6b 65 79 20 77 68 65  6e 20 72 65 61 64 f9 0d  | key when read?.|
00000140  0a 00 cd 18 0d 0a 44 69  73 6b 20 42 6f 6f 74 20  |......Disk Boot |
00000150  66 61 69 6c 75 72 e5 0d  0a 00 50 52 8b c6 bf 00  |failur?.........|
00000160  02 f7 e7 03 d8 5a 58 c3  52 6f 62 65 72 74 20 4f  |........Robert O|
00000170  27 52 65 61 72 20 69 62  6d 62 69 6f 20 20 63 6f  |'Rear ibmbio  co|
00000180  6d b0 69 62 6d 64 6f 73  20 20 63 6f 6d b0 c9 00  |m.ibmdos  com...|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200
</pre>
<p>DOS 1.0 shipped on a 160 KB single sided disk. The boot code in the IBM PC&#8217;s BIOS loaded the first sector into RAM at segment 0&#215;0000, offset 0x7C00 and ran it. Later versions of BIOS checked for 0xAA55 in the last word of the bootsector, but the first version did not. Note that DOS 1.0 is also pre-BIOS Parameter Block, i.e. the bootsector does not contain any information about the physical layout of the disk, since there was only a single disk size.</p>
<p>What the boot sector is supposed to do is read &#8220;IBMBIO.COM&#8221; and &#8220;IBMDOS.COM&#8221; into RAM and run them &#8211; these are the DOS system files for machine abstraction and DOS API, respectively. In MS-DOS, they would be called &#8220;IO.SYS&#8221; and &#8220;MSDOS.SYS&#8221;.</p>
<p>But the DOS 1.0 bootsector takes quite a lot of shortcuts. It assumes it&#8217;s always a 40 track, 8 sectors single-sided disk and the two files occupy the first sectors of the data area contiguously &#8211; something that SYS.COM could guarantee when making a disk bootable.</p>
<p>So the bootsector first loads the first sector of the root directory (hardcoded to track 0, sector 4) and compares the first two entries with &#8220;IBMBIO.COM&#8221; and &#8220;IBMDOS.COM&#8221;. For some reason, the comparison is case-insensitive, although DOS only allows uppercase filenames.</p>
<pre>
00000600  49 42 4d 42 49 4f 20 20  43 4f 4d 06 00 00 00 00  |IBMBIO  COM.....|
00000610  00 00 00 00 00 00 00 00  f7 02 02 00 80 07 00 00  |................|
00000620  49 42 4d 44 4f 53 20 20  43 4f 4d 06 00 00 00 00  |IBMDOS  COM.....|
00000630  00 00 00 00 00 00 00 00  0d 03 06 00 00 19 00 00  |................|
</pre>
<p>If they are not there, it prompts the user to replace the disk and tries again. Otherwise, it loads 20 sectors starting from track 0, sector 8 to segment 0&#215;0060, offset 0&#215;0000 into memory and jumps there.</p>
<p>0&#215;60:0&#215;0000 is the same as the linear address 0&#215;0600. On the IBM PC, 0&#215;0000 to 0x03FF are occupied by the interrupts vectors, 0&#215;0400 to 0x4FF is used by BIOS for its variables, and DOS 1.0 uses 0&#215;500 to 0x5FF as the &#8220;DOS Communication Area&#8221;, so code can start at 0&#215;0600.</p>
<pre>
00000e00  e9 62 01 e9 6d 00 e9 b2  00 e9 d8 00 e9 e8 00 e9  |................|
00000e10  24 01 e9 3a 01 e9 51 03  e9 52 03 e9 44 01 b1 00  |................|
00000e20  22 00 42 49 4f 53 20 56  65 72 73 69 6f 6e 20 31  |..BIOS Version 1|
00000e30  2e 30 30 a0 32 32 2d 4a  75 6c 2d 38 31 00 0d 0a  |.00.22-Jul-81...|
</pre>
<p>These are the first few bytes of IBMBIO.COM. Its birthday is about six weeks from now, but I am going to post about its internals next week.</p>
<p>Let us finally look at the complete commented disassembly of the boot sector. It compiles with NASM, but will emit a few bytes differently because of variations in the assembly encoding &#8211; but variations in size have been compensated wit NOPs. It is actually quite easy to read.</p>
<pre>
<font color=#007400>;-----------------------------------------------------------------------------</font>
<font color=#007400>; DOS 1.0 Boot Sector (disk image MD5 73c919cecadf002a7124b7e8bfe3b5ba)</font>
<font color=#007400>;   http://www.pagetable.com/</font>
<font color=#007400>;-----------------------------------------------------------------------------</font>

Â  Â  Â  Â  Â  Â  Â  Â  org <font color=#1c00cf>0x7C00</font>

Â  Â  Â  Â  Â  Â  Â  Â  jmpÂ  Â   short start

<font color=#007400>;-----------------------------------------------------------------------------</font>

os_numsectors Â  dw <font color=#1c00cf>20</font> Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; how many sectors to read</font>
os_offset Â  Â  Â  dw <font color=#1c00cf>0</font>Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; segment to load code into</font>
os_segmentÂ  Â  Â  dw <font color=#1c00cf>0x60</font> Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; offset to load code into</font>

Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#c41a16>" 7-May-81"</font>,<font color=#1c00cf>0</font>Â  Â  Â  Â  <font color=#007400>; timestamp</font>
Â  Â  Â  Â  Â  Â  Â  Â  times <font color=#1c00cf>31</font> db <font color=#1c00cf>0</font> Â  Â  Â  Â  Â  <font color=#007400>; padding</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

start Â  Â  Â  Â  Â  cli
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, cs
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ds, axÂ  Â  Â  Â  Â  <font color=#007400>; DS := CS</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   dx, <font color=#1c00cf>0</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ss, dxÂ  Â  Â  Â  Â  <font color=#007400>; SS := 0000</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   sp, <font color=#1c00cf>0x7C00</font>Â  Â  Â  <font color=#007400>; stack below code</font>
Â  Â  Â  Â  Â  Â  Â  Â  sti
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, [os_segment]
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ds, ax
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   es, axÂ  Â  Â  Â  Â  <font color=#007400>; ES := DS := where to load DOS</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   dx, <font color=#1c00cf>0</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, dx
Â  Â  Â  Â  Â  Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x13</font>Â  Â  Â  Â  Â  Â  <font color=#007400>; reset drive 0</font>
Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  disk_error
again Â  Â  Â  Â  Â  callÂ  Â  check_sys_files <font color=#007400>; check for presence of IBMDOS/IBMBIO</font>
Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  again Â  Â  Â  Â  Â  <font color=#007400>; not found, try another disk</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, [cs:os_numsectors]
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  cxÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; remaining sectors</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   bx, <font color=#1c00cf>0</font>
Â  Â  Â  Â  Â  Â  Â  Â  xorÂ  Â   dx, dxÂ  Â  Â  Â  Â  <font color=#007400>; drive 0, head 0</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, <font color=#1c00cf>8</font> Â  Â  Â  Â  Â  <font color=#007400>; track 0, sector 8</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   si, <font color=#1c00cf>1</font> Â  Â  Â  Â  Â  <font color=#007400>; read 1 sector in first found</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  si
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   al, <font color=#1c00cf>1</font> Â  Â  Â  Â  Â  <font color=#007400>; 1 sector</font>
read_loop Â  Â  Â  movÂ  Â   ah, <font color=#1c00cf>2</font>
Â  Â  Â  Â  Â  Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x13</font>Â  Â  Â  Â  Â  Â  <font color=#007400>; read sector(s)</font>
Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  disk_error
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   siÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; sectors read</font>
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   axÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; remaining sectors</font>
Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  add_si_sectorsÂ  <font color=#007400>; bx += si*512</font>
Â  Â  Â  Â  Â  Â  Â  Â  subÂ  Â   ax, siÂ  Â  Â  Â  Â  <font color=#007400>; remaining -= read</font>
Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  doneÂ  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; none left</font>
Â  Â  Â  Â  Â  Â  Â  Â  incÂ  Â   chÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; next track</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cl, <font color=#1c00cf>1</font> Â  Â  Â  Â  Â  <font color=#007400>; start at sector 1</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   si, <font color=#1c00cf>8</font> Â  Â  Â  Â  Â  <font color=#007400>; read up to 8 sectors</font>
Â  Â  Â  Â  Â  Â  Â  Â  cmpÂ  Â   ax, siÂ  Â  Â  Â  Â  <font color=#007400>; how many are left to read?</font>
Â  Â  Â  Â  Â  Â  Â  Â  jaeÂ  Â   at_least_8_left <font color=#007400>; at least 8</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   si, axÂ  Â  Â  Â  Â  <font color=#007400>; only read remaining amount</font>
Â  Â  Â  Â  Â  Â  Â  Â  jmpÂ  Â   short skip
at_least_8_left xchgÂ  Â  ax, siÂ  Â  Â  Â  Â  <font color=#007400>; read 8 sectors this time</font>
skipÂ  Â  Â  Â  Â  Â  pushÂ  Â  siÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; number of remaining sectors</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  axÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; number of sectors to read this time</font>
Â  Â  Â  Â  Â  Â  Â  Â  jmpÂ  Â   read_loop Â  Â  Â  <font color=#007400>; next read</font>
doneÂ  Â  Â  Â  Â  Â  jmpÂ  Â   far [cs:os_offset]<font color=#007400>; jump to IBMBIO.COM</font>

disk_errorÂ  Â  Â  movÂ  Â   si, FAILUREÂ  Â   <font color=#007400>; string to print</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, rom_basic Â  <font color=#007400>; put return address of "int 18" code</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  axÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; onto stack</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>
<font color=#007400>; print zero-terminated string pointed to by DS:SI</font>
<font color=#007400>;-----------------------------------------------------------------------------</font>

print Â  Â  Â  Â  Â  xorÂ  Â   bh, bhÂ  Â  Â  Â  Â  <font color=#007400>; XXX unnecessary</font>
print_loopÂ  Â  Â  lodsb
Â  Â  Â  Â  Â  Â  Â  Â  andÂ  Â   al, <font color=#1c00cf>0x7F</font>Â  Â  Â  Â  <font color=#007400>; clear bit 7 XXX why is it set?</font>
Â  Â  Â  Â  Â  Â  Â  Â  jzÂ  Â  Â  ret0Â  Â  Â  Â  Â  Â  <font color=#007400>; zero-termination</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  si
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ah, <font color=#1c00cf>0x0E</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   bx, <font color=#1c00cf>7</font> Â  Â  Â  Â  Â  <font color=#007400>; light grey, text page 0</font>
Â  Â  Â  Â  Â  Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x10</font>Â  Â  Â  Â  Â  Â  <font color=#007400>; write character</font>
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   si
Â  Â  Â  Â  Â  Â  Â  Â  jmpÂ  Â   print_loop
ret0Â  Â  Â  Â  Â  Â  retn

<font color=#007400>;-----------------------------------------------------------------------------</font>
<font color=#007400>; test for IBMBIO.COM and IBMDOS.COM in the first two directory entries</font>
<font color=#007400>;-----------------------------------------------------------------------------</font>

check_sys_files movÂ  Â   bx, <font color=#1c00cf>0</font> Â  Â  Â  Â  Â  <font color=#007400>; read to address 0 in the DOS segment</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, <font color=#1c00cf>4</font> Â  Â  Â  Â  Â  <font color=#007400>; track 0, sector 4</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, <font color=#1c00cf>0x0201</font>
Â  Â  Â  Â  Â  Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x13</font>Â  Â  Â  Â  Â  Â  <font color=#007400>; read 1 sector</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  ds
Â  Â  Â  Â  Â  Â  Â  Â  jcÂ  Â  Â  non_system_disk <font color=#007400>; error case</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, cs
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ds, axÂ  Â  Â  Â  Â  <font color=#007400>; DS := CS</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   di, <font color=#1c00cf>0</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, <font color=#1c00cf>11</font>Â  Â  Â  Â  Â  <font color=#007400>; convert 11 bytes of first two</font>
to_lowerÂ  Â  Â  Â  orÂ  Â  Â  byte [es:di], <font color=#1c00cf>0x20</font><font color=#007400>; directory entries to lowercase</font>
Â  Â  Â  Â  Â  Â  Â  Â  orÂ  Â  Â  byte [es:di+<font color=#1c00cf>0x20</font>], <font color=#1c00cf>0x20</font>
Â  Â  Â  Â  Â  Â  Â  Â  nop           Â  Â  Â  Â  Â  <font color=#007400>; XXX original assembler wasted a byte</font>
Â  Â  Â  Â  Â  Â  Â  Â  incÂ  Â   di
Â  Â  Â  Â  Â  Â  Â  Â  loopÂ  Â  to_lower
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   di, <font color=#1c00cf>0</font> Â  Â  Â  Â  Â  <font color=#007400>; first entry</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   si, IBMBIO_COM
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, <font color=#1c00cf>11</font>
Â  Â  Â  Â  Â  Â  Â  Â  cld
Â  Â  Â  Â  Â  Â  Â  Â  rep cmpsb Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; compare first entry with IBMBIO.COM</font>
Â  Â  Â  Â  Â  Â  Â  Â  jnzÂ  Â   non_system_disk
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   di, <font color=#1c00cf>0x20</font>Â  Â  Â  Â  <font color=#007400>; second entry</font>
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   si, IBMDOS_COM
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   cx, <font color=#1c00cf>11</font>
Â  Â  Â  Â  Â  Â  Â  Â  rep cmpsb Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; compare second entry with IBMDOS.COM</font>
Â  Â  Â  Â  Â  Â  Â  Â  jnzÂ  Â   non_system_disk
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   ds
Â  Â  Â  Â  Â  Â  Â  Â  retnÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; return with carry clear</font>
non_system_disk movÂ  Â   si, NON_SYSTEM_DISK
Â  Â  Â  Â  Â  Â  Â  Â  callÂ  Â  print
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ah, <font color=#1c00cf>0</font>
Â  Â  Â  Â  Â  Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x16</font>Â  Â  Â  Â  Â  Â  <font color=#007400>; wait for key</font>
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   ds
Â  Â  Â  Â  Â  Â  Â  Â  stc</font>
Â  Â  Â  Â  Â  Â  Â  Â  retnÂ  Â  Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; return with carry set</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

NON_SYSTEM_DISK db <font color=#1c00cf>13</font>,<font color=#1c00cf>10</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#c41a16>"Non-System disk or disk erro"</font>,<font color=#1c00cf>'r'</font>+</font><font color=#1c00cf>0x80</font></font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#1c00cf>13</font>,<font color=#1c00cf>10</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#c41a16>"Replace and strike any key when read"</font>,<font color=#1c00cf>'y'</font>+</font><font color=#1c00cf>0x80</font>
Â  Â  Â  Â  Â  Â  Â  Â  dbÂ  <font color=#1c00cf>13</font>,<font color=#1c00cf>10</font>,<font color=#1c00cf>0</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

rom_basic Â  Â  Â  intÂ  Â   <font color=#1c00cf>0x18</font>Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; ROM BASIC</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

FAILURE Â  Â  Â  Â  db <font color=#1c00cf>13</font>,<font color=#1c00cf>10</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#c41a16>"Disk Boot failur"</font>,<font color=#1c00cf>'e'</font>+<font color=#1c00cf>0x80</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#1c00cf>13</font>,<font color=#1c00cf>10</font>,<font color=#1c00cf>0</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

add_si_sectorsÂ  pushÂ  Â  axÂ  Â  Â  Â  Â  Â  Â  <font color=#007400>; bx += si*512</font>
Â  Â  Â  Â  Â  Â  Â  Â  pushÂ  Â  dx
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   ax, si
Â  Â  Â  Â  Â  Â  Â  Â  movÂ  Â   di, <font color=#1c00cf>512</font>
Â  Â  Â  Â  Â  Â  Â  Â  mulÂ  Â   di
Â  Â  Â  Â  Â  Â  Â  Â  addÂ  Â   bx, ax
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   dx
Â  Â  Â  Â  Â  Â  Â  Â  popÂ  Â   ax
Â  Â  Â  Â  Â  Â  Â  Â  retn

<font color=#007400>;-----------------------------------------------------------------------------</font>

Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#c41a16>"Robert O'Rear "</font>

IBMBIO_COMÂ  Â  Â  db <font color=#c41a16>"ibmbioÂ  com"</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#1c00cf>0xB0</font> Â  Â  Â  Â  Â  Â  Â  Â  <font color=#007400>; XXX unused</font>
IBMDOS_COMÂ  Â  Â  db <font color=#c41a16>"ibmdosÂ  com"</font>
Â  Â  Â  Â  Â  Â  Â  Â  db <font color=#1c00cf>0xB0</font>, <font color=#1c00cf>0xC9</font> Â  Â  Â  Â  Â  <font color=#007400>; XXX unused</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>

Â  Â  Â  Â  Â  Â  Â  Â  times <font color=#1c00cf>512</font>-($-$$) db <font color=#1c00cf>0</font>

<font color=#007400>;-----------------------------------------------------------------------------</font>
</pre>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=165&amp;ts=1284078728" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=165</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>The 6502 in &#8220;The Terminator&#8221;</title>
		<link>http://www.pagetable.com/?p=64</link>
		<comments>http://www.pagetable.com/?p=64#comments</comments>
		<pubDate>Tue, 05 May 2009 08:01:54 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=64</guid>
		<description><![CDATA[In the first Terminator movie, the audience sees the world from the T-800&#8242;s view several times. It is well-known that in two instances, there is 6502 assembly code on the T-800&#8242;s HUD, and many sites have analyzed the contents: It&#8217;s Apple-II code taken from Nibble Magazine. Here are HD versions of the shots, thanks to [...]]]></description>
			<content:encoded><![CDATA[<p>In the first <a href="http://en.wikipedia.org/wiki/The_Terminator">Terminator</a> movie, the audience sees the world from the T-800&#8242;s view several times. It is <a href="http://en.wikipedia.org/wiki/MOS_6502#6502_in_popular_culture">well-known</a> that in two instances, there is 6502 assembly code on the T-800&#8242;s <a href="http://en.wikipedia.org/wiki/Head-up_display">HUD</a>, and <a href="http://blogs.computerworld.com/do_androids_dream_of_electric_apples">many</a> <a href="http://www.dienstagstreff.de/de/famous/commodore/terminator1/index.php3">sites</a> have analyzed the contents: It&#8217;s Apple-II code taken from <a href="http://www.nibblemagazine.com/">Nibble Magazine</a>. Here are HD versions of the shots, thanks to Dominik Wagner:</p>
<p>This is the first assembly snippet:</p>
<p><a href="docs/terminator/00-37-23.jpg"><img src="docs/terminator/t_00-37-23.jpg" width="440"></a><br />
<a href="docs/terminator/01-23-27.jpg"><img src="docs/terminator/t_01-23-27.jpg" width="440"></a></p>
<p>This is the second assembly snippet:</p>
<p><a href="docs/terminator/00-37-19.jpg"><img src="docs/terminator/t_00-37-19.jpg" width="440"></a><br />
<a href="docs/terminator/01-23-18.jpg"><img src="docs/terminator/t_01-23-18.jpg" width="440"></a></p>
<p>There are some assembly equates:</p>
<p><a href="docs/terminator/00-37-18.jpg"><img src="docs/terminator/t_00-37-18.jpg" width="440"></a><br />
<a href="docs/terminator/01-23-22.jpg"><img src="docs/terminator/t_01-23-22.jpg" width="440"></a></p>
<p>On the left, these are the assembled opcodes of the second assembly listing, reaching from &#8220;LDY#10&#8243; to &#8220;SEC&#8221;. On the right, there is output of a run of the checksum application <a href="http://www.nibblemagazine.net/nibble_disks.htm">Key Perfect</a> on a file names &#8220;OVLY.OBJ&#8221;, which prints a 16 bit checksum for every 0&#215;50 bytes:</p>
<p><a href="docs/terminator/00-37-17.jpg"><img src="docs/terminator/t_00-37-17.jpg" width="440"></a><br />
<a href="docs/terminator/01-23-13.jpg"><img src="docs/terminator/t_01-23-13.jpg" width="440"></a><br />
<a href="docs/terminator/01-23-14.jpg"><img src="docs/terminator/t_01-23-14.jpg" width="440"></a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=64&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=64</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>The History of OS Migration</title>
		<link>http://www.pagetable.com/?p=152</link>
		<comments>http://www.pagetable.com/?p=152#comments</comments>
		<pubDate>Tue, 28 Apr 2009 08:01:17 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=152</guid>
		<description><![CDATA[Operating system vendors face this problem once or twice a decade: They need to migrate their user base from their old operating system to their very different new one, or they need to switch from one CPU architecture to another one, and they want to enable users to run old applications unmodified, and help developers [...]]]></description>
			<content:encoded><![CDATA[<p>Operating system vendors face this problem once or twice a decade: They need to migrate their user base from their old operating system to their very different new one, or they need to switch from one CPU architecture to another one, and they want to enable users to run old applications unmodified, and help developers port their applications to the new OS. Let us look at how this has been done in the last 3 decades, looking at DOS/Windows, Macintosh, Amiga and Palm.</p>
<h3>CP/M to PC-DOS/MS-DOS</h3>
<p>CP/M was an 8 bit operating system by Digital Research that ran on all kinds of Intel 8080-based systems. Seattle Computer Products &#8220;86-DOS&#8221;, which later became MS-DOS (called &#8220;PC-DOS&#8221; on IBM machines), was a clone of CP/M, but for the Intel 8086, much like DR&#8217;s own CP/M-86 (which later became DR-DOS).</p>
<p>While not binary compatible, the Intel 8086 was &#8220;assembly source compatible&#8221; with the 8080, which meant that it was easily possible to convert 8 bit 8080/Z80 assembly source into 8086 assembly, since the two architectures were very similar (backward-compatible memory model; one register set could be mapped onto the other) and only the instruction encoding was different.</p>
<p>Since MS-DOS implemented the same ABI and memory map, it was source-code compatible with CP/M. On a CP/M system, which could access a total of 64 KB of memory, the region from 0&#215;0000 to 0&#215;0100 (Zero Page) was reserved to the operating system and contained, among other things, the command line arguments. The running application was located from 0&#215;0100 up, and the operating system was at the top of memory, with the application stack growing down from just below the start of the OS. The memory model of the 8086 partitions memory into (overlapping) chunks of contiguous 64 KB, so one of these segments is basically a virtual 8080 machine. MS-DOS &#8220;.COM&#8221; files are executables below 64 KB that are loaded at address 0&#215;0100 of such a segment. 0&#215;0000-0&#215;0100 is called the Program Segment Prefix and is very similar to the CP/M zero page, the stack grows down from the end of code segment, and the operating system resides in a different segment.</p>
<p>Because of the high compatibility of the CPUs and the ABIs, a port of a program from CP/M to DOS was pretty painless. Such a direct port could only support up to 64 KB of memory (like WordStar 3.0 from 1982), but it was also possible to maintain a single source base for both CP/M and MS-DOS just by using a few macros and two different assemblers.</p>
<p>DOS 2.0 then introduced more powerful APIs (file handles instead of FCBs, subdirectories, relocatable .EXE files), obsoleting most of the CP/M API &#8211; but DOS kept CP/M compatibility until the last version.</p>
<table border="1">
<tr>
<td colspan="2"><b>CP/M to PC-DOS/MS-DOS</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU<br />New OS codebase</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Not supported</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source/ABI compatibility</td>
</tr>
</table>
<h3>DOS to Windows</h3>
<p>Microsoft Windows was first architected as a graphical shell on top of MS-DOS: All device and filesystem access was done by making DOS API calls, so all MS-DOS drivers ran natively, and Windows could use them. DOS applications could still be used by just exiting Windows.</p>
<p>Windows/386 2.1 changed this model, as it was a real operating system kernel that ran a number of &#8220;virtual 8086 mode&#8221; (V86) virtual machines side by side: One for the MS-DOS operating system and one per Windows application. The DOS VM was used by Windows to call out to device drivers and the filesystem, so it was basically a driver compatibility environment running inside a VM. The user could start any number of additional DOS VMs to run DOS applications, and each of these contained a copy of DOS. Windows hooked memory accesses to screen RAM as well as some system calls to route them to the Windows graphics driver or through the &#8220;root&#8221; DOS VM.</p>
<p>Windows 3.x started using Windows-native drivers that replaced calls into the DOS VM, and had the DOS VM call up to Windows for certain device accesses. The standard Windows 95 installation didn&#8217;t use the DOS VM for drivers or the filesystem at all, but could do so if necessary.</p>
<p>DOS was not only a compatibilty environment for old drivers and applications, it was also the command line of Windows, so when Windows 95 introduced long file names, it trapped DOS API calls to provide a new interface for this functionality to command line tools.</p>
<table border="1">
<tr>
<td colspan="2"><b>MS-DOS to Windows</b></td>
<tr>
<tr>
<td>Change</td>
<td>New OS</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Virtual machine with old OS</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Virtual machine with old OS</td>
</tr>
<tr>
<td>Porting applications</td>
<td>No migration path</td>
</tr>
</table>
<h3>DOS to Windows NT</h3>
<p>Windows NT was never based on DOS, but still allowed running MS-DOS applications since its first version, NT 3.1. Like non-NT Windows, it runs DOS applications in V86 mode. But instead of running a copy of MS-DOS, using its logic and trapping its device accesses, NT just runs the application in V86 mode and traps all system calls and I/O accesses and maps them to NT API calls. It is not a virtual machine: V86 mode is merely used to provide the memory model necessary to support DOS applications.</p>
<p>One common misconception is that the Windows NT command line is a &#8220;DOS box&#8221;: The command line interpreter and its support tools are native NT applications, and a Virtual DOS Machine (NTVDM) is not started until a real DOS program is launched from the command line.</p>
<table border="1">
<tr>
<td colspan="2"><b>DOS to Windows NT</b></td>
<tr>
<tr>
<td>Change</td>
<td>New OS</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>API reimplementation</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>No migration path</td>
</tr>
</table>
<h3>Windows 3.1 (Win16) to Windows 95 (Win32)</h3>
<p>Since the release of Windows NT 3.1 in 1993, it was clear that it would replace classic Windows eventually, but although it had the same look-and-feel and good Win16 and decent DOS compatibility, every current version of NT typically required quite high-end hardware. The migration from Windows to Windows NT was done by slowly making Windows more like Windows NT, and when they were similar enough, and even low-end computers were powerful enough to run NT well, switching the users to the new codebase.</p>
<p>The big step to make Windows more like Windows NT was supporting NT&#8217;s 32 bit Win32 API: The first step was the free &#8220;Win32S&#8221; update to Windows 3.1, which provided a subset (thus the &#8220;S&#8221;) of the Win32 API on classic Windows. Win32S extended the Windows kernel to create a 32 bit address space for all 32 bit applications (NT had a separtate address space for each application). It also provided ported versions of some new NT libraries (e.g. RICHED32.DLL), as well as 32 bit DLLs that accepted the low-level Win32 API calls (&#8220;GDI&#8221; and &#8220;USER&#8221;) and forwarded them to the Win16 system (&#8220;thunking&#8221;).</p>
<p>Windows 95 included this functionality by default, ran 32 bit applications in separate address spaces, supported more of the Win32 API and included several 32 bit core applications (like Explorer), but a good chunk of the core system was still 16 bit. With Windows 95, most developers switched to writing 32 bit applications, making them instantly available as native applications on Windows NT.</p>
<table border="1">
<tr>
<td colspan="2"><b>Windows 3.1 (Win16) to Windows 95 (Win32)</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU mode/bitness</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Thunking</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Native</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<h3>Windows 9X to Windows NT</h3>
<p>The second step in the migration from 16 bit Windows to Windows NT was the switch from Windows ME to the NT-based Windows XP in 2001. Windows NT (2000/XP/&#8230;) was a fully 32 bit operating system with the Win32 API, but it also allowed running 16 bit Windows applications by forwarding their Win16 API calls to the Win32 libraries (thunking).</p>
<p>The driver model of Windows NT 3.1/3.5/4.0 (&#8220;Windows NT Driver Model&#8221;) and classic Windows (&#8220;VxD&#8221;) was different, so Windows 98 (successor of Windows 95) and Windows 2000 (successor to Windows NT 4.0) both supported the new &#8220;Windows Driver Model&#8221;. A single driver could now work on both operating systems, but each OS continued to support their original driver mode.</p>
<p>When Microsoft switched the home users to the NT codebase, most current applications, games and drivers worked on Windows XP as well. It was only the system tools that had to be rewritten.</p>
<table border="1">
<tr>
<td colspan="2"><b>Windows 9X to Windows NT</b></td>
<tr>
<tr>
<td>Change</td>
<td>New OS</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Win16: Thunking<br />Win32: Native</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Providing the same API for the old OS</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility<br />Providing the same API for the old OS</td>
</tr>
</table>
<h3>Windows i386 (Win32) to Windows x64/x86_64 (Win64)</h3>
<p>The switch from 32 bit Windows to 64 bit Windows is currently in progress: Windows XP was the first version to be available for AMD64/Intel64, and both Windows Vista and Windows 7 are available as both 32 bit and 64 bit editions. On the 64 bit edition, the kernel is 64 bit native, and so are all libraries and most applications. The 32 bit API is still supported using the &#8220;WOW64&#8243; (Windows-on-Windows 64-bit) subsystem: A 32 bit application links against all 32 bit libraries, but the low-level API calls it wants to make get translated by the WOW64 DLL into their 64 bit counterparts.</p>
<p>Since drivers run in the same address space as the kernel, 32 bit drivers could not be easily supported on 64 bit Windows, and thus are not. Support for DOS and Win16 applications was dropped on 64 bit Windows.</p>
<table border="1">
<tr>
<td colspan="2"><b>Windows i386 (Win32) to Windows x64/x86_64 (Win64)</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU mode/bitness</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Thunking</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<h3>Macintosh on 68K to Macintosh on PowerPC</h3>
<p>Apple switched their computers from using Motorola 68K processors to Motorola/IBM PowerPC processors between 1994 and 1996. Since the Macintosh operating system, called System 7 at that time, was mostly written in 68K assembly, it could not be easily converted into a PowerPC operating system. Instead, most of the system was run in emulation: The new &#8220;nanokernel&#8221; handled and dispatched interrupts and did some basic memory management to abstract away the PowerPC, and the tightly integrated 68K emulator ran the old operating system code, which was modified to hook into the nanokernel for interrupts and memory management. So System 7.1.2 for PowerPC was basically a paravirtualized operating system running inside emulation on top of a very thin hypervisor.</p>
<p>The first version of Mac OS for PowerPC ran most of the operating system inside 68K emulation, even drivers, but some performance-sensitive code was native. The executable loader detected binaries with PowerPC code in them and could run them natively inside the same context. Most communication to the OS APIs went back through the emulator. Later versions of Mac OS replaced more and more of the 68K code with PowerPC code.</p>
<table border="1">
<tr>
<td colspan="2"><b>Macintosh on 68K to Macintosh on PowerPC</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Thunking</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Paravirtualized old OS in emulator</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Paravirtualized old OS in emulator</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<h3>Classic Mac OS to Mac OS X</h3>
<p>Just like Microsoft switched from Windows to Windows NT, Apple switched from Classic Mac OS to Mac OS X. While Classic Mac OS was a hacky OS with cooperative multitasking and without memory protection that still ran some of the OS code in 68K emulation, Mac OS X was based on NEXTSTEP, a modern UNIX-like operating system with a completely different API.</p>
<p>When Apple decided to migrate towards a new operating system, they ported the system libraries of Classic Mac OS (&#8220;Toolbox&#8221;) to Mac OS X, omitting the calls that could not be supported on the modern OS (and replacing them with alternatives), and called the new API &#8220;Carbon&#8221;. They provided the same API for (Classic) Mac OS 8.1 in 1998, so developers could already update their applications for OS X, while maintaining compatibility with Classic Mac OS. When Mac OS X was introduced in 2001, binaries of &#8220;carbonized&#8221; applications would then run unmodified on both operating systems. This is similar to the &#8220;make Windows more like Windows NT&#8221; approach by Microsoft.</p>
<p>But since not all applications were expected to exist as carbonized versions with the introduction of OS X, the new operating system also contained a virtual machine called &#8220;Classic&#8221; or &#8220;Blue Box&#8221; in which the unmodified Mac OS 9 was run together with any number of legacy applications. Hooks were installed inside the VM to route network and filesystem requests to the host OS, and window manager integration allowed the two desktop environments to blend almost seamlessly together.</p>
<table border="1">
<tr>
<td colspan="2"><b>Classic Mac OS to Mac OS X</b></td>
<tr>
<tr>
<td>Change</td>
<td>New OS</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Classic: Virtual machine with old OS<br />Carbon: Intermediate API for both systems</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Virtual machine with old OS</td>
</tr>
<tr>
<td>Porting applications</td>
<td>Intermediate API for both systems</td>
</tr>
</table>
<h3>Mac OS X on PowerPC to Mac OS X on Intel</h3>
<p>In 2005, Apple announced that they would switch CPUs a second time, this time away from the PowerPC towards the Intel i386 architecture. Being a modern operating system mostly written in C and Objective C, it could be easily ported to i386 &#8211; actually, Apple claims that they have always maintained i386 versions of the whole operating systems since the first release.</p>
<p>In order to run legacy applications that had not yet been ported to i386, Apple included the emulator &#8220;Rosetta&#8221; with the operating system; but this time, it was not tighltly integrated into the kernel as with the 68K to PowerPC switch, but the kernel only added support to run an external recompiler with the application as a parameter whenever a PowerPC application was launched. Rosetta translated all application code as well as the libraries it linked against, and interfaced to the native OS kernel.</p>
<table border="1">
<tr>
<td colspan="2"><b>Mac OS X on PowerPC to Mac OS X on Intel</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>User mode emulator</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<h3>Mac OS X (32 bit) to Mac OS X (64 bit)</h3>
<p>The next switch for Apple was the migration from 32 bit Intel (i386) to 64 bit (x86_64) in Mac OS X 10.4 in 2006. Although the whole operating system could have been ported to 64, as it was done with Windows, Apple decided to take an approach which is closer to the Windows 95 one: The kernel stayed 32 bit, but got support for 64 bit user applications. All applications and drivers on the system were still 32 bit, but some system libraries were also available as ported 64 bit versions. A 64 bit application thus linked against 64 bit libraries, and made 64 bit syscalls that were converted to 32 bit calls inside the kernel.</p>
<p>Mac OS X 10.5 then provided all libraries in 64 bit versions, but the kernel remained 32 bit. OS X 10.6 will be the first version with a 64 bit kernel, requiring new 64 bit drivers.</p>
<table border="1">
<tr>
<td colspan="2"><b>Mac OS X (32 bit) to Mac OS X (64 bit)</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU mode/bitness</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Thunking</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Native</td>
</tr>
<tr>
<td>Porting applications</td>
<td>Carbon: Not supported<br />Cocoa: High level of source compatibility</td>
</tr>
</table>
<h3>AmigaOS on 68K to AmigaOS on PowerPC</h3>
<p>The Amiga platform was the same OS on the same 68K CPU architecture in the Commodore days between 1985 and 1994, but third-party manufacturers offered PowerPC CPU upgrade boards since 1997. The closed source operating system could not be ported to PowerPC by these third parties, so AmigaOS continued to run on the 68K CPU, and an extension in the binary loader detected PowerPC code and handed it off to the other CPU. All system calls then went though a thunking library back to the 68K.</p>
<p>AmigaOS 4 (2006) is a native port of AmigaOS to the PowerPC, which was a major effort, since a lot of operating system code had to be converted from BCPL to C first. 68K application support is done by emulating the binary code and interfacing it to the native API.</p>
<table border="1">
<tr>
<td colspan="2"><b>AmigaOS on 68K to AmigaOS on PowerPC (3.x)</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Thunking (new CPU)</td>
</tr>
<tr>
<td>Running old applications</td>
<td>Native (old CPU)</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Native</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<table border="1">
<tr>
<td colspan="2"><b>AmigaOS on 68K to AmigaOS on PowerPC (4.0)</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Native</td>
</tr>
<tr>
<td>Running old applications</td>
<td>User mode emulator</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>High level of source compatibility</td>
</tr>
</table>
<h3>Palm OS on 68K to Palm OS on ARM</h3>
<p>Palm switched from 68K processors to the ARM architecture with Palm OS 5 in 2002. The operating system was ported to ARM, and a the &#8220;Palm Application Compatibility Environment&#8221; (&#8220;PACE&#8221;) 68K emulator was included to run old applications. But Palm discouraged developers from switching to ARM code and did not even provide an environment in the OS to run native ARM applications. They claimed that most applications on Palm OS did most of their work in the native operating system code anyway, so they would not see a significant speedup.</p>
<p>But for applications that were heavily CPU bound and contained compression or crypto code, Palm provided a way to run small chunks of native ARM code inside a 68K application. These &#8220;ARMlets&#8221; (later called &#8220;PNOlets&#8221; for &#8220;Palm Native Object&#8221;) could be called from 68K code and provided a minimal interface with a single integer for input and output, so the developer had to write the code to pass extra parameters in structs and care about endianness and alignment. ARM code could neither call back to 68K code, nor could it call operating systems API directly.</p>
<p>Sticking with 68K code for most applications practically meant having a virtual architecture for user mode programs, not unlike Java or .NET. The switch to ARM was mostly unnoticed by developers, and this approach could have allowed Palm to switch architectures again in the future with little effort.</p>
<table border="1">
<tr>
<td colspan="2"><b>Palm OS on 68K to Palm OS on ARM</b></td>
<tr>
<tr>
<td>Change</td>
<td>New CPU</td>
</tr>
<tr>
<td>Running new applications</td>
<td>Not supported (PNOlet for subroutines)</td>
</tr>
<tr>
<td>Running old applications</td>
<td>User mode emulation</td>
</tr>
<tr>
<td>Running old drivers</td>
<td>Not supported</td>
</tr>
<tr>
<td>Porting applications</td>
<td>Not supported (PNOlet for subroutines)</td>
</tr>
</table>
<h3>Summary</h3>
<p>Let us summarize the OS and CPU switches and how the different vendors approached their respective problems.</p>
<h4>Bitness</h4>
<p>Switching to a new CPU mode is the easiest change in an operating system, since old applications code can run natively, and API calls can be translated. An operating system can either stay in the old bitness and convert calls from new applications for the old system, or move up to the new bitness and convert calls fom old applications. There are also two ways where to hook the calls: An operating systems could hook into high-level API calls like creating a GUI window, but this is hard to do, since the high-level API is typically very wide, and it is very hard to get a converter for so many calls correct and compatible. Alternatively, the OS can convert low-level system calls. With this solution, the interface is quite narrow. But since all old applications link against the old libraries and new applications against the new libraries, equivalent libraries will end up twice in memory if the user runs old and new applications concurrently.</p>
<table border="1">
<tr>
<td colspan="5"><b>New CPU mode/bitness</b></td>
<tr>
<tr>
<td><b>OS</b></td>
<td><b>Old mode</b></td>
<td><b>New mode</b></td>
<td><b>Thunking direction</b></td>
<td><b>Thunking level</b></td>
</tr>
<tr>
<td>Windows</td>
<td>16 bit</td>
<td>32 bit</td>
<td>new to old</td>
<td>library</td>
</tr>
<tr>
<td>Windows NT</td>
<td>32 bit</td>
<td>64 bit</td>
<td>old to new</td>
<td>kernel</td>
</tr>
<tr>
<td>Mac OS X</td>
<td>32 bit</td>
<td>64 bit</td>
<td>new to old</td>
<td>kernel</td>
</tr>
</table>
<p>For the 16 to 32 bit switch in Windows, the operating system stayed 16 bit and converted 32 bit calls into 16 bit calls at the API level. When Windows NT switched from 32 bit to 64 bit, the whole OS became 64 bit, and low-level kernel calls were converted for old applications. The same switch was done differently on Mac OS X: The OS stayed 32 bit, and 64 bit calls were translated at the kernel level.</p>
<p>The solutions of Windows NT and Mac OS X are quite similar, as they both run all 32 bit code with 32 bit libraries, and all 64 bit code with 64 bit libraries, and it is just the kernel that is different. For Windows, this has the advantage of having access to more than 4 GB in kernel mode, as well as some speedup from the new registers in x86_64 long mode, and for Mac OS X, it has the advantage of running old 32 bit drivers unmodified. (In a second step, Mac OS X later switched to a 64 bit kernel.)</p>
<h4>CPU</h4>
<p>It is harder to switch to a new CPU, because the new CPU just cannot run the old application code any more, and some operating systems cannot be easily adapted to a new CPU.</p>
<table border="1">
<tr>
<td colspan="5"><b>New CPU</b></td>
<tr>
<tr>
<td><b>OS</b></td>
<td><b>Old CPU</b></td>
<td><b>New CPU</b></td>
<td><b>Running old apps</b></td>
<td><b>Thunking level</b></td>
</tr>
<tr>
<td>CP/M, DOS</td>
<td>8080/Z80</td>
<td>8086</td>
<td>Developer has to recompile</td>
<td>-</td>
</tr>
<tr>
<td>Macintosh</td>
<td>68K</td>
<td>PowerPC</td>
<td>Run OS and app in emulation</td>
<td>-</td>
</tr>
<tr>
<td>Mac OS X</td>
<td>PowerPC</td>
<td>i386</td>
<td>User mode emulation</td>
<td>kernel</td>
</tr>
<tr>
<td>Amiga</td>
<td>68K</td>
<td>PowerPC</td>
<td>Dual-CPU thunking</td>
<td>library</td>
</tr>
<tr>
<td>Palm</td>
<td>68K</td>
<td>ARM</td>
<td>User mode emulation</td>
<td>library</td>
</tr>
</table>
<p>Mac OS X Intel and Palm OS ARM were written in a platform independent enough way so that they could be ported to the new architecture. They both included recompilers that ran the old code. This is the easy way. Amiga OS could not be ported, because the source code was not available. So systems had both CPUs, the original operating system code ran on the old CPU, and new applications ran on the new CPU, switching back to the old CPU for system calls.</p>
<p>For Classic Macintosh (68K to PowerPC), the OS source code was available, but could not be ported easily, so it was done similarly to the Amiga, although with a single CPU: Most of the old operating system ran inside emulation, and new applications ran natively, calling back into the emulator for system calls.</p>
<p>DOS was a reimplementation of the old OS by a different company that did not support running old binary code. Instead, it made the developer recompile their code.</a></p>
<h4>OS</h4>
<p>Switching to a new operating system, but keeping your users and developers is the hardest of all switches.</p>
<table border="1">
<tr>
<td colspan="3"><b>New OS</b></td>
<tr>
<tr>
<td><b>Old OS</b></td>
<td><b>New OS</b></td>
<td><b>Running old apps</b></td>
</tr>
<tr>
<td>CP/M</td>
<td>DOS</td>
<td>Compatible API</td>
</tr>
<tr>
<td>DOS</td>
<td>Windows</td>
<td>Virtual machine with old OS</td>
</tr>
<tr>
<td>DOS</td>
<td>Windows NT</td>
<td>API emulation</td>
</tr>
<tr>
<td>Windows 9X</td>
<td>Windows NT</td>
<td>Compatible API</td>
</tr>
<tr>
<td>Mac OS</td>
<td>Mac OS X</td>
<td>Classic: Virtual machine with old OS<br />Carbon: Compatible API</td>
</tr>
</table>
<p>The approach to take depends on the plans with the API of the old operating system. If the API is good enough to be worth supporting in the new OS, the new OS should just have the same API. This has been the case for the CP/M to DOS and the Windows 9X to Windows NT migrations. In a way, this was also true for Classic Mac OS to Mac OS X, but in this case, Carbon was not the main API of the new OS, but one of three APIs (Carbon, Cocoa, Java; while everything but Cocoa is pretty much deprectated today).</p>
<p>If the old API is not worth maintaining on the new OS, but it is important that old applications run very well, it makes sense to run the old operating system in a virtual machine, together with its applications. This was done by Windows to run DOS applications as well as Mac OS X to run old Mac OS applications.</p>
<p>If the OS interface of the old operating system is relatively small and easy, or perfect accuracy is not necessary, the best solution might be API emulation, i.e. hooking the system calls of the old application and mapping them into the new operating system. This was done by Windows NT to run DOS applications, and was only moderately compatible.</p>
<h3>Conclusion</h3>
<p>It is interesting how different the solutions for all these OS migrations were: There have been hardly two instances that followed the same approach. The reason for it might be that the situations were all subtly different, and a lot of time was spend to work out the perfect solution for the specific problem.</p>
<p>But there is a trend that can be seen: As systems are getting more modern, solutions tend to get less hacky, and migrations tend to happen in many small steps instead of few big steps. Modern operating systems like Windows NT and Mac OS X can be ported to new architectures quite easily, emulators help running old applications, and thunking can be used to interface with the native syscall interface. Because of the abstractions in a system, an operating system can be ported to a new architecture or a new CPU bitness in steps, with some parts in the new system, and others still in the old system. These abstractions also allow developers swapping out complete subsystems or rearchitecting parts of the operating system without much user impact. It is getting more and more convenient for OS developers &#8211; but unfortunately, it&#8217;s also getting less exciting.</p>
<h3>Links</h3>
<p>
<a href="http://books.google.com/books?id=1yozoAjCy7sC&#038;pg=PA26&#038;lpg=PA26&#038;dq=cp/m+syscall&#038;source=bl&#038;ots=f8LxqEhAaT&#038;sig=C4AgHRMhRWz_ofyeO-lFTU_b_-4&#038;hl=en&#038;ei=CsLuSb3RA6XotAOQ3pXkAQ&#038;sa=X&#038;oi=book_result&#038;ct=result&#038;resnum=6">1</a><a href="http://developer.apple.com/documentation/mac/PPCSoftware/PPCSoftware-12.html#HEADING12-0">2</a><a href="http://dogbert.mse.cs.cmu.edu/charlatans/References/Tech_Doc/Palm%20OS%205.0%20Docs/Palm%20OS%205%20ARM%20Programming.pdf">3</a><a href="http://www.macs.hw.ac.uk/~rjp/teaching/PUMA/samples/PNOLet/">4</a></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=152&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=152</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>The Easiest Way to Reset an i386/x86_64 System</title>
		<link>http://www.pagetable.com/?p=140</link>
		<comments>http://www.pagetable.com/?p=140#comments</comments>
		<pubDate>Thu, 23 Apr 2009 08:01:46 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>
		<category><![CDATA[trivia]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=140</guid>
		<description><![CDATA[Try this in kernel mode: uint64_t null_idtr = 0; asm("xor %%eax, %%eax; lidt %0; int3" :: "m" (null_idtr)); This can be quite helpful when doing operating system development on an i386/x86_64 system. You can use this for the regular restart case or when a kernel panic is supposed to restart immediately and you cannot make [...]]]></description>
			<content:encoded><![CDATA[<p>Try this in kernel mode:</p>
<pre>uint64_t null_idtr = 0;
asm("xor %%eax, %%eax; lidt %0; int3" :: "m" (null_idtr));</pre>
<p>This can be quite helpful when doing operating system development on an i386/x86_64 system. You can use this for the regular restart case or when a kernel panic is supposed to restart immediately and you cannot make any assumptions on what is still working in the system.</p>
<p>You can also use this for debugging very low-level code if you don&#8217;t have a serial port or even an LED to report the most basic information: First make sure your code is reached by putting the reset code there. Then remove it again and put this code in:</p>
<pre>if (condition)
    reset();
else
    for(;;);
</pre>
<p>The system will either hang or reset, depending on the condition.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=140&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=140</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>LodgeNet Reverse Engineering</title>
		<link>http://www.pagetable.com/?p=108</link>
		<comments>http://www.pagetable.com/?p=108#comments</comments>
		<pubDate>Tue, 21 Apr 2009 08:01:19 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=108</guid>
		<description><![CDATA[Many hotels (at least in the USA) equip their room TVs with a &#8220;LodgeNet&#8221; entertainment system. The TV will show regular free television channels, but also have an interactive channel controlled by the remote that features video on demand and video games. The setup consists of a regular TV, a set-top-box and a Nintendo 64 [...]]]></description>
			<content:encoded><![CDATA[<p>Many hotels (at least in the USA) equip their room TVs with a &#8220;LodgeNet&#8221; entertainment system. The TV will show regular free television channels, but also have an interactive channel controlled by the remote that features video on demand and video games.</p>
<p><img width="440" height="330" src="docs/lodgenet/setup.jpg" border="1"><br />The setup consists of a regular TV, a set-top-box and a Nintendo 64 controller.</p>
<p>If you play with the system a bit, it&#8217;s be quite easy to reverse engineer the architecture:</p>
<p><a href="docs/lodgenet/lodgenet.png"><img width="440" height="330" src="docs/lodgenet/lodgenet.png" border="1"></a></p>
<p>All TVs in the hotel are connected to the same internal TV cable. The cable carries one channel per room, and the TV is locked to that channel. This gives the TV a point-to-point channel to a multiplexer in the server room.</p>
<p>This analog multiplexer has the free-to-air channels as inputs as well as &#8220;channel 00&#8243;, which is the entertainment system. Another multiplexer switches channel 00 between the &#8220;welcome&#8221; screen and one of the servers. It is the servers that provide the image as soon as the user browses through the menu or selects video on demand or a game.</p>
<p><img width="330" height="440" src="docs/lodgenet/remote.jpg" border="1"><br />The remote is custom. The volume buttons will control the TV directly, and all other buttons are sent to the set-top-box.</p>
<p><img width="440" height="330" src="docs/lodgenet/controller.jpg" border="1"><br />The Nintendo 64 controller has extra buttons and a custom (RJ) connector.</p>
<p><img width="440" height="330" src="docs/lodgenet/set_top_box.jpg" border="1"><br />The set-top-box has an IR receiver at the front, and sits on the cable between the multiplexer in the server room and the TV (&#8220;CABLE IN&#8221;, &#8220;TV&#8221;), in order to be able to send the commands from the remote. &#8220;DATA&#8221; connects to the Nintendo 64 controller. It is unknown what &#8220;IR&#8221; and &#8220;MTI&#8221; would be for.</p>
<p><img width="220" height="165" src="docs/lodgenet/ch00.jpg" border="1"><img width="220" height="165" src="docs/lodgenet/ch2.jpg" border="1"><img width="220" height="165" src="docs/lodgenet/ch3.jpg" border="1"><img width="220" height="165" src="docs/lodgenet/ch36.jpg" border="1"><br />If you switch channels, the set-top-box tunnels the command to the multiplexer. The on-screen-display is generated by the multiplexer. Channel &#8220;00&#8243; is the entertainment system, which by default is connected to the &#8220;welcome&#8221; channel, a series of static screens that are hotel-global.</p>
<p><img width="440" height="330" src="docs/lodgenet/volume.jpg" border="1"><br />The volume button on the remote targets the TV directly. You can tell that the on-screen-display is generated by the TV and not the multiplexer.</p>
<p><img width="440" height="330" src="docs/lodgenet/channel_fixed.jpg" border="1"><br />Switching channels with the buttons on the TV itself does not succeed. Otherwise you could watch your neighbor&#8217;s channel.</p>
<p><img width="440" height="330" src="docs/lodgenet/please_wait.jpg" border="1"><br />If you press the MENU key, the second-level multiplexer will switch you away from the global &#8220;welcome&#8221; channel and connect you to one of the servers. Since most hotel guests do not use the entertainment system most of the time, the number of servers is only a fraction of the number of rooms. While the multiplexer is finding a free server, it displays a &#8220;Please Wait&#8221; picture for about a second.</p>
<p><img width="440" height="330" src="docs/lodgenet/main_menu.jpg" border="1"><br />The user is connected to the server that is now dedicated to his TV. Key presses on the remote (except volume and channel) will be sent to the server.</p>
<p>A very obvious attack on the system would be to connect the cable to a TV receiver that allows switching channels.</p>
<p>Does anyone know more about this system? How are the games done &#8211; emulation or dedicated N64 hardware? Are the movies streamed from disk? Is there a dedicated storage server? How is the system updated with new movies? What operating system are the servers running?</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=108&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=108</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Bringup History of Mac OS X</title>
		<link>http://www.pagetable.com/?p=121</link>
		<comments>http://www.pagetable.com/?p=121#comments</comments>
		<pubDate>Tue, 14 Apr 2009 07:09:46 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=121</guid>
		<description><![CDATA[The heritage of different operating systems has been discussed many times. Mac OS X includes code from Mach and BSD, AmigaOS is based on TRIPOS, MS-DOS is a CP/M-86 clone and Windows NT is modeled after VMS. But what machines and operating systems were used for cross-compilation and bringup of these systems? In order to [...]]]></description>
			<content:encoded><![CDATA[<p>The heritage of different operating systems has been discussed many times. Mac OS X includes code from Mach and BSD, AmigaOS is based on TRIPOS, MS-DOS is a CP/M-86 clone and Windows NT is modeled after VMS. But what machines and operating systems were used for cross-compilation and bringup of these systems? In order to find this out about Mac OS X, I talked to a few people working at NEXT and Apple, and people that worked on Mach and BSD.</p>
<p>Currently, Apple only ships Intel-based machines. Mac OS X for Intel was released in 2006. The Intel version had been &#8220;leading a secret double life&#8221; since 2000, i.e. Mac OS X existed for Intel all the time, but was not released. In that time, Mac OS X was never self-hosting; instead, it was cross-compiled on PowerPC Macs. The first released version of Intel Mac OS X was a version of 10.4 for the Pentium 4 based &#8220;Developer Transition Kit&#8221; in 2005.</p>
<p>The first version of what would later be Mac OS X was &#8220;Rhapsody DR1&#8243; released in 1997. It ran on PowerPC 604 Macintoshes (the 603 was not supported because it lacked a hardware pagetable walker) and was cross-compiled from OpenStep 4.2 running on Intel Pentium II CPUs. Rhapsody, which was basically OpenStep 5.0, also continued to run on Intel, but as mentioned before, Intel became a second-class architecture. Actually, somewhere between Rhapsody and OS X 10.0, there was a time when the GUI was not built for Intel.</p>
<p>Nextstep 3.1 from 1993 was the first version of Nextstep/OpenStep to support Intel CPUs (and also PA-RISC and SPARC) next to the existing Motorola 68K support. Bringup was done on a 25 MHz 68040 NeXTstation running NextStep 2.1, and the target CPU was a 486DX50.</p>
<p>At NEXT, the systems used for bringup of the original 68030 NeXT Computer were Sun machines running SunOS 3.0, a BSD-derivative. The NEXT engineers ported the Mach 2.0 kernel from VAX to M68K. So this port was not only cross-architecture, but cross-OS.</p>
<p>Mach 1.0 was first written for VAX and was brought up on VAX-based 4.2BSD machines at Carnegie-Mellon University. Coincidently, 4.2BSD evolved into SunOS 1.0 (and 4.2BSD/VAX machines were used for its bringup), and the BSD codebase also ended up in Nextstep.</p>
<p>Now that we arrived at BSD, we could go back the history of UNIX, which I am not going to do at this point.</p>
<p><img width="440" height="330" src="docs/osx_bringup/osx_bringup.png" border="1"></p>
<p>So, to summarize, BSD/VAX was used to develop Mach/VAX, and SunOS/M68K was used to port Mach to 68K, Nextstep/68K was used to port itself to i386, and the i386 version to port itself to PowerPC, and then the PowerPC version to maintain the i386 version. Today, Mac OS X for Intel is self-hosting again.</p>
<p>Now I would love to see is the same kind of bringup history for Linux (Minix, &#8230;), AmigaOS (SunOS 1.x, &#8230;), BeOS, Copland (Mac OS?), Windows NT (VMS? DOS?), OS/2 (DOS? AIX?), MS-DOS (CP/M?), and of course the common bringup ancestors of so many systems, BSD and UNIX. It would also be interesting to extend this information with the respective compilers used. So if you can contribute something in the comments here or on your blogs, that would be great.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=121&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=121</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>cbmbasic 1.0 with Plugins</title>
		<link>http://www.pagetable.com/?p=114</link>
		<comments>http://www.pagetable.com/?p=114#comments</comments>
		<pubDate>Wed, 08 Apr 2009 06:07:19 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=114</guid>
		<description><![CDATA[I moved cbmbasic development to SourceForge and released version 1.0, which has the following added features: RDTIM/SETTIM support (George Talbot) LOAD&#8221;$&#8221; on Win32 (Lorenzo) RND() is now random (Wolfram Sang) The C code now hooks into the cbmbasic plugin infrastructure. This lets developers add additional statements, functions etc. Right now, you can turn this on [...]]]></description>
			<content:encoded><![CDATA[<p>I moved cbmbasic development to <a href="http://cbmbasic.sourceforge.net/">SourceForge</a> and released version 1.0, which has the following added features:</p>
<ul>
<li>RDTIM/SETTIM support (George Talbot)</li>
<li>LOAD&#8221;$&#8221; on Win32 (Lorenzo)</li>
<li>RND() is now random (Wolfram Sang)</li>
<li>The C code now hooks into the cbmbasic plugin infrastructure. This lets developers add additional statements, functions etc. Right now, you can turn this on with &#8220;SYS 1&#8243; (turn off with &#8220;SYS 0&#8243;), and use the new statements LOCATE <i>y</i>,<i>x</i> (set cursor position), SYSTEM <i>string</i> (run command line command) and the extended WAIT <i>port</i>,<i>mask</i>, which implements the <a href="http://www.pagetable.com/?p=43">Bill Gates easter egg</a>.</li>
</ul>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=114&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=114</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Amiga/Lorraine Mugs</title>
		<link>http://www.pagetable.com/?p=95</link>
		<comments>http://www.pagetable.com/?p=95#comments</comments>
		<pubDate>Tue, 07 Apr 2009 02:56:26 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[hacks]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=95</guid>
		<description><![CDATA[Every touristy place has them: Souvenirs with given names on them. If you have an uncommon name, or a friend with an uncommon name, you might look through the whole collection &#8211; and notice that they have generic ones like &#8220;#1 FRIEND&#8221; (i case you really don&#8217;t find your friend&#8217;s name), and, sometimes, generic ones [...]]]></description>
			<content:encoded><![CDATA[<p>Every touristy place has them: Souvenirs with given names on them. If you have an uncommon name, or a friend with an uncommon name, you might look through the whole collection &#8211; and notice that they have generic ones like &#8220;#1 FRIEND&#8221; (i case you really don&#8217;t find your friend&#8217;s name), and, sometimes, generic ones in Spanish.</p>
<p>Who can resist a Las Vegas souvenir mug with &#8220;AMIGA&#8221; on it? Especially if you can get &#8220;AMIGA&#8221; and &#8220;LORRAINE&#8221; together at twice the price?</p>
<p><img width="220" height="240" src="docs/amiga_lorraine/mug_amiga.jpg"><img width="220" height="240" src="docs/amiga_lorraine/mug_lorraine.jpg"></p>
<p>Note to self: I travel too much.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=95&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=95</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zuse Z1 at the Deutsches Technikmuseum</title>
		<link>http://www.pagetable.com/?p=86</link>
		<comments>http://www.pagetable.com/?p=86#comments</comments>
		<pubDate>Sat, 04 Apr 2009 03:11:20 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=86</guid>
		<description><![CDATA[My last blog post showed the Zuse Z3 (1939-1941), the world&#8217;s first working digital Turing-complete computer. Let&#8217;s go back two more steps: The Zuse Z1 (1936-1938) shared its design with the Z3: It read its program from punched film and used floating point as its internal representation of numbers. But since it was all mechanical, [...]]]></description>
			<content:encoded><![CDATA[<p>My last blog post showed the <a href="http://www.pagetable.com/?p=74">Zuse Z3</a> (1939-1941), the world&#8217;s first working digital Turing-complete computer. Let&#8217;s go back two more steps: The Zuse Z1 (1936-1938) shared its design with the Z3: It read its program from punched film and used floating point as its internal representation of numbers. But since it was all mechanical, it never worked reliably.</p>
<p>Just like the Z3, the Z1 was destroyed in the second world war. The <a href="http://www.dtmb.de/index_en.html">Deutsches Technikmuseum</a> in Berlin has a replica built by Zuse in the 1980s &#8211; but it&#8217;s not working either.</p>
<p><center></p>
<p><a href="docs/zuse/deutsches_technikmuseum_zuse_z1.mp4"><img width="384" height="288" src="docs/zuse/deutsches_technikmuseum_zuse_z1.jpg"><br />(MP4/H.264 Video, 384&#215;288, 00:42 min, 12.5 MB)</a></p>
<p><a href="docs/zuse/zuse_ehrenurkunde_schaufelbagger.jpg"><img width="440" height="274" src="docs/zuse/zuse_ehrenurkunde_schaufelbagger.jpg" border="1"></a><br />
<br />In 1925, Zuse receives an award document for his shovel excavator from the firm Walthers Metallbaukasten.</p>
<p><a href="docs/zuse/patent_zuse_speicher.pdf"><img width="243" height="330" src="docs/zuse/patent_zuse_speicher.png" border="1"></a><br />
<br />Patent application for mechanical memory (1937)</p>
<p><a href="docs/zuse/zuse_z1_living_room.jpg"><img width="300" height="200" src="docs/zuse/zuse_z1_living_room.jpg" border="1"></a></p>
<p>The Z1 in the living room of Zuse&#8217;s parents in Kreuzberg, Berlin (1937).</p>
<p></center></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=86&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=86</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zuse Z3 at the Deutsches Museum</title>
		<link>http://www.pagetable.com/?p=74</link>
		<comments>http://www.pagetable.com/?p=74#comments</comments>
		<pubDate>Sat, 31 Jan 2009 11:14:15 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=74</guid>
		<description><![CDATA[The Z3 by Konrad Zuse was the world&#8217;s first working digital Turing-complete computer. It did floating point arithmetic, had two registers accessible to the programmer, was microcoded, and clocked at about 5 Hz. The original Z3 was destroyed in the second world war. The Deutsches Museum in Munich has the only working replica, built by [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://en.wikipedia.org/wiki/Z3_(computer)">Z3</a> by <a href="http://en.wikipedia.org/wiki/Konrad_Zuse">Konrad Zuse</a> was the world&#8217;s first working digital <a href="http://www.zib.de/zuse/Inhalt/Kommentare/Html/0684/universal2.html">Turing-complete</a> computer. It did floating point arithmetic, had two registers accessible to the programmer, was microcoded, and clocked at about 5 Hz.</p>
<p>The original Z3 was destroyed in the second world war. The <a href="http://www.deutsches-museum.de/">Deutsches Museum</a> in Munich has the only working replica, built by Zuse in the 1960s.</p>
<p>Here is a video of a demonstration of the Z3, including a lot of biographical information on Zuse. If you speak German, you will be blown away by the wit of the presenter; if you don&#8217;t, enjoy the clicking relays!</p>
<p><center><a href="docs/zuse/deutsches_museum_zuse_z3.mp4"><img width="384" height="288" src="docs/zuse/deutsches_museum_zuse_z3.jpg"><br />(MP4/H.264 Video, 384&#215;288, 14:30 min, 31 MB)</a></center></p>
<p><i>Zuse Apparatebau: Er kriegte sogar noch drei ArbeitskrĂ¤fte. Das waren die, die sonst keiner mehr haben wollte. Die Zuse-Firma bestand aus ihm selber, der Chef, dann ein vorbestrafter Buchhalter, ein blinder Mathelehrer &#8211; der hat die Filme gelocht&#8230; ja, der hat das Tag und Nacht gemacht &#8211; das war dem auch wurscht, ob&#8217;s Tag oder Nacht war. Und dann kam noch ein Konstrukteur aus einer Nervenheilanstalt. Was sehen wir an der Story? In der Branche waren immer schon die abgefahrensten Typen!</i></p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=74&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=74</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Archimedes Operating System (PDF)</title>
		<link>http://www.pagetable.com/?p=68</link>
		<comments>http://www.pagetable.com/?p=68#comments</comments>
		<pubDate>Mon, 26 Jan 2009 01:03:33 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[literature]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=68</guid>
		<description><![CDATA[Van Someren, Alex, and Nic Van Someren.Archimedes Operating System. A Dabhand guide.Prestwich: Dabs Press, 1991.ISBN 1-870336-48-8(320 pages, 7.5 MB PDF) For Archimedes users who take their computing seriously, this guide to the Operating System gives you a real insight into the micro&#8217;s inner workings. The book is applicable to any model of Archimedes whether running [...]]]></description>
			<content:encoded><![CDATA[<p><a href="docs/Archimedes Operating System.pdf"><img src="docs/Archimedes Operating System.png" width="440" height="700"><br />
Van Someren, Alex, and Nic Van Someren.<br />Archimedes Operating System. A Dabhand guide.<br />Prestwich: Dabs Press, 1991.<br />ISBN 1-870336-48-8</a><br />(320 pages, 7.5 MB PDF)</p>
<table border="1">
<tr>
<td>
<p>For Archimedes users who take their computing seriously, this guide to the Operating System gives you a real insight into the micro&#8217;s inner workings. The book is applicable to any model of Archimedes whether running the Arthur or RISC OS Operating Systems.</p>
<p>The Relocatable Module system is one of the many areas covered â its format is explained, and the information necessary to enable you to write your own modules and applications is provided. This tutorial approach is repeated through the book.</p>
<p>The sound system is explained and the text includes much information never before published.</p>
<p>The discerning user will revel in the wealth of information covering many aspects of Arthur and RISC OS including:</p>
<p><ui></p>
<li>The ARM Instruction Set</li>
<li>Writing Relocatable Modules</li>
<li>Writing Applications</li>
<li>VIDC, MEMC and IOC</li>
<li>Sound</li>
<li>The Voice Generator</li>
<li>SWIs</li>
<li>Vectors and Events</li>
<li>Command Line Interpreter</li>
<li>The FileSwitch Module</li>
<li>Floating Point Model</li>
</ul>
<p>and much more&#8230;</p>
<p>Throughout the book, programs are used to provide practical examples to use side by side with the text, which go to make this publication <i>the</i> table-side companion for all Archimedes users.</p>
<p>Alex and Nic van Someren have both worked for Acorn Computers. Alex is a former Technical Editor of <i>Acorn User</i> magazine and author of numerous computer-related books.</p>
</td>
</tr>
</table>
<p>In my <a href="http://www.pagetable.com/?cat=9">quest to preserve retrocomputing documents</a>, here is a very interesting reference of the orginal Acorn RISC Machine (ARM) computing platform and the RISC OS Operating System. Thanks to Dominik Wagner for the book. As always, my scanned books come with a table of contents and are fully searchable.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=68&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=68</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Amiga &amp; Supergrips</title>
		<link>http://www.pagetable.com/?p=56</link>
		<comments>http://www.pagetable.com/?p=56#comments</comments>
		<pubDate>Thu, 15 Jan 2009 11:41:50 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=56</guid>
		<description><![CDATA[This article is in German, since it is about the German TV show &#8220;Supergrips&#8221; and how the scoreboard was implemented. Supergrips war eine Spielshow des Bayerischen Rundfunks in Zusammenarbeit mit dem Mitteldeutschen Rundfunks, die von 1988 bis 1995 ausgestrahlt wurde. Was besonders interessant war: Die Spielwand wurde auf einem Amiga gemacht, in einer Kombination aus [...]]]></description>
			<content:encoded><![CDATA[<p><i>This article is in German, since it is about the German TV show &#8220;Supergrips&#8221; and how the scoreboard was implemented.</i></p>
<p><a href="http://de.wikipedia.org/wiki/Supergrips">Supergrips</a> war eine Spielshow des Bayerischen Rundfunks in Zusammenarbeit mit dem Mitteldeutschen Rundfunks, die von 1988 bis 1995 ausgestrahlt wurde.</p>
<p>Was besonders interessant war: Die Spielwand wurde auf einem <b>Amiga</b> gemacht, in einer Kombination aus Basic und Assembler. So sieht es aus, wenn eine neue Wand ge&ouml;ffnet wird:</p>
<p><a href="docs/supergrips/supergrips1.mp4"><img width="440" height="330" src="docs/supergrips/supergrips1.jpg"><br />(MP4/H.264 Video, 768&#215;576)</a></p>
<p>So gewinnt man einen Block:</p>
<p><a href="docs/supergrips/supergrips2.mp4"><img width="440" height="330" src="docs/supergrips/supergrips2.jpg"><br />(MP4/H.264 Video, 768&#215;576)</a></p>
<p>Und so sieht es aus, wenn man eine Runde gewinnt:</p>
<p><a href="docs/supergrips/supergrips3.mp4"><img width="440" height="330" src="docs/supergrips/supergrips3.jpg"><br />(MP4/H.264 Video, 768&#215;576)</a></p>
<p>Programmiert wurde das ganze 1986/1987 von <a href="http://seibold.net/">Stefani Seibold</a> aus M&uuml;nchen, die mir auf meine Anfrage hin ein wenig &uuml;ber die Hintergr&uuml;nde erz&auml;hlte:</p>
<p><i></p>
<p>Der BR wollte eine Spielshow aus GB &uuml;bernehmen, leider war daf&uuml;r so eine Tafel wie beim gro&szlig;en Preis oder Jeopardy erfoderlich, welche gut und gerne 100.000 DM und mehr kosten w&uuml;rde. Das war f&uuml;r eine billige Jugendsendung zu teuer.</p>
<p>So fragte mich ein Redaktuer vom BR, ob es nicht noch einen anderen Weg geben w&uuml;rde, z.B. mit dem Amiga.</p>
<p>So dachte ich ein bischen dr&uuml;ber nach um kam zum Schlu&szlig;, da&szlig; das ganze durchaus mit dem Basic der Kiste zu realisieren sei. Nur die Steuerung machte etwas Probleme, wie sollte man die Felder m&ouml;glichst Fehlerfrei anw&auml;hlen? Tastatur-K&uuml;rzel, no way, das w&auml;re nicht intuitiv und schnell zu zuordnen. Also ersann ich den 1 Pixel gro&szlig;en Maus Cursor.</p>
<p>Den sieht man normalerweise nur dann, wenn man wei&szlig;, da&szlig; er da ist und wo er ist. Auf den alten PAL Fernsehern von damals wurde der sowieso von fast allen Modellen verschmiert.</p>
<p>Aber wenn man genau hinsieht, dann kann man den 1 Pixel Cursor auch sehen ;-)</p>
<p>Leider war ich keine so gute Grafikerin, so wurde das Projekt dann nach den ersten Pilot-Aufnahmen noch einmal von einen mehr erfahren Entwickler &uuml;bernommen, der dann noch die Sterne, die r&auml;umlich Tiefe u.a. einbaute.</p>
<p></i></p>
<p>Danke Stefani!</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=56&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=56</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The Ultimate Commodore 64 Talk: Pushing Keynote to its Limits</title>
		<link>http://www.pagetable.com/?p=55</link>
		<comments>http://www.pagetable.com/?p=55#comments</comments>
		<pubDate>Mon, 12 Jan 2009 09:23:41 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=55</guid>
		<description><![CDATA[Download the Apple Keynote 08 presentation.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.pagetable.com/docs/The Ultimate Commodore 64 Talk.zip">Download</a> the Apple Keynote 08 presentation.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=55&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=55</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The Ultimate Commodore 64 Talk: Video Recording</title>
		<link>http://www.pagetable.com/?p=54</link>
		<comments>http://www.pagetable.com/?p=54#comments</comments>
		<pubDate>Wed, 31 Dec 2008 08:28:32 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=54</guid>
		<description><![CDATA[Link: Thanks to F!XMBR for providing the flash video. Additionally, here are a few links to the video recording of the talk: Bittorrent (OGG), Mirror 1 (OGG), Mirror 1 (WMV), Mirror 2 (OGG), Mirror 2 (WMV), Mirror 3 (OGG), Mirror 3 (WMV), Mirror 4 (OGG), Mirror 4 (WMV), Mirror 5 (OGG) The OGG version seems [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript" src="http://de.sevenload.com/pl/6aSoxEC/500x366"></script>
<p>Link: <a href="http://de.sevenload.com/videos/6aSoxEC-25C3-The-Ultimate-Commodore-64-Talk"><img src="http://static.sevenload.com/img/sevenload.png" width="66" height="10" alt="25C3: The Ultimate Commodore 64 Talk" /></a></p>
<p>Thanks to <a href="http://www.fixmbr.de/25c3-the-ultimate-commodore-64-talk/">F!XMBR</a> for providing the flash video.</p>
<p>Additionally, here are a few links to the video recording of the talk:</p>
<p>
<a href="http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main">Bittorrent (OGG)</a>, <a href="ftp://25c3.sys-panel.de/25c3-mirror/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A03+0100.ogm">Mirror 1 (OGG)</a>, <a href="ftp://25c3.sys-panel.de/25c3-mirror/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A04+0100.wmv">Mirror 1 (WMV)</a>, <a href="ftp://25c3videos.lug-in.de/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A03+0100.ogm">Mirror 2 (OGG)</a>, <a href="ftp://25c3videos.lug-in.de/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A04+0100.wmv">Mirror 2 (WMV)</a>, <a href="ftp://mirror.sys-panel.de/25c3-mirror/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A03+0100.ogm">Mirror 3 (OGG)</a>, <a href="ftp://mirror.sys-panel.de/25c3-mirror/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A04+0100.wmv">Mirror 3 (WMV)</a>, <a href="http://mirror.informatik.uni-mannheim.de/pub/ccc/streamdump/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A03+0100.ogm">Mirror 4 (OGG)</a>, <a href="http://mirror.informatik.uni-mannheim.de/pub/ccc/streamdump/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A04+0100.wmv">Mirror 4 (WMV)</a>, <a href="http://c3.thematrix-reloaded.de/25c3/realtime/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A03+0100.ogm">Mirror 5 (OGG)</a>
</p>
<p>The OGG version seems to be in better quality. I&#8217;ll post new links as soon as the talk is available in a standards-compliant version (MPEG-4).</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=54&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=54</wfw:commentRss>
		<slash:comments>15</slash:comments>
<enclosure url="http://mirror.informatik.uni-mannheim.de/pub/ccc/streamdump/saal2/Tag3-Saal2-Slot16%3A00--ID2874-the_ultimate_commodore_64_talk-Main-2008-12-29T16%3A00%3A04+0100.wmv" length="761013587" type="video/x-ms-wmv" />
		</item>
		<item>
		<title>The Ultimate Commodore 64 Talk @25C3</title>
		<link>http://www.pagetable.com/?p=53</link>
		<comments>http://www.pagetable.com/?p=53#comments</comments>
		<pubDate>Mon, 15 Dec 2008 22:15:23 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=53</guid>
		<description><![CDATA[Update: Video recording available. I am going to present The Ultimate Commodore 64 Talk (Everything about the C64 in 64 Minutes) at the 25th Chaos Communication Congress 2008 (25C3) in Berlin on 29 Dec 2008. The following article, which will be printed in the Congress Proceedings, is supposed to give you an overview of what [...]]]></description>
			<content:encoded><![CDATA[<p><i>Update:</i> <a href="http://www.pagetable.com/?p=54">Video recording</a> available.</p>
<p>I am going to present <a href="http://events.ccc.de/congress/2008/Fahrplan/events/2874.en.html">The Ultimate Commodore 64 Talk</a> (Everything about the C64 in 64 Minutes) at the <a href="http://events.ccc.de/congress/2008/">25th Chaos Communication Congress 2008 (25C3)</a> in Berlin on 29 Dec 2008. The following article, which will be printed in the Congress Proceedings, is supposed to give you an overview of what I am going to talk about. If you cannot attend 25C3, you will be able to watch a recoding afterwards, which I am going to link to. And yes, it is a lot of information, and it&#8217;ll be about 256 slides (in 64 minutes) &#8211; that is exactly the challenge. If you don&#8217;t believe I cannot present all this in a way that the audience can understand it: Watch it!</p>
<hr />
<p>Retrocomputing is cool as never before. People play C64 games in emulators and listen to SID music, but few people know much about the C64 architecture and its limitations, and what programming was like back then. This paper attempts to give a comprehensive overview of the Commodore 64, including its internals and quirks, making the point that classic computer systems aren&#8217;t all that hard to understand &#8211; and that programmers today should be more aware of the art that programming once used to be.</p>
<h3>Commodore History</h3>
<p>The company that became Commodore Business Machines was founded in 1954 by Jack Tramiel. The company specialized on electronic calculators, and in 1976, Commodore bought the chip manufacturer MOS Technology and decided to have Chuck Peddle from MOS evolve their KIM-1 computer kit (a design that demos their new MOS 6502 8 bit CPU) into the Commodore PET series: computers with built-in monitors for the home, school and small business market that ended up competing with devices from Atari and Apple.</p>
<p>In 1981, Commodore introduced the VIC-20, a 5 KB stripped down monitorless computer-in-the-keyboard design based on the PET for the home computer market. This was followed by the (incompatible) higher-end Commodore 64 in 1982 that included more PET features, came with 64 KB of RAM (an immense amount compared to the rest of the market) and was very aggressively priced at US$595 beating the competition by a factor of two. This was made possible by designing and building most of the system in-house.</p>
<p>Although some features of the C64 were taken from the PET models of the time, it had to be connected to a TV set, which only made 40 columns of text possible (as opposed to then-current 80 columns on the PET). Also, the BASIC 4.0 codebase was stripped down to the old 2.0 feature set to make it fit into 8 KB.</p>
<p>In the beginning, the C64 did well in the competition. The superior but compatible C128 from 1985 did well, too, but was never more popular than the C64, which continued to be sold. The direct successor to the low-end VIC-20, the 1984 Plus/4 and its siblings, the C16 and the C116, failed, mostly because they were incompatible with the C64, which at that time already had a remarkable software library.</p>
<p>A few years after the introduction, the C64 was still offered as a low-end alternative to the Commodore Amiga, and while it became less popular in the USA, it gained more and more popularity in Europe. In the early 90s, when manufacturing costs of a C64 were as low as $25, it gained a second life in Eastern Europe. Production did not end until the liquidation of Commodore in 1994. According to the 1993 Annual Report, 17 million C64 had been produced in by then, as well as 4.5 million C128.</p>
<h3>Look and Feel</h3>
<p>A C64 only needs to be connected to power and a TV set (or monitor) to be fully functional. When turned on, it shows a blue-on-blue theme with a startup message and drops into a BASIC interpreter derived from Microsoft BASIC. In order to load and save BASIC programs or use third party software, the C64 requires mass storage &#8211; either a âdatasetteâ cassette tape drive or a disk drive like the 5.25&#8243; Commodore 1541.</p>
<p>Unless the user really wanted to interact with the BASIC interpreter, he would typically only use the BASIC instructions LOAD, LIST and RUN in order to access mass storage. LOAD&#8221;$&#8221;,8 followed by LIST shows the directory of the disk in the drive, and LOAD&#8221;filename&#8221;,8 followed by RUN would load and start a program. If a tape drive is connected, LOAD and RUN will launch the first program on tape &#8211; pressing SHIFT and the RUN/STOP key has the same effect.</p>
<p>By default, typing characters without SHIFT will result in upper case characters being shown on the screen. This can be changed by pressing the Commodore key and SHIFT at the same time, which switches to the upper/lower character set. This behavior is due to the fact that the first PET only had uppercase characters, and that BASIC required keywords unshifted &#8211; but all tutorials taught them as uppercase. This is also the reason why in Commodore&#8217;s version of ASCII, called PETSCII, the codes for uppercase and lowercase characters are reversed.</p>
<p>The text based user interface is not a line editor, but a screen editor, i.e. the cursor can be moved freely on the screen, and pressing RETURN on a line with existing text will present the text to the application as if it were just typed in.</p>
<p>While a physical screen line is only 40 characters, the screen editor logic can extend it to a logical 80 characters &#8211; whenever a character is entered on the 40th column, the rest of the screen is moved down by one line, âopeningâ a line that extends the previous line to 80 characters.</p>
<p>The C64 screen editor supports selecting one out of 16 color for the foreground text by pressing the key combinations Ctrl+1 to Ctrl+8 and Commodore+1 to Commodore+8. Reverse text mode can be turned on and off with Ctrl+9 and Ctrl+0.</p>
<h3>Ports and Connections</h3>
<p>The C64 has a whole range of connection possibilities. On the side, it has two 9 pin Atari-style joystick connectors that can also be used for a mouse, light pens or paddles. On the back, there is the expansion port, which exports the complete processor bus, allowing not only game cartridges but also cartridges with I/O chips that map themselves into the CPU&#8217;s address space &#8211; or even cartridges that completely replace the CPU. For a conventional TV connection, there is an RCA connector that outputs an RF signal. For monitors, there is an extra DIN connector that carries separate chroma, luma and audio signals (although not 100% S-Video, it is compatible with a lot of S-Video equipment).</p>
<p>For connecting Commodore compatible printers and disk drives, there is a DIN connector for the IEC bus. There is also a dedicated connector for datasette drives. The âUser Portâ consists of several GPIO pins that can be used for custom hardware projects, or as a RS-232 port (with TTL levels), for which support exists in the ROM.</p>
<h3>Board</h3>
<p>On the C64 motherboard, there is a dedicated IC each for the main tasks. There is the MOS 6510 CPU, eight 64 KBit RAM chips (later consolidated into 2), three ROM chips with KERNAL (I/O library), BASIC and the character set (KERNAL and BASIC were later consolidated), two 6526 CIA I/O controllers (one for keyboard and joystick, one for the IEC bus and the user port), the 6581 SID sound chip, and the 6567/6569 VIC video chip, as well as the  RAM chip that holds the 512 bytes of Color RAM.</p>
<p>All non-RAM chips are custom chips designed manufactured by MOS, Commodore&#8217;s inhouse chip company.</p>
<h3>Address Space</h3>
<p>The 8 bit C64 design has a 16 bit address bus, allowing the CPU to address 64 KB of memory. Since the C64 has 64 KB of RAM, filling the complete address space, ROM and I/O chips are mapped into regions of the address space that are shared with RAM: The CPU can switch these regions between RAM and a second or third mapping. These regions are as follows:</p>
<ul>
<li>$0000-$9FFF: RAM
<li>$A000-$BFFF: RAM or BASIC ROM
<li>$C000-$CFFF: RAM
<li>$D000-$DFFF: RAM or memory mapped I/O chips or character ROM
<li>$E000-$FFFF: RAM or KERNAL ROM
</ul>
<p>In contrast to CPUs like the Z80 and the 8086, and like most modern CPUs, I/O devices are memory mapped on the C64&#8242;s 6510 CPU. The mapping is as follows:</p>
<ul>
<li>$D000-$D3FF: VIC video controller
<li>$D400-$D7FF: SID sound controller
<li>$D800-$DBFF: Color RAM
<li>$DC00-$DCFF: CIA 1 I/O controller
<li>$DD00-$DDFF: CIA 2 I/O controller
<li>$DE00-$DFFF: for extensions on the expansion port
</ul>
<h3>6502 CPU</h3>
<p>The CPU inside the C64 is a 0.985 MHz (on PAL) MOS 6510, which is a close derivative of the well-known 8 bit little-endian MOS 6502. The 6502 was introduced in 1975 by MOS Technology, a company formed earlier the same year by former Motorola engineers, with engineering headed by Chuck Peddle. The philosophy of the 6502 was to have a reduced instruction set and a small register file, making it simpler and faster than CPUs like the Z80 at the same clock speed, as well as cheaper to manufacture.</p>
<p>Unlike most modern CPUs, the 6502 does not have a set of general purpose registers. Instead, it has a single accumulator A (for arithmetic and logic), two index registers X and Y (for incrementing, decrementing and indexing memory) and a stack pointer. All  these registers are 8 bits. The processor status, consisting of the negative (N), overflow (V), break (B), decimal (D), interrupt (I), zero (Z) and carry (C) flags is exposed as register P. The program counter (PC) is 16 bits wide. The fact that the stack pointer is 8 bit means that the stack is confined to the area between $0100 and $01FF in the address space, i.e. the upper half of the effective stack pointer is hard-coded to $01. There is another special area in the address space: The first 256 bytes, at $0000 to $00FF are referred to as the zero page (ZP). Many instructions support special encodings for zero page addresses, which saves one byte in the instruction encoding as well as at least one cycle of execution time. This can be seen as an extension of the register file to another 256 (though external) registers.</p>
<p>All opcodes are one byte, and have 0, 1 or 2 byte operands. The 8&#215;8 opcode matrix is somewhat logical (e.g. branch instructions are encoded as $10, $30, $50, &#8230;), but there is no easy rule to construct the opcode table. Nevertheless, the opcode table is a minimal encoding for optimal decoding in the 6502&#8242;s internal PLA ROM.</p>
<h4>Instruction Set</h4>
<p>The instruction set is very streamlined, and avoids redundancies. There are load instructions (LDA/LDX/LDY to load A, X and Y respecively), store instructions (STA/STX/STY), read-modify-write instructions (logic: ASL/LSR/ROL/ROR, count: INC/DEC), arithmetic (ADC/SBC; note that these always include the carry: CLC/ADC is a regular addition, and SEC/SBC is a regular subtraction, because of the one&#8217;s complement logic), compare (CMP/CPX/CPY; these are subtractions without storing the result), logic (AND/ORA/EOR, and BIT, which is AND without storing the result), as well as branch instructions, flag manipulation, register transfer and stack manipulation.</p>
<h4>Addressing Modes</h4>
<p>Each instruction supports one or more addressing modes. Common instructions like LDA (load accumulator) support more addressing modes than less common ones (BIT).</p>
<ul>
<li>The immediate addressing mode is indicated with a # sign: LDA #$17 loads the immediate value of $17 into the accumulator.
<li>Absolute addressing specifies a 16 bit address as an operand: LDA $0314 loads from the memory address $0314.
<li>Zero page addressing is an optimized version of absolute addressing: LDA $02 will read from address $0002 in memory, but the instruction can be encoded more tightly, and execution is faster.
<li>Absolute-X-indexed addressing reads from a specified address, to which the contents of the X register is added. LDA $0200,X reads from the address $020A, in case X is $0A. This allows reading from tables.
<li>Absolute-Y-indexed is the same thing, but with the Y register.
<li>Zero-Page-X-indexed is an optimized version of Absolute-X-indexed. LDA $F0,X reads from the Xth location in a table stored starting at $00F0 in memory. Note that all zero page addresses will wrap around, so $F0 + $10 = $00.
<li>Zero-Page-Y-indexed is the same thing, but with the Y register.
<li>Zero-Page-X-indexed-indirect adds X to a specified zero page address, reads a 16 bit pointer from the resulting address and finally accesses memory at that address. So LDA ($80,X) will read from an address specified by the array of pointers at $0080 and the index X into the array. This addressing mode is rarely used.
<li>Zero-Page-indirect-Y-indexed treats two consecutive bytes in zero page as an address and adds Y to the address. LDA ($14),Y will read from $E020, if the address stored at $14/$15 is $E000 and Y is $20. This addressing mode is the most convenient way to work with pointers, as no register can hold 16 bits.
</ul>
<h4>Register Transfer and Stack</h4>
<p>There are several 1 byte instructions without operands that move data between registers. TAX, TXA, TAY and TYA move between A, X and Y. TSX and TXS copies between X and the stack pointer.</p>
<p>The stack pointer always points to the next address that is written to. This means that an empty stack has a stack pointer of $FF, and pushing a value first writes the value and then decrements the stack pointer. The 6502 can move the accumulator from and to the stack (PHA/PLA), as well as the processor status P (PHP/PLP).</p>
<h4>Control Transfer</h4>
<p>Next to the absolute JMP instruction, there is an indirect version that jumps over a vector (e.g. JMP ($FFFC)). JSR (jump to subroutine) only has an absolute version, and stores the address of the next instruction minus one on the stack. RTS (return from subroutine) takes the address from the stack, adds one, and moves it into the program counter. The âminus oneâ logic was chosen because it could save one cycle in the implementation of JSR.</p>
<p>A hardware interrupt, unless disabled by a set interrupt (I) flag, pushes the address of the next instruction minus one (just like JSR), pushes the processor status afterwards, disables interrupts, and jumps over the vector at $FFFE/$FFFF. RTI return from interrupt) is the same as the combination of PLP and RTS. BRK causes a software interrupt and behaves the same as a hardware interrupt, except that it sets the B flag in the processor status on the stack to 1 (a hardware interrupt sets it to 0). Note that the B flag does not exist in the actual processor status register, the corresponding bit is only used in a status byte on the stack.</p>
<p>From a software perspective, NMIs behave the same as IRQs, but they cannot be masked, and they use the $FFFA/$FFFB vector. The reset vector is at $FFFC/$FFFD.</p>
<h4>Flags and Branches</h4>
<p>All load and logic instructions set N and Z accordingly, shift instructions also modify C, and arithmetic instructions touch N V, Z and C. The D (decimal), I (interrupt disable) and C flags can be set and cleared programmatically (CLD/SED, CLI/SEI, CLC/SEC), while the V flag can only be cleared (CLV). Conditional branches are possible based on the value of the negative (BPL/BMI), overflow (BVC/BVS), zero (BNE/BEQ) and carry (BCC/BCS) flags. Branches encode an 8 bit relative offset and can therefore reach code in the area of +127 and -128, counting from the byte after the branch instruction. Since a compare is the same as a subtraction, BCC is a branch on (unsigned) below, and BCS is a branch on above-or-equal.</p>
<h4>NOP</h4>
<p>NOP (no operation) does nothing. Its encoding is $EA.</p>
<h4>Decimal Mode</h4>
<p>If the D flag is set, all ADC and SBC operations will be BCD-adjusted afterwards, i.e. $09+$02 won&#8217;t be $0B, but $11, since 9+2=11. The BCD correction circuit has been patented in US patent 3,991,307.</p>
<h4>Cycle Counting</h4>
<p>It is quite straightforward to find out how many cycles an instruction takes. As a rule of thumb, an instruction takes as many cycles as the number of memory fetches it has to perform, but at least two.</p>
<p>Therefore, single-byte opcodes (one byte fetches; NOP/TAX/INX etc.) as well as instructions with immediate operands take two cycles. Zero page instructions take three memory accesses (opcode, address, data), so they are three cycles. Absolute instructions take four accesses (opcode, address low, address high, data), so they are four cycles.</p>
<p>Read-modify-write instructions (INC/DEC/shift/rotate) are an exception: They require 4 memory accesses for the zero page case and 5 otherwise, but they take 5 and 6 cycles, respectively.</p>
<p>Branches take 3 cycles if they are taken and two if they are not taken. And extra cycle has to be added if the branch crosses a page boundary. JMP is 3, push is 3, pull is 4, JSR and RTS are 6 each.</p>
<p>All other timings can be looked up in the 6502&#8242;s reference, but they are very easy to memorize.</p>
<h4>Common Tricks</h4>
<p>The BIT instruction exists in a two-byte (immediate operand) and three-byte (absolute operand) variant. Since BIT only changes the flags, it effectively skips one or two bytes in the instruction stream. This can be used to replace a two-byte branch or a three-byte JMP with a one-byte BIT if only one or two bytes have to be skipped.</p>
<p>The architecture allows safe self-modifying code, so a common optimization for copy loops is to use LDA $nn00,X and STA $mm00,X, looping X from $00 to $FF and then incrementing the bytes that encode nn and mm for the next page. Compared to a LDA (zp1),Y: STA (zp2),Y sequence, this gets the inner loop down from 16 cycles (5 LDA, 6 STA, 2 INY, 3 BNE) to 14 (4 LDA, 5 STA, 2 INY, 3 BNE).</p>
<p>A PHA/PLA combination is 7 cycles, while an STA/LDA combination in the zero page is 6 cycles, so unless there is no free zero page space, PHA/PLA should be avoided to quickly store a value. Using an absolute store to write the value into the operand of a future immediate load (i.e. self modification) is the same speed at the zero page solution, but does not waste zero page space.</p>
<p>An elegant way to store a flag is to have it in bit #7 of a zero page address. While a load/store combination has to be used to set the flag (or the slower, but register-preserving SEC/ROR combination), it can be cleared with a simple LSR (5 cycles) and tested with BIT (3 cycles), without affecting register contents.</p>
<p>Since the 6502 is so register starved, only 3 bytes can be passed to a subroutine in registers. Also, the stack is small, and accessing it is slow, so stack frames as seen on modern architectures are very uncommon. Many applications and libraries (e.g. GEOS) use a dedicated area in the zero page as virtual registers.</p>
<p>The 6502 has no instructions for multiplication, division or floating point arithmetic. Most 6502-based computers have a BASIC interpreter in ROM though, and they typically include a math and floating point library.</p>
<h4>Bugs and Quirks</h4>
<p>The original 6502 implementation has a series of bugs and other anomalies that have never been fixed in MOS chips (not counting the 65CE02, which was only used in Amiga peripherals).</p>
<p>The indirect version of JMP loads the program counter from the wrong address, if the vector&#8217;s address lies on a page boundary: JMP ($23FF) will read the address from $23FF and $2300 instead of $23FF and $2400.</p>
<p>When in decimal mode, the negative flag reflects the original binary result, not the effective decimal result.</p>
<p>If a software interrupt (BRK) and a hardware interrupt occur at the same time, the BRK is dropped.</p>
<p>STA with the absolute-indexed addressing mode takes first reads from the absolute address without the index register added, and then reads again from the correct address. LDX #$07 STA $DC0D,X will first read from $DC0D, discard the result, and then write to $DC14. On the C64, this read form $DC0D would ACK all pending CIA 1 interrupts, while it is only supposed to write to $DC14.</p>
<p>Read-modify-write instructions with absolute addresses first read the value, but one cycle before they store the result, they store the original value again. On a C64, this can be seen when incrementing the screen border color at a defined area of the screen, as every write to the register will cause a tiny gray dot on the screen (on later HMOS versions of the VIC). When this is used with certain I/O ports, this can have other side effects. The latter two quirks have been used heavily for obfuscating copy protection software.</p>
<p>Instruction decoding in the 6502 is done by a PLA that compares the current cycle number within the instruction and the current opcode against a ROM of 130 mask lines, of which any number can fire independently. The outputs of these lines are then fed into components like the ALU, bus control, register control and program counter logic. The instruction set only consists of 151 defined opcodes, and since handling the remaining 105 opcodes as NOPs or traps would have required extra lines in the PLA, they will match against some lines that were meant for instructions with similar opcodes. Some of these âillegal opcodesâ lead to useful results and are used in some software (SAX = store A &#038; X), but most of the instructions make little sense (LAS = loads from memory, ANDs it with S and stores it into A, X and S), and some even lock up the CPU, disabling IRQs and NMIs (CRA/KIL).</p>
<h4>The MOS 6510</h4>
<p>Except for the pin layout, the MOS 6510 that is used in the C64 differs from the generic MOS 6502 in two ways: It can make the bus tri-state when not used, so the VIC can use it, and it has a 6 bit I/O port built in, which can be controlled using zero page locations 0 and 1. In register 0, each bit from 0-5 set it to output if 1, and to input if 0. Bits 0-5 in register 1 are the actual I/O pins. On the C64, bits 0-2 are outputs and control bank switching, they turn the ROMs and the I/O area on and off. Bits 3-5 go to the tape connector and control the motor and the data sent to the head, and detect whether a key on the tape deck is pressed.</p>
<h3>BASIC</h3>
<p>Microsoft had a strong position in the market for (mostly ROM) BASIC interpreters in 8080-based home computers when the MOS 6502 was released in 1975, so they rewrote their interpreter in 6502 assembly. Microsoft BASIC was pure 6502 code with a minimal character I/O interface to the machine&#8217;s âmonitorâ, i.e. I/O library.</p>
<p>Commodore decided to license the interpreter for the 1977 PET and extended it slightly to interface with their disk and tape libraries. Commodore BASIC was very buggy, so they went back to Microsoft for an update, which, with the Commodore changes re-applied, shipped in newer PETs as BASIC V2. For version 4, Commodore added several instructions for more conveniently dealing with disk.</p>
<p>Being a low-end machine, Commodore took the bugfixed BASIC V4 codebase and removed all features after V2, making it independent of the machine&#8217;s graphics and sound features again, and fitting it back into 8 KB, and shipped this version on the VIC-20. The Commodore 64 got the almost exact same version, but it runs at a different memory address ($A000-$BFFF).</p>
<p>Microsoft BASIC is a line-based editor, that is, lines can be shown with the LIST command, and they can be modified by re-typing them. This integrates nicely with the KERNAL screen editor: The cursor can be moved up to LISTed lines, the lines can be modified, and when RETURN is pressed, the whole line is fed into BASIC again.</p>
<p>A nice feature of this and later versions of Commodore BASIC is the fact that all important parts, like the tokenizer, the detokenizer and the interpreter loop jump over a jump table in RAM before they do their work, allowing the user to extend BASIC arbitrarily. The most well-known BASIC extension is Simons&#8217; BASIC, a cartridge that maps 8 KB of extra ROM at $8000-$9FFF.</p>
<h3>KERNAL</h3>
<p>The C64 has an 8 KB I/O library at $E000-$FFFF which is utilized by BASIC, but is intended to be used by other applications as well. All Commodore 8 bit systems have a standardized library call interface in the form of jump tables at the very top of memory that call into machine-specific functions for I/O.</p>
<p>KERNAL is started form the RESET vector, initializes the machine, sets up an interrupt service routine that handles the keyboard, animates the cursor and does the real time clock. The C64 has a hardware clock in each of the CIA chips, but KERNAL has not been updated to use this feature since the VIC-20.</p>
<p>KERNAL provides an abstract character I/O interface to a number of devices. All devices support open, read, write and close. The open call takes three parameters: The logical file number (there is a maximum of 16 channels), the device number and the secondary address. There are 32 device numbers statically assigned to the devices. The 8 bit secondary address can signal something to the device, like speed or an operation mode. Some devices (tape and IEC) support an optional filename.</p>
<p>Device 0 is the keyboard. While KERNAL exports raw key presses, the keyboard can also be accessed through character I/O, which will go through the screen editor and replay all characters on the screen that are in the line of the cursor, regardless of whether the user typed them or they had been there before.</p>
<p>Device 1 is the tape drive. KERNAL reads and writes blocks of data at a time and buffers them for character I/O.</p>
<p>Device 2 is RS-232. KERNAL contains a very sophisticated (but rarely used) software RS-232 implementation that supports up to 2400 baud.</p>
<p>Device 3 is the screen. KERNAL interprets special codes, manages the cursor position and handles scrolling.</p>
<p>Devices 4 and greater will be directed to the IEC bus. By convention, devices 4 to 7 are printers and plotters, and devices 8 to 30 are floppy drives or hard disks.</p>
<p>KERNAL allows interacting with the IEC bus manually by sending TALK and LISTEN requests to the bus.</p>
<h3>GEOS</h3>
<p>While KERNAL is a minimal character-based operating system in ROM, there is also a disk-based operating system with a graphical user interface for the C64. GEOS was released by Berkeley Softworks in 1986 and Commodore bundled it with the C64 for some time. The GUI, which can be controlled by a joystick or a mouse, runs in 320&#215;200 graphics mode and resembles early versions of MacOS. GEOS is a 16 KB library that includes an optimized disk interface (faster, support for timstamps, icons and multi-fork âVLIRâ files), library code for drawing to the screen, high level UI primitives for menus, buttons and dialog boxes (with callbacks) and a simple memory swapping facility. Furthermore GEOS allows input and printer driver plugins, as well as proportional fonts in different sizes. Internally, GEOS has a jump table to its library routines that consists of about 150 entries.</p>
<p>GEOS came with applications like GeoPaint and GeoWrite; Berkeley Softworks themselves offered solutions like GeoPublish and GeoCalc, and more software was available from third parties.</p>
<p>GEOS&#8217; only requirement is a 1541 disk drive, but a 3.5&#8243; 1581 drive, a RAM extension or one of the later hard drives helped speed it up a lot.</p>
<h3>6526 CIA</h3>
<p>The C64 has two identical 6526 CIAs (Complex Interface Adapter) that are mostly used for I/O. One CIA features 16 general purpose I/O pins (8 bit port A and 8 bit port B) that can be used either as an input or an output, two programmable timers and a real-time-clock.</p>
<p>The timers have 16 bit counters and count down by one either on each clock cycle, or on an external event, or on a timer A underflow (in the case of timer B). This allows concatenating the timers to one 32 bit timer. On an underflow, the CIA can be programmed to cause an IRQ or to send data through a serial shift register. The CIA also supports receiving data through a shift register.</p>
<p>The real-time-clock has a resolution of 1/10 of seconds and supports generating interrupts at a certain time.</p>
<p>CIA 1 is hooked up to the keyboard and the joystick ports. Since the keyboard consists of 64 keys (plus SHIFT LOCK, which is parallel to the left SHIFT key, and RESTORE, which is directly connected to the CPU&#8217;s NMI line), these can be laid out in a 8&#215;8 matrix of lines, key presses connecting the intersections. One side of the matrix is connected to port A (output), and the perpendicular side is connected to port B (input). The keyboard driver can now write the values of $01, $02, $04 etc. in port A and test the input of port B to see which keys are pressed. The two joysticks are connected in parallel to port A and port B, so they can cause spurious keyboard events.</p>
<p>CIA 2 is hooked up to the IEC bus, and I/O lines control the VIC bank. The rest is exposed on the user port, and can be used for RS-232.</p>
<p>KERNAL uses CIA 1 for the 60 Hz system timer, but, apart from the ports, doesn&#8217;t use any of the extra features of either CIA.</p>
<h3>6581 SID</h3>
<p>The SID (Sound Interface Device) is a whole topic of its own.</p>
<h3>6567/6569 VIC</h3>
<p>The video chip inside the C64 is called the MOS 6567/6569 VIC-II (Video Interface Controller) &#8211; the video chip in the VIC-20 had been the original VIC, and was the reason for the marketing name of the VIC-20.</p>
<p>The VIC supports a 40&#215;25 text mode, a 320&#215;200 bitmap mode, 16 colors and 8 sprites &#8211; all of these features have lots of sub-modes and options. The amount of memory the VIC can address is 16 KB, and while by default, it accesses the first 16 KB of the C64 RAM, it can be configured to use any of the four banks.</p>
<p>The 16 colors of the VIC are divided into two sets of eight. The first eight are the more important colors, as some modes only support the first eight. The colors are, in the original order: black, white, red, cyan, purple, green, blue, yellow, orange, brown, pink, dark gray, gray, light green, light blue and light gray.</p>
<h4>Character Mode</h4>
<p>The C64 has two built-in character sets that the VIC can access. They can be shown on the screen by writing the numbers 0 to 255 into screen RAM (at $0400 by default). The default font has uppercase characters and lots of line-drawing symbols in the lower 128 characters, and the second half consists of the same characters, but inverse. The alternative font has upper- and lowercase characters and omits some of the symbols.</p>
<p>The foreground color of the characters can be changed by writing the color numbers into the Color RAM, which is located at $D800-$DBFF. There is one byte per character, but only the lower 4 bits are actually preserved by Color RAM.</p>
<p>Each character is 8&#215;8 pixels, and stored as eight bytes in the character ROM (or RAM, if a user-defined character set is enabled), one line being one byte. A 1-bit will take the color from the Color RAM ($D800-$DBFF), and a 0 bit will take it from the global background color register ($D021). The pixel matrix is determined by looking up the character index in the screen RAM (at $0400-$07FF by default) and consequently looking up the pattern the current character set (the VIC sees the default font at $1000, although for the 6502 it is invisible there).</p>
<p>In Extended Color Mode (ECM), it is possible to chose between one of four background colors (registers $D021 to $D024) with the upper two bits of the character index, but then only 6 bits will be used to look up the character pattern, decreasing the number of possible characters to 64. The built-in (uppercase) character set is well-suited for this: While it is similar to the ASCII encoding, it has the uppercase characters mapped to codes $01 to $1A, so the most important characters are within the first $40.</p>
<p>Multi-Color Character Mode allows up to four colors per character and is intended for tile-based games, like platformers. If bit 3 of the value in Color RAM is 0, then the character gets displayed just like in non-multicolor mode, but colors are restricted to the first eight. If bit 3 is 1, then pairs of horizontally adjacent bits are combined in their meaning: 00 represents the screen background ($D021), 01 is the second background register ($D022), 10 is the third background register ($D023), and 11 is the color specified in bits 0-2 of the Color RAM. Pixels in these characters are twice as wide, so the resolution of a character is 4&#215;8.</p>
<h4>Bitmap Mode</h4>
<p>In hi-res graphics mode, the VIC supports a resolution of 320&#215;200, which uses the same pixel frequency as 40&#215;25 character mode (40*8=320, 25*8=200). The bitmap can reside at $0000 or $2000, and the VIC reads one byte for 8 pixels. But hi-res mode does not only support monochrome graphics: The foreground and background colors of each 8&#215;8 tile are taken from the high and low nibble of screen RAM, which would otherwise be unused. Color RAM is not used in this mode.</p>
<p>The encoding of the bitmap is identical to the encoding of a character set, making it a non-linear framebuffer: The first eight bytes of the bitmap represent the pixels in the tile at character position (0,0), the second eight bytes represent the tile at character position (1,0), which is pixel position (8,0), and so on. This layout makes pixel addressing in software slower.</p>
<p>In Multi-Color Bitmap Mode, the horizontal resolution is halved to 160&#215;200, and pixels are twice the width. Every set of two bits in the encodes one of four colors per tile: 00 takes it from the global background register ($D021), 01 and 10 take it from the upper and lower nibble of screen RAM, respectively, and 11 takes it from Color RAM.</p>
<h4>Scrolling</h4>
<p>The VIC supports hardware X and Y scrolling by 0 to 7 pixels. Since the 40th column is half visible and another column left of the first column is half-visible when the horizontal shift register is set to e.g. 4, a 41th column would be needed. Instead, it is possible to switch the screen to 38 column mode, i.e. the whole screen is a little narrower, and more border is shown on the left and on the right. The screen can also be switched from 25 to 24 lines the same way.</p>
<h4>Sprites</h4>
<p>The VIC has eight hardware sprites (also called MOBs, movable objects). Each sprite is 24&#215;21 pixels, which is encoded in 63 bytes. Set bits will be drawn in the sprite&#8217;s individual foreground color, and cleared bits will be transparent. The index to the sprite&#8217;s bitmap data in memory is an 8 bit value that is read from the last 8 bytes of screen RAM &#8211; since the screen is only 1000 characters, the last 24 characters of the $0400=1024 bytes area would otherwise be unused.</p>
<p>There is also a multicolor mode for sprites, which makes pixels twice as wide and decreases the horizontal resolution to 12 pixels. In this mode, 00 is still transparent, and 10 encodes the sprite&#8217;s individual color. The codes 01 and 11 take the color out of the sprite multicolor registers ($D025 and $D026), which are shared among all sprites.</p>
<p>Sprites can be positioned at arbitrary pixel positions on the screen, and overlap. In this case, sprites with lower numbers have priority over sprites with higher numbers. Each sprite can either be shown in front or behind background pixels. Sprites can be X- and Y-expanded by a factor of two, and collision of two sprites or of a sprite and background pixels is detected by hardware: Whenever two non-transparent sprite pixels are drawn at the same position on the screen, they have collided. Whenever a non-background pixel is drawn by the character generator at the same position where a non-background pixel of a sprite is draw, the sprite has collided with the background. An exception from this rule is the 01 code in the character data, which also counts as background. This way, a background picture can be constructed that does not cause collisions in certain areas. In practice, most newer games do not use the hardware functionality, but instead test for overlapping sprite bounding boxes in software.</p>
<h4>Memory Layout</h4>
<p>The VIC can address 16 KB at a time. All VIC data structures can be stored anywhere in these 16 KB, but they have to be aligned to their size.</p>
<ul>
<li>The screen RAM is $0400 bytes in size and can be at $0000, $0400, &#8230;
<li>The character set is $0800 bytes, and can be at $0000, $0800, &#8230;
<li>The bitmap is $2000 bytes and can be at $0000 or $2000.
<li>Sprites are $40 bytes, and can be at $0000, $0040, &#8230;
</ul>
<p>Two GPIO pins of the second 6526 CIA are connected to bits 6 and 7 of RAM when the VIC accesses it. By changing the lower 2 bits of $DD02, the VIC can be switched between banks $0000-$3FFF (11), $4000-$7FFF (10), $8000-$BFFF (01) and $C000-$FFFF (00).</p>
<p>If the VIC is set to banks $0000 or $8000, then the two built-in character sets shadow RAM in the area of $1000-$1FFF. This means that the built-in character set can be used on those banks without occupying RAM, but it also means that the area from $1000-$1FFF cannot be used for bitmap, screen RAM or sprite data either.</p>
<p>For timing reasons, color information is not taken from main RAM, but from a dedicated Color RAM. These $0400 half-bytes are accessible to the C64 at $D800-$DBFF and can not be bank switched.</p>
<h4>Timing</h4>
<p>For advanced VIC programming, it is necessary to not just set up a certain mode and have the VIC display it, but to reprogram the VIC while it is drawing the picture. For this, it is necessary, to understand its timing.</p>
<p>While the pixels within the screen area are 320 by 200, the VIC actively draws pixels in the border color outside of this area, which (on PAL) is 403&#215;284 pixels. Analog TV standards specify an H blank area at the end of every line, and V blank area at the end of every screen. So counting this timing as pixels, this gives an absolute resolution of 504&#215;312 pixels. The interesting and very useful connection about the pixel clock and the system clocks is that an 8 pixel character is drawn every system clock cycle, i.e. about 1 million times a second. The 504 horizontal pixels therefore mean that a line is drawn on the screen every 63 cycles. With this information, it is possible to do cycle-exact timing of assembly code to switch a VIC register at an 8 pixel granularity.</p>
<p>Further timing details (badlines, sprite timing), as well as the application of this information to do tricks like FLD, FLI and AGSP would go beyond the scope of this article, but are talked about in the presentation at the 25th Chaos Communication Congress.</p>
<h3>Memory Configuration</h3>
<p>In a running system with BASIC and KERNAL, the BASIC and KERNAL ROMs are turned on and visible at $A000-$BFFF and $E000-$FFFF respectively, and at $D000-$DFFF, the I/O area is visible. Using the 3 lowest bits in the processor port at address 1, this configuration can be altered. The ROMs can be turned off, revealing RAM instead, and the I/O area can be configured to show either RAM or the character set ROM. Note that writing to ROM will always direct the data to the underlying RAM.</p>
<p>In practice, many programs run in the default configuration and use both KERNAL library routines, as well as functions in BASIC, to keep their own code as small as possible. More recent programs and almost all games turn off all of ROM, to get direct control of the interrupt vector without having to go though the KERNAL handler first.  The I/O area is typically configured to show the I/O registers and Color RAM, and only rarely switched to a different configuration to temporarily access the RAM underneath. A few applications read the character ROM at program start and modify the copy.</p>
<p>The C64 supports another ROM bank at $8000-$9FFF, which can only be serviced by an external cartridge connected to the expansion port. Also, the $A000-$BFFF bank can be overridden by an external ROM. If KERNAL detects the magic string âCBM80â at $8004 on startup, it will jump to the code of the cartridge right away.</p>
<p>Expansion port cartidges can also put the C64 into &#8220;ULTIMAX&#8221; mode, in which the it can play game cartridges for the failed C64-based stripped down &#8220;ULTIMAX&#8221; system (&#8220;Commodore MAX&#8221;, &#8220;VC-10&#8243;): All internal ROM is disabled, $8000-$9FFF and $E000-$FFFF show external ROM, RAM is only visible at $0000-$0FFF, and the VIC has a different view on the address space. This mode is used by freezer cartridges which can use it to replace the $E000-$FFFF bank and thus override the hardware vectors.</p>
<h3>Tape Interface</h3>
<p>The tape interface consists of a single line each for data input and output, motor control and key sense. The raw data is read from and written to the data lines, and all encoding and decoding of the data stream is done in software. 3 of the required lines are connected to the processor port at zero page location 1, and one (data input) is connected to CIA 2.</p>
<h3>IEC Bus</h3>
<p>The IEC bus is a serial version of the IEEE-488 bus used on the PET. Devices on the IEC bus are daisy-chained, and are all connected to the same three lines: ATN (attention), clock and data. IEC has a single bus master, which is the computer. It is the only device to ever raise ATN, while every device can output to clock and data, depending on the state of the bus.</p>
<p>If the computer raises ATN, every device on the bus listens for the command which includes the 5 bit device number (0-30) and compares it with its own. The protocol on who sends and who receives is determined by the computer sending TALK/UNTALK and LISTEN/UNLISTEN commands.</p>
<p>While KERNAL exports the interface at this level, it also allows high-level open, close, read and write operations on the IEC bus, as well as load and save operations. The BASIC LOAD and SAVE commands are directly hooked up to this interface.</p>
<p>The IEC bus was designed for the serial shift register in the VIA (Versatile Interface Adapter) of the VIC-20 and its disk drive, but it turned out that the VIA had a bug that made the shift register unusable, so the IEC protocol had to be implemented in software. While the C64 has CIAs, in which the bug has been fixed, the 1541 still used VIAs. It wasn&#8217;t until the C128 (in its native mode only) that the computer could talk to the floppy drive (Commodore 1570/1571/1581) in its intended speed.</p>
<h3>1541 Disk Drive</h3>
<p>The Commodore 1541 Disk Drive is the most common disk drive used with the C64. It uses 5.25&#8243; SS/DD (single side, double density) disks, but disks can be flipped, and the other side can be used as well, if the disks are double sided. The 1541 does not use the index hole, and uses software markers (SYNC) instead to be able to tell the start of a sector. Due to reliability problems of early drives, the 1541 only uses 35 out of the 40 possible tracks on a 5.25&#8243; disk. The tracks have a variable number of 256 byte sectors, ranging from 21 on the outside to 17 on the inside. The data is written in 4 different speeds. This makes an overall 683 sectors, or 174,848 bytes.</p>
<p>The file system is stored on track 18. Track 18, sector 0 contains the disk name and the BAM (block availability map), which stores one bit per sector (1 = free). Track 18, sector 1 is the first sector containing directory entries: There are eight 32 byte entries per sector, with a maximum filename length of 16 characters. The first two bytes of a directory sector point to the next directory entry sector.</p>
<p>The files on disk are also stored as a linked list. The first two bytes of every sector are either the track and sector number of the next block, or the first byte is 0 and the second byte is the number of valid bytes in this sector.</p>
<p>The 1541 is a stripped down version of the PET drive series, which had a parallel connection, and contained two 6502 CPUs: One for doing the filesystem and communicating with the computer, and one for reading data from disk and writing data to it, as well as encoding and decoding the data. The 1541 only has a single 6502 CPU running at 1 MHz, which (using timer IRQs) regularly switches itself between the two modes. The two virtual CPUs still communicate with each other using a messaging interface in the zero page. The 1541 has 2 KB of RAM at $0000-$07FF.</p>
<p>The 1541 has two VIA I/O controllers at $1800 (for the IEC bus) and at $1C00 (for the drive). The firmware is located at $C000-$FFFF.</p>
<p>Since loading an application or a game takes minutes on an unmodified C64, several âfloppy speedersâ appeared (either as software on disk or built into applications, as ROM extension cartridges, or as internal replacement ROMs), that consisted of implementations of more optimized protocols for the IEC bus for both the C64 and the 1541. The 1541 code was uploaded using the old bus protocol. Such a new protocol would for example not do a handshake on every bit using the clock line, but shift a complete byte through in 4 steps, two bits at a time, using the clock and data line at the same time. This would of course only work if both CPUs were not interrupted. VIC timing on the C64 side could already affect this, so many floppy speeders turned off the screen while loading.</p>
<h3>Other Peripherals</h3>
<p>The 1541 is the necessary companion to a C64. It can be replaced by a 1570 (1541 with fast bus routines for the C128) or a 1571 (double-sided 1570), since they include a 1541 compatibility mode. The 3.5&#8243; Commodore 1581, which supports 880 KB per disk, can hardly be a replacement for a 1541, because most applications contain their own floppy speeders that make lots of assumptions on the exact on-disk format. For GEOS, it can be very useful though.</p>
<p>Creative Micro Devices sold and continues to sell a line of hard drives that have an IEC connection but contain a 3.5&#8243; SCSI drive inside. Although they have a 6502 CPU built in and allow code execution on their CPU, they are not compatible enough to replace a 1541 either.</p>
<p>Several memory extension cartridges exist for the expansion port of the C64: The Commodore REU (contains a DMA chip that transfers data between itself and main RAM), as well as the third party GeoRAM (maps a block to the $DE00-$DFFF area) and RAMLink (battery backed, designed as RAM disk).</p>
<p>Freezer cartridges like the Action Replay and the Final Cartridge were not only popular because they could dump all of memory to disk and thus copy certain copy-protected games, but also because they featured floppy speeders that disabled the original routines directly at startup time, without any effort from the user.</p>
<p>In the mid 90s, CPU speeders for the expansion port became popular. The 8 MHz Flash 8 is rare today, but many enthusiasts have a SuperCPU, which replaces the onboard CPU with a 20 MHz 65C816, which has a native 16 bit mode that can address up to 16 MB or RAM. There are a few applications and games that require a SuperCPU. The speedup of GEOS with a SuperCPU is significant.</p>
<p>In the 2000s, the enthusiast scene created all kinds of peripherals, like ethernet interfaces, IDE interfaces and SD card readers.</p>
<p>And there are not only peripherals: In 2004, the Commodore 64 DTV, a reimplemented C64 appeared in the form of a Joystick. The device is fairly compatible and can be extended to connect to a keyboard and a 1541.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=53&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=53</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>Copland D9 Booting</title>
		<link>http://www.pagetable.com/?p=52</link>
		<comments>http://www.pagetable.com/?p=52#comments</comments>
		<pubDate>Sat, 06 Dec 2008 08:31:05 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=52</guid>
		<description><![CDATA[Click on the image for a video of Copland D9 (the first developer release; the second one being D11E4), booting a bit, then hanging. It is running on a Power Macintosh 6100.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.weihenstephan.org/~michaste/pagetable/copland/copland-d9.mp4"><img src="http://www.weihenstephan.org/~michaste/pagetable/copland/copland-d9.jpg" width="440"></a></p>
<p>Click on the image for a video of Copland D9 (the first developer release; the second one being D11E4), booting a bit, then hanging. It is running on a Power Macintosh 6100.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=52&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=52</wfw:commentRss>
		<slash:comments>5</slash:comments>
<enclosure url="http://www.weihenstephan.org/~michaste/pagetable/copland/copland-d9.mp4" length="499010" type="video/mp4" />
		</item>
		<item>
		<title>What Operating System Is This?</title>
		<link>http://www.pagetable.com/?p=51</link>
		<comments>http://www.pagetable.com/?p=51#comments</comments>
		<pubDate>Fri, 21 Nov 2008 05:50:48 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[puzzle]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=51</guid>
		<description><![CDATA[Unfortunately, I have not been able to successfully boot this up all the way on this machine &#8211; it hangs on this screen. Edit: Thanks for the great comments. It is indeed Copland. See my followup post for details.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.weihenstephan.org/~michaste/pagetable/misc/unknown.jpg"><img src="http://www.weihenstephan.org/~michaste/pagetable/misc/unknown.jpg" width="440"></a></p>
<p>Unfortunately, I have not been able to successfully boot this up all the way on this machine &#8211; it hangs on this screen.</p>
<p><i>Edit: Thanks for the great comments. It is indeed Copland. See my <a href="http://www.pagetable.com/?p=52">followup post</a> for details.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=51&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=51</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Inside Macintosh Volumes I, II, III (PDF)</title>
		<link>http://www.pagetable.com/?p=50</link>
		<comments>http://www.pagetable.com/?p=50#comments</comments>
		<pubDate>Tue, 18 Nov 2008 09:10:58 +0000</pubDate>
		<dc:creator>Michael Steil</dc:creator>
				<category><![CDATA[archeology]]></category>
		<category><![CDATA[literature]]></category>

		<guid isPermaLink="false">http://www.pagetable.com/?p=50</guid>
		<description><![CDATA[Here are all three volumes of the original 1985 edition of Inside Macintosh as a searchable PDF: Inside Macintosh Volumes I, II, III(1284 pages, 18 MB) Inside Macintosh consists of three volumes. Volume I begins with the following information of general interest: a &#8220;road map&#8221; to the software and the rest of the documentation the [...]]]></description>
			<content:encoded><![CDATA[<p>Here are all three volumes of the original 1985 edition of <b>Inside Macintosh</b> as a searchable PDF:</p>
<p align="center"><a href="http://www.weihenstephan.org/~michaste/pagetable/mac/Inside_Macintosh.pdf"><img src="http://www.weihenstephan.org/~michaste/pagetable/mac/Inside_Macintosh.png" border="2"><br />Inside Macintosh Volumes I, II, III<br /></a>(1284 pages, 18 MB)</p>
<table border="1">
<tr>
<td>
<p><i>Inside Macintosh</i> consists of three volumes. Volume I begins with the following information of general interest:</p>
<ul>
<li>a &#8220;road map&#8221; to the software and the rest of the documentation</li>
<li>the user interface guidelines</li>
<li>an introduction to memory management (the least you need to know, with a complete discussion following in Volume II)</li>
<li>some general information for assembly-language programmers</li>
</ul>
<p>It then describes the various parts of the <b>User Interface Toolbox</b>, the software in ROM that helps you implement the standard Macintosh user interface in your application. This is followed by descriptions of other, RAM-based software that&#8217;s similar in function to the User Interface Toolbox. (The software overview in the Road Map chapter gives further details.)</p>
<p>Volume II describes the <b>Operating System</b>, the software in ROM that does basic tasks such as input and output, memory management, and interrupt handling. As in Volume I, some functionally similar RAM-based software is then described.</p>
<p>Volume III discusses your program&#8217;s interface with the Finder and then describes the Macintosh 128K and 512K hardware. A comprehensive summary of all the software is provided, followed by some useful appendices and a glossary of all terms defined in Inside Macintosh.</p>
</td>
</tr>
</table>
<p>I have been told that there are several people in Apple&#8217;s operating system kernel team today that are younger than the original Macintosh, therefore I see this as act of preserving retrocomputing documents; the times when someone cared about the copyright of this must have long been gone.</p>
<img src="http://www.pagetable.com/wp-content/plugins/pixelstats/trackingpixel.php?post_id=50&amp;ts=1284078729" style="display:none;" alt="pixelstats trackingpixel"/>]]></content:encoded>
			<wfw:commentRss>http://www.pagetable.com/?feed=rss2&amp;p=50</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>
