<?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>G33K @ Work &#187; OSDev</title>
	<atom:link href="http://www.geekatwork.de/category/osdev/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.geekatwork.de</link>
	<description>Basteleien eines Geeks</description>
	<lastBuildDate>Tue, 13 Sep 2011 17:20:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Easterhegg 2011 Talk</title>
		<link>http://www.geekatwork.de/2011/04/25/easterhegg-2011-talk/</link>
		<comments>http://www.geekatwork.de/2011/04/25/easterhegg-2011-talk/#comments</comments>
		<pubDate>Mon, 25 Apr 2011 17:35:32 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[OSDev]]></category>
		<category><![CDATA[Chaos]]></category>
		<category><![CDATA[Easterhegg]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[slides]]></category>

		<guid isPermaLink="false">http://www.geekatwork.de/?p=304</guid>
		<description><![CDATA[Dieses Jahr fand das Easterhegg wieder in Hamburg statt. Die Slides zu dem von mir gehaltenen Talk/Workshop gibts nun hier für alle, die es interessiert Slides]]></description>
			<content:encoded><![CDATA[<p>Dieses Jahr fand das Easterhegg wieder in Hamburg statt.</p>
<p>Die Slides zu dem von <a href="http://eh2011.hamburg.ccc.de/fahrplan/events/4352.de.html" target="_blank">mir gehaltenen Talk/Workshop</a> gibts nun hier für alle, die es interessiert <img src='http://www.geekatwork.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><a href="http://www.geekatwork.de/wp-content/uploads/eh11_workshop.pdf">Slides</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.geekatwork.de/2011/04/25/easterhegg-2011-talk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Solving Other People’s Problems</title>
		<link>http://www.geekatwork.de/2011/01/31/solving-other-people%e2%80%99s-problems/</link>
		<comments>http://www.geekatwork.de/2011/01/31/solving-other-people%e2%80%99s-problems/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 07:57:20 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[OSDev]]></category>
		<category><![CDATA[10.6.3]]></category>
		<category><![CDATA[10.6.6]]></category>
		<category><![CDATA[assembler]]></category>
		<category><![CDATA[cpu]]></category>
		<category><![CDATA[gdb]]></category>
		<category><![CDATA[instruction]]></category>
		<category><![CDATA[intel]]></category>
		<category><![CDATA[Mac OS]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[patching]]></category>
		<category><![CDATA[x86]]></category>
		<category><![CDATA[x86_64]]></category>

		<guid isPermaLink="false">https://www.geekatwork.de/?p=283</guid>
		<description><![CDATA[I needed a virtualized Mac OS. I want to know how a special EFI extension works which permanently changes the harddisk. I don&#8217;t want to do this on my real machine. I would have to reboot it several times and perhaps loose all my data on my HDD if something goes wrong while I&#8217;m experimenting [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a virtualized Mac OS. I want to know how a special EFI extension works which permanently changes the harddisk. I don&#8217;t want to do this on my real machine. I would have to reboot it several times and perhaps loose all my data on my HDD if something goes wrong while I&#8217;m experimenting which this extension. Also live debugging would be next to impossible.</p>
<p>Luckily, VMware and VirtualBox are able to virtualize Apple&#8217;s Mac OS X Server. His holy Steveness decided to allow virtualization only for the Server version of Mac OS. But there is <a href="http://hints.macworld.com/article.php?story=20080805081909302" target="_blank">help</a>, so I &#8220;fixed&#8221; the DVD to be able to boot a Mac OS X 10.6.3 retail DVD in VMware.</p>
<p>Unfortunately VMware then told me that the CPU was halted by the guest operating system. This happens if a kernel issues a &#8220;hlt&#8221; statement on all currently active cores without interrupts enabled to wake up the CPU later. This is bad because the whole operating system is trapped in this state. But why did this happen with OS X?<span id="more-283"></span></p>
<p>The most usual causes for this are a) a programming error or b) a panic issued by some code in the kernel. A programming error can be excluded here, so the kernel must panic in a very early state. I googled the error message I got (&#8220;The CPU has been disabled by the guest operating system.&#8221;) and found <a href="http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&amp;cmd=displayKC&amp;externalId=1026103" target="_blank">this</a>. Great. So the kernel seems to have problems with newer CPUs and I do have an i5 in my machine.</p>
<p>First I tried to circumvent this issue by several configuration changes in the VM configuration file and using different EFI Loaders but all those attempts failed, because it wasn&#8217;t some issue with the loaders. It was the kernel itself which panicked.</p>
<p>So I googled for a way to attach a debugger to the VM and I found one. VMware itself has a <a href="http://communities.vmware.com/docs/DOC-1201" target="_blank">GDB Stub</a> (see &#8220;GDB Server&#8221;). I configured the VM, ran it, attached the GDB to the VM, continued to execution and let the kernel panic. After that I hit CTRL+C in the GDB and the VM is halted in a state where I can modify it with the GDB completely:</p>
<pre class="brush:plain">andy@geekbook ~/Desktop % gdb mach_kernel
GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...

&gt; target remote localhost:8864
[New thread 1]
0x000000003fc40786 in ?? ()

&gt; c
^C
Program received signal SIGINT, Interrupt.
0xffffff800022ddcf in Debugger ()

&gt;</pre>
<p>But what to do now? Well, we want to find out where the kernel panics and do something against it.<br />
The VM already has panicked, so we can have a look at a stacktrace to determine which function caused the panic:</p>
<pre class="brush:plain">&gt; bt
#0  0xffffff800022ddcf in Debugger ()
#1  0xffffff8000204ac3 in panic ()
#2  0xffffff80002cef74 in kernel_trap ()
#3  0xffffff80002e0e9a in return_from_trap ()
#4  0x0000000000002206 in ?? ()
#5  0xffffff80002d6bb1 in cnputc ()
#6  0xffffff800027cf30 in consdebug_putc ()
#7  0xffffff8000206577 in __doprnt ()
#8  0xffffff80002073b8 in kdb_printf ()
#9  0xffffff8000204b2b in panic ()
#10 0xffffff8000228834 in cpuid_set_info ()
#11 0xffffff80002c1c00 in cpuid_extfeatures ()
#12 0xffffff80002c4178 in vstart ()</pre>
<p>What can we see here? This is the chain of functions the kernel called until it got into the state where it is now. Especially #9 is interesting. This is the panic() function which apparently lets the kernel panic, hence the name. It is called by #10 at address 0xffffff8000228834 which is the function cpuid_set_info.</p>
<p>This makes totally sense. It seems that the kernel tries to detect the CPU very early. Intel (and compatible) CPUs have a special assembler instruction to retrieve information about the CPU the code is running on. Now guess its name: &#8220;cpuid&#8221;. It seems that the kernel pedantically checks which CPU it is running on and if it is unknown, it panics.</p>
<p>Let&#8217;s fix this behaviour. What do we need for this? We need a good disassembler and our 1337 x86 Assembler skills.</p>
<p>We already got the first one. It&#8217;s the GDB:</p>
<pre class="brush:plain">&gt; disassemble cpuid_set_info
Dump of assembler code for function cpuid_set_info:
0xffffff800022829e &lt;cpuid_set_info+0&gt;:	push   rbp
0xffffff800022829f &lt;cpuid_set_info+1&gt;:	mov    rbp,rsp
0xffffff80002282a2 &lt;cpuid_set_info+4&gt;:	push   r15
0xffffff80002282a4 &lt;cpuid_set_info+6&gt;:	push   r14
0xffffff80002282a6 &lt;cpuid_set_info+8&gt;:	push   r13
0xffffff80002282a8 &lt;cpuid_set_info+10&gt;:	push   r12
0xffffff80002282aa &lt;cpuid_set_info+12&gt;:	push   rbx
0xffffff80002282ab &lt;cpuid_set_info+13&gt;:	sub    rsp,0xa8
0xffffff80002282b2 &lt;cpuid_set_info+20&gt;:	mov    esi,0x198
0xffffff80002282b7 &lt;cpuid_set_info+25&gt;:	lea    rdi,[rip+0x49e6c2]        # 0xffffff80006c6980
0xffffff80002282be &lt;cpuid_set_info+32&gt;:	call   0xffffff80002c17f0 &lt;bzero&gt;
0xffffff80002282c3 &lt;cpuid_set_info+37&gt;:	xor    eax,eax
0xffffff80002282c5 &lt;cpuid_set_info+39&gt;:	cpuid
0xffffff80002282c7 &lt;cpuid_set_info+41&gt;:	mov    DWORD PTR [rbp-0x40],eax
.......
0xffffff8000228ba1 &lt;cpuid_set_info+2307&gt;:	leave
0xffffff8000228ba2 &lt;cpuid_set_info+2308&gt;:	ret
0xffffff8000228ba3 &lt;cpuid_set_info+2309&gt;:	mov    eax,0x6b5a4cd2
0xffffff8000228ba8 &lt;cpuid_set_info+2314&gt;:	mov    DWORD PTR [rip+0x49df4e],eax        # 0xffffff80006c6afc
0xffffff8000228bae &lt;cpuid_set_info+2320&gt;:	jmp    0xffffff8000228834 &lt;cpuid_set_info+1430&gt;
End of assembler dump.

&gt;</pre>
<p>I shortened the dump, because it is too long and I will pick out the interesting things by hand and post them separately.</p>
<p>Puh, that&#8217;s much code. Where do we start? We have the address of the call to the panic function. The one from the stacktrace. Let&#8217;s have a look there:</p>
<pre class="brush:plain">0xffffff80002287d5 &lt;cpuid_set_info+1335&gt;:	add    BYTE PTR [rax],al
0xffffff80002287d7 &lt;cpuid_set_info+1337&gt;:	add    BYTE PTR [rax-0x50000000],dh
0xffffff80002287dd &lt;cpuid_set_info+1343&gt;:	add    BYTE PTR [rax],al
0xffffff80002287df &lt;cpuid_set_info+1345&gt;:	add    BYTE PTR [rax-0x50000000],dh
0xffffff80002287e5 &lt;cpuid_set_info+1351&gt;:	add    BYTE PTR [rax],al
0xffffff80002287e7 &lt;cpuid_set_info+1353&gt;:	add    BYTE PTR [rax-0x50000000],dh
0xffffff80002287ed &lt;cpuid_set_info+1359&gt;:	add    BYTE PTR [rax],al
0xffffff80002287ef &lt;cpuid_set_info+1361&gt;:	add    BYTE PTR [rdi],dh
0xffffff80002287f1 &lt;cpuid_set_info+1363&gt;:	add    al,0x0
0xffffff80002287f3 &lt;cpuid_set_info+1365&gt;:	add    BYTE PTR [rax-0x55ccc6d5],bh
0xffffff80002287f9 &lt;cpuid_set_info+1371&gt;:	jmp    0xffffff8000228ba8 &lt;cpuid_set_info+2314&gt;
0xffffff80002287fe &lt;cpuid_set_info+1376&gt;:	mov    eax,0x73d67300
0xffffff8000228803 &lt;cpuid_set_info+1381&gt;:	jmp    0xffffff8000228ba8 &lt;cpuid_set_info+2314&gt;
0xffffff8000228808 &lt;cpuid_set_info+1386&gt;:	mov    eax,0x426f69ef
0xffffff800022880d &lt;cpuid_set_info+1391&gt;:	jmp    0xffffff8000228ba8 &lt;cpuid_set_info+2314&gt;
0xffffff8000228812 &lt;cpuid_set_info+1396&gt;:	mov    eax,0x78ea4fbc
0xffffff8000228817 &lt;cpuid_set_info+1401&gt;:	jmp    0xffffff8000228ba8 &lt;cpuid_set_info+2314&gt;
0xffffff800022881c &lt;cpuid_set_info+1406&gt;:	mov    DWORD PTR [rip+0x49e2d6],0x0        # 0xffffff80006c6afc
0xffffff8000228826 &lt;cpuid_set_info+1416&gt;:	lea    rdi,[rip+0x348073]        # 0xffffff80005708a0
0xffffff800022882d &lt;cpuid_set_info+1423&gt;:	xor    eax,eax
0xffffff800022882f &lt;cpuid_set_info+1425&gt;:	call   0xffffff8000204939 &lt;panic&gt;</pre>
<p>The last instruction is indeed a call to &#8220;panic&#8221;. But why is it called? There is no conditional branch instruction which decides whether to panic or not, but some weird jumps and obove them obviously incorrect code. Not necessarily incorrect, but semantically these instructions don&#8217;t make sense. We&#8217;ll leave them for now. Let&#8217;s see where other code could jump to the code that actually calls &#8220;panic&#8221;. A few instructions above, we find this:</p>
<pre class="brush:plain">0xffffff800022871f &lt;cpuid_set_info+1153&gt;:	lea    rsi,[rip+0x49e25a]        # 0xffffff80006c6980
0xffffff8000228726 &lt;cpuid_set_info+1160&gt;:	lea    rdi,[rip+0x348163]        # 0xffffff8000570890
0xffffff800022872d &lt;cpuid_set_info+1167&gt;:	call   0xffffff8000224574 &lt;strncmp&gt;
0xffffff8000228732 &lt;cpuid_set_info+1172&gt;:	test   eax,eax
0xffffff8000228734 &lt;cpuid_set_info+1174&gt;:	jne    0xffffff8000228826 &lt;cpuid_set_info+1416&gt;
0xffffff800022873a &lt;cpuid_set_info+1180&gt;:	cmp    BYTE PTR [rip+0x49e28b],0x6        # 0xffffff80006c69cc
0xffffff8000228741 &lt;cpuid_set_info+1187&gt;:	jne    0xffffff800022881c &lt;cpuid_set_info+1406&gt;
0xffffff8000228747 &lt;cpuid_set_info+1193&gt;:	movzx  eax,BYTE PTR [rip+0x49e27f]        # 0xffffff80006c69cd
0xffffff800022874e &lt;cpuid_set_info+1200&gt;:	sub    eax,0xd
0xffffff8000228751 &lt;cpuid_set_info+1203&gt;:	cmp    al,0x21
0xffffff8000228753 &lt;cpuid_set_info+1205&gt;:	ja     0xffffff800022881c &lt;cpuid_set_info+1406&gt;
0xffffff8000228759 &lt;cpuid_set_info+1211&gt;:	movzx  eax,al
0xffffff800022875c &lt;cpuid_set_info+1214&gt;:	lea    rdx,[rip+0x9]        # 0xffffff800022876c &lt;cpuid_set_info+1230&gt;
0xffffff8000228763 &lt;cpuid_set_info+1221&gt;:	movsxd rax,DWORD PTR [rdx+rax*4]
0xffffff8000228767 &lt;cpuid_set_info+1225&gt;:	add    rax,rdx
0xffffff800022876a &lt;cpuid_set_info+1228&gt;:	jmp    rax</pre>
<p>What does this code do? At the beginning it seems to load 2 values relative to the instruction pointer into registers rsi and rdi. Then it calls &#8220;strncmp&#8221;. strncmp usually takes two pointers to strings. So let&#8217;s have a look where these pointers actually point to with the GDB:</p>
<pre class="brush:plain">&gt; print (char*)0xffffff80006c6980
$1 = 0xffffff80006c6980 "GenuineIntel"

&gt; print (char*)0xffffff8000570890
$2 = 0xffffff8000570890 "GenuineIntel"</pre>
<p>Both strings are the same. One string seems to be a constant and the other one is retrieved by a &#8220;cpuid&#8221; instruction. We could look further into this but it&#8217;s not interesting to us.<br />
These strings are the same. strncmp will return 0 and the &#8220;jne&#8221; instruction after the &#8220;test&#8221; will not branch. This is not the place where we are panicking.<br />
The next instruction then loads some value into the eax register and then some other value is subtracted and compared with 0&#215;21. The following &#8220;ja&#8221; instruction (jump if above/greater than for unsigned values) jumps to &#8220;panic&#8221;. Perhaps this is where we panic? But I&#8217;m too lazy to read all this assembly and figure out what those values actually mean.<br />
The solution is easy: I restarted the VM, set a breakpoint to the beginning of the code and single stepped until I hit the jump to the panic-calling code. It wasn&#8217;t the first compare and it also wasn&#8217;t the second one. It was this last &#8220;jmp rax&#8221;.</p>
<p>Huh? What&#8217;s happening here? Actually it&#8217;s quite easy. Let&#8217;s do it step by step.</p>
<p>The &#8220;lea    rdx,[rip+0x9]&#8221; loads the address of the current instruction pointer + 9 into register rdx. GDB is nice to us and shows the resulting address as a comment next to the instruction: 0xffffff800022876c.<br />
The following &#8220;movsxd rax,DWORD PTR [rdx+rax*4]&#8221; instruction looks weird. It loads a 32 bit value (DWORD) at address rdx+rax*4 into the register rax. The address in rax seems to be some kind of a table. A value in rax then is the offset inside this table. The *4 is done because one entry inside the table is 4 bytes long and the x86 addresses are bytewise.<br />
After that rdx itself is added to rax and then a jmp occurs. And this jump really landed in the panic code. But why? And what&#8217;s this table address that is loaded into rdx at the beginning?</p>
<p>Remember the code I mentioned above which didn&#8217;t make sense? That&#8217;s where the address points to. This is just no code. It&#8217;s a table full of offsets. It looks like this if the don&#8217;t try to disassemble it but display these values as 4 byte unsigned values:</p>
<pre class="brush:plain">dd 88h
dd 92h
dd 9Ch
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0A6h
dd 0B0h
dd 0B0h
dd 437h
dd 0B0h
dd 0B0h
dd 0B0h
dd 437h
dd 437h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 0B0h
dd 437h</pre>
<p>What value of this table was actually used? I again reset the VM, set a proper breakpoint and looked at the registers (GDB command &#8220;info reg&#8221;) while the address to jump to was calculated. It turned out that on my Core i5 machine offset 0&#215;18 was used, which is a value of 0x0B0.</p>
<p>Adding this value to the beginning of the table (0xffffff800022876c + 0xB0 = 0xffffff800022881C) leads us directly to the code which calls panic. Cool. At least we now know what exactly happens. How do we fix this?</p>
<p>We just patch this table. We need to find the right value for our CPU or perhaps jump to a completely own stub which does some initialization work. This is what in the 10.6.6 kernel happens. The offsets are different because the linker put the symbols on different addresses but they also added one completely different and new value to the table for all the new CPUs.</p>
<p>I just tried value 0&#215;437 and it works like a charm. I booted the vm again, set a breakpoint at &#8220;cpuid_set_info&#8221; and patched the table with a simple &#8220;set *0xFFFFFF80002287CC=0&#215;00000437&#8243; and continued the execution. The kernel boots, I installed the machine and now I need to do the same shit again to get the kernel on the HDD to boot. After that I can update the OS to 10.6.6 what should solve the issue.</p>
<p>But why the fuck did I do all this? The problem is that I needed the VM now. And not when I got a proper CD which runs on i5/i7 processors. I also didn&#8217;t have another Mac here to setup and update the VM.</p>
<p>It also seems that all retail DVDs are an older build which does not run on i5 and i7 CPUs. Well done, Apple&#8230; Hence the name of this article: &#8220;Fixing Other People&#8217;s Problems&#8221;. It should just not be my problem to patch a kernel to install an operating system in a virtualized environment. And all this, just because Apple decided to just &#8220;support&#8221; a hand full of CPUs.</p>
<p><strong>Update:</strong> I just had a look at the XNU source code and found the c code I patched. Now it should be obvious why there was a branch table.</p>
<pre class="brush:c">void
cpuid_set_info(void)
{
	i386_cpu_info_t		*info_p = &amp;cpuid_cpu_info;

	bzero((void *)info_p, sizeof(cpuid_cpu_info));

	cpuid_set_generic_info(info_p);

	/* verify we are running on a supported CPU */
	if ((strncmp(CPUID_VID_INTEL, info_p-&gt;cpuid_vendor,
		     min(strlen(CPUID_STRING_UNKNOWN) + 1,
			 sizeof(info_p-&gt;cpuid_vendor)))) ||
	   (cpuid_set_cpufamily(info_p) == CPUFAMILY_UNKNOWN))
		panic("Unsupported CPU");

	info_p-&gt;cpuid_cpu_type = CPU_TYPE_X86;
	info_p-&gt;cpuid_cpu_subtype = CPU_SUBTYPE_X86_ARCH1;

	cpuid_set_cache_info(&amp;cpuid_cpu_info);

	/*
	 * Find the number of enabled cores and threads
	 * (which determines whether SMT/Hyperthreading is active).
	 */
	switch (info_p-&gt;cpuid_cpufamily) {
	/*
	 * This should be the same as Nehalem but an A0 silicon bug returns
	 * invalid data in the top 12 bits. Hence, we use only bits [19..16]
	 * rather than [31..16] for core count - which actually can't exceed 8.
	 */
	case CPUFAMILY_INTEL_WESTMERE: {
		uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);
		info_p-&gt;core_count   = bitfield32((uint32_t)msr, 19, 16);
		info_p-&gt;thread_count = bitfield32((uint32_t)msr, 15,  0);
		break;
		}
	case CPUFAMILY_INTEL_NEHALEM: {
		uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);
		info_p-&gt;core_count   = bitfield32((uint32_t)msr, 31, 16);
		info_p-&gt;thread_count = bitfield32((uint32_t)msr, 15,  0);
		break;
		}
	}
	if (info_p-&gt;core_count == 0) {
		info_p-&gt;core_count   = info_p-&gt;cpuid_cores_per_package;
		info_p-&gt;thread_count = info_p-&gt;cpuid_logical_per_package;
	}

	cpuid_cpu_info.cpuid_model_string = ""; /* deprecated */
}

static uint32_t
cpuid_set_cpufamily(i386_cpu_info_t *info_p)
{
	uint32_t cpufamily = CPUFAMILY_UNKNOWN;

	switch (info_p-&gt;cpuid_family) {
	case 6:
		switch (info_p-&gt;cpuid_model) {
		case 13:
			cpufamily = CPUFAMILY_INTEL_6_13;
			break;
		case 14:
			cpufamily = CPUFAMILY_INTEL_YONAH;
			break;
		case 15:
			cpufamily = CPUFAMILY_INTEL_MEROM;
			break;
		case 23:
			cpufamily = CPUFAMILY_INTEL_PENRYN;
			break;
		case CPUID_MODEL_NEHALEM:
		case CPUID_MODEL_FIELDS:
		case CPUID_MODEL_DALES:
		case CPUID_MODEL_NEHALEM_EX:
			cpufamily = CPUFAMILY_INTEL_NEHALEM;
			break;
		case CPUID_MODEL_DALES_32NM:
		case CPUID_MODEL_WESTMERE:
		case CPUID_MODEL_WESTMERE_EX:
			cpufamily = CPUFAMILY_INTEL_WESTMERE;
			break;
		}
		break;
	}

	info_p-&gt;cpuid_cpufamily = cpufamily;
	return cpufamily;
}</pre>
<p>At the beginning of &#8220;cpuid_set_info&#8221; we can see the strncmp of the vendor name followed by a call to &#8220;cpuid_set_cpufamily&#8221; where then the type of CPU is determined. The switch/case is the reason for the branch table.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geekatwork.de/2011/01/31/solving-other-people%e2%80%99s-problems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OS Development Demo Code</title>
		<link>http://www.geekatwork.de/2010/07/12/os-development-demo-code/</link>
		<comments>http://www.geekatwork.de/2010/07/12/os-development-demo-code/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 08:36:14 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[OSDev]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[demo]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[interrupts]]></category>
		<category><![CDATA[low level]]></category>
		<category><![CDATA[pic]]></category>
		<category><![CDATA[pit]]></category>
		<category><![CDATA[sigint]]></category>
		<category><![CDATA[x86]]></category>

		<guid isPermaLink="false">https://www.geekatwork.de/?p=274</guid>
		<description><![CDATA[A while ago, I wrote some demo code to demonstrate various things you need to do to write your own operating system. In May 2010 I held a lecture and workshop about this code and the concepts at SigInt conference in Cologne, Germany. I just thought that this code may be interesting to other people [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago, I wrote some demo code to demonstrate various things you need to do to write your own operating system.<br />
In May 2010 I held a lecture and workshop about this code and the concepts at <a href="http://events.ccc.de/sigint/2010/wiki/Hauptseite" target="_blank">SigInt conference in Cologne</a>, Germany.</p>
<p>I just thought that this code may be interesting to other people who did not attend this conference.<span id="more-274"></span></p>
<p><a href="http://github.com/G33KatWork/SigInt10OSWorkshop" target="_blank">The demo code</a> includes mainly x86 specific stuff and it is truly demo code, so don&#8217;t just copy it into another project. Even if it works at first sight, it it is highly likely to break sooner or later <img src='http://www.geekatwork.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>The code contains samples for:</p>
<ul>
<li>A small &#8220;Hello World&#8221; bootsector in realmode</li>
<li>A sample how to enable the A20 gate. This works at least in QEMU</li>
<li>Loading a barebone-kernel written in C by GRUB</li>
<li>Switching to protected mode and writing to the textmode framebuffer</li>
<li>Handling interrupts in protected mode using the old PIC</li>
<li>Configuring and using the old PIT (Timer)</li>
<li>Switching to longmode (64 Bit)</li>
<li>A multitasking demo how to do context switching</li>
</ul>
<p>The first two samples are completely written in Assembly and are loaded directly by the BIOS from a floppy drive. All other samples are mainly written in C spiced with some Assembly and are loaded from a FAT formatted floppy disk by a GRUB bootloader.</p>
<p>For those of you who speak german, here are the slides of the conference:<br />
<a href="http://events.ccc.de/sigint/2010/wiki/Fahrplan/events/3889.de.html" target="_blank">Talk</a><br />
<a href="http://events.ccc.de/sigint/2010/wiki/Fahrplan/events/3890.de.html" target="_blank">Workshop </a></p>
<p>If you do anything with this demo code, I would appreciate to hear about your project or experiences. Also, If there are specific questions or problems about/with this code which are not easily resolvable by Googling and using your brain, feel free to ask in the comments. <img src='http://www.geekatwork.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.geekatwork.de/2010/07/12/os-development-demo-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dumping the VMware BIOS</title>
		<link>http://www.geekatwork.de/2010/05/27/dumping-the-vmware-bios-2/</link>
		<comments>http://www.geekatwork.de/2010/05/27/dumping-the-vmware-bios-2/#comments</comments>
		<pubDate>Thu, 27 May 2010 00:48:18 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[OSDev]]></category>
		<category><![CDATA[BIOS]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[dumping]]></category>
		<category><![CDATA[extracting]]></category>
		<category><![CDATA[MacOS]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[VMware]]></category>

		<guid isPermaLink="false">http://www.geekatwork.de/?p=228</guid>
		<description><![CDATA[Sometimes, even if you don&#8217;t want to install a pirated Windows version, you may want to dump and modify the BIOS of a computer. Especially if you are developing some kind of an ACPI subsystem for your own small operating system kernel. Doing this with real hardware is kinda risky and complex. But what about [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes, even if you don&#8217;t want to install a pirated Windows version, you may want to dump and modify the BIOS of a computer.<br />
Especially if you are developing some kind of an ACPI subsystem for your <a href="projekte/geexos/">own small operating system kernel</a>.</p>
<p>Doing this with real hardware is kinda risky and complex.<br />
But what about virtual machines like VMware? They have a BIOS, but how can we get our hands on it?<span id="more-228"></span><br />
As I&#8217;m using Mac OS X for all my daily work, I&#8217;m using VMware Fusion as a virtualization program.</p>
<p>The BIOS seems to be hidden inside the virtual machine monitor executable itself.<br />
To make our lifes easier, we are going to extract only the x86_64 part out of the universal binary with the following command:</p>
<pre class="brush:shell">lipo /Libary/Application\ Support/VMware\ Fusion/vmware-vmx -thin x86_64 -output /Users/user/Desktop/vm64</pre>
<p>Now, we have a Mach-O file with only one architecture, which is x86_64.<br />
It doesn&#8217;t matter if you are dumping the BIOS out of the i386 or x86_64 version of the binary. It should be the same for both architectures.</p>
<p>After that, we can extract the appropriate section in the Mach-O file which contains the BIOS itself:</p>
<pre class="brush:shell">segedit /Users/user/Desktop/vm64 -extract __VMWARE bios440 /Users/user/Desktop/bios440.rom</pre>
<p>And here, you go: bios440.rom contains your VMware BIOS.</p>
<p>After you modified it to your wishes, you can use a handy VMware feature which lets you specify a custom BIOS for a virtual machine inside its vmx-file.<br />
Just add this line to the vmx-file of the machine you want a custom BIOS for and place the rom file in the proper folder:</p>
<pre>bios440.filename = "bios.rom"</pre>
<p>Happy BIOS modding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geekatwork.de/2010/05/27/dumping-the-vmware-bios-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Systemprogrammierung</title>
		<link>http://www.geekatwork.de/2010/01/03/systemprogrammierung/</link>
		<comments>http://www.geekatwork.de/2010/01/03/systemprogrammierung/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 00:08:14 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[OSDev]]></category>
		<category><![CDATA[The usual rants]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Virtualisierung]]></category>

		<guid isPermaLink="false">http://www.geekatwork.de/?p=81</guid>
		<description><![CDATA[Mein momentanes Interessenfeld bezieht sich ja sehr stark auf alles, was mit System- und Hardwarenaher Programmierung zu tun hat. Da ich auf der Zugfahrt zum 26c3 nicht besonders viel zu tun hatte und die AMD und Intel Dokumentationen auf meinem Rechner hatte, habe ich mal angefangen mich um die Virtualisierungsfunktionen, die diese beiden Hersteller da [...]]]></description>
			<content:encoded><![CDATA[<p>Mein momentanes Interessenfeld bezieht sich ja sehr stark auf alles, was mit System- und Hardwarenaher Programmierung zu tun hat.<br />
Da ich auf der Zugfahrt zum <a href="http://events.ccc.de/congress/2009" target="_blank">26c3</a> nicht besonders viel zu tun hatte und die AMD und Intel Dokumentationen auf meinem Rechner hatte, habe ich mal angefangen mich um die <a href="http://de.wikipedia.org/wiki/Virtualisierung_%28Informatik%29" target="_blank">Virtualisierungsfunktionen</a>, die diese beiden Hersteller da so in ihre Prozessoren verpflanzen, zu kümmern.<span id="more-81"></span></p>
<p>Nachdem ich dann auch irgendwann mal raushatte, wie ich das vierstufige (!) Paging mit 4KB großen Pages beim Booten zusammenbauen konnte, um so einen Prozessor in den <a href="http://de.wikipedia.org/wiki/AMD64#Betriebsmodi" target="_blank">Long Mode</a> zu bekommen, hab ich mich mal an die Virtualisierung machen wollen.<br />
Zu diesem Zeitpunkt saß ich allerdings schon im Hackcenter.</p>
<p>Wie ich dann, mal wieder, feststellen musste, hat so ein Low Level Zeug einen unglaublichen Rattenschwanz, den man immer wieder hinter sich herzieht. In diesem konrekten Fall brauchte ich also ein vernünftiges <a href="http://de.wikipedia.org/wiki/Interrupt" target="_blank">Interrupthandling</a>. Ist ja schnell implementiert, dachte ich mir und kopier mir meinen Code aus meinen anderen <a href="http://www.geekatwork.de/projekte/geexos/" target="_self">Projekten</a> fröhlich zusammen.</p>
<p>Interrupts konnte ich dann handlen. Problem war jetzt nur, dass 2 Instruktionen nach dem Aktivieren der Interrupts sofort der Interrupt #8 auftrat, was nach Dokumentation ein Double Fault gewesen sein müsste. Dieser tritt aber nur nach einer fatalen, vorhergegangenen Exception auf, wovon ich aber nichts mitbekommen habe. Wieso fliegt da also ein Double Fault? Nichtmal die 2 Instruktionen, die nach dem setzen des Interrupt Enable Flags ausgeführt wurden konnten einen solchen Interrupt auslösen, weil es Sprünge zu sich selbst waren, um die CPU in einer Endlosschleife zu halten.</p>
<p>Kommen wir zurück zum Rattenschwanz: Nachdem ich dann die Interrupt Handler und die Verwaltung der IDT hatte, habe ich noch Routinen zur Verwaltung der <a href="http://de.wikipedia.org/wiki/Global_Descriptor_Table" target="_blank">GDT</a> implementiert. Es funktionierte immernoch nicht, was allerdings zu erwarten war, da es mehr eine Verzweifelungstat war als ein richtiger Lösungsansatz. Wir sind zu diesem Zeitpunkt bei Tag 3 des Kongresses.<br />
Allerdings war das ja auch nicht das Einzige, was ich da gemacht habe. Gab ja noch Vorträge.</p>
<p>Danach gings ans Debuggen. Ich habe VMware probiert, um zu sehen, was das Ding sagt. Wie erwartet: nichts. Es fehlen einfach die Debuggingmöglichkeiten unter Mac OS mit VMware.<br />
Dann gibts noch Qemu, an den man einen GDB klemmen kann. Gesagt getan. Nach wie vor nichts gefunden.<br />
Als letztes bin ich mit dem integrierten Debugger in Bochs dem Kram zu Leibe gerückt, mit dem man seinen Code auf Assemblerebene Debuggen konnte. Auch hier habe ich wieder nichts gefunden.</p>
<p>Was war das Ende vom Lied? Es gibt einen extra Chip auf x86 Systemem, der externe Interrupts handlet. Früher war das der <a href="http://de.wikipedia.org/wiki/Programmable_Interrupt_Controller" target="_blank">PIC (Programmable Interrupt Controller)</a> und heute ist es der <a href="http://de.wikipedia.org/wiki/APIC" target="_blank">APIC (Advanced Programmable Interrupt Controller)</a>, der auch Mehrprozessorsysteme ohne Gefrickel unterstützt.<br />
Diese Chips kann man so konfigurieren, dass jeder externe Interrupt (Tastatur, Floppy, Timer etc) auf einen der 256 Interrupts der CPU gemappt werden kann.</p>
<p>Irgendein Stück Software vor meinem Kernel hat genau das anscheinend mit dem Timerinterrupt gemacht und ihn auf Interrupt #8 gelegt.<br />
Das würde dann auch erklären, warum bei einem Double Fault eigentlich ein Errorcode auf den Stack gepusht werden sollte, was bei mir aber nie passiert ist. Es war schlicht und ergreifend kein Double Fault.</p>
<p>Also hab ich dann doch, entgegen meiner vorherigen &#8220;Brauchste eh nich&#8221;-Meinung, auch noch Code hinzugefügt, der den PIC (eigentlich sind es 2 PICs) entsprechend konfiguriert und die 16 Interrupts, die er verwalten kann, hinter die Exceptions mappt.</p>
<p>Was ist? Es funktioniert endlich.</p>
<p>Und so kann man sich wunderschön auf die Fresse legen und Zeit verbraten.<br />
Ich will nicht sagen ich hab nichts gelernt, genervt hat es aber doch schon ziemlich. Gedauert hat der ganze Prozess jetzt 6 Tage. Und ich hab immernoch keinen virtualisierten Code laufen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geekatwork.de/2010/01/03/systemprogrammierung/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

