tag:blogger.com,1999:blog-36327080763049462332024-02-19T07:43:12.186-05:00SYS$OUTPUTLow level programming - hypervisors, firmware, kernels, virtualization, storage and file systemsAnonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.comBlogger87125tag:blogger.com,1999:blog-3632708076304946233.post-44389767000541935392017-07-04T01:27:00.001-04:002017-07-04T18:08:51.972-04:00Porting UEFI to XXX, step 1<span style="color: red;"><b>I've decided to do the actual blogging for this project *in* the repo itself. See <a href="https://github.com/andreiw/ppcnw-edk2/blob/master/README.md">https://github.com/andreiw/ppcnw-edk2/blob/master/README.md</a>. After all, markdown is convenient enough and using Blogger on the G4 is p-a-i-n-f-u-l.</b></span><br />
<br />
So it turns out that blogging about something after the fact is pretty tough. I really wanted to blog about my PoC port of UEFI to the OpenPower ecosystem, but it's incredibly difficult to go back and try to systematize something that's been a few years back.<br />
<div>
<br /></div>
<div>
So let's try this again. This time, our victim will be a G4 12" PowerBook6,8 with a 7447A. That's a 32-bit PowerPC. Now, I'll go in small steps and document *everything*. For added fun, we'll begin porting on the target itself, at least until that gets too tedious.</div>
<div>
<br /></div>
<div>
First, I updated to the latest (and last) Debian 8 (Jessie).</div>
<div>
<br /></div>
<div>
Now let's clone the tree.</div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">$ git clone https://github.com/tianocore/edk2</span></b></div>
</div>
<div>
<br /></div>
<div>
Setup the UEFI environment.</div>
<div>
<br /></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">$ cd edk2</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">$ . edksetup.sh</span></b></div>
<div>
<br /></div>
<div>
Now we need to get the BaseTools building.</div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">pbg4:~/src/edk2/BaseTools/ make</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">make -C Source/C</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">make[1]: Entering directory '/home/andreiw/src/edk2/BaseTools/Source/C'</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">Attempting to detect ARCH from 'uname -m': ppc</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">Could not detected ARCH from uname results</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">GNUmakefile:36: *** ARCH is not defined!. Stop.</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">make[1]: Leaving directory '/home/andreiw/src/edk2/BaseTools/Source/C'</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">GNUmakefile:25: recipe for target 'Source/C' failed</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">make: *** [Source/C] Error 2</span></b></div>
</div>
<div>
<br /></div>
<div>
Ok. Let's fix that. We'll first need a <b>Source/C/Include/PPC/ProcessorBind.h</b> file.</div>
<div>
<br /></div>
<div>
<b>ProcessorBind.h</b> I've derived from another 32-bit CPU, like IA32 or ARM. This contains type definitions, mostly. It's boilerplate. In case there are multiple coding conventions for your architectures and it's not obvious which one you should be using, you might wish to specify what the EFIAPI attribute will be. Like, on x86 Windows-style cdecl is used, regardless of how you build the rest of Tiano. On most architectures an empty define is fine.</div>
<div>
<br /></div>
<div>
<div style="font-family: sans-serif;">
Now appropriately hook it into <b>Source/C/Makefiles/header.makefile.</b></div>
<div style="font-family: sans-serif;">
<b><br /></b></div>
<div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">--- a/BaseTools/Source/C/Makefiles/header.makefile</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">+++ b/BaseTools/Source/C/Makefiles/header.makefile</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">@@ -43,6 +43,10 @@ ifeq ($(ARCH), AARCH64)</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> ARCH_INCLUDE = -I $(MAKEROOT)/Include/AArch64/</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> endif</span></b></div>
<div>
</div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">+ifeq ($(ARCH), PPC)</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">+ARCH_INCLUDE = -I $(MAKEROOT)/Include/PPC/</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">+endif</span></b></div>
<div style="font-family: sans-serif;">
<br /></div>
</div>
</div>
<div>
<div style="font-family: sans-serif;">
Fix the <b>ARCH</b> detection in <b>Source/C/GNUmakefile</b>.</div>
<div>
<br /></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">--- a/BaseTools/Source/C/GNUmakefile</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">+++ b/BaseTools/Source/C/GNUmakefile</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;">@@ -31,6 +31,9 @@ ifndef ARCH</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> ifneq (,$(findstring arm,$(uname_m)))</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> ARCH=ARM</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> endif</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> ifneq (,$(findstring ppc,$(uname_m)))</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> ARCH=PPC</span></b></div>
<div>
<b><span style="font-family: "courier new" , "courier" , monospace;"> endif</span></b></div>
</div>
<div>
<br /></div>
<div>
<div style="font-family: sans-serif;">
Ok, ensure you have the libuuid headers (Debian <b>uuid-dev</b>) and g++. And...</div>
</div>
<div style="font-family: sans-serif;">
<br /></div>
<div style="font-family: sans-serif;">
You are done. This gives you the tools need to help build UEFI. Now we need to teach the build system about PowerPC...</div>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-31281294721820223762016-06-08T02:19:00.000-04:002016-06-08T02:20:25.370-04:00Disassembling NT system filesMost NT files are stripped. This means that trying to disassemble them is a bit annoying because there are no symbols available. Checked builds of NT came with the symbol files (e.g. support/debug/ppc/symbols/exe/ntoskrnl.dbg for ntoskrnl.exe), but tools like Microsoft's dumpbin or OpenWatcom's wdis don't use them.<br />
<br />
Now there's <a href="https://github.com/andreiw/dbgsplice">https://github.com/andreiw/dbgsplice</a> to add the COFF symbol table back!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsqEPK43E6t_1zerFxejs5gQrRyqo5FaRULkCR8tjRD4sFcuqtOwfA1zk4BHvpOg3qIg2SNwA9_lOJ35R_Wh3mvVuur0U9b8ETYwm2CLVzfMx55WnmMt4qGthtKi_0XGbXO7bVapZ1CcUx/s1600/syms.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsqEPK43E6t_1zerFxejs5gQrRyqo5FaRULkCR8tjRD4sFcuqtOwfA1zk4BHvpOg3qIg2SNwA9_lOJ35R_Wh3mvVuur0U9b8ETYwm2CLVzfMx55WnmMt4qGthtKi_0XGbXO7bVapZ1CcUx/s320/syms.png" width="320" /></a></div>
<br />
Sadly, the OpenWatcom analogue is quite buggy, so it's hard to suggest. It was a capable disassembler around setupldr and veneer.exe, but it gets horribly confused with complicated section layouts.<br />
<br />
Of course the DBG files contain quite a bit more info (and we can do a lot more with the aux COFF syms too for annotating code than dumpbin suggests).Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com2tag:blogger.com,1999:blog-3632708076304946233.post-84510504166615563412016-05-08T23:41:00.001-04:002016-05-08T23:46:13.848-04:00Easy creation of proxy DLL pragmas<h2>
Converting dumpbin DLL exports information to MSVC linker pragmas</h2>
<div>
Yes, a bit of a weird request. But imagine you want to create a dummy DLL that forwards all the existing symbols of another DLL. Of course you're not going to do it by hand.</div>
<div>
<br /></div>
<div>
You have dumpbin output that looks like:</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit9DZYOheuH0B5GB8KTveePjIEeRaGSLkhze_5N0T1YAVJ8QuTNIZ-CEPmHU6JngQWFHOV06wR5KCEXcQHu5NJHifJe5KefB9SBqbIwjG88ZTl1nzrsBNwm451d8OLzSjMDrIiyP010wGf/s1600/dumpbin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit9DZYOheuH0B5GB8KTveePjIEeRaGSLkhze_5N0T1YAVJ8QuTNIZ-CEPmHU6JngQWFHOV06wR5KCEXcQHu5NJHifJe5KefB9SBqbIwjG88ZTl1nzrsBNwm451d8OLzSjMDrIiyP010wGf/s320/dumpbin.png" width="320" /></a></div>
<br /></div>
<div>
And you want:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZKjAuoauUyYdwpM3UPw-Chyphenhyphen-Z4cWnFlmewZ__UVhCBZrxiOZI7xPKVaZ-UHOnkVmBu1-2pQ41Yz0FSCiUhna1246FdIGXKJmrBMZ4uWG72WFQdko3TtKimb5hjGfC8T04sqW4qhRL569b/s1600/forwards.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZKjAuoauUyYdwpM3UPw-Chyphenhyphen-Z4cWnFlmewZ__UVhCBZrxiOZI7xPKVaZ-UHOnkVmBu1-2pQ41Yz0FSCiUhna1246FdIGXKJmrBMZ4uWG72WFQdko3TtKimb5hjGfC8T04sqW4qhRL569b/s320/forwards.png" width="320" /></a></div>
<br />
I'm not an awk expert, but this works, except the dumpbin I ran on WIndows and awk I ran on OS X, hahah. But you get the gist...
<pre class="brush: plain">
dumpbin /exports C:\winnt\system32\ntdll.dll |
awk 'NR > 19 && $3 != "" { printf "#pragma comment(linker, \"/export:%s=ntdll.%s\")\n", $3, $3 }'
</pre>
Might have to tweak number of lines to skip, depending on your tools. I'm on MSVC 4.0 (hello '90s!).
</div>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-62422462459960584372016-05-08T16:21:00.000-04:002016-05-08T16:35:47.809-04:0064-bit ARM OS/Kernel/Systems Development Demo on an nVidia Shield TV (Tegra X1)<h2>
64-bit ARM OS/Kernel/Systems Development on an nVidia Shield TV (Tegra X1)</h2>
The Shield TV is based on the 64-bit nVidia X1 chip. Unlike the K1, this is actually a Cortex-A57 based design, instead of being based on the nVidia "Denver" design. That by itself is kind of interesting already.
The Shield TV was available much much earlier than the X1-based nVidia development board (<a href="http://www.nvidia.com/object/jetson-tx1-dev-kit.html" style="white-space: pre-wrap;">Jetson TX1</a>, you can <a href="http://www.amazon.\
com/NVIDIA-Jetson-TX1-Development-Kit/dp/B017NWO6LG" style="white-space: pre-wrap;">even buy it on Amazon</a>), and costs about a <a href="http://www.amazon.com/NVIDIA-SHIELD-Streaming-Chromecast-Advanced-Performance/dp/B00U33Q940/ref=\
sr_1_1?s=pc&ie=UTF8&qid=1462737297&sr=8-1&keywords=Tegra+Shield+TV">third of the TX1</a>. The Shield TV allows performing an unlock via "fastboot oem unlock", allowing custom OS images to be booted. Unlike the TX1, you don't get a UART (and I haven't found the UART pads yet, either).
<h3>What this is</h3>
<a href="https://github.com/andreiw/shieldTV_demo">https://github.com/andreiw/shieldTV_demo</a><br /><br />
This is a small demo, demonstrating how to build and boot arbitrary code on your Tegra Shield TV. Unlike the previous Tegra K1 demo, you get EL2 (hypervisor mode!).
<h3></h3>
<ul>
<li>A Shield TV, unlocked. Search Youtube for walkthroughs.</li>
<li>Shield OS version >= 1.3.</li>
<li>GNU Make.</li>
<li>An AArch64 GNU toolchain.</li>
<li>ADB/Fastboot tools.</li>
<li>Bootimg tools (https://github.com/pbatard/bootimg-tools), built and somewhere in your path.</li>
<li>An HDMI-capable screen. Note, HDMI, not DVI-HDMI adapter. You want the firmware to configure the screen into 1920x1080 mode, otherwise you'll be in 640x480 and we don't want that...</li>
</ul>
<h3>How to build</h3>
<pre class="brush: plain">$ CROSS_COMPILE=aarch64-linux-gnu- make</pre>...should yield 'shieldTV_demo'.
<h3>How to boot</h3>
<ol>
<li>Connect the Shield TV a USB cable to your dev workstation.</li>
<li>Reboot device via:<br /><pre class="brush: plain">$ adb reboot-bootloader</pre>...you should now see the nVidia splash screen, followed by the boot menu.</li>
<li>If OS is 1.3, you can simply:<br /><pre class="brush: plain">$ fastboot boot shieldTV_demo</pre></li>
<li>If OS is 1.4 or 2.1, you will need to:<br /><pre class="brush: plain">$ fastboot flash recovery shieldTV_demo</pre>...and then boot the "recovery kernel" by following instructions on screen.</li>
</ol>
The code will now start. You will see text and some drawn diagonal lines black background. The
text should say we're at EL2 and the lines should be green. The drawing will be slow - the MMU is off and the caches are thus disabled.
<br /><br />
Let me know if it's interesting to see the MMU setup code.
<h3>Final thoughts</h3>
The Shield TV is a better deal than the TX1 for the average hobbyist, even with the missing UART. For the price being sold the TX1 should come with a decent amount of RAM, not 1GB more than the Shield TV. nVidia...are you listening? Uncripple your firmware so booting custom images is not a song-and-dance (you broke it in 1.4!) and at least TELL us where the UART pads are on the motherboard. If you're really cool put together an "official" Ubuntu image that runs on the TX1 and the Shield (and fix SCR_EL3.HCE, too). Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-85782872096757680922016-05-07T07:49:00.002-04:002016-05-07T07:56:50.596-04:00Porting TianoCore to a new architecture<h2>
"UEFI" on...?</h2>
This article is the first in a series of posts touching on the general process of bringing up TianoCore EDK2 on an otherwise unsupported architecture. Maybe you want to support UEFI for your CPU architecture, or simply have a reasonable firmware environment. In either case, because UEFI is not actually defined for your architecture, you're going to have to do a bit more work than your typical platform bring-up. By the time you're done, you could become a perfect addition to the UEFI forum and its specification committees...yeah!<br />
<br />
This blog post and the ones following it continually refer to the <a href="https://firmwaresecurity.com/2015/10/12/tianocore-for-openpower/">ongoing PPC64LE Tiano</a> port I am working on, available at <a href="https://github.com/andreiw/ppc64le-edk2/">https://github.com/andreiw/ppc64le-edk2/</a>. Since everyone can read the fine code, this document mostly highlights the various steps performed throughout the commits. The git repo isn't perfect, though. Some changes ended up evolving over a few commits while I ironed things out and brought in more code. Hopefully I don't miss mentioning anything important.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Gp8gyfhEDhZ9wQzBgBo28yiPkfbFzXBrMASvNdp0DMZO9p0Tykqs4lgEqAIi8KmcHQ-NTnyfWZqel6pG5cbk3F-K95fUxvZ128MEuIGoXCDMWtG_A28v3R4RDx5na4YAaDgTZ18A06lD/s1600/edk2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4Gp8gyfhEDhZ9wQzBgBo28yiPkfbFzXBrMASvNdp0DMZO9p0Tykqs4lgEqAIi8KmcHQ-NTnyfWZqel6pG5cbk3F-K95fUxvZ128MEuIGoXCDMWtG_A28v3R4RDx5na4YAaDgTZ18A06lD/s320/edk2.png" width="320" /></a></div>
<br />
<h3>
TianoCore</h3>
<div>
<a href="http://www.tianocore.org/">Tiano</a> is Intel's open-source (BSD-licensed) implementation of the UEFI specification. <a href="http://www.tianocore.org/edk2/">EDK2</a> is the <a href="http://tianocore.sourceforge.net/wiki/Differences_between_EDK_and_EDK_II">second and current iteration of the implementation</a>.</div>
<div>
<br /></div>
<div>
<a href="http://uefi.org/">UEFI</a> officially is supported on IA32, X64, IPF, ARM and AARCH64 architectures, the EDK2 has CPU support code for the x86 and ARM variants. There's a <a href="http://sourceforge.net/projects/efi-mips/">MIPS EDK1</a> port floating about, and <a href="https://github.com/ozbenh/edk2">now</a> <a href="https://github.com/andreiw/ppc64le-edk2">two</a> <a href="https://www.ibm.com/developerworks/community/blogs/fe313521-2e95-46f2-817d-44a4f27eba32/entry/just_the_faqs_about_little_endian?lang=en">PPC64LE</a> <a href="http://openpowerfoundation.org/">OpenPower</a> EDK2 ports, one of which ended up fueling this article...</div>
<div>
<br /></div>
<div>
I'm not going to focus on the architecture of either UEFI or Tiano. <a href="http://www.amazon.com/Beyond-BIOS-Developing-Extensible-Interface/dp/1934053295">Good books</a> have been written on the subject. Here's some tl;dr material, though, for the hopelessly impatient:</div>
<div>
<ul>
<li><a href="http://uefi.org/learning_center/papers">http://uefi.org/learning_center/papers</a></li>
<li><a href="http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf">http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf</a></li>
<li><a href="https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-white-papers">https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-white-papers</a></li>
<li><a href="https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-User-Documentation">https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-User-Documentation</a></li>
<li><a href="http://tianocore.sourceforge.net/wiki/PI_Boot_Flow">http://tianocore.sourceforge.net/wiki/PI_Boot_Flow</a> </li>
</ul>
<div>
At least read the User Documentation and glance at the boot flow diagram. You should be now able to fetch, build and boot Tiano Core using the emulation package and have a rough understanding of what it takes to get a build going via Conf/target.txt and Conf/tools_def.txt.</div>
</div>
<h3>
Your Target</h3>
<div>
Your target is a 32-bit or 64-bit little-endian chip. I suppose big-endian is doable, but none of the Tiano code is endian safe and UEFI is strictly little-endian.</div>
<h3>
Development Environment</h3>
<div>
This assumes that you are doing development on Linux and are using and ELF toolchain and GCC compilers. You are going to need:</div>
<div>
<ul>
<li>A compiler. <a href="https://www.kernel.org/pub/tools/crosstool">https://www.kernel.org/pub/tools/crosstool</a>/ is a good source.</li>
<li>A simulator, virtual machine or target with some monitor environment to upload and run code from RAM.</li>
</ul>
<h3>
Basic Project Setup</h3>
</div>
<div>
Pick a short identifier for your architecture. Pick a name that's unused - for the Power8 port I picked PPC64. This tag will be used with the Tiano build scripts. The next step is to create a couple of Pkg directories that will contain our stuff. In my PPC64 port I initially went with a single-package solution, but I should be working on splitting it up into the more conventional layout, where platform-independent portions are in PPC64Pkg and platform-dependent parts (including build scripts for building for actual boards) are in PPC64PlatformPkg. You can refer <a href="https://github.com/andreiw/ppc64le-edk2/commit/413c1cf7ce97a0e5da3ea4449f4d3214e694e9e6">to this commit</a> as an example for the minimum required to build a dummy EFI application that does nothing.</div>
<div>
<br />
If our architecture was supported, then running a similar build command for your package would succeed.
<br />
<pre class="brush: text">build -p YourArchPlatformPkg/YourArchPlatformPkg.dsc
</pre>
<h3>
Build Infrastructure</h3>
<div>
The next step is to enable the build infrastructure and scripts to understand your architecture identifier. Here's a list of files I had to modify - this is all stuff under BaseTools/Source/Python and the changes are incredibly mechanical.</div>
<div>
<ul>
<li>Common/DataType.py</li>
<li>Common/EdkIIWorkspaceBuild.py</li>
<li>Common/FdfParserLite.py</li>
<li>Common/MigrationUtilities.py</li>
<li>CommonDataClass/CommonClass.py</li>
<li>CommonDataClass/ModuleClass.py</li>
<li>CommonDataClass/PlatformClass.py</li>
<li>GenFds/FdfParser.py</li>
<li>GenFds/FfsInfStatement.py</li>
<li>GenFds/GenFds.py</li>
<li>TargetTool/TargetTool.py</li>
<li>build/build.py</li>
</ul>
<div>
See <a href="https://github.com/andreiw/ppc64le-edk2/commit/2fef3116f0c732036588af12cd409f8f3d96436b">https://github.com/andreiw/ppc64le-edk2/commit/2fef3116f0c732036588af12cd409f8f3d96436b</a> for my PPC64 implementation.</div>
</div>
<h3>
Build tools</h3>
<div>
UEFI executables are PE/COFF files. Since we are building on Linux, EDK2 uses a workflow where ELF artifacts produced by the cross-compiler are converted into PE32/PE32+ files with the GenFw tool. The PE/COFF artifacts are then wrapped into an FFS object and assembled into what is known as an FV ("firmware volume"). Multiple FVs are put into an FD. The FV is really a flat file system that uses GUIDs for everything and can store other types of objects as well. You could also generate what is known as a TE (terse executable), but it's basically a cut down version of COFF FWIW.</div>
<div>
<br /></div>
<div>
Tiano deals with several kinds of executables. The UEFI runtime (DXE core, UEFI drivers, and so on) are relocated as they are loaded, while the code that runs prior to the UEFI runtime itself is XIP (execute-in-place) and is thus pre-relocated to fixed addresses by the tool constructing the FV. The point behind this being that such pre-UEFI code (which is the SEC and PEI phases for Tiano), is run in an environment before the DRAM is available.</div>
<div>
<br /></div>
<div>
Thus we need to enable GenFw to create PE/COFF executables from ELF for our architecture. This ties into the compiler options we're going to use, which is not something we've addressed yet. It helps to understand that a PE/COFF file is basically a position-independent executable. Although there is "preferred linking address" that all symbols are relocated against, the PE/COFF image contains a sufficient amount of relocation information, known as "base relocations", to allow loading at any address. So it would appear, that the easiest approach is to generate a position-independent ET_DYN ELF executable (with the -pie flag to the linker) and then focus on converting the output to COFF. This is the approach I highly suggest adopting. You will only have to deal with a single relocation type (R_PPC64_RELATIVE in my case) that will map naturally to either the 64-bit or the 32-bit COFF base relocation type, depending on the bit width of your architecture.</div>
<div>
<br /></div>
<div>
Other approaches are possible, such as embedding all relocations with the --emit-relocs linker flag and dealing with the entire soup of crazy relocs later, but the success of this approach is highly dependent on the architecture and ABI. It may be impossible to convert to PE/COFF due to a mismatch between ELF and COFF base relocs and ABI issues. When first working on the PPC64 port, I first followed the AArch64 approach that did just this, and ended up being forced to use the older (and not really meant for LE) ELFv1 ABI. Don't do it.</div>
<div>
<br /></div>
<div>
Note that depending on the ABI, you may have to do a bit of tool work. I am guessing this was the reason why the AArch64 port never adopted using PIE ELF binaries. Fortunately, you should be able to follow along my changes to <a href="https://github.com/andreiw/ppc64le-edk2/blob/master/BaseTools/Source/C/GenFw/Elf64Convert.c">Elf64Convert.c</a>. You may also have to make <a href="https://github.com/andreiw/ppc64le-edk2/blob/master/BaseTools/Scripts/GccBase.lds">changes to the base linker script used with the GNU toolchains</a>.</div>
<div>
<br />
Don't forget that you will need to manually rebuild the BaseTools if you make any changes!
<br />
<pre class="brush: text">make -C BaseTools</pre>
<br /></div>
<div>
At this point we can go back and figure out the compile options. This is the <a href="https://github.com/andreiw/ppc64le-edk2/blob/master/BaseTools/Conf/tools_def.template">BaseTools/Conf/tools_def.template</a> file, that is then copied to Conf/ by <a href="https://github.com/andreiw/ppc64le-edk2/blob/master/edksetup.sh">edksetup.sh </a>on freshly checked-out trees. The compiler options heavily depend on your architecture, of course, but generally speaking:</div>
<div>
<ul>
<li>build on top of definitions made for new architectures like AArch64, because there's simply less of them in this file to wrap your mind around</li>
<li>consider the PPC64 definitions in my tree</li>
<li>-pie, unless position-independent executables don't work for you for some reason</li>
<li>large model</li>
<li>soft float (you can always move to hard float later if that rocks your boat, but it's just more CPU state to wrap your head around)</li>
<li>PECOFF_HEADER_SIZE=0x228 for 64-bit chips, 0x220 for 32-bit ones</li>
</ul>
This is the point where trying to build again should start giving you compile errors, because we still haven't modified any of the Tiano include and library files to be aware of the new architecture.<br />
<br />
<b>To be continued.</b></div>
</div>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-61145980897825036542015-10-01T23:05:00.000-04:002015-10-01T23:11:07.749-04:00Toying around with LE PowerPC64 via the PowerNV QEMUI've validated that my <a href="https://github.com/andreiw/ppc64le_hello">ppc64le_hello</a> example runs on top of BenH's <a href="https://github.com/ozbenh/qemu">PowerNV QEMU tree</a>. Runs really snappy!<br />
<br />
The only thing that doesn't work is mixed page-size segment support (MPSS, like 16MB in a 4K segment). QEMU does not support MPSS at the moment. Also, QEMU does not implement any of the IBM simulator's crazy Mambo calls.Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com1tag:blogger.com,1999:blog-3632708076304946233.post-55190040392732280362015-07-13T18:24:00.000-04:002015-07-13T18:24:32.992-04:00Toying around with LE PowerPC64 via the Power8 simulator<a href="https://github.com/andreiw/ppc64le_hello">ppc64le_hello</a> is simple example of what it takes to write stand-alone (that is, system or OS) code that runs in Little-Endian and Hypervisor modes on the latest OpenPOWER/Power8 chips. Of course, I don't have a spare $3k to get one of <a href="http://www.tyan.com/campaign/openpower/">these nice Tyan reference systems</a>, but IBM does have a free, albeit glacially slow and non-OSS, <a href="https://www.flamingspork.com/blog/2014/12/03/running-skiboot-opal-on-the-power8-simulator/">POWER8 Functional Simulator</a>.
<br />
<br />
What you get is a simple payload you can boot via <a href="https://github.com/open-power/skiboot">skiboot</a>, or another OPAL-compatible firmware. Features, in no particular order:<br />
<ul>
<li>64-bit real-mode HV LE operation.</li>
<li>logging via sim inteface (mambo_write).</li>
<li>logging via OPAL firmware (opal_write).</li>
<li>calling C code, stack/BSS/linkage setup/TOC.</li>
<li>calling BE code from LE.</li>
<li>FDT parsing, dumping FDT.</li>
<li>Taking and returning from exceptions, handling unrecoverable/nested exceptions.</li>
<li>Timebase (i.e. the "timestamp counter"), decrementer and hypervisor decrementer manipulation with some basic timer support (done for periodic callbacks into OPAL).</li>
<li>Running at HV alias addresses (loaded at 0x00000000200XXXXX, linked at 0x80000000200XXXXX). The idea being that the code will access physical RAM and its own data structures solely using the HV addresses.</li>
<li>SLB setup: demonstrates 1T segments with 4K base page and 16M base page size. One segment (slot = 0) is used to back the HV alias addresses with 16M pages. Another segment maps EA to VA 1:1 using 4K pages.</li>
<li>Very basic HTAB setup. Mapping and unmapping for pages in the 4K and 16M segments, supporting MPSS (16M pages in the 4K segment). No secondary PTEG. No eviction support. Not SMP safe. Any access within the HV alias addresses get mapped in. Any faults to other unmapped locations are crashes, as addresses below 0x8000000000000000 should only be explicit maps.</li>
<li>Taking exception vectors with MMU on at the alternate vector location (AIL) 0xc000000000004000.</li>
<li>Running unpriviledged code.</li>
</ul>
See <a href="https://github.com/andreiw/ppc64le_hello">README</a> for more information, including how to build and run. <a href="http://sthbrx.github.io/blog/2015/06/03/ppc64le-hello-on-real-hardware/">At some point it ran on a real Power8 machine</a> - and may run still ;-).Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-23193034927216957022015-07-06T02:04:00.001-04:002015-07-06T02:43:51.602-04:00DOES> in JonesforthJonesforth 47 quoth:
<br />
<pre class="brush: text">
NOTES ----------------------------------------------------------------------
DOES> isn't possible to implement with this FORTH because we don't have a separate
data pointer.
</pre>
<br />
Thankfully, that's not true. The following is a tad AArch32-specific, given that I am playing with pijFORTHos (<a href="https://github.com/organix/pijFORTHos">https://github.com/organix/pijFORTHos</a>), but the principle remains the same. Let's first look at how DOES> gets used.
<pre class="brush: text">
: MKCON WORD CREATE 0 , , DOES> @ ;
</pre>
This creates a word MKCON, that when invoked like:
<pre class="brush: text">
1337 MKCON PUSH1337
</pre>
...creates a new word PUSH1337 that will behave, as if it were defined as:
<pre class="brush: text">
: PUSH1337 1337 ;
</pre>
Recall the <a href="http://osdevnotes.blogspot.com/2015/07/implementing-code-in-aarch32-jonesforth.html">CREATE...;CODE example</a>. DOES> is very similar to ;CODE, except you want Forth words, not native machine words invoked. In ;CODE, the native machine words are embedded in the word using CREATE...;CODE, and in CREATE...DOES> it will be Forth words instead. So if we had no DOES> word, we could write something like:
<pre class="brush: text">
: MKCON WORD CREATE 0 , , ;CODE $DODOES @ ;
</pre>
...where $DODOES is the machine code generator word that creates the magic we've yet to figure out. $DODOES needs to behave like a mix between DOCOL and NEXT, that is adjusting FIP (the indirect threaded code instruction pointer, pointing to the next word to execute) to point past $DODOES to the @ word. The DFA of the CREATEd word (i.e. PUSH1337) is put on the stack, so @ can read the constant (1337) out. This means the simplest CREATE...DOES> example is:
<pre class="brush: text">
: DUMMY WORD CREATE 0 , DOES> DROP ;
DUMMY ADUMMY
</pre>
...because we need to clean up the DFA for ADUMMY that is pushed on its invocation. Anyway, we could thus define DOES> like:
<pre class="brush: text">
: DOES> IMMEDIATE ' (;CODE) , [COMPILE] $DODOES ;
</pre>
Let's look at two ways of implementing $DODOES. Way 1 - fully inline. The address of the Forth words (the new FIP) is calculated by skipping past the bits emitted by $DODOES.
<pre class="brush: text">
.macro COMPILE_INSN, insn:vararg
.int LIT
\insn
.int COMMA
.endm
.macro NEXT_BODY, wrap_insn:vararg=
\wrap_insn ldr r0, [FIP], #4
\wrap_insn ldr r1, [r0]
\wrap_insn bx r1
.endm
@
@ A CREATE...DOES> word is basically a special CREATE...;CODE
@ word, where the forth words follow $DODOES. $DODOES thus
@ adjusts FIP to point right past $DODOES and does NEXT.
@
@ You can think of this as a special DOCOL that sets FIP to a
@ certain offset into the CREATE...DOES> word's DFA. This
@ version is embedded into the DFA so finding FIP is
@ as easy as moving FIP past itself.
@
@ - Just like DOCOL, we enter with CFA in r0.
@ - Just like DOCOL, we need to push (old) FIP for EXIT to pop.
@ - The forth words expect DFA on stack.
@
.macro DODOES_BODY, magic=, wrap_insn:vararg=
0: \wrap_insn PUSHRSP FIP
1: \wrap_insn ldr FIP, [r0]
\wrap_insn add FIP, FIP, #((2f-0b)/((1b-0b)/(4)))
\wrap_insn add r0, r0, #4
\wrap_insn PUSHDSP r0
NEXT_BODY \wrap_insn
2:
.endm
@
@ $DODOES ( -- ) emits the machine words used by DOES>.
@
defword "$DODOES",F_IMM,ASMDODOES
DODOES_BODY ASMDODOES, COMPILE_INSN
.int EXIT
</pre>
Way 2 - partly inline, where the emitted code does an absolute branch and link. This reduces the amount of memory used per definition at the cost of a branch. Ultimately this is the solution adopted. _DODOES calculates the new FIP adjusting the return address from the branch-and-link done by the inlined bits.
<pre class="brush: text">
_DODOES:
PUSHRSP FIP @ just like DOCOL, for EXIT to work
mov FIP, lr @ FIP now points to label 3 below
add FIP, FIP, #4 @ add 4 to skip past ldr storage
add r0, r0, #4 @ r0 was CFA
PUSHDSP r0 @ need to push DFA onto stack
NEXT
.macro DODOES_BODY, wrap_insn:vararg=
1: \wrap_insn ldr r12, . + ((3f-1b)/((2f-1b)/(4)))
2: \wrap_insn blx r12
3: \wrap_insn .long _DODOES
.endm
@
@ $DODOES ( -- ) emits the machine words used by DOES>.
@
defword "$DODOES",F_IMM,ASMDODOES
DODOES_BODY COMPILE_INSN
.int EXIT
</pre>
In either case, just like DOCOL, we need to push the old FIP pointer before calculating the new one. The old FIP pointer corresponds to the address within the word that called the DOES>-created word. In both cases we need to push the DFA of the executing word onto the stack (this is in r0 on the AArch32 Jonesforth).<br /><br />
Finally, in both cases the CREATE...DOES> word is indistinguishable from a CREATE...;CODE word, and the created word is indistinguishable from a word created by a CREATE...;CODE word.
<pre class="brush: text">
\ This is the CREATE...;CODE $DOCON END-CODE example before.
: MKCON WORD CREATE 0 , , ;CODE ( MKCON+7 ) E590C004 E52DC004 E49A0004 E5901000 E12FFF11 (END-CODE)
CODE CON ( CODEWORD MKCON+7 ) 5 (END-CODE)
\ Fully inlined CREATE...DOES>.
: MKCON_WAY1 WORD CREATE 0 , , ;CODE ( MKCON_WAY1+7) E52BA004 E590A000 E28AA020 E2800004 E52D0004 E49A0004 E5901000 E12FFF11 9714 938C (END-CODE)
CODE CON_BY_WAY1 ( CODEWORD MKCON_WAY1+7 ) 5 (END-CODE)
\ Partly-inlined CREATE...DOES>.
: MKCON_WAY2 WORD CREATE 0 , , ;CODE ( MKCON_WAY2+7 ) E59FC000 E12FFF3C 9F64 9714 938C (END-CODE)
CODE CON_BY_WAY2 ( CODEWORD MKCON_WAY2+7 ) 5 (END-CODE)
</pre>
This makes decompiling (i.e. SEE) a bit tricky, but not impossible. As you can see here, I haven't written a good disassembler yet, which would detect these sequences as $DOCON. IMHO this is still a lesser evil than introducing new fields or flags into the word definition header.<br /><br />
P.S. Defining constants is a classical example of using DOES>, but a bit silly when applied to Jonesforth, where it's an intrinsic. It's an intrinsic so that certain compile-time constants, known only at assembler time, can be exposed to the Forth prelude and beyond. The other classical example of DOES> is struct-like definitions.<br /><br />
P.P.S. You might be wondering how I'm SEEing into code words, as neither Jonesforth nor pijFORTHos support it. I guess I'll blog about that next real soon whenever... The ( CODEWORD XXX ) business here shows the "code word" pointed to by the CFA, which is necessarily not DOCOL (otherwise it would be a regular colon definition, not CODE). The ( CODEWORD word+offset ) notation tells you that the machine words pointed to by the CFA are part of a different word. Native (jonesforth.s-defined) intrinsics would decompile as something like:
<pre class="brush: text">
CODE 2SWAP ( CODEWORD 85BC ) (END-CODE)
</pre>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-27804523037404572912015-07-05T01:45:00.001-04:002015-07-05T17:14:17.074-04:00Implementing ;CODE in AArch32 Jonesforth for realThe Jonesforth ;CODE definition is unfortunately little more than a curiosity. After all, if you wanted
to write a native machine word, you'd probably follow along and implement it inside jonesforth.s proper using the defcode macro. The real power of ;CODE would be in coupling with the CREATE word, letting you have words that define other words.<br />
<br />
I.e. we want to be able to do something like:
<pre class="brush: text">
defword "$DOCON",F_IMM,ASMDOCON
.int LIT @ r0 points to DFA
ldr r12, [r0, #4] @ read cell from DFA
.int COMMA
.int LIT
PUSHDSP r12 @ push to stack
.int COMMA
.int EXIT
: MKCON
WORD CREATE
0 , ( push dummy codeword, rewritten by (;CODE) )
, ( actual constant )
;CODE
$DOCON
END-CODE
5 MKCON CON5 ( create word CON5 that will push 5 on stack )
CON5 . CR ( prints 5 )
</pre>
So ;CODE is the variant to be used with CREATE, while the plain ol' make-me-a-native-word variant is called CODE. And both get to be matched with END-CODE, not semicolon. At least according to F83 or something. We're not trying to stick to any Forth standard, but the definitions have to be useful...right? So the ;CODE business now looks a bit different:
<pre class="brush: text">
\ This used to look like : FOO ;CODE
CODE FOO CODE-END
@ push r0 to stack
defword "$<R0",F_IMM,ASMFROMR0
.int LIT
PUSHDSP r0
.int COMMA
.int EXIT
@ push r7 to stack
defword "$<R7",F_IMM,ASMFROMR7
.int LIT
PUSHDSP r7
.int COMMA
.int EXIT
@ pop stack to r0
defword "$>R0",F_IMM,ASMTOR0
.int LIT
POPDSP r0
.int COMMA
.int EXIT
@ pop stack to r7
defword "$>R7",F_IMM,ASMTOR7
.int LIT
POPDSP r7
.int COMMA
.int EXIT
CODE SWAP $>R0 $>R7 $<R0 $<R7 END-CODE
HEX 1337 FOOF SWAP . . ( prints 1337 FOOF )
</pre>
So now for the actual definitions. It /looks/ pretty tame...but it took me a week to wrap my mind around it.
<pre class="brush: text">
: (;CODE) R> LATEST @ >CFA ! ;
: ;CODE IMMEDIATE ' (;CODE) , ;
: (CODE) HERE @ LATEST @ >CFA ! ;
: CODE : (CODE) ;
: (END-CODE-INT) LATEST @ HIDDEN [COMPILE] [ ;
: (END-CODE) IMMEDIATE (END-CODE-INT) ;
: END-CODE IMMEDIATE [COMPILE] $NEXT (END-CODE-INT) ;
HIDE (END-CODE-INT)
HIDE (CODE)
</pre>
Most interesting here is the behavior of ;CODE. Let's examine the example I gave first. It's an IMMEDIATE word that will compile (;CODE) into MKCON, followed by the machine code placed by generators like $NEXT or $DOCON. When MKCON is executed, it will then update the CFA of CON5 to point to the machine words inside MKCON that followed (;CODE), instead of DOCOL. The address of machine words of course is on the return stack since it's the first word following (;CODE). Aaaaand because we pop the return address, we end up EXITing not to MKCON from (;CODE) but to its caller, thereby not crashing on the crazy machine code placed by $DOCON.
<br /><br />
Fun. Hope that made sense. I had to meditate for a while over Brad Rodriguez' Moving Forth 3 (<a href="http://www.bradrodriguez.com/papers/moving3.htm">http://www.bradrodriguez.com/papers/moving3.htm</a>) article before it made any sense to me. But like all ingenious beautiful things, it ends up being dead simple.Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-39367470412803476492015-07-05T01:11:00.000-04:002015-07-05T23:10:56.842-04:00Implementing ;CODE in AArch32 JonesforthSo I got a new Raspberry Pi and me being me got sidetracked playing with a toy Forth implementation, pijFORTHos (<a href="https://github.com/organix/pijFORTHos">https://github.com/organix/pijFORTHos</a>),which is a standalone AArch32 port of Jonesforth (<a href="https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/">https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/</a>), which is/was an IA32-only affair. Of course I've always been amused by the idea of writing a kernel in Forth...so why not? Sadly, I probably won't do much with this...<br />
<br />
Anyway. To cut to the chase, pijFORTHos was missing the ;CODE functionality from Jonesforth 47, which let you define native machine words in Forth... i.e. an assembler, basically. A couple of completely empty and useless examples that do nothing (and yet not crash) would look like:<br />
<pre class="brush: text">
: FOO ;CODE
: BAR $NEXT ;CODE
</pre>
The later is redundant, since $NEXT is already emitted by ;CODE. <a href="https://github.com/andreiw/pijFORTHos/commit/ac99b06e4b722926f0b5a5d31e97ba91eba6f4e4">The implementation is straighforward.</a>. Although I took the liberty of sticking it into jonesforth.s instead of the Forth prelude, and in the actual commit I'm a bit smarter about defining $NEXT and the actual _NEXT/NEXT bits used by the Forth core itself. You wonder why bother emitting the NEXT bits inline instead of branching, but the later would take up 3 cells as well (ldr, bx and immed for ldr) and also involve a branch. Look at how the $NEXT word is defined. Isn't this crazy? It's an IMMEDIATE word that writes literals, which just happen to be machine code, at HERE, effectively compiling them into the current word definition when used in compiler mode (such as a colon definition).
<pre class="brush: text">
@
@ $NEXT ( -- ) emits the _NEXT body at HERE, to be used
@ in ;CODE or ;CODE-defined words.
@
defword "$NEXT",F_IMM,ASMNEXT
.int LIT
ldr r0, [FIP], #4
.int COMMA
.int LIT
ldr r1, [r0]
.int COMMA
.int LIT
bx r1
.int COMMA
.int EXIT
@
@ Finishes a machine code colon definition in Forth, as
@ a really basic assembler.
@
defword ";CODE",F_IMM,SEMICODE
.int ASMNEXT @ end the word with NEXT macro
.int LATEST, FETCH, DUP @ LATEST points to the compiled word
.int HIDDEN @ unhide the compiled word
.int DUP, TDFA, SWAP, TCFA, STORE @ set codeword to data instead of DOCOL
.int LBRAC @ just like ";" exit compile mode
.int EXIT
</pre>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-54208544795432315992014-12-07T23:21:00.001-05:002014-12-07T23:21:54.358-05:00iQUIK supports the Performa 6400After fixing some sad bugs from the last refactoring binge and adding support for OF 2.0, the 6400 (and likely all "Alchemy"-based Macs) can be booted via iQUIK.<div><br></div><div>Just like OpenFirmware 2.0.1, 2.0 seems to suffer from the "shallow setprop" bug, that results in bogus values for the /chosen/linux,initrd-start and /chosen/linux,initrd-end properties.</div><div><br></div><div><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0ortZ95Vp_Hqi7Oc1ALtRO8TXpIBM4zq4sKXFRsFCWUhRfw_l04vbS4A5C4p0n1zp6XywP6Ub1YKqgDhN9DN4xCYzTa0ZshGYW3KnihPJqZl-QAFrDU4O0ul2SkulU6DcNH25eY5z39S8/s640/blogger-image--1981681049.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0ortZ95Vp_Hqi7Oc1ALtRO8TXpIBM4zq4sKXFRsFCWUhRfw_l04vbS4A5C4p0n1zp6XywP6Ub1YKqgDhN9DN4xCYzTa0ZshGYW3KnihPJqZl-QAFrDU4O0ul2SkulU6DcNH25eY5z39S8/s640/blogger-image--1981681049.jpg"></a></div><br></div>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com2tag:blogger.com,1999:blog-3632708076304946233.post-87696117308717374932014-11-28T01:42:00.000-05:002014-11-28T01:44:17.869-05:00Using the Nexus 9 secure agent for debug logging<pre class="brush: python">
#!/usr/bin/python
import fileinput, re, sys
#
# It turns out the "Trusty Secure OS" Crippleware on the Nexus 9 is
# good for least something. It is thankfully pretty chatty, meaning
# you can use it for logging from code where it's inconvenient
# or impossible to write to the UART directly, like MMU bringup code ;-).
#
# A sequence like:
# mov x0, #'V'
# smc #0xFFFF
#
# ...will result in the following getting emitted. I am guessing x1...x3
# get printed here as param0..2 but I am too lazy to check.
#
# smc_undefined:67: Undefined monitor call!
# smc_undefined:67: SMC: 0x56 (Stdcall entity 0 function 0x56)
# smc_undefined:67: param0: 0xf77c2e69
# smc_undefined:67: param1: 0xf77c2e68
# smc_undefined:67: param2: 0x0
#
# Now you can do basic logging to debug early bring-up. The following
# Python will turn your giant Minicom capture into something more
# sensible.
#
def process(line):
m = re.match('\s*smc_undefined:67: SMC: (0x[0-9a-f]+)', line)
if m:
sys.stdout.write(chr(int(m.groups()[0], 16)))
for line in fileinput.input():
process(line)
print("\n");
</pre>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-39123891951671668032014-11-23T23:00:00.003-05:002014-11-24T14:33:04.007-05:0064-bit ARM OS/Kernel/Systems Development Demo on a Nexus 9<h2>64-bit ARM OS/Kernel/Systems Development on a Nexus 9</h2>
The Nexus 9 is based on a 64-bit nVidia K1 chip. At the moment it is the most affordable (price wise) and accessible (unit-wise) platform for exploring OS work on an AArch64 platform. The Nexus 9 allows performing an unlock via "fastboot oem unlock", allowing custom Android images to be booted.<br /><a href="https://github.com/andreiw/nexus9_demo">https://github.com/andreiw/nexus9_demo</a>
<h3>What this is</h3>
This is a small demo, demonstrating how to build and boot arbitrary code on your Nexus 9 and do some basic I/O. The demo demonstrates serial I/O and draws two black diagonal lines on the framebuffer.<br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg04dfhc13y4FqVi_PrhP8J8hJTFO14kL_AB-zN_nxcQCJbqCnit98aI-wthrYIXZSZ7mGk6nIQiSzK6RZ6xm4rFN-Y9sAY4q0FfHphhwC4lvy1oun_TaF2rZmm2Egkd3asgYSUIxVSqQK2/s1600/demo_pic.jpg"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg04dfhc13y4FqVi_PrhP8J8hJTFO14kL_AB-zN_nxcQCJbqCnit98aI-wthrYIXZSZ7mGk6nIQiSzK6RZ6xm4rFN-Y9sAY4q0FfHphhwC4lvy1oun_TaF2rZmm2Egkd3asgYSUIxVSqQK2/s1600/demo_pic.jpg" alt="" width="239" height="320" border="0" /></a>
<h3>What you need - required</h3>
<ul>
<li>A Nexus 9, unlocked. Search Youtube for walkthroughs</li>
<li>GNU Make</li>
<li>An AArch64 GNU toolchain</li>
<li>ADB/Fastboot tools</li>
<li>Booting tools from <a href="https://github.com/pbatard/bootimg-tools">https://github.com/pbatard/bootimg-tools</a> somewhere in your path</li>
</ul>
<h3>What you need - optional</h3>
<ul>
<li>A headset to RS232 adapter. I've used a cable I've had from the Motorola Xoom project (the first...errr, Nexus, before the devices got called a "Nexus"). You can try <a href="http://www.accuvant.com/blog/building-a-nexus-4-uart-debug-cable">http://www.accuvant.com/blog/building-a-nexus-4-uart-debug-cable</a></li>
</ul>
<h3>How it works</h3>
HBOOT, the Nexus bootloader, expects images to be in a certain format. The booted kernel/code must:
<ul>
<li>Be 64-bit</li>
<li>Be binary (not ELF)</li>
<li>Be linked at 0x80080000</li>
<li>Be compressed using "gzip"</li>
<li>Be followed by the binary FDT</li>
<li>Be contained in an "ANDROID!" boot image.</li>
</ul>
<p>Some notes:</p>
<ul>
<li>The link address appears to be hardcoded in HBOOT. The Android boot image bases and the AArch64 kernel header fields appear to be ignored.</li>
<li>The boot image can contain an additional ramdisk/initrd/payload.</li>
<li>The FDT is patched by HBOOT to contain correct linux,initrd-start and linux,initrd-end addresses.</li>
</ul>
<h3>How to build</h3>
<pre class="brush: plain">$ CROSS_COMPILE=aarch64-linux-gnu- make</pre>
<h3>How to boot</h3>
Connect your Android tablet via a USB cable. Optionally connect the UART headphone jack adapter to your computer. The settings are 115200 8-n-1.
<pre class="brush: plain">$ adb reboot-bootloader
$ fastboot boot nexus9_demo</pre>
<h3>Actual output of the demo</h3>
<pre class="brush: plain">Hello!
CurrentEL = 0000000000000001
SCTLR_EL1 = 0000000010C5083A
Bye!</pre>
<h3>Where to go from here</h3>
<p>"nexus9_dts" is the decompiled "nexus9_dtb". "nexus9_dtb" was extracted from the Android boot.img.</p>
<ul>
<li><a href="https://android.googlesource.com/kernel/tegra/+/android-tegra-3.10/">https://android.googlesource.com/kernel/tegra/+/android-tegra-3.10/</a></li>
<li><a href="https://developer.nvidia.com/tegra-k1-technical-reference-manual">https://developer.nvidia.com/tegra-k1-technical-reference-manual</a></li>
</ul>
<h3>Final thoughts</h3>
From studying the Tegra K1 TRM, the K1 should have virtualization support (i.e. EL2). However, the HTC firmware does not allow booting an EL2-enabled OS. All kernels are booted in EL1. This is rather unfortunate and prevents playing around with KVM and Xen on this platform. Perhaps there are some problems with EL2 support. Or perhaps HTC/nVidia/Google were too myopic to allow EL2 access. It's unclear if the "oem unlock" allows reflashing custom unsigned firmware. "nvtboot" seems to enforce signed "Trusted OS" payloads, at least from dumping the strings. The boot flow looks something like this:
<ul>
<li>"nvtboot" (32-bit) runs on the AVP/COP.</li>
<li>"nvtboot" loads "tos" (64-bit) (Trusty aka Secure OS) on the AArch64 chip.</li>
<li>"tos" loads HBOOT (32-bit).</li>
<li>HBOOT loads Android and implements the fastboot protocol.</li>
</ul>
It's unclear how to enter NVFlash/APX mode, or how helpful that would be.Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com2tag:blogger.com,1999:blog-3632708076304946233.post-89677301207729215732014-06-25T14:27:00.000-04:002014-06-25T14:27:46.739-04:00Solaris/PPCApparently back around 2006 there was an effort at Sun Labs to get OpenSolaris to work on CHRP(like) PowerPC machines. And according to the documentation, the kernel could even boot to shell on a G4 Apple.<br />
<br />
That effort was called Polaris. It was difficult to find the CDDL-licensed sources, but I've made them available for everyone else to play with at <a href="https://github.com/andreiw/polaris">https://github.com/andreiw/polaris</a><br />
<br />
I haven't tried it out or done anything with the sources yet. The Solaris kernel is a pretty amazing piece of software, and a very portable and well-designed one to boot. I am glad Sun open-sourced it before folding, as it's code like this that should be influencing OS R&D for generations to come. It would be interesting to see the Polaris code being used as a base for an AArch64 investigation...<br />
<br />
AAnonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com3tag:blogger.com,1999:blog-3632708076304946233.post-34765881239740754512014-06-24T19:27:00.000-04:002014-06-24T19:27:37.187-04:00What's special about...<br />
addi r0,r1,0x138<br />
ori r0,r0,0x60<br />
<br />
...and I/O port 0x92 :-)?<br />
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-58410712854441957212014-06-22T02:41:00.000-04:002014-06-22T02:41:38.381-04:00iQUIK updateI now have a 1.5Ghz PowerBook 12" in my possession to test iQUIK with. This is of course a NewWorld, and not a primary target for the iQUIK boot loader...<br />
<br />
Couple of observations to be made:<br />
<ul>
<li>OpenFirmware 3.0 doesn't support partition zero booting (i.e. hd:0 or CHRP-spec hd:%BOOT). This means that iQUIK cannot be booted the same way as it boots on OldWorlds, but neither is it required. iQUIK can be booted on NewWorlds the same way as Yaboot, i.e. placing 'iquik.elf' on an HFS+ partition and blessing it. </li>
<li>NewWorld OF requires appending ":0" for full-disk access to disk devices</li>
</ul>
<div>
I've also fixed a bug inside partition code that truncated offsets to 32 bits, and improved device path handling and parsing.</div>
<div>
<br /></div>
<div>
In short, though, it works. And it works quite well. So iQUIK now works on OldWorld and NewWorld machines. Yaboot - only on NewWorlds. Of course, Yaboot also supports CHRP machines, network booting and reads all filesystems supported by the underlying OpenFirmware implementation. So there's plenty of work to reach feature parity in that regard.</div>
<div>
<br /></div>
<div>
A</div>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-83519264142811087682014-06-03T23:36:00.001-04:002014-06-03T23:36:26.435-04:00Detecting 'make' environment variables changeWhile playing with 'iquik' and trying to add a mode to build a reduced-logging version that is smaller, I ran into an interesting question - how do I force a rebuild of everything with a clean?
<br />
<pre class="brush: plain">
#
# Example of a Makefile that detects "environment change".
#
# I.e.:
#
# andreiw-lnx:~/src/ make clean
# Cleaning
# andreiw-lnx:~/src/ make
# Resuming build with env ""
# Building with ""
# andreiw-lnx:~/src/ make CONFIG_EXAMPLE=1
# Cleaning due to env change (was "" now "-DCONFIG_EXAMPLE")
# Cleaning
# Building with "-DCONFIG_EXAMPLE"
# andreiw-lnx:~/src/ make CONFIG_EXAMPLE=1
# Resuming build with env "-DCONFIG_EXAMPLE"
# Building with "-DCONFIG_EXAMPLE"
# andreiw-lnx:~/src
#
ENV_FILE=old_build_env
-include $(ENV_FILE)
#
# Environment definition.
#
ifeq ($(CONFIG_EXAMPLE), 1)
BUILD_FLAGS = -DCONFIG_EXAMPLE
endif
BUILD_ENV = "OLD_BUILD_FLAGS=$(BUILD_FLAGS)"
#
# Detect environment change.
#
ifneq ($(BUILD_FLAGS),$(OLD_BUILD_FLAGS))
PRETARGET=clean_env
else
PRETARGET=log_env
endif
all: $(PRETARGET) target
target:
@echo Building with \"$(BUILD_FLAGS)\"
log_env:
@echo Resuming build with env \"$(BUILD_FLAGS)\"
log_clean_env:
@echo Cleaning due to env change \(was \"$(OLD_BUILD_FLAGS)\" now \"$(BUILD_FLAGS)\"\)
clean_env: log_clean_env clean
@rm -f $(ENV_FILE)
@echo $(BUILD_ENV) > $(ENV_FILE)
clean:
@echo Cleaning
</pre>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-63797399613619736482014-05-31T00:58:00.000-04:002014-05-31T03:19:23.344-04:00Musings on device workarounds and attributionI was trading war stories with some colleagues today, and remembered the time I was chasing crazy UART bugs.<br />
<br />
So I <i>just had </i>to go look at my battlefields of past and reminisce...<br />
<br />
Ever look at a random driver and wonder how convoluted weird code gets written? Then you look at the git history and see - nothing useful. No history. It was <i>apparently </i>all written at once, by some crazy smart engineer based on thorough and clean specs, right ;-)?<br />
<br />
<a href="https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/drivers/tty/serial/serial-tegra.c?id=refs/tags/v3.15-rc7">Like the serial-tegra driver, for example.</a> Ever wonder why UART waits for a certain bit of time after switching baud rate?<br />
<br />
I used to work on the Moto Xoom tablet - the first official Android tablet, based around the Tegra 2 SoC. Once upon a time I was investigating a bug around suspend-resume. We were seeing a kernel crash when waking the tablet up occasionally with a paired Bluetooth keyboard. The actual crash was the result of a BlueZ bug that didn't defensively treat BT HCI connect events for devices that weren't disconnected (have a gander at <a href="http://www.spinics.net/lists/linux-bluetooth/msg10690.html">http://www.spinics.net/lists/linux-bluetooth/msg10690.html</a> - yes, a rogue Bluetooth adapter /can/ crash the system, wonderful, right?)<br />
<br />
But why weren't the BT disconnect messages coming through?<br />
<br />
The tablet was asleep at the time of the disconnect, and the disconnect woke it up. The Bluetooth host was connected to the CPU via a UART, and the UART needed to be resumed before the BT host could send data. UART resume, among other things, needs to set the baud rate. What was happening, is that the the hardware flow control allowed RX before the baud rate change fully propagated through the UART block. The result is that the received data was corrupted. Oops.<br />
<br />
Knowing what was happening didn't mean I had a solution, of course. The docs were useless, and <a href="https://gitorious.org/trimslice-kernel/jeremiahs-trimslice-kernel/commit/aaf98d1380d04fa16584f41b5b4fcf184b9eac85">it took another fun half a week to figure out the solution</a> :-). Too bad I can't remember <a href="https://android.googlesource.com/kernel/tegra/+/db8872556e282e57992b28c3a0aade43ca5744f7%5E%5E!/">what this fix </a>was for... Probably more BT issues :).<br />
<br />
So what point did I want to make? The Tegra HSUART driver "<a href="https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/tty/serial/serial-tegra.c?id=e9ea096dd2259454e0d09d0b0445fe8f0117add4">got rewritten</a>" when Tegra 2/3 support was upstreamed. But it's the same code, basically, even down to the code flow and comments. You put in time, sleepless nights and life energy and you can't get basic attribution from some unknown dude at NV.<br />
<br />
Behind every line of code is some story. Some feeling of exhilaration, success and victory. I almost made a t-shirt with the fix :-). So always attribute contributions out of solidarity with your fellow hackers. Heh.<br />
<br />
BlueZ is a train wreck, though... There. I said it.Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-432350097670855212014-05-30T01:27:00.002-04:002014-05-30T01:28:09.800-04:00MkLinuxThe first step to getting MkLinux to run is to get the build tools to run.<br />
<br />
Build tools?<br />
<br />
The OSF Open Development Environment tools. Which have been very hard to find (<a href="https://github.com/slp/mkunity/issues/1">https://github.com/slp/mkunity/issues/1</a>).
But now you can find them and even build them - <a href="https://github.com/andreiw/ode4linux">https://github.com/andreiw/ode4linux</a><br />
<br />
If I ever find time I'll clean up the code so it doesn't build with a million warnings.<br />
<br />
AAnonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-75445942340028076422014-04-12T00:03:00.002-04:002014-04-12T00:06:21.170-04:00Inline assembler stupidityI keep getting caught by this, because this is a perfect example of the compiler doing something contrary to what you're writing.
<pre class="brush: c">
asm volatile (
"ldr %0, [%1]\n\t"
"add %0, %0, #1\n\t"
"str %0, [%1]\n\t"
: "=r" (tmp)
: "r" (p)
:
);
</pre>
<br />
Guess what this gets compiled to?
<pre class="brush: plain">
30: f9400000 ldr x0, [x0]
34: 91000400 add x0, x0, #0x1
38: f9000000 str x0, [x0]
</pre>
<br />
...equivalent to, of course,
<pre class="brush: c">
asm volatile (
"ldr %0, [%0]\n\t"
"add %0, %0, #1\n\t"
"str %0, [%0]\n\t"
: "+r" (p)
:
:
);
</pre>
The sort of aggressive and non-obvious optimization is crazy because if I really wanted the generated code, I'd have written the inline asm the second way with a read and write modifier. Maybe for architectures with specialized and very few registers this is a reasonable approach, but for RISCish instruction sets with large instruction files this is nuts. There should be a warning option for this nonsense.
<br />
<br />
This "correct way" is to use an earlyclobber modifier.
<pre class="brush: c">
asm volatile (
"ldr %0, [%1]\n\t"
"add %0, %0, #1\n\t"
"str %0, [%1]\n\t"
: "=&r" (tmp)
: "r" (p)
:
);
</pre>
IMO anything that needs a separate paragraph in third-party documents as "a caveat" needs to be fixed.
<br />
<br />
Speaking of which... Given that C really is a high-level assembly, why not finally standardize on inline asm?Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-88426623651344501692014-04-02T13:49:00.000-04:002014-04-04T01:26:51.778-04:00Exotic QEMU bugs and fixesI found that the linux-user portion of QEMU has a few bugs around signals. Really, around handling "self-modifying" code and having the code generator step on unmapped memory.<br />
<br />
The test is pretty simple. Have a page of memory containing one instruction which will cause SIGILL
to be delivered, followed by a 'ret'. On a SIGILL, unmap the page. On a SIGSEGV, map the page back in. I've two of these tests - one with actual mmap/munmap, and another with mprotect. The tests verify corner conditions in the binary translation logic, with back-to-back signals and an attempt to execute unmapped code.
<br />
<a href="https://github.com/andreiw/andreiw-wip/blob/master/qemu/tests/sigtest.c">https://github.com/andreiw/andreiw-wip/blob/master/qemu/tests/sigtest.c</a><br />
<a href="https://github.com/andreiw/andreiw-wip/blob/master/qemu/tests/sigtest_mprotect.c">https://github.com/andreiw/andreiw-wip/blob/master/qemu/tests/sigtest_mprotect.c</a><br />
<br />
"self-modifying" code sounds grand, but it's just the signal return path. While newer Linux kernels use VDSO symbols for the restorer (that's the part that does the sigreturn syscall), QEMU still creates an
on-the-stack trampoline. When QEMU creates a translation block for the trampoline, it marks the
page internally as read-only so that it can detect when the TB should be invalidated. It is this later logic
which was short-circuiting and exiting earlier than needed.
<br />
That's fixed in <a href="https://github.com/andreiw/andreiw-wip/blob/master/qemu/0001-qemu-fix-page_check_range.patch">https://github.com/andreiw/andreiw-wip/blob/master/qemu/0001-qemu-fix-page_check_range.patch</a><br />
<br />
The second problem is that QEMU doesn't deal very well with being forced to run code that's unmapped. The TCG generator walks over the unmapped memory, gets a SIGSEGV, which attempts delivery of the signal to the translated program (which again, means getting and/or creating more TBs). The problem, though, is that we attempt to reacquire the tcg_ctx.tb_ctx.tb_lock, which we never
dropped due to the signal. i.e. after a SIGSEGV here:
<br />
<pre class="brush: plain">#0 disas_a64_insn (s=0x7fffffffdc40, env=<optimized out>) at /target-arm/translate-a64.c:8972
#1 gen_intermediate_code_internal_a64 (cpu=cpu@entry=0x62532200, tb=tb@entry=0x7ffff440b120, search_pc=search_pc@entry=false) at /target-arm/translate-a64.c:9097
#2 0x00000000600d76e5 in gen_intermediate_code_internal (search_pc=false, tb=0x7ffff440b120, cpu=0x62532200) at /target-arm/translate.c:10629
#3 gen_intermediate_code (env=env@entry=0x6253a468, tb=tb@entry=0x7ffff440b120) at /target-arm/translate.c:10904
#4 0x00000000600e4851 in cpu_arm_gen_code (env=env@entry=0x6253a468, tb=tb@entry=0x7ffff440b120, gen_code_size_ptr=gen_code_size_ptr@entry=0x7fffffffdd64) at /translate-all.c:159
#5 0x00000000600e5152 in tb_gen_code (cpu=cpu@entry=0x62532200, pc=pc@entry=4820992, cs_base=cs_base@entry=0, flags=<optimized out>, cflags=cflags@entry=0) at /translate-all.c:973
#6 0x0000000060040e7a in tb_find_slow (flags=<optimized out>, pc=4820992, env=0x6253a468, cs_base=<optimized out>) at /cpu-exec.c:162
#7 tb_find_fast (env=0x6253a468) at /cpu-exec.c:193
#8 cpu_arm_exec (env=env@entry=0x6253a468) at /cpu-exec.c:611
#9 0x000000006005ad2c in cpu_loop (env=env@entry=0x6253a468) at /linux-user/main.c:1015
#10 0x0000000060004dd1 in main (argc=1, argv=<optimized out>, envp=<optimized out>) at /linux-user/main.c:4392
</pre>
<br />
We longjmp back to the CPU loop and deadlock here:
<br />
<pre class="brush: plain">#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:132
#1 0x000000006012991d in _L_lock_858 ()
#2 0x000000006012978a in __pthread_mutex_lock (mutex=0x604ffa98 <tcg_ctx+350904>) at pthread_mutex_lock.c:61
#3 0x0000000060040bfd in cpu_arm_exec (env=env@entry=0x6253a228) at /cpu-exec.c:610
#4 0x000000006005ad2c in cpu_loop (env=env@entry=0x6253a228) at /linux-user/main.c:1015
#5 0x0000000060004dd1 in main (argc=1, argv=<optimized out>, envp=<optimized out>) at /linux-user/main.c:4392
</pre>
The solution is to allow tb_gen_code to back out if it knows it can't read the memory. A new exception type is added, EXCP_TB_EFAULT, which then needs to be handled just like an address fault inside cpu_loop.<br />
<br />
<a href="https://github.com/andreiw/andreiw-wip/blob/master/qemu/0002-qemu-handle-tb_gen_code-getting-called-for-unmapped-.patch">https://github.com/andreiw/andreiw-wip/blob/master/qemu/0002-qemu-handle-tb_gen_code-getting-called-for-unmapped-.patch</a><br />
<a href="https://github.com/andreiw/andreiw-wip/blob/master/qemu/0003-x86-implement-EXCP_TB_EFAULT.patch">https://github.com/andreiw/andreiw-wip/blob/master/qemu/0003-x86-implement-EXCP_TB_EFAULT.patch</a><br />
<br />
This makes the above tests pass on AArch64 and x86 (32-bit only, since there is no signal handling support for the x86_64-linux-user target at the moment).<br />
<br />
<span style="color: red;">Update: Fixes look like they're going in. The TCG deadlock is getting fixed in a simpler way. It is a better and more self-contained fix. <a href="http://www.mail-archive.com/qemu-devel@nongnu.org/msg225421.html">http://www.mail-archive.com/qemu-devel@nongnu.org/msg225421.html</a></span>Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-7030470633230832272014-03-18T12:16:00.002-04:002014-03-18T12:18:31.349-04:00OpenBIOS and partition-zero booting, reduxAs of r1280 OpenBIOS now correctly implements booting via partition-zero boot block.<br />
<br />
<a href="http://git.qemu.org/?p=openbios.git;a=commit;h=1ac3fb92c109f5545d373a0576b87750c53cce19">http://git.qemu.org/?p=openbios.git;a=commit;h=1ac3fb92c109f5545d373a0576b87750c53cce19</a><br />
<br />
That's the power of Open Source.<br />
<br />Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-85555200319060459722014-03-05T04:50:00.002-05:002014-03-05T04:50:55.188-05:00Preboot scripts, redux.The old implementation suffered from a couple problems:<br />
<ul>
<li>Chain booting and separate boot blocks made installation fussy</li>
<li>I discovered that some OF versions don't quite claim more than a certain amount of memory for loading, making dual boot blocks waste a lot of precious RAM (I had two useless 4K stacks, for example). The symptom is a DSI during the actual load by the firmware - the same problem as seen trying to boot *BSD boot floppies on the 3400c. There might be a work around manually claiming the memory, but... heh.</li>
</ul>
<div>
I then realized I could have well added the preboot script at the end of the iquik.b block, and have the later be smart enough to eval the script prior to looking for the boot-file.</div>
<div>
<br /></div>
<div>
Usage is pretty simple (the -p option):
<br />
<pre class="brush: plain">$ cat > hello.of
$ cr cr cr ." Hello OF!!!" cr cr cr
$ iquik -p hello.of
</pre>
<br />
Of course, this works only if booting iQUIK via partition zero (i.e. :0 or %BOOT). Presumably if you're running the ELF directly (hi CHRP!), you'll use a normal CHRP boot script.</div>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-85098554492677704872014-03-05T04:07:00.001-05:002014-03-05T04:08:17.070-05:00Making OpenBIOS support Apple partition-zero bootingTo speed up my development cycle on iQUIK and make it less painful I really needed to get OpenBIOS to boot via bootcode correctly. The current sources (r1272) hard code the load address for the legacy QUIK bootloader, which makes it useless for me or for anyone else (like the NetBSD or OpenBSD bootloaders).<br />
<br />
I didn't try very hard, but the end result works, and hopefully the OpenBIOS guys will just take my fix.<br />
<br />
SVN workflow seems so...senescent compared to git. Sigh.
<pre class="brush: plain">Index: forth/debugging/client.fs
===================================================================
--- forth/debugging/client.fs (revision 1272)
+++ forth/debugging/client.fs (working copy)
@@ -28,7 +28,13 @@
0 state-valid !
variable want-bootcode
+variable bootcode-base
+variable bootcode-size
+variable bootcode-entry
0 want-bootcode !
+0 bootcode-base !
+0 bootcode-size !
+0 bootcode-entry !
variable file-size
Index: libopenbios/bootcode_load.c
===================================================================
--- libopenbios/bootcode_load.c (revision 1272)
+++ libopenbios/bootcode_load.c (working copy)
@@ -12,13 +12,11 @@
#define printf printk
#define debug printk
-#define OLDWORLD_BOOTCODE_BASEADDR (0x3f4000)
-
int
bootcode_load(ihandle_t dev)
{
int retval = -1, count = 0, fd;
- unsigned long bootcode, loadbase, offset;
+ unsigned long bootcode, loadbase, offset, loadsize, entry;
/* Mark the saved-program-state as invalid */
feval("0 state-valid !");
@@ -33,34 +31,59 @@
loadbase = POP();
#ifdef CONFIG_PPC
- /* ...except that QUIK (the only known user of %BOOT to date) is built
- with a hard-coded address of 0x3f4000. Let's just use this for the
- moment on both New World and Old World Macs, allowing QUIK to also
- work under a New World Mac. If we find another user of %BOOT we can
- rethink this later. PReP machines should be left unaffected. */
+ /*
+ * Apple OF does not honor load-base and instead uses pmBootLoad
+ * value from the boot partition descriptor.
+ *
+ * Tested with:
+ * a debian image with QUIK installed
+ * a debian image with iQUIK installed (https://github.com/andreiw/quik)
+ * an IQUIK boot floppy
+ * a NetBSD boot floppy (boots stage 2)
+ */
if (is_apple()) {
- loadbase = OLDWORLD_BOOTCODE_BASEADDR;
+ feval("bootcode-base @");
+ loadbase = POP();
+ feval("bootcode-size @");
+ loadsize = POP();
+ feval("bootcode-entry @");
+ entry = POP();
+
+ printk("bootcode base 0x%lx, size 0x%lx, entry 0x%lx\n",
+ loadbase, loadsize, entry);
+ } else {
+ entry = loadbase;
+
+ /* Load as much as we can. */
+ loadsize = 0;
}
#endif
bootcode = loadbase;
offset = 0;
- while(1) {
+ if (loadsize) {
+ if (seek_io(fd, offset) != -1)
+ count = read_io(fd, (void *) bootcode, loadsize);
+ } else {
+ while(1) {
if (seek_io(fd, offset) == -1)
- break;
+ break;
count = read_io(fd, (void *)bootcode, 512);
offset += count;
bootcode += count;
+ }
}
/* If we didn't read anything then exit */
if (!count) {
goto out;
}
+
+ printk("entry = 0x%lx\n", entry);
/* Initialise saved-program-state */
- PUSH(loadbase);
+ PUSH(entry);
feval("saved-program-state >sps.entry !");
PUSH(offset);
feval("saved-program-state >sps.file-size !");
Index: libopenbios/load.c
===================================================================
--- libopenbios/load.c (revision 1272)
+++ libopenbios/load.c (working copy)
@@ -1,6 +1,6 @@
/*
* Creation Date: <2010/06/25 20:00:00 mcayland>
- * Time-stamp: <2010/06/25 20:00:00 mcayland>
+ * Time-stamp: <2014-03-05 03:18:49 andreiw>
*
* <load.c>
*
Index: packages/mac-parts.c
===================================================================
--- packages/mac-parts.c (revision 1272)
+++ packages/mac-parts.c (working copy)
@@ -1,6 +1,6 @@
/*
* Creation Date: <2003/12/04 17:07:05 samuel>
- * Time-stamp: <2004/01/07 19:36:09 samuel>
+ * Time-stamp: <2014-03-05 03:42:07 andreiw>
*
* <mac-parts.c>
*
@@ -237,6 +237,19 @@
size = (long long)__be32_to_cpu(par.pmPartBlkCnt) * bs;
if (want_bootcode) {
+ ucell loadaddr = 0;
+ ucell loadsize = 0;
+ ucell loadentry = 0;
+
+ loadaddr = __be32_to_cpu(par.pmBootLoad);
+ loadsize = __be32_to_cpu(par.pmBootSize);
+ loadentry = __be32_to_cpu(par.pmBootEntry);
+ PUSH(loadaddr);
+ feval("bootcode-base !");
+ PUSH(loadsize);
+ feval("bootcode-size !");
+ PUSH(loadentry);
+ feval("bootcode-entry !");
offs += (long long)__be32_to_cpu(par.pmLgBootStart) * bs;
size = (long long)__be32_to_cpu(par.pmBootSize);
}
@@ -249,6 +262,10 @@
di->size_hi = size >> BITS;
di->size_lo = size & (ucell) -1;
+ if (want_bootcode) {
+ goto out;
+ }
+
/* We have a valid partition - so probe for a filesystem at the current offset */
DPRINTF("mac-parts: about to probe for fs\n");
DPUSH( offs );
@@ -277,7 +294,7 @@
/* If we have been asked to open a particular file, interpose the filesystem package with
the passed filename as an argument */
- if (!want_bootcode && strlen(argstr)) {
+ if ( strlen(argstr)) {
push_str( argstr );
PUSH_ph( ph );
fword("interpose");
@@ -286,6 +303,10 @@
goto out;
} else {
DPRINTF("mac-parts: no filesystem found on partition %d; bypassing misc-files interpose\n", parnum);
+
+ /* Fail out instead of having macparts_load get called uselessly, allowing trying the next
+ boot device */
+ ret = 0;
}
}
</pre>
This does make booting iQUIK on OpenBIOS now very easy.
<br />
<pre class="brush: plain">qemu-system-ppc -hda ~/src/quik/distrib/floppy-cfg.img -prom-env "boot-file=hd:3"
</pre>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com0tag:blogger.com,1999:blog-3632708076304946233.post-38636760370092888432014-03-05T02:15:00.000-05:002014-03-05T02:15:41.063-05:00Getting PowerPC OpenBIOS to run on QEMU<ul>
<li>You've apt-get installed qemu, but qemu-system-ppc boots to a blank (white or black) screen?</li>
<li>You've pulled the OpenBIOS SVN, built qemu-openbios.elf, but it boots to a blank screen?</li>
</ul>
<div>
On serial output, you might see "<< set_property: NULL phandle" messages, and the CPU is stuck in a perpetual ISI.
<br />
<br />
Have no fear. Apparently GCC versions > 4.6 miscompile OpenBIOS, so you need to disable optimization. This is presently set to "-Os" under "Makefile.target". Setting it t "-O0" should do.<br />
<br />
I'll probably investigate this deeper after fixing partition-zero booting...<br />
<br />
A</div>
Anonymoushttp://www.blogger.com/profile/14797486015152693336noreply@blogger.com1