<?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>vm-kernel &#187; yajin</title>
	<atom:link href="http://vm-kernel.org/blog/author/yajin/feed/" rel="self" type="application/rss+xml" />
	<link>http://vm-kernel.org/blog</link>
	<description>All about emulation and virtualization</description>
	<lastBuildDate>Sat, 17 Apr 2010 03:51:46 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Gdium linux kernel support status</title>
		<link>http://vm-kernel.org/blog/2010/04/16/gdium-linux-kernel-support-status/</link>
		<comments>http://vm-kernel.org/blog/2010/04/16/gdium-linux-kernel-support-status/#comments</comments>
		<pubDate>Fri, 16 Apr 2010 13:20:42 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[kernel]]></category>
		<category><![CDATA[loongson]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/?p=227</guid>
		<description><![CDATA[After several days working, the 2.6.34-rc2 kernel is working on gdium expect sound. Of course most of the codes are from mandriva and Philippe's work.
I will make some code clean and make the sound work in the next few days. It seems the sm501 sound driver needs a hardcoded 8051 firmware to work. Damn it. [...]]]></description>
			<content:encoded><![CDATA[<p>After several days working, the 2.6.34-rc2 kernel is working on gdium expect sound. Of course most of the codes are from mandriva and Philippe's work.</p>
<p>I will make some code clean and make the sound work in the next few days. It seems the sm501 sound driver needs a hardcoded 8051 firmware to work. Damn it. After these works are done, I will send the patches to<a href="http://groups.google.com/group/loongson-dev"> loongson-dev</a> maillist and merge it to <a href="http://dev.lemote.com/code/linux-loongson-community">linux-loongson-community</a> and linux-mips mainline at last.</p>
<p>I am keeping moving....... Please wait.</p>
<p>ps: The linux kernel for gdium repository is <a href="http://repo.or.cz/w/linux-2.6/linux-mips/linux-gdium.git">here</a>.</p>
<blockquote><p>kill-bill:~# uname -a<br />
Linux kill-bill 2.6.34-rc2 #24 PREEMPT Fri Apr 16 21:01:51 CST 2010 mips64 GNU/Linux<br />
kill-bill:~# cat /proc/cpuinfo<br />
system type             : dexxon-gdium-2f-10inches<br />
processor               : 0<br />
cpu model               : ICT Loongson-2 V0.3  FPU V0.1<br />
BogoMIPS                : 598.01<br />
wait instruction        : no<br />
microsecond timers      : yes<br />
tlb_entries             : 64<br />
extra interrupt vector  : no<br />
hardware watchpoint     : yes, count: 0, address/irw mask: []<br />
ASEs implemented        :<br />
shadow register sets    : 1<br />
core                    : 0<br />
VCED exceptions         : not available<br />
VCEI exceptions         : not available
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2010/04/16/gdium-linux-kernel-support-status/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Install debian lenny on yeeloong 8089/8101</title>
		<link>http://vm-kernel.org/blog/2010/03/27/install-debian-lenny-on-yeeloong-80898101/</link>
		<comments>http://vm-kernel.org/blog/2010/03/27/install-debian-lenny-on-yeeloong-80898101/#comments</comments>
		<pubDate>Sat, 27 Mar 2010 06:28:51 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[loongson]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[yeeloong]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/?p=221</guid>
		<description><![CDATA[NOTICE/TIPS:
[For one want to install the debian 6.0, there is a more easy way. See the following link.
http://www.anheng.com.cn/loongson/install/readme.txt (In Chinese).]
Yesterday I installed the debian lenny on yeeloong 8101, the 10.1 inch notebook based on loongson 2F CPU for a friend. Then I find there is less English document describing how to do this. So I [...]]]></description>
			<content:encoded><![CDATA[<p>NOTICE/TIPS:<br />
[For one want to install the debian 6.0, there is a more easy way. See the following link.<br />
<a href="http://www.anheng.com.cn/loongson/install/readme.txt">http://www.anheng.com.cn/loongson/install/readme.txt</a> (In Chinese).]</p>
<p>Yesterday I installed the debian lenny on yeeloong 8101, the 10.1 inch notebook based on loongson 2F CPU for a friend. Then I find there is less English document describing how to do this. So I write the process down to anyone who is interested in installing debian on yeloong. There are many ways to do it I choose the way of using a debian network installer. Please make sure you have a internet connection first.</p>
<p>1. First download the kernel and initrd to your PC.</p>
<blockquote><p>wget http://dev.lemote.com/drupal/sites/default/files/kernel-2.6.27-LM8089.tar.gz<br />
wget http://dev.lemote.com/drupal/sites/default/files/initrd_yl_netboot.gz</p></blockquote>
<p>2. Decompress kernel on your PC.</p>
<blockquote><p>tar zxvf kernel-2.6.27-LM8089.tar.gz</p></blockquote>
<p>You will get the kernel vmlinux and the directory named lib. The lib directory contains all the kernel modules.</p>
<p>3. Format your USB disk with ext2 partition and copy vmlinux, directory lib and initrd_yl_netboot.gz to the usb disk.</p>
<p>4. Insert the usb disk to your netbook and boot it</p>
<p>5. Enter the PMON command line.</p>
<p>There are two ways to enter the PMON(the bootloader of yeeloong) command line. One is press DEL when booting. The other way is click C when you see the boot menu.</p>
<p>Use the following commands to load the kernel and initrd, which contains the debian network installer.</p>
<blockquote><p>load /dev/fs/ext2@usb0/vmlinux<br />
initrd /dev/fs/ext2@usb0/initrd_yl_netboot.gz</p></blockquote>
<p>Please be patient. The initrd command may need more than 5 miniutes to be finished.</p>
<p>Sometimes the PMON bootloader may hang when you boot with a usb disk inserted. I do not know why. The workaround is booting into the default linux system and inserting the usb disk and then rebooting. Or you can use a tftp method to load the kernel and initrd.</p>
<p>At last use the following command to launch the debian network installer.</p>
<blockquote><p>g console=tty no_auto_cmd</p></blockquote>
<p>Then just install the debian as normal.</p>
<p>6. Install debian lenny</p>
<p>After debian configurating the DHCP, it will complain about "no kernel modules were found" and will let you choose "continue the install without loading kernel modules?", just choose Yes(the default answer is No) to continue.</p>
<p>When in the part of Partition disks, it will complain about "The current kernel doesn't support the Logical Volume Manager. You may need to load the lvm-mod modules" and the background becomes red. Do not be scared. Just click continue. <img src='http://vm-kernel.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Then everything goes as it should be. But at last, debian installer will say "no installable kernel was found in the defined APT sources.... Continue without installing a kernel". Do not click Yes too quickly. We need to copy the kernel and all the modules into new system first. Please make sure that the USB disk is still inserting on the notebook. Use ALT+F2 to active a console. Mount the use disk and copy kernel and libs.</p>
<blockquote><p>mount /dev/sda1 /target/mnt<br />
cp /mnt/vmlinux /target/boot<br />
cp -rf /mnt/lib/modules /target/lib/</p></blockquote>
<p>Then click ALT+F1 return to the debian installer. Click Yes to continue installing.</p>
<p>7. Install Desktop environment</p>
<p>You can install LXDE or gnome as your desktop. I prefer LXDE because it is light.</p>
<blockquote><p>apt-get install lxde</p></blockquote>
<p>Install the X server driver.</p>
<blockquote><p>wget http://www.anheng.com.cn/loongson2f/lenny/xorg-server/xserver-xorg-video-siliconmotion_2.2.8-lemote.r04_mipsel.deb<br />
dpkg -i xserver-xorg-video-siliconmotion_2.2.8-lemote.r04_mipsel.deb</p></blockquote>
<p>Change the xorg.conf according to <a href="http://wiki.gnewsense.org/Projects/GNewSenseToMIPSYeeloongXorgConf">this link</a>.</p>
<p>8. Trouble shooting</p>
<p>(1) My wifi does not work</p>
<p>You can see "rtl8187: rtl8187_open process failed because radio off" if you use dmesg to see the message. Use FN+F5 to turn on the wifi first. You will see such message "<span style="font-family: Courier New;">rtl8187: SCI interrupt Methord Will Turn Radio On</span>" on your console.</p>
<p>(2) My sound does not work</p>
<p>Use alsamixer to adjust the volume. But install alsa-utils first.</p>
<p>(3) OOPS, I forget to copy kernel to my new installed system. I can not boot it now. What should I do?</p>
<p>You can load the kernel using tftp method.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2010/03/27/install-debian-lenny-on-yeeloong-80898101/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>UNSW Advanced OS about L4</title>
		<link>http://vm-kernel.org/blog/2010/01/22/unsw-advanced-os/</link>
		<comments>http://vm-kernel.org/blog/2010/01/22/unsw-advanced-os/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 08:18:05 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[Micro-kernel]]></category>
		<category><![CDATA[L4]]></category>
		<category><![CDATA[Mircro-kernel]]></category>
		<category><![CDATA[OS]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/?p=206</guid>
		<description><![CDATA[For someone who is interested in OS and micro-kernel especially L4.
Part 1:

Part 2:


Part 3:

Part 4:

Part 5:

Part 6:

Part 7:

Part 8:

]]></description>
			<content:encoded><![CDATA[<p>For someone who is interested in OS and micro-kernel especially L4.</p>
<p>Part 1:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/v/KtyIFdPd0bU" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/v/KtyIFdPd0bU" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 2:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/v/3ZN40MyiGuk" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/v/3ZN40MyiGuk" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><span id="more-206"></span></p>
<p>Part 3:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/v/pWnzaGezzmw" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/v/pWnzaGezzmw" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 4:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/v/NdztxXTG-AQ" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/v/NdztxXTG-AQ" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 5:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/v/YhMEBQPZ__U" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/v/YhMEBQPZ__U" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 6:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/l/cz-uhtvDLk0" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/l/cz-uhtvDLk0" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 7:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/l/cz-uhtvDLk0" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/l/cz-uhtvDLk0" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Part 8:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="420" height="363" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="wmode" value="opaque" /><param name="src" value="http://www.tudou.com/l/cz-uhtvDLk0" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="420" height="363" src="http://www.tudou.com/l/cz-uhtvDLk0" wmode="opaque" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2010/01/22/unsw-advanced-os/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>performance of loongson 2f</title>
		<link>http://vm-kernel.org/blog/2009/10/30/performance-of-loongson-2f/</link>
		<comments>http://vm-kernel.org/blog/2009/10/30/performance-of-loongson-2f/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 09:11:31 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[loongson]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[loongson 2f]]></category>
		<category><![CDATA[nbench]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/10/30/performance-of-loongson-2f/</guid>
		<description><![CDATA[Some friends ask me about the performance of loongson2f. They want to know whether the performance of loongson 2f can surpass Marvell Sheeva CPU. Well I can not just say it's better or worse without giving the benchmark data.
Since there is a benchmark result of Marvell Sheeva CPU, we can run the same benchmark program [...]]]></description>
			<content:encoded><![CDATA[<p>Some friends ask me about the performance of loongson2f. They want to know whether the performance of loongson 2f can surpass Marvell Sheeva CPU. Well I can not just say it's better or worse without giving the benchmark data.<br />
Since there is a <a href="http://computingplugs.com/index.php/SheevaPlug_Performance#CPU_performance_with_nbench-byte-2.2.3">benchmark result</a> of Marvell Sheeva CPU, we can run the same benchmark program on loongson 2f. The benchmark program is nbench.<br />
Machine: gdium<br />
OS: Debian squeeze<br />
Kernel: Linux</p>
<p>1. gcc-4.3.4<br />
CFLAGS = -s -static -Wall -O3</p>
<table border="1">
<tbody>
<tr>
<td>TEST</td>
<td>Iterations/sec.</td>
<td>Old Index</td>
<td>New Index</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td>Pentium 90*</td>
<td>AMD K6/233*</td>
</tr>
<tr>
<td>NUMERIC SORT</td>
<td>358.24.</td>
<td>9.19</td>
<td>3.02</td>
</tr>
<tr>
<td>STRING SORT</td>
<td>33.041</td>
<td>14.76</td>
<td>2.29</td>
</tr>
<tr>
<td>BITFIELD</td>
<td>5.5164e+07</td>
<td>9.46</td>
<td>1.98</td>
</tr>
<tr>
<td>FP EMULATION</td>
<td>47.402</td>
<td>22.75</td>
<td>5.25</td>
</tr>
<tr>
<td>FOURIER</td>
<td>4721.1</td>
<td>5.37</td>
<td>3.02</td>
</tr>
<tr>
<td>ASSIGNMENT</td>
<td>7.0534</td>
<td>26.84</td>
<td>6.96</td>
</tr>
<tr>
<td>IDEA</td>
<td>1597.4</td>
<td>24.43</td>
<td>7.25</td>
</tr>
<tr>
<td>HUFFMAN</td>
<td>575.17</td>
<td>15.95</td>
<td>5.09</td>
</tr>
<tr>
<td>NEURAL NET</td>
<td>4.2065</td>
<td>6.76</td>
<td>2.84</td>
</tr>
<tr>
<td>LU DECOMPOSITION</td>
<td>107.28</td>
<td>5.56</td>
<td>4.01</td>
</tr>
</tbody>
</table>
<p>==========ORIGINAL BYTEMARK RESULTS========<br />
INTEGER INDEX : 16.297<br />
FLOATING-POINT INDEX: 5.864<br />
Baseline (MSDOS*) : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0<br />
==========LINUX DATA BELOW============<br />
CPU                 :<br />
L2 Cache            :<br />
OS                  : Linux 2.6.24-gdium-1<br />
C compiler          : gcc version 4.3.4 (Debian 4.3.4-5)<br />
libc                : libc-2.9.so<br />
MEMORY INDEX        : 3.156<br />
INTEGER INDEX       : 4.918<br />
FLOATING-POINT INDEX: 3.252<br />
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38<br />
* Trademarks are property of their respective holder.</p>
<p>2. gcc-4.4<br />
CFLAGS = -s -static -Wall -O3 -fomit-frame-pointer -funroll-loops<br />
CFLAGS += -march=loongson2f  -mtune=loongson2f  -mabi=n32</p>
<table border="1">
<tbody>
<tr>
<td>TEST</td>
<td>Iterations/sec.</td>
<td>Old Index</td>
<td>New Index</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td>Pentium 90*</td>
<td>AMD K6/233*</td>
</tr>
<tr>
<td>NUMERIC SORT</td>
<td>366.08</td>
<td>9.39</td>
<td>3.08</td>
</tr>
<tr>
<td>STRING SORT</td>
<td>46.686</td>
<td>20.86</td>
<td>3.23</td>
</tr>
<tr>
<td>BITFIELD</td>
<td>4.764e+07</td>
<td>8.17</td>
<td>1.71</td>
</tr>
<tr>
<td>FP EMULATION</td>
<td>90.2</td>
<td>43.28</td>
<td>9.99</td>
</tr>
<tr>
<td>FOURIER</td>
<td>5171.9</td>
<td>5.88</td>
<td>3.30</td>
</tr>
<tr>
<td>ASSIGNMENT</td>
<td>11.094</td>
<td>42.21</td>
<td>10.95</td>
</tr>
<tr>
<td>IDEA</td>
<td>1726.9</td>
<td>26.41</td>
<td>7.84</td>
</tr>
<tr>
<td>HUFFMAN</td>
<td>605</td>
<td>16.78</td>
<td>5.36</td>
</tr>
<tr>
<td>NEURAL NET</td>
<td>9.761</td>
<td>15.68</td>
<td>6.60</td>
</tr>
<tr>
<td>LU DECOMPOSITION</td>
<td>215.64</td>
<td>11.17</td>
<td>8.07</td>
</tr>
</tbody>
</table>
<p>==========ORIGINAL BYTEMARK RESULTS========<br />
INTEGER INDEX       : 20.035<br />
FLOATING-POINT INDEX: 10.100<br />
Baseline (MSDOS*)   : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0<br />
==========LINUX DATA BELOW============<br />
CPU                 :<br />
L2 Cache            :<br />
OS                  : Linux 2.6.24-gdium-1<br />
C compiler          : gcc-4.4<br />
libc                : libc-2.9.so<br />
MEMORY INDEX        : 3.922<br />
INTEGER INDEX       : 5.997<br />
FLOATING-POINT INDEX: 5.602<br />
Baseline (LINUX)    : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38<br />
* Trademarks are property of their respective holder.</p>
<div class="zemanta-pixie"><img class="zemanta-pixie-img" src="http://img.zemanta.com/pixy.gif?x-id=fe9d2c4f-b064-8a94-9f49-f0e49d152a7a" alt="" /></div>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/10/30/performance-of-loongson-2f/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>qemu mips msub instruction emulation bug</title>
		<link>http://vm-kernel.org/blog/2009/10/15/qemu-mips-msub-instruction-emulation-bug/</link>
		<comments>http://vm-kernel.org/blog/2009/10/15/qemu-mips-msub-instruction-emulation-bug/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 05:06:22 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[ARM/MIPS]]></category>
		<category><![CDATA[emulation]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/10/15/qemu-mips-msub-instruction-emulation-bug/</guid>
		<description><![CDATA[It's really a long time since last post. Now I am working on the android mips porting project. I want to run android on the MIPS emulator.
The problem is that when I run mips-android on qemu, it hangs when executing init program in the initramfs root file-system. Then I use the remote gdb to debug [...]]]></description>
			<content:encoded><![CDATA[<p>It's really a long time since last post. Now I am working on the android mips porting project. I want to run android on the MIPS emulator.</p>
<p>The problem is that when I run mips-android on qemu, it hangs when executing init program in the initramfs root file-system. Then I use the remote gdb to debug the init and finds out that it it because pa_workspace is not initiated.</p>
<p>Function ashmem_create_region will open /dev/ashmem and return the fd if succeed. However, it returns -1 and the errno is 19 which means NO SUCH DEVICES.</p>
<blockquote><p>fd = ashmem_create_region("system_properties", size);</p></blockquote>
<p>The problem is who is responsible for creating /dev/ashmem?</p>
<p>In fact, in android it uses udev mechanism to create devices in /dev when executing function device_init. The full cold patch to create a device is as following:</p>
<blockquote><p>device_init-&gt;coldboot-&gt;do_coldboot-&gt;write(fd, "add\n", 4)-&gt;handle_device_fd-&gt;handle_device_event-&gt;make_device</p></blockquote>
<p>In function parse_event, it will parse the uevent msg and then pass uevent to handle_device_event. However, I find that the uevent message is a little weird. I use remote gdb to dump this message.</p>
<blockquote><p>0x7ff3d250:     "add@/class/tty/console"<br />
0x7ff3d267:     "ACTION=add"<br />
0x7ff3d272:     "DEVPATH=/class/tty/console"<br />
0x7ff3d28d:     "SUBSYSTEM=tty"<br />
0x7ff3d29b:     "MAJOR=+"<br />
0x7ff3d2a3:     "MINOR=/"<br />
0x7ff3d2ab:     "SEQNUM=31+"<br />
0x7ff3d2b6:     ""<br />
0x7ff3d2b7:     ""<br />
0x7ff3d2b8:     ""</p></blockquote>
<p>You see, in the message the MAJOR is +. It will confuse the parse_event so that the corresponding device won't be created.</p>
<p>It looks the kernel passes wrong uevent message to user space. So the question is who has messed up the uevent message?</p>
<p>Then I recall that when booting linux kernel, there are some weird messages.</p>
<blockquote><p>Primary instruction cache .kB, VIPT, 2-way, linesize 1* bytes.<br />
Primary data cache .kB, 2-way, VIPT, no aliases, linesize 1* bytes</p></blockquote>
<p>You see the instruction cache is .kB and linesize is 1* bytes, not a valid number at all.</p>
<p>Then I suspect that something is wrong in kernel when parsing the numbers. So I use the remote gdb to debug the kernel again.</p>
<blockquote><p>r4k_cache_init-&gt;probe_pcache-&gt;printk-&gt;vprintk-&gt;vscnprintf-&gt;vsnprintf-&gt;number-&gt;put_dec-&gt;put_dec_trunc</p></blockquote>
<p>Function put_dec_trunc uses a unsigned int between[0,99999] as input and outputs the number as a string. But I find that when the input is 2, the output is '.', not the expected '2'. So maybe this function is the bad boy.</p>
<p>In the following function I assume q=2.</p>
<blockquote><p>277 static char* put_dec_trunc(char *buf, unsigned q)<br />
278 {<br />
279         unsigned d3, d2, d1, d0;<br />
280         d1 = (q&gt;&gt;4) &amp; 0xf;            /*d1=0*/<br />
281         d2 = (q&gt;&gt;8) &amp; 0xf;            /*d2=0*/<br />
282         d3 = (q&gt;&gt;12);                 /*d3=0*/<br />
283<br />
284         d0 = 6*(d3 + d2 + d1) + (q &amp; 0xf);  /*d0=2*/<br />
285         q = (d0 * 0xcd) &gt;&gt; 11;              /*q=0*/<br />
286         d0 = d0 - 10*q;                     /*d==2*/<br />
287         *buf++ = d0 + ''; /* least significant digit */<br />
288         d1 = q + 9*d3 + 5*d2 + d1;   /*d1=0*/<br />
289         if (d1 != 0) {               /* it is false so we won't get into here.*/<br />
290                 q = (d1 * 0xcd) &gt;&gt; 11;<br />
291                 d1 = d1 - 10*q;<br />
292                 *buf++ = d1 + ''; /* next digit */<br />
293<br />
294                 d2 = q + 2*d2;<br />
295                 if ((d2 != 0) || (d3 != 0)) {<br />
296                         q = (d2 * 0xd) &gt;&gt; 7;<br />
297                         d2 = d2 - 10*q;<br />
298                         *buf++ = d2 + ''; /* next digit */<br />
299<br />
300                         d3 = q + 4*d3;<br />
301                         if (d3 != 0) {<br />
302                                 q = (d3 * 0xcd) &gt;&gt; 11;<br />
303                                 d3 = d3 - 10*q;<br />
304                                 *buf++ = d3 + '';  /* next digit */<br />
305                                 if (q != 0)<br />
306                                         *buf++ = q + '';  /* most sign. digit */<br />
307                         }<br />
308                 }<br />
309         }    <br />
310         return buf;<br />
311 }</p></blockquote>
<blockquote><p>/*  MIPS uses a0/a1 to pass arguments.<br />
 *  a0= address of bu<br />
 *  a1= q = 2<br />
 */<br />
8015a040 &lt;put_dec_trunc&gt;:<br />
8015a040:    00051202     srl    v0,a1,0x8        /* v0= q&gt;&gt;8*/<br />
8015a044:    00053102     srl    a2,a1,0x4        /* a2= q&gt;&gt;4*/<br />
8015a048:    30c6000f     andi    a2,a2,0xf        /* a2= (q&gt;&gt;4) &amp; 0xf = d1 in line 280*/<br />
8015a04c:    3048000f     andi    t0,v0,0xf        /* t0 = (q&gt;&gt;8) &amp; 0xf = d2 in line 281*/<br />
8015a050:    00054b02     srl    t1,a1,0xc        /* t1= (q&gt;&gt;12) = d3 in line 282*/<br />
8015a054:    00c81021     addu    v0,a2,t0        <br />
8015a058:    00491021     addu    v0,v0,t1          /* v0 = d1+d2+d3 in line 284*/<br />
8015a05c:    24030006     li    v1,6<br />
8015a060:    70433802     mul    a3,v0,v1          /*a3= 6*(d3 + d2 + d1)*/<br />
8015a064:    30a5000f     andi    a1,a1,0xf         /*a1= q &amp; 0xf*/<br />
8015a068:    24020009     li    v0,9               /*v0=9*/<br />
8015a06c:    00e56021     addu    t4,a3,a1          /*t4= 6*(d3 + d2 + d1) + (q &amp; 0xf) = d0 in line 284*/<br />
8015a070:    240b00cd     li    t3,205            /*t3= 0xcd*/<br />
8015a074:    71223802     mul    a3,t1,v0          /*a3= 9*d3 in line 288. Apparently gcc has reordered the code.*/   <br />
8015a078:    718b1802     mul    v1,t4,t3          /*v1= (d0*0xcd)*/<br />
8015a07c:    24020005     li    v0,5<br />
8015a080:    00e62821     addu    a1,a3,a2          /*a1= 9*d3 + d1 in line 288*/<br />
8015a084:    71023002     mul    a2,t0,v0          /*a2= 5*d2 in line 288*/<br />
8015a088:    00031ac2     srl    v1,v1,0xb         /*v1= (d0*0xcd)&gt;&gt;11 in line 285*/<br />
8015a08c:    240a000a     li    t2,10             /*t2=10*/<br />
8015a090:    01800013     mtlo    t4                /*put t4-&gt;lo. lo=t4= 6*(d3 + d2 + d1) + (q &amp; 0xf) = d0 in line 284 */<br />
8015a094:    706a0004     msub    v1,t2             /*hilo = v1*t2 - hilo = 10*(q) - hilo in line 286*/<br />
8015a098:    00c51021     addu    v0,a2,a1<br />
8015a09c:    00002812     mflo    a1                /*lo-&gt;a1*/    <br />
8015a0a0:    00431821     addu    v1,v0,v1<br />
8015a0a4:    24a20030     addiu    v0,a1,48         <br />
8015a0a8:    00803821     move    a3,a0<br />
8015a0ac:    a0820000     sb    v0,0(a0)</p></blockquote>
<p>We just need to see the instruction in 0x8015a094, it is a msub instruction. The defination of msub is as following:</p>
<blockquote><p>(HI,LO) = (HI,LO) - (GRP[RS]*GPR[RT])</p></blockquote>
<p>Then after executing the instruction in 0x8015a094, the HI/LO should be 0/2. But qemu produces the value 0xffffffff/0xfffffffe, which is -2 indeed. Maybe this is the problem.</p>
<p>Then I need to find how qemu emulates msub instruction.</p>
<blockquote><p>2178     case OPC_MSUB:<br />
2179         {<br />
2180             TCGv r_tmp1 = tcg_temp_new(TCG_TYPE_I64);<br />
2181             TCGv r_tmp2 = tcg_temp_new(TCG_TYPE_I64);<br />
2182             TCGv r_tmp3 = tcg_temp_new(TCG_TYPE_I64);<br />
2183<br />
2184             tcg_gen_ext32s_tl(t0, t0);<br />
2185             tcg_gen_ext32s_tl(t1, t1);<br />
2186             tcg_gen_ext_tl_i64(r_tmp1, t0);<br />
2187             tcg_gen_ext_tl_i64(r_tmp2, t1);<br />
2188             tcg_gen_mul_i64(r_tmp1, r_tmp1, r_tmp2);  /*r_tmp1= gpr[rs]*gpr[rt] */<br />
2189             gen_load_LO(t0, 0);                /*t0 &lt;- lo*/<br />
2190             gen_load_HI(t1, 0);                /*t1 &lt;- hi*/<br />
2191             tcg_gen_extu_tl_i64(r_tmp2, t0);   /*r_tmp2 = 64bit expand of lo*/<br />
2192             tcg_gen_extu_tl_i64(r_tmp3, t1);   /*r_tmp3 = 64bit expand of hi*/<br />
2193             tcg_gen_shli_i64(r_tmp3, r_tmp3, 32);<br />
2194             tcg_gen_or_i64(r_tmp2, r_tmp2, r_tmp3);<br />
2195             tcg_temp_free(r_tmp3);<br />
2196             tcg_gen_sub_i64(r_tmp1, r_tmp1, r_tmp2); /*r_tmp1= r_tmp1 - r_tmp2 = gpr[rs]*gpr[rt] - HI/LO */<br />
2197             tcg_temp_free(r_tmp2);<br />
2198             tcg_gen_trunc_i64_tl(t0, r_tmp1);<br />
2199             tcg_gen_shri_i64(r_tmp1, r_tmp1, 32);<br />
2200             tcg_gen_trunc_i64_tl(t1, r_tmp1);<br />
2201             tcg_temp_free(r_tmp1);<br />
2202             tcg_gen_ext32s_tl(t0, t0);<br />
2203             tcg_gen_ext32s_tl(t1, t1);<br />
2204             gen_store_LO(t0, 0);<br />
2205             gen_store_HI(t1, 0);<br />
2206         }<br />
2207         opn = "msub";<br />
2208         break;</p></blockquote>
<p>You see, qemu makes an error emulation of msub instruction. It uses gpr[rs]*gpr[rt]-HI/LO and then put the results to HI/LO, which is different from the defination of msub instruction. I patched the qemu code and it works.</p>
<p>BTW: MIPS32 4KTM Processor Core Family Software User’s Manual version MD00016 gives an error operation of msub instruction on papge 253.</p>
<blockquote><p>Operation:<br />
   temp ← (HI || LO) - (GPR[rs] * GPR[rt])<br />
   HI ← temp63..32<br />
   LO ← temp31..0</p></blockquote>
<p>Maybe this misleads the qemu developers. The latest qemu version has fixed this bug. We can see this instruction emulation in qemu-svn-20091014.</p>
<blockquote><p>2195     case OPC_MSUB:<br />
2196         {<br />
2197             TCGv_i64 t2 = tcg_temp_new_i64();<br />
2198             TCGv_i64 t3 = tcg_temp_new_i64();<br />
2199<br />
2200             tcg_gen_ext_tl_i64(t2, t0);<br />
2201             tcg_gen_ext_tl_i64(t3, t1);<br />
2202             tcg_gen_mul_i64(t2, t2, t3);  /*t2=GPR[RS]*GPR[RT] */<br />
2203             tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);  /*t3= HI/LO*/<br />
2204             tcg_gen_sub_i64(t2, t3, t2); /*t2= HI/LO - GPR[RS]*GPR[RT] */<br />
2205             tcg_temp_free_i64(t3);<br />
2206             tcg_gen_trunc_i64_tl(t0, t2);<br />
2207             tcg_gen_shri_i64(t2, t2, 32);<br />
2208             tcg_gen_trunc_i64_tl(t1, t2);<br />
2209             tcg_temp_free_i64(t2);<br />
2210             tcg_gen_ext32s_tl(cpu_LO[0], t0);<br />
2211             tcg_gen_ext32s_tl(cpu_HI[0], t1);<br />
2212         }<br />
2213         opn = "msub";<br />
2214         break;</p></blockquote>
<p>See <a href="http://www.archivum.info/qemu-devel@nongnu.org/2009-07/00011/%5BQemu-devel%5D_%5BPATCH%5D_target-mips:_fix_MADD_and_MSUB_MSUBU_instructions" target="_blank">this link</a> for more information.</p>
<p>So finding this bug is really not easy. I have to dig dig and dig from userland to linux kernel and then to qemu until catching this bad qemu bug. Thanks to the remote gdb and gdb stub in qemu, it makes life easier.</p>
<p>Following is the patch of qemu.</p>
<blockquote><p>diff --git a/target-mips/translate.c b/target-mips/translate.c<br />
index 3dded6c..0a1b461 100644<br />
--- a/target-mips/translate.c<br />
+++ b/target-mips/translate.c<br />
@@ -2193,7 +2193,11 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,<br />
             tcg_gen_shli_i64(r_tmp3, r_tmp3, 32);<br />
             tcg_gen_or_i64(r_tmp2, r_tmp2, r_tmp3);<br />
             tcg_temp_free(r_tmp3);<br />
-            tcg_gen_sub_i64(r_tmp1, r_tmp1, r_tmp2);<br />
+            /* msub means HI/LO = HI/LO - GPR[RS]*GPR[RT],<br />
+             * not HI/LO = GPR[RS]*GPR[RT] - HI/LO<br />
+             */<br />
+            //tcg_gen_sub_i64(r_tmp1, r_tmp2, r_tmp2);<br />
+            tcg_gen_sub_i64(r_tmp1, r_tmp2, r_tmp1);<br />
             tcg_temp_free(r_tmp2);<br />
             tcg_gen_trunc_i64_tl(t0, r_tmp1);<br />
             tcg_gen_shri_i64(r_tmp1, r_tmp1, 32);</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/10/15/qemu-mips-msub-instruction-emulation-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>qemu internal part 3: memory watchpoint</title>
		<link>http://vm-kernel.org/blog/2009/07/15/qemu-internal-part-3-memory-watchpoint/</link>
		<comments>http://vm-kernel.org/blog/2009/07/15/qemu-internal-part-3-memory-watchpoint/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 09:31:00 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[qemu]]></category>
		<category><![CDATA[watchpoint]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/07/15/qemu-internal-part-3-memory-watchpoint/</guid>
		<description><![CDATA[In qemu there is an amazing feature – memory watchpoint. It can watch all the memory access including memory read, write or both of them. When guest os/application touches the memory region watched by qemu, a registered function will be called and you can do everything as you want in this function. The gdb stub [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">In qemu there is an amazing feature – memory watchpoint. It can watch all the memory access including memory read, write or both of them. When guest os/application touches the memory region watched by qemu, a registered function will be called and you can do everything as you want in this function. The gdb stub in qemu uses it to implement the memory watch command.</p>
<p align="justify">The implemention of memory watchpoint is tricky in qemu. <a href="http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/">In last article of qemu internal</a>, we know that when emulating memory access, qemu needs to distinguish the normal RAM read/write from memory mapped I/O read/write. If it is a memory mapped I/O address access, qemu will dispatch this access to the registered I/O emulation functions. Qemu use this mechanism to implement the memory watchpoint. When accessing the memory address watched by qemu, qemu will dispatch this access to the registered memory watch functions, even if this address is normal guest RAM address or memory mapped I/O address! Qemu will do all the magic things in these memory watch functions.</p>
<p align="justify">In the following, I will use an example to explain the whole process of memory watch implement of qemu.</p>
<blockquote><p>80103c60 &lt;memcpy&gt;:     <br />80103c60:&#160;&#160;&#160;&#160;&#160;&#160; 00801021&#160;&#160;&#160;&#160;&#160;&#160;&#160; move&#160;&#160;&#160; v0,a0      <br />80103c64 &lt;__copy_user&gt;:      <br />80103c64:&#160;&#160;&#160;&#160;&#160;&#160; 2cca0004&#160;&#160;&#160;&#160;&#160;&#160;&#160; sltiu&#160;&#160; t2,a2,4      <br />80103c68:&#160;&#160;&#160;&#160;&#160;&#160; 30890003&#160;&#160;&#160;&#160;&#160;&#160;&#160; andi&#160;&#160;&#160; t1,a0,0x3      <br />80103c6c:&#160;&#160;&#160;&#160;&#160;&#160; 15400068&#160;&#160;&#160;&#160;&#160;&#160;&#160; bnez&#160;&#160;&#160; t2,80103e10 &lt;__copy_user+0x1ac&gt;      <br />80103c70:&#160;&#160;&#160;&#160;&#160;&#160; 30a80003&#160;&#160;&#160;&#160;&#160;&#160;&#160; andi&#160;&#160;&#160; t0,a1,0x3      <br />80103c74:&#160;&#160;&#160;&#160;&#160;&#160; 1520003d&#160;&#160;&#160;&#160;&#160;&#160;&#160; bnez&#160;&#160;&#160; t1,80103d6c &lt;__copy_user+0x108&gt;      <br />80103c78:&#160;&#160;&#160;&#160;&#160;&#160; 00000000&#160;&#160;&#160;&#160;&#160;&#160;&#160; nop      <br />80103c7c:&#160;&#160;&#160;&#160;&#160;&#160; 15000046&#160;&#160;&#160;&#160;&#160;&#160;&#160; bnez&#160;&#160;&#160; t0,80103d98 &lt;__copy_user+0x134&gt;      <br />80103c80:&#160;&#160;&#160;&#160;&#160;&#160; 00064142&#160;&#160;&#160;&#160;&#160;&#160;&#160; srl&#160;&#160;&#160;&#160; t0,a2,0x5      <br />80103c84:&#160;&#160;&#160;&#160;&#160;&#160; 11000017&#160;&#160;&#160;&#160;&#160;&#160;&#160; beqz&#160;&#160;&#160; t0,80103ce4 &lt;__copy_user+0x80&gt;      <br />80103c88:&#160;&#160;&#160;&#160;&#160;&#160; 30d8001f&#160;&#160;&#160;&#160;&#160;&#160;&#160; andi&#160;&#160;&#160; t8,a2,0x1f      <br />80103c8c:&#160;&#160;&#160;&#160;&#160;&#160; 00000000&#160;&#160;&#160;&#160;&#160;&#160;&#160; nop      <br />80103c90:&#160;&#160;&#160;&#160;&#160;&#160; 8ca80000&#160;&#160;&#160;&#160;&#160;&#160;&#160; lw&#160;&#160;&#160;&#160;&#160; t0,0(a1)</p>
</blockquote>
<p align="justify">These asm lines are objdumped from linux 2.6.30 kernel for mips malta. Assume that I want to&#160; watch the memory access of virtual address 0x804cd000(<em>swapper_pg_dir</em> in linux kernel).</p>
<p align="justify">First I insert the watchpoint into cpu. </p>
<blockquote><p>cpu_watchpoint_insert(env, 0x804cd000, 4, BP_GDB | BP_MEM_ACCESS,     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; NULL);</p>
</blockquote>
<p>And then I need to register the vm state changing call back functions.</p>
<blockquote><p>qemu_add_vm_change_state_handler(spy_vm_state_change, NULL);</p>
</blockquote>
<p align="justify">If register a1=0x804cd000, guest linux kernel will touch the watched memory region when pc is 0x80103c90, then qemu dispatches this access to the registered memory watch function, even if this access is a noram guest RAM access.The memory watch functions in qemu are in array <em>watch_mem_read/watch_mem_write</em>.</p>
<blockquote><p>exec.c</p>
<p>2649 static CPUReadMemoryFunc *watch_mem_read[3] = {     <br />2650&#160;&#160;&#160;&#160; watch_mem_readb,      <br />2651&#160;&#160;&#160;&#160; watch_mem_readw,      <br />2652&#160;&#160;&#160;&#160; watch_mem_readl,      <br />2653 };      <br />2654       <br />2655 static CPUWriteMemoryFunc *watch_mem_write[3] = {      <br />2656&#160;&#160;&#160;&#160; watch_mem_writeb,      <br />2657&#160;&#160;&#160;&#160; watch_mem_writew,      <br />2658&#160;&#160;&#160;&#160; watch_mem_writel,      <br />2659 };</p>
</blockquote>
<p>In function <em>watch_mem_readl</em>, it will call function <em>check_watchpoint</em> first.</p>
<blockquote><p>exec.c</p>
<p>2622 static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)     <br />2623 {      <br />2624&#160;&#160;&#160;&#160; check_watchpoint(addr &amp; ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);      <br />2625&#160;&#160;&#160;&#160; return ldl_phys(addr);      <br />2626 }</p>
</blockquote>
<blockquote><p>2563 static void check_watchpoint(int offset, int len_mask, int flags)     <br />2564 {      <br />2565&#160;&#160;&#160;&#160; CPUState *env = cpu_single_env;      <br />2566&#160;&#160;&#160;&#160; target_ulong pc, cs_base;      <br />2567&#160;&#160;&#160;&#160; TranslationBlock *tb;      <br />2568&#160;&#160;&#160;&#160; target_ulong vaddr;      <br />2569&#160;&#160;&#160;&#160; CPUWatchpoint *wp;      <br />2570&#160;&#160;&#160;&#160; int cpu_flags;      <br />2571       <br />2572&#160;&#160;&#160;&#160; if (env-&gt;watchpoint_hit) {      <br />2573&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* We re-entered the check after replacing the TB. Now raise      <br />2574&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * the debug interrupt so that is will trigger after the      <br />2575&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; * current instruction. */      <br />2576&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_interrupt(env, CPU_INTERRUPT_DEBUG);      <br />2577&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;      <br />2578&#160;&#160;&#160;&#160; }      <br />2579&#160;&#160;&#160;&#160; vaddr = (env-&gt;mem_io_vaddr &amp; TARGET_PAGE_MASK) + offset;      <br />2580&#160;&#160;&#160;&#160; TAILQ_FOREACH(wp, &amp;env-&gt;watchpoints, entry) {      <br />2581&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ((vaddr == (wp-&gt;vaddr &amp; len_mask) ||      <br />2582&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (vaddr &amp; wp-&gt;len_mask) == wp-&gt;vaddr) &amp;&amp; (wp-&gt;flags &amp; flags)) {      <br />2583&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; wp-&gt;flags |= BP_WATCHPOINT_HIT;      <br />2584&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!env-&gt;watchpoint_hit) {      <br />2585&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; env-&gt;watchpoint_hit = wp;      <br />2586&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; tb = tb_find_pc(env-&gt;mem_io_pc);      <br />2587&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!tb) {      <br />2588&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_abort(env, &quot;check_watchpoint: could not find TB for &quot;      <br />2589&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;pc=%p&quot;, (void *)env-&gt;mem_io_pc);      <br />2590&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />2591&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_restore_state(tb, env, env-&gt;mem_io_pc, NULL);      <br />2592&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; tb_phys_invalidate(tb, -1);      <br />2593&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (wp-&gt;flags &amp; BP_STOP_BEFORE_ACCESS) {      <br />2594&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; env-&gt;exception_index = EXCP_DEBUG;      <br />2595&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {      <br />2596&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_get_tb_cpu_state(env, &amp;pc, &amp;cs_base, &amp;cpu_flags);      <br />2597&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; tb_gen_code(env, pc, cs_base, cpu_flags, 1);      <br />2598&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />2599&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_resume_from_signal(env, NULL);      <br />2600&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />2601&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {      <br />2602&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; wp-&gt;flags &amp;= ~BP_WATCHPOINT_HIT;      <br />2603&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />2604&#160;&#160;&#160;&#160; }      <br />2605 }</p>
</blockquote>
<p align="justify">When <em>check_watchpoint</em> is executed in the first time, <em>env-&gt;watchpoint_hit</em> is null. Then it will check whether the address is a watched address. If so, set the flag BP_WATCHPOINT_HIT in <em>wp-&gt;flags</em>(line 2583) and set <em>env-&gt;watchpoint_hit</em> to <em>wp</em>. Then it will find and invalidate the current translation block(line 2586-2592). If the flag BP_STOP_BEFORE_ACCESS in <em>wp</em> is not set, then qemu will translate the code from current pc(line 2596-2597) and resume the guest instruction emulation(line 2599). Function <em>cpu_resume_from_signal</em> will jump to line 256 in cpu-exec.c and rerun the emulation process from the lw instruction(pc=0x80103c90). </p>
<blockquote><p align="justify">cpu-exec.c</p>
<p>255&#160;&#160;&#160;&#160; for(;;) {     <br />256&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (setjmp(env-&gt;jmp_env) == 0) {      <br />257&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; env-&gt;current_tb = NULL;      <br />258&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* if an exception is pending, we execute it here */      <br />259&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (env-&gt;exception_index &gt;= 0) {      <br />260&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (env-&gt;exception_index &gt;= EXCP_INTERRUPT) {      <br />261&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* exit request from the cpu execution loop */      <br />262&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ret = env-&gt;exception_index;      <br />263&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (ret == EXCP_DEBUG)      <br />264&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_handle_debug_exception(env);      <br />265&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; break;      <br />266&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {</p>
</blockquote>
<p align="justify">Why do qemu need to invalidate current translation block and regenerate the code? Because this memory access(pc=0x80103c90) is in the middle of a translation block. If we want to rerun this instruction, we need to regenerate the code from this instruction(pc=0x80103c90). Moreover before invalidating the translation block, qemu needs to sync the cpu state to guest cpu(<em>cpu_restore_state</em>). That’s because the cpu state in the middle of translation block is different from the actual cpu state. Understanding this process needs some knowledge of binary translation. If you find it is hard to understand, just ignore it.</p>
<p align="justify">Now qemu rerun the guest os from pc=0x80103c90. Because the memory address is a watched memory address, qemu will call <em>watch_mem_readl-&gt;check_watchpoint</em> again. But this time, <em>env-&gt;watchpoint_hit</em> is not null(qemu set it in last call), then it will call <em>cpu_interrupt</em> and return from function <em>check_watchpoint</em>. Then in <em>watch_mem_readl</em> it will call <em>ldl_phys</em> to fetch the value from guest RAM. Function <em>cpu_interrupt</em> in <em>check_watchpoint</em>&#160; sets the <em>CPU_INTERRUPT_DEBUG</em> to flag to <em>env-&gt;interrupt_request</em>.&#160; </p>
<p align="justify">Then qemu runs normally just like nothing has happened. Because the <em>CPU_INTERRUPT_DEBUG</em> has been set in <em>env-&gt;interrupt_request</em>, the main loop of cpu emulation will return.</p>
<blockquote><p>cpu-exec.c</p>
<p>355&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (interrupt_request &amp; CPU_INTERRUPT_DEBUG) {     <br />356&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; env-&gt;interrupt_request &amp;= ~CPU_INTERRUPT_DEBUG;      <br />357&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; env-&gt;exception_index = EXCP_DEBUG;      <br />358&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; cpu_loop_exit();      <br />359&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p>
<p> 54 void cpu_loop_exit(void)     <br /> 55 {      <br /> 56&#160;&#160;&#160;&#160; /* NOTE: the register at this point must be saved by hand because      <br /> 57&#160;&#160;&#160;&#160;&#160;&#160;&#160; longjmp restore them */      <br /> 58&#160;&#160;&#160;&#160; regs_to_env();      <br /> 59&#160;&#160;&#160;&#160; longjmp(env-&gt;jmp_env, 1);      <br /> 60 }</p>
</blockquote>
<p align="justify">Function <em>cpu_loop_exit</em> will do longjmp to line 256 in cpu-exec.c. Because <em>env-&gt;exception_index</em> is <em>EXCP_DEBUG</em>, it will break from the loop of function <em>cpu_exec</em>. Function <em>cpu_exec</em> returns to <em>main_loop</em> in vl.c.</p>
<blockquote><p>vl.c</p>
<p>3800&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ret = cpu_exec(env);</p>
<p>3850&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (unlikely(ret == EXCP_DEBUG)) {     <br />3851&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; gdb_set_stop_cpu(cur_cpu);      <br />3852&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; vm_stop(EXCP_DEBUG);      <br />3853&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p>
</blockquote>
<p align="justify">It will call <em>gdb_set_stop_cpu</em> and then <em>vm_stop</em> to stop the qemu. It the virtual state is changed, qemu will the call the callback functions registered by <em>qemu_add_vm_change_state_handler</em>. So the function <em>spy_vm_state_change</em> will be called.</p>
<p align="justify">In sum, when accessing the watched memory address, the memory watch functions will be called. It will call function<em> check_watchpoint</em>. Function <em>check_watchpoint</em> will set <em>env-&gt;watchpoint_hit</em> to current watchpoint and rerun the guest os/applicaton from current pc. Then memory watched functions will be called again. It will call <em>function check_watchpoint</em>. This time, function <em>check_watchpoint</em> just set the flag in <em>env-&gt;interrupt_request</em> and tells cpu to interrupt the emulation process. And then qemu will return to the <em>main_loop</em> and stop the vm. At last it will call the registered vm change state callback functions. </p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/07/15/qemu-internal-part-3-memory-watchpoint/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>qemu internal part 2: softmmu</title>
		<link>http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/</link>
		<comments>http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 03:14:00 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[qemu]]></category>
		<category><![CDATA[softmmu]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/</guid>
		<description><![CDATA[Qemu uses softmmu to accelerate the process of finding the mapping between guest physical address and host virtual address and the mapping between guest I/O region and qemu I/O emulation functions. In this article, I assume the guest page table size is 4K.
1. the two level guest physical page descriptor table
Qemu uses a two level [...]]]></description>
			<content:encoded><![CDATA[<p>Qemu uses softmmu to accelerate the process of finding the mapping between guest physical address and host virtual address and the mapping between guest I/O region and qemu I/O emulation functions. In this article, I assume the guest page table size is 4K.</p>
<p>1. the two level guest physical page descriptor table</p>
<p>Qemu uses a two level guest physical page descriptor table to maintain the guest memory space and MMIO space. The table is pointed by <em>l1_phys_map</em>. Bits [31:22] is used to index first level entry and bits [21:12] is used to index the second level entry. The entry of the second level table is <em>PhysPageDesc</em>.</p>
<blockquote><p>exec.c</p>
<p>146 typedef struct PhysPageDesc {      <br />147&#160;&#160;&#160;&#160; /* offset in host memory of the page + io_index in the low bits */       <br />148&#160;&#160;&#160;&#160; ram_addr_t phys_offset;       <br />149&#160;&#160;&#160;&#160; ram_addr_t region_offset;       <br />150 } PhysPageDesc;</p>
</blockquote>
<p>If the memory region is RAM, then the bits [31:12] of <em>phys_offset</em> means the offset of this page in emulated physical memory. If the memory region is memory mapped I/O, then the bits of [11:3] of <em>phys_offset</em> means the index in <em>io_mem_write/io_mem_read</em> array. When accessing this memory region, the functions in <em>io_mem_write/io_mem_read</em> of index phys_offset will be called.</p>
<p>2. register the guest physical memory</p>
<p>Function <em>cpu_register_physical_memory</em> is used to register a guest memory region. If <em>phys_offset</em> is IO_MEM_RAM then it means this region is guest RAM space. If the <em>phys_offset</em> &gt;IO_MEM_ROM, then it means this memory region is MMIO space.</p>
<blockquote><p>898 static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,      <br />899&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ram_addr_t size,       <br />900&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ram_addr_t phys_offset)       <br />901 {       <br />902&#160;&#160;&#160;&#160; cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0);       <br />903 }</p>
</blockquote>
<p>Function <em>cpu_register_physical_memory_offset</em> will first find the PhysPageDesc in table <em>l1_phys_map</em> using the given guest physical address<em>.</em> If finding the entry, qemu will update the entry. If not finding the entry, then qemu creates a new entry and updates its value and insert this entry to the table at last.</p>
<p>In malta emulation, the following is the code to register malta RAM space.</p>
<blockquote><p>hw/mips_malta.c</p>
<p>811&#160;&#160;&#160;&#160; cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);</p>
</blockquote>
<p>3. register the mmio space</p>
<p>Before registering mmio space using <em>cpu_register_physical_memory,</em> qemu uses the function <em>cpu_register_io_memory</em> to register the I/O emulation functions to array <em>io_mem_write/io_mem_read.</em> </p>
<blockquote><p>exec.c</p>
<p>2851 int cpu_register_io_memory(int io_index,      <br />2852&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CPUReadMemoryFunc **mem_read,       <br />2853&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CPUWriteMemoryFunc **mem_write,       <br />2854&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; void *opaque)</p>
</blockquote>
<p>This function will return the index in array io_mem_write/io_mem_read and this index will be passed to function <em>cpu_register_physical_memory</em> via parameter <em>phys_offset</em>.</p>
<blockquote><p>hw/mips_malta.c</p>
<p>malta = cpu_register_io_memory(0, malta_fpga_read,      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; malta_fpga_write, s); </p>
<p>cpu_register_physical_memory(base, 0x900, malta);</p>
</blockquote>
<p>4. softmmu</p>
<p>Given the guest virtual address, how does qemu find the corresponding host virtual address? First qemu needs to translate the guest virtual address to guest physical address. Then qemu needs to find the PhysPageDesc entry in table <em>l1_phys_map</em> and get the <em>phys_offset</em>. At last qemu should add <em>phys_offset</em> to <em>phys_ram_base</em> to get the host virtual address.</p>
<p>Qemu uses a softmmu model to speed up this process. Its main idea is storing the offset of guest virtual address to host virtual address in a TLB table. When translating the guest virtual address to host virtual address, it will search this TLB table firstly. If there is an entry in the table, then qemu can add this offset to guest virtual address to get the host virtual address directly. Otherwise, it needs to search the l1_phys_map table and then fill the corresponding entry to the TLB table. The index of this TLB table is bits [19:12] of guest virtual address and there is no asid field in tlb entry. This means the TLB table needs to be flushed in process switch!</p>
<p>This TLB table idea is just like the most traditional hardware TLB. However, to MIPS cpu, there is another mmu model in qemu. Unlike x86 cpu, MIPS does <strong>NOT</strong> care about hardware page table. Instead it uses hardware TLB which is <strong>NOT</strong> transparent to software. Maybe It is another topic I will explain in another article. What we need to understand here is that the softmmu model in this article is not the mmu model of MIPS cpu itself.</p>
<p>Moreover, besides helping speed up the process of translating guest virtual address to host virtual address, this softmmu model can speed up the process of dispatching I/O emulation functions according to guest virtual address too. In this case, the idex of I/O emulation functions in <em>io_mem_write/io_mem_read</em> is stored in iotlb.</p>
<p>The format of TLB entry is as flowing:</p>
<blockquote><p>cpu-defs.h</p>
<p>176&#160;&#160;&#160;&#160; CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE];&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \      <br />177&#160;&#160;&#160;&#160; target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE];&#160;&#160; </p>
</blockquote>
<blockquote><p>108 typedef struct CPUTLBEntry {      <br />109&#160;&#160;&#160;&#160; /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address       <br />110&#160;&#160;&#160;&#160;&#160;&#160;&#160; bit TARGET_PAGE_BITS-1..4&#160; : Nonzero for accesses that should not       <br />111&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; go directly to ram.       <br />112&#160;&#160;&#160;&#160;&#160;&#160;&#160; bit 3&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; : indicates that the entry is invalid       <br />113&#160;&#160;&#160;&#160;&#160;&#160;&#160; bit 2..0&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; : zero       <br />114&#160;&#160;&#160;&#160; */       <br />115&#160;&#160;&#160;&#160; target_ulong addr_read;       <br />116&#160;&#160;&#160;&#160; target_ulong addr_write;       <br />117&#160;&#160;&#160;&#160; target_ulong addr_code;       <br />124&#160;&#160;&#160;&#160; target_phys_addr_t addend;       <br />131 } CPUTLBEntry;</p>
</blockquote>
<p>Field <em>addr_read/write/code</em> stores the guest virtual address for TLB entry. It is the tag of this entry. Filed a<em>ddend</em> is the offset of host virtual address to guest virtual address. We can add this value to guest virtual address to get the host virtual address.</p>
<blockquote><p>addend = host_virtual_address – guest_virtual_address</p>
<p>host_virtual_address = <em><strong>phys_ram_base(qemu variable)</strong></em> + guest_physical_address – guest_physical_address_base(0 in MIPS) </p>
</blockquote>
<p>The <em>iotlb</em> stores the index of I/O emulation function in <em>io_mem_write/io_mem_read.</em></p>
<p>Function __ldb_mmu/__ldl_mmu/__ldw_mmu is used to translating the guest virtual address to host virtual address or dispatching guest virtual address to I/O emulation functions.</p>
<blockquote><p>softmmu_template.h</p>
<p> 86 DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,     <br /> 87&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int mmu_idx)      <br /> 88 {      <br /> 89&#160;&#160;&#160;&#160; DATA_TYPE res;      <br /> 90&#160;&#160;&#160;&#160; int index;      <br /> 91&#160;&#160;&#160;&#160; target_ulong tlb_addr;      <br /> 92&#160;&#160;&#160;&#160; target_phys_addr_t addend;      <br /> 93&#160;&#160;&#160;&#160; void *retaddr;      <br /> 94       <br /> 95&#160;&#160;&#160;&#160; /* test if there is match for unaligned or IO access */      <br /> 96&#160;&#160;&#160;&#160; /* XXX: could done more in memory macro in a non portable way */      <br /> 97&#160;&#160;&#160;&#160; index = (addr &gt;&gt; TARGET_PAGE_BITS) &amp; (CPU_TLB_SIZE - 1);      <br /> 98&#160; redo:      <br /> 99&#160;&#160;&#160;&#160; tlb_addr = env-&gt;tlb_table[mmu_idx][index].ADDR_READ;      <br />100&#160;&#160;&#160;&#160; if ((addr &amp; TARGET_PAGE_MASK) == (tlb_addr &amp; (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {      <br />101&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (tlb_addr &amp; ~TARGET_PAGE_MASK) {      <br />102&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* IO access */      <br />103&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ((addr &amp; (DATA_SIZE - 1)) != 0)      <br />104&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; goto do_unaligned_access;      <br />105&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; retaddr = GETPC();      <br />106&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; addend = env-&gt;iotlb[mmu_idx][index];      <br />107&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; res = glue(io_read, SUFFIX)(addend, addr, retaddr);      <br />108&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else if (((addr &amp; ~TARGET_PAGE_MASK) + DATA_SIZE - 1) &gt;= TARGET_PAGE_SIZE) {      <br />109&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* slow unaligned access (it spans two pages or IO) */      <br />110&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; do_unaligned_access:      <br />111&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; retaddr = GETPC();      <br />112 #ifdef ALIGNED_ONLY      <br />113&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);      <br />114 #endif      <br />115&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,      <br />116&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mmu_idx, retaddr);      <br />117&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } else {      <br />118&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* unaligned/aligned access in the same page */      <br />119 #ifdef ALIGNED_ONLY      <br />120&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ((addr &amp; (DATA_SIZE - 1)) != 0) {      <br />121&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; retaddr = GETPC();      <br />122&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);      <br />123&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />124 #endif      <br />125&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; addend = env-&gt;tlb_table[mmu_idx][index].addend;      <br />126&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));      <br />127&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }      <br />128&#160;&#160;&#160;&#160; } else {      <br />129&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* the page is not in the TLB : fill it */      <br />130&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; retaddr = GETPC();      <br />131 #ifdef ALIGNED_ONLY      <br />132&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if ((addr &amp; (DATA_SIZE - 1)) != 0)      <br />133&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);      <br />134 #endif      <br />135&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);      <br />136&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; goto redo;      <br />137&#160;&#160;&#160;&#160; }      <br />138&#160;&#160;&#160;&#160; return res;      <br />139 }      </p>
</blockquote>
<p>In this function, it will get the index of TLB table and compare the guest virtual address with the address stored in this tlb entry(line 97-100). If these two addresses match, it means this guest virtual address hits the tlb entry. Then qemu will determine this virtual address is a MMIO address or RAM address. If it is a MMIO address, get the index of IO emulation functions from <em>env-&gt;iotlb </em>and call these functions(line 103-117). If it is a RAM space, add the guest virtual address to addend to get the host virtual address(line 118-128). If there is no matched tlb entry, then fietch the entry from table <em>l1_phys_map </em>and insert the entry to tlb table(line 135).</p>
<p>5. an example</p>
<p>When fetching code from guest memory, the whole code path is as flowing:</p>
<blockquote><p>cpu_exec-&gt;tb_find_fast-&gt;tb_find_slow-&gt;get_phys_addr_code-&gt;(if tlb not match)ldub_code(softmmu_header.h)-&gt;__ldl_mmu(softmmu_template.h)-&gt;tlb_fill-&gt;cpu_mips_handle_mmu_fault-&gt;tlb_set_page-&gt;tlb_set_page_exec</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>qemu internal part 1: the code path of memory load emulation</title>
		<link>http://vm-kernel.org/blog/2009/07/08/qemu-internal-part-1-the-code-path-of-memory-load-emulation/</link>
		<comments>http://vm-kernel.org/blog/2009/07/08/qemu-internal-part-1-the-code-path-of-memory-load-emulation/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 06:58:00 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[qemu]]></category>
		<category><![CDATA[tcg]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/07/08/qemu-internal-part-1-the-code-path-of-memory-load-emulation/</guid>
		<description><![CDATA[In qemu, there are two different meanings of target. The first meaning of ‘target’ means the emulated target machine architecture. For example, when emulating mips machine on x86, the target is mips and host is x86. However, in tcg(tiny code generator), target has a different meaning. It means the generated binary architecture. In the example [...]]]></description>
			<content:encoded><![CDATA[<p>In qemu, there are two different meanings of target. The first meaning of ‘target’ means the emulated target machine architecture. For example, when emulating mips machine on x86, the target is mips and host is x86. However, in tcg(tiny code generator), target has a different meaning. It means the generated binary architecture. In the example of emulating mips on x86, in tcg the target means x86 because tcg will generate x86 binary.</p>
<p>This article is based on qemu version 0.10.5 and target machine emulated is little endian mips. I will summarize the code path of mips lw instruction emulation in qemu.</p>
<p>Function <i>decode_opc</i> is used for decoding all the fetched instructions before tcg generating the target binary.</p>
<blockquote><p>target-mips/translate.c</p>
<p>7566 static void decode_opc (CPUState *env, DisasContext *ctx)</p>
<p>7960&#160;&#160;&#160;&#160; case OPC_LB ... OPC_LWR: /* Load and stores */      <br />7961&#160;&#160;&#160;&#160; case OPC_SB ... OPC_SW:       <br />7962&#160;&#160;&#160;&#160; case OPC_SWR:       <br />7963&#160;&#160;&#160;&#160; case OPC_LL:       <br />7964&#160;&#160;&#160;&#160; case OPC_SC:       <br />7965&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; gen_ldst(ctx, op, rt, rs, imm);       <br />7966&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; break;</p>
</blockquote>
<p>It will call function <em>gen_ldst</em> which is also in <em>target-mips/translate.c</em>.</p>
<blockquote style="margin-right: 0px" dir="ltr"><p>target-mips/translate.c</p>
<p>973 static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,      <br />974&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int base, int16_t offset)</p>
<p>1046&#160;&#160;&#160;&#160; case OPC_LW:      <br />1047&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; op_ldst_lw(t0, ctx);       <br />1048&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; gen_store_gpr(t0, rt);       <br />1049&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; opn = &quot;lw&quot;;       <br />1050&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; break;</p>
</blockquote>
<p>Function <em>op_ldst_lw</em> will generate the target binary which fetches the value from the emulated guest memory and <em>gen_store_gpr</em> will store this value to the emulated cpu’s general register rt.</p>
<p>Function <em>op_ldst_lw </em>is generated by the macro <em>OP_LD</em>.</p>
<blockquote><p>target-mips/translate.c</p>
<p>901 #define OP_LD(insn,fname)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \      <br />902 static inline void op_ldst_##insn(TCGv t0, DisasContext *ctx)&#160;&#160;&#160; \       <br />903 {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \       <br />904&#160;&#160;&#160;&#160; tcg_gen_qemu_##fname(t0, t0, ctx-&gt;mem_idx);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \       <br />905 }</p>
<p>910 OP_LD(lw,ld32s);</p>
</blockquote>
<p>We can find that <em>op_ldst_lw </em>is a function which calls function <em>tcg_gen_qemu_ld32s</em>. It will output the OPC(<em>INDEX_op_qemu_ld32u</em>) and args to <em>gen_opc_ptr</em>.</p>
<blockquote><p>tcg/tcg-op.h</p>
<p>1793 static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)      <br />1794 {       <br />1795 #if TARGET_LONG_BITS == 32       <br />1796&#160;&#160;&#160;&#160; tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index);       <br />1797 #else       <br />1798&#160;&#160;&#160;&#160; tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr),       <br />1799&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TCGV_HIGH(addr), mem_index);       <br />1800&#160;&#160;&#160;&#160; tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);       <br />1801 #endif       <br />1802 }</p>
<p>99 static inline void tcg_gen_op3i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,      <br />100&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TCGArg arg3)       <br />101 {       <br />102&#160;&#160;&#160;&#160; *gen_opc_ptr++ = opc;       <br />103&#160;&#160;&#160;&#160; *gen_opparam_ptr++ = GET_TCGV_I32(arg1);       <br />104&#160;&#160;&#160;&#160; *gen_opparam_ptr++ = GET_TCGV_I32(arg2);       <br />105&#160;&#160;&#160;&#160; *gen_opparam_ptr++ = arg3;       <br />106 }</p>
</blockquote>
<p>The path of generation of target binary code of tcg is as following.</p>
<blockquote><p>cpu_gen_code-&gt;tcg_gen_code-&gt;tcg_gen_code_common-&gt;tcg_reg_alloc_op-&gt;tcg_out_op</p>
</blockquote>
<blockquote><p>tcg/i386/tcg-target.c</p>
<p>856 static inline void tcg_out_op(TCGContext *s, int opc,      <br />857&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; const TCGArg *args, const int *const_args)</p>
<p>1041&#160;&#160;&#160;&#160; case INDEX_op_qemu_ld32u:     <br />1042&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; tcg_out_qemu_ld(s, args, 2);      <br />1043&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; break;</p>
<p>431 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,     <br />432&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int opc)</p>
<p>508 #if TARGET_LONG_BITS == 32     <br />509&#160;&#160;&#160;&#160; tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index);      <br />510 #else      <br />511&#160;&#160;&#160;&#160; tcg_out_mov(s, TCG_REG_EDX, addr_reg2);      <br />512&#160;&#160;&#160;&#160; tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);      <br />513 #endif      <br />514&#160;&#160;&#160;&#160; tcg_out8(s, 0xe8);      <br />515&#160;&#160;&#160;&#160; tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] -       <br />516&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (tcg_target_long)s-&gt;code_ptr - 4);</p>
</blockquote>
<p>In line 514, tcg outputs 0xe8 which means a call instruction in x86. It will call the functions in array <em>qemu_ld_helpers.</em> The args to the functions is passed by registers EAX,EDX and ECX.</p>
<blockquote><p>tcg/i386/tcg-target.c</p>
<p>413 static void *qemu_ld_helpers[4] = {     <br />414&#160;&#160;&#160;&#160; __ldb_mmu,      <br />415&#160;&#160;&#160;&#160; __ldw_mmu,      <br />416&#160;&#160;&#160;&#160; __ldl_mmu,      <br />417&#160;&#160;&#160;&#160; __ldq_mmu,      <br />418 };</p>
</blockquote>
<p>These functions <em>__ldb_mmu/__ldw_mmu</em> are defined in softmmu_template.h.</p>
<blockquote><p>softmmu_tempate.h</p>
<p>DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int mmu_idx)</p>
</blockquote>
<p>In sum, function <em>gen_ldst</em> outputs the OPC(INDEX_op_qemu_ld32u) to <em>gen_opc_ptr</em> and <em>tcg_out_op</em> will generates the target binary according to the OPC. In the lw instruction emulation, it will generate the x86 binary calls the functions in <em>softmmu_template.h</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/07/08/qemu-internal-part-1-the-code-path-of-memory-load-emulation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>a little progress on qemu-loongson</title>
		<link>http://vm-kernel.org/blog/2009/06/10/a-little-progress-on-qemu-loongson/</link>
		<comments>http://vm-kernel.org/blog/2009/06/10/a-little-progress-on-qemu-loongson/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 03:15:00 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[emulatuion]]></category>
		<category><![CDATA[qemu]]></category>
		<category><![CDATA[qemu-loongson]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/07/08/a-little-progress-on-qemu-loongson/</guid>
		<description><![CDATA[Hi guys, it is about one month since posting last blog entry. These days I am really very busy preparing the GRE and Tofel test. Moreover I have to work to support my life. So I have to spend less time on qemu-loongson.
Anyway, there are progress these days. 

Rewrite the GPIO I2C emulation for gdium. [...]]]></description>
			<content:encoded><![CDATA[<p>Hi guys, it is about one month since posting last blog entry. These days I am really very busy preparing the GRE and Tofel test. Moreover I have to work to support my life. So I have to spend less time on qemu-loongson.</p>
<p>Anyway, there are progress these days. </p>
<ul>
<li>Rewrite the GPIO I2C emulation for gdium. Now it is more clear than before.</li>
<li>add st4180 rtc emulation to qemu</li>
<li>add stds75 temperature sensor emulation to qemu</li>
<li>change a little in uart emulation to satisfy pmon’s uart probing process</li>
<li>fix a little bug in pflash_cfi02.c</li>
<li>fix gdb stub bug in qemu to support mips64</li>
<p> Follow is the uart output of qemu-loongson.</p>
</ul>
<ul>
<blockquote dir="ltr" style="margin-right: 0px;">
<p>kill-bill:/home/root/sdd/gdium/qemu-loongson/mips64el-softmmu# ./qemu-system-mips64el -M gdium -pflash gzrom.bin.gdb -nographic -S -s <br />Register sst39vf040&nbsp; size 80000&nbsp; at offset 08800000 addr 1fc00000 'pflash0' 80        <br />devfn 70         <br />unassigned_mem_readl Unassigned mem read 000000001fbffffc        <br />unassigned_mem_readl Unassigned mem read 000000001fbffffc        <br />new_sm502_mm_io 7000000 pci_mem _base 10000000        <br />PMON2000 MIPS Initializing. Standby...        <br /> PRID=00006302        <br />enable register space of MEMORY        <br />DDR2 config begin_whd        <br />DIMM read        <br />0000008000000008read DIMM number of rows        <br />read number of cols        <br />module data width        <br />DIMM SIZE=20000000        <br />cols rows:        <br />04030940DDR2 config end        <br />DDR2 DLL locked        <br />00000004        <br />disable register space of MEMORY        <br />jlliu : rom speed reg : 0x00000f8c        <br />Init SDRAM Done!        <br />Sizing caches...        <br />Init caches...        <br />godson2 caches found        <br />Init caches done, cfg = 00030932        <br />Copy PMON to execute location...        <br />copy text section done.        <br />Copy PMON to execute location done.        <br />sp=80ffc000...............new_sm502_mm_io 6000000 pci_mem _base 10000000        <br />cmd 7        <br />mmio 6000000        <br />FREQ        <br />FREI        <br />DONE        <br />DEVI        <br />ENVI        <br />MAPV        <br />nvram=bfc00000        <br />NVRAM is invalid!        <br />NVRAM@bfc00000        <br />STDV        <br />80100000: heap is already above this point        <br />SBDD        <br />P12PCIH</p>
</blockquote>
</ul>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/06/10/a-little-progress-on-qemu-loongson/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>what&#039;s the difference between these two definitions</title>
		<link>http://vm-kernel.org/blog/2009/04/23/whats-the-difference-between-these-two-definitions/</link>
		<comments>http://vm-kernel.org/blog/2009/04/23/whats-the-difference-between-these-two-definitions/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 01:39:03 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[kernel]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/04/23/whats-the-difference-between-these-two-definitions/</guid>
		<description><![CDATA[I write this article because some guys are talking about it in CLF. The question is: what is the difference between the two following definitions:
A. const char temp[]=&#34;abc&#34;;
B. const char *temp=&#34;abc&#34;;

You may have your own answer already. But wait a moment, let me write some test cases first and you can see whether your answer [...]]]></description>
			<content:encoded><![CDATA[<p>I write this article because some guys are talking about it in <a href="http://www.linuxforum.net/forum/showflat.php?Cat=&amp;Board=embedded&amp;Number=717266&amp;page=0&amp;view=collapsed&amp;sb=5&amp;o=0&amp;fpart=">CLF</a>. The question is: what is the difference between the two following definitions:</p>
<blockquote><p>A. const char temp[]=&quot;abc&quot;;</p>
<p>B. const char *temp=&quot;abc&quot;;</p>
</blockquote>
<p>You may have your own answer already. But wait a moment, let me write some test cases first and you can see whether your answer is right or not. <img src='http://vm-kernel.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>(1) Test case 1</p>
<blockquote><p>const char temp[]=&quot;abc&quot;;      <br />int main()       <br />{       <br />temp[0]='c';       <br />printf(&quot;temp %s \n&quot;,temp);       <br />}       <br />debian:~# gcc -o test test.c       <br />test.c: In function `main':       <br />test.c:8: error: assignment of read-only location `temp[0]'</p>
</blockquote>
<p>(2) Test case 2</p>
<blockquote><p>const char temp[]=&quot;abc&quot;;      <br />char temp1[]=&quot;def&quot;;       <br />int main()       <br />{       <br />temp = temp1;       <br />printf(&quot;temp %s \n&quot;,temp);       <br />}       <br />debian:~# gcc -o test test.c       <br />test.c: In function `main':       <br />test.c:8: error: assignment of read-only variable `temp'</p>
</blockquote>
<p>(3) Test case 3</p>
<blockquote><p>const char* temp=&quot;abc&quot;;      <br />char temp1[]=&quot;def&quot;;       <br />int main()       <br />{       <br />temp = temp1;       <br />printf(&quot;temp %s \n&quot;,temp);       <br />}       <br />debian:~# gcc -o test test.c       <br />debian:~# ./test       <br />temp def</p>
</blockquote>
<p>(4) Test case 4</p>
<blockquote><p>const char* temp=&quot;abc&quot;;      <br />int main()       <br />{       <br />temp[0] = 'd';       <br />printf(&quot;temp %s \n&quot;,temp);       <br />}       <br />debian:~# gcc -o test test.c       <br />test.c: In function `main':       <br />test.c:8: error: assignment of read-only location `*temp'</p>
</blockquote>
<p>So the definition A means both temp and array is const and you can not change it. Definition B means temp points to a const string, which you can not change its content. But you can change temp itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/04/23/whats-the-difference-between-these-two-definitions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I2C emulation in qemu-loongson</title>
		<link>http://vm-kernel.org/blog/2009/04/22/i2c-emulation-in-qemu-loongson/</link>
		<comments>http://vm-kernel.org/blog/2009/04/22/i2c-emulation-in-qemu-loongson/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 03:52:11 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[loongson]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[i2c]]></category>
		<category><![CDATA[qemu-loongson]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/04/22/i2c-emulation-in-qemu-loongson/</guid>
		<description><![CDATA[I think most of you may think it is easy to emulate I2C device in qemu, for qemu has provided a framework of i2c, both the master and slave devices. You are right. Emulating the I2C is not difficult in qemu.
What I want to post here is not emulating I2C device directly, but emulating GPIO [...]]]></description>
			<content:encoded><![CDATA[<p>I think most of you may think it is easy to emulate I2C device in qemu, for qemu has provided a framework of i2c, both the master and slave devices. You are right. Emulating the I2C is not difficult in qemu.</p>
<p>What I want to post here is not emulating I2C device directly, but emulating GPIO logic which pmon uses to emulate I2C. A little confused? Me too. Ok, let me talk the story from the began.</p>
<p>In pmon, it uses sm502 gpio pin 6 and 13 to emulate I2C master devices, which communicates with other slave device, such as SPD EEPROM and temperature sensors. I do not know why lemote uses gpio to emulate i2c, instead of using the I2C master in sm502. When the data is written to gpio pins according to I2C state machine, pmon expects the gpio pins acting like the I2C master devices. So qemu needs to emulate the I2C cycle accurate state machine, not only the I2C function.</p>
<p>I summarize the I2C emulation code logic of pmon here for reference.</p>
<p>(1) Start Bit</p>
<p>SCL=0 -&gt; SDA=1 -&gt; SCL=1 -&gt; SDA=0 -&gt; SCL=0</p>
<p>(2)Stop Bit</p>
<p>SCL=0 -&gt; SDA=0 -&gt;SCL=1 -&gt;SDA=1 -&gt; SCL=0</p>
<p>(3)Write a bit</p>
<p>Put data on sda -&gt; SCL=1 -&gt; SCL=0</p>
<p>(4)Write a byte</p>
<p>repeating (3) 8 times -&gt; SDA=1</p>
<p>(5)Recv ACK</p>
<p>SCL=1 -&gt;read sda until sda=0 -&gt; SCL=0</p>
<p>(6)Read a bit</p>
<p>SCL=1 -&gt; read data on SDA -&gt; SCL=0</p>
<p>(7)Read a byte</p>
<p>repeating (6) 8 times</p>
<p>(8)Send ACK</p>
<p>put ACK on sda -&gt; SCL=1 -&gt; SCL=0</p>
<p>(9)Send a buffer</p>
<p>Do the following steps until the buffer is empty</p>
<ol>
<li>START </li>
<li>Send slave address </li>
<li>Recv ACK </li>
<li>Send reg address </li>
<li>Recv ACK </li>
<li>Send one byte </li>
<li>Recv ACK </li>
<li>STOP </li>
</ol>
<p>(10) Recv many bytes from slave deviceDo the following steps until finished </p>
<ol>
<li>START </li>
<li>Send slave address </li>
<li>Recv ACK </li>
<li>Send reg address </li>
<li>Recv ACK</li>
<li>Repeat START </li>
<li>Send slave address+1(tell slave we want to recv) </li>
<li>Recv ACK </li>
<li>Recv a byte </li>
<li>Send ACK </li>
<li>STOP </li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/04/22/i2c-emulation-in-qemu-loongson/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>eth0 is missing on my gdium PCB board</title>
		<link>http://vm-kernel.org/blog/2009/03/28/eth0-is-missing-on-my-gdium-pcb-board/</link>
		<comments>http://vm-kernel.org/blog/2009/03/28/eth0-is-missing-on-my-gdium-pcb-board/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 09:32:03 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[loongson]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[udev]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/03/28/eth0-is-missing-on-my-gdium-pcb-board/</guid>
		<description><![CDATA[I have an extra gdium pcb board with uart interface from fred. Thanks  .
Today I try to compile the kernel by myself and the new kernel works well except for network card. I can not see eth0 using ifconfig command. Then I check the pci list of my gdium PCB and find the RTL8139D [...]]]></description>
			<content:encoded><![CDATA[<p>I have an extra gdium pcb board with uart interface from fred. Thanks <img src='http://vm-kernel.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Today I try to compile the kernel by myself and the new kernel works well except for network card. I can not see eth0 using ifconfig command. Then I check the pci list of my gdium PCB and find the RTL8139D is on the list.</p>
<blockquote><p>kill-bill:~# ifconfig eth0   <br />eth0: error fetching interface information: Device not found</p></blockquote>
<blockquote></blockquote>
<blockquote><p>kill-bill:~# lspci     <br />00:00.0 MIPS: STMicroelectronics STLS2F Host Bridge (rev 01)      <br />00:0d.0 Network controller: RaLink RT2561/RT61 802.11g PCI      <br />00:0e.0 Display controller: Silicon Motion, Inc. SM501 VoyagerGX Rev. AA (rev c0      <br />)      <br />00:0f.0 USB Controller: NEC Corporation USB (rev 44)      <br />00:0f.1 USB Controller: NEC Corporation USB 2.0 (rev 05)      <br />00:10.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139      <br />C+ (rev 10)      <br />00:11.0 USB Controller: NEC Corporation USB (rev 44)      <br />00:11.1 USB Controller: NEC Corporation USB 2.0 (rev 05)</p>
</blockquote>
<p>That shows rtl8139 is successfully initialized by the kernel. But why there is no eth0 device?</p>
<p>Then I grep eth0 in dmesg and find that something is wrong with udev.</p>
<blockquote><p>kill-bill:~# dmesg | grep eth0     <br />eth0: RealTek RTL8139 at 0x9000000051a2a100, 00:d0:35:10:00:20, IRQ 39      <br />eth0:&#160; Identified 8139 chip type 'RTL-8100B/8139D'      <br />udev: renamed network interface eth0 to eth1</p>
</blockquote>
<p>I cat the udev net rule and find that it sets 8139d with MAC address 00:d0:35:10:00:20 to eth1. That's exactly the network card on my gdium PCB. </p>
<blockquote><p>kill-bill:~# cat /etc/udev/rules.d/70-persistent-net.rules     <br /># This file was automatically generated by the /lib/udev/write_net_rules      <br /># program run by the persistent-net-generator.rules rules file.      <br />#      <br /># You can modify it, as long as you keep each rule on a single line. </p>
<p># PCI device 0x10ec:0x8139 (8139too)     <br />SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;00:d0:35:10:04:a9&quot;, ATTR{type}==&quot;1&quot;, KERNEL==&quot;eth*&quot;, NAME=&quot;eth0&quot; </p>
<p># PCI device 0x1814:0x0301 (rt61pci)     <br />SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;00:0e:8e:19:3d:68&quot;, ATTR{type}==&quot;1&quot;, KERNEL==&quot;wlan*&quot;, NAME=&quot;wlan0&quot; </p>
<p># PCI device 0x10ec:0x8139 (8139too)     <br />SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;00:d0:35:10:00:20&quot;, ATTR{type}==&quot;1&quot;, KERNEL==&quot;eth*&quot;, NAME=&quot;eth1&quot; </p>
<p># PCI device 0x1814:0x0301 (rt61pci)     <br />SUBSYSTEM==&quot;net&quot;, ACTION==&quot;add&quot;, DRIVERS==&quot;?*&quot;, ATTR{address}==&quot;00:0e:8e:19:3b:18&quot;, ATTR{type}==&quot;1&quot;, KERNEL==&quot;wlan*&quot;, NAME=&quot;wlan1&quot;</p>
</blockquote>
<p>I know why dev does that now. The debian system is installed on my gdium, not on the PCB and then I just use it on the PCB board. When udev finds there is another 8139d network card with different MAC address it adds another entry in rules to rename it to eth1. After changing the eth1 to eth0 in 70-persistent-net.rules, the network works now.</p>
<p>Following is the kernel information of my new kernel.:)</p>
<blockquote><p>kill-bill:~# dmesg | grep 2.6.24     <br />Linux version 2.6.24.5-gdiumv3-2.2mnb (root@debian) (gcc version 4.3.3 (GCC) ) #      <br />2 Sat Mar 28 16:00:59 CST 2009</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/03/28/eth0-is-missing-on-my-gdium-pcb-board/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>QEMU Does NOT Support MIPS Host Anymore</title>
		<link>http://vm-kernel.org/blog/2009/03/26/qemu-does-not-support-mips-host-anymore/</link>
		<comments>http://vm-kernel.org/blog/2009/03/26/qemu-does-not-support-mips-host-anymore/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 06:42:03 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[emulation]]></category>
		<category><![CDATA[loongson]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[MIPS]]></category>
		<category><![CDATA[qemu]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/03/26/qemu-does-not-support-mips-host-anymore/</guid>
		<description><![CDATA[New version of qemu does not support MIPS host anymore.
For the sake of portability, the new version of qemu uses TCG, a tiny code generator, instead of dyngen to generate host code. That means one backend is needed for each host architecture. There are i386,x86_64,ppc,ppc64 and hppa backend in TCG, but MIPS is not on [...]]]></description>
			<content:encoded><![CDATA[<p>New version of qemu does not support MIPS host anymore.</p>
<p align="justify">For the sake of portability, the new version of qemu uses TCG, a tiny code generator, instead of dyngen to generate host code. That means one backend is needed for each host architecture. There are i386,x86_64,ppc,ppc64 and hppa backend in TCG, but MIPS is not on the list.</p>
<p align="justify">I confirm this conclusion on the <a href="http://www.nongnu.org/qemu/status.html">status page of qemu web site</a>. The MIPS's status is 'Not Supported'. Perhaps these days the most emergent work is to add MIPS host support, instead of loongson guest support to qemu.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/03/26/qemu-does-not-support-mips-host-anymore/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to Install Debian Lenny on Gdium</title>
		<link>http://vm-kernel.org/blog/2009/03/20/how-to-install-debian-lenny-on-gdium/</link>
		<comments>http://vm-kernel.org/blog/2009/03/20/how-to-install-debian-lenny-on-gdium/#comments</comments>
		<pubDate>Fri, 20 Mar 2009 07:01:01 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[loongson]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[lenny]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/03/20/how-to-install-debian-lenny-on-gdium/</guid>
		<description><![CDATA[Although Vincent has given us a how to article of debian on gdium, but there are some detailed things missed. So I rewrite it here with some more detailed steps.
(1) Prepare the new USB disk
Format the new USB disk with at least tow partitions, one is ext2 partition for the root file system and the [...]]]></description>
			<content:encoded><![CDATA[<p>Although <a href="http://www.gdium.com/en/user/408">Vincent</a> has given us <a href="http://www.gdium.com/en/node/872">a how to article</a> of debian on gdium, but there are some detailed things missed. So I rewrite it here with some more detailed steps.</p>
<p>(1) Prepare the new USB disk</p>
<p>Format the new USB disk with at least tow partitions, one is ext2 partition for the root file system and the other is swap space. You can use fdisk to do this.</p>
<p>(2) Install the debian base system using debootstrap</p>
<p>You need to install the debootstrap in gdium first.</p>
<blockquote><p>urpmi debootstrap</p></blockquote>
<p>Mount the new USB disk to your gdium, /mnt for example. Replace /dev/sdc1 to the name of your USB device.</p>
<blockquote><p><span style="background-color: #ffffff;">mount /dev/sdc1 /mnt</span></p></blockquote>
<p>Install the debian base system using debootstrap. You can change lenny to sid if you want to use the debian testing system. To me, I prefer lenny.</p>
<blockquote><p>debootstrap --arch=mipsel lenny /mnt</p></blockquote>
<p>It will download the packages and install to system. So please be patient if your network speed is slow.</p>
<p>Copy /etc/resolv.conf  to your new system and set the hostname of the new system.</p>
<blockquote><p><span style="background-color: #ffffff;">copy /etc/resolv.conf  /mnt/etc/resolv.conf</span></p>
<p><span style="background-color: #ffffff;">echo YOUHOSTNAME &gt; /mnt/etc/hostname</span></p></blockquote>
<p>Chroot to your new system.</p>
<blockquote><p><code>chroot /mnt /bin/bash</code></p></blockquote>
<p><span id="more-155"></span></p>
<p><code>(3) Install the kernel image</code></p>
<blockquote><p><code><span style="background-color: #ffffff;">wget <a title="http://lebesgue.cowpig.ca/~philippe/gdium/linux-2.6.24-gdium-1_2.6.24-gdium-1_mipsel.deb" href="http://lebesgue.cowpig.ca/~philippe/gdium/linux-2.6.24-gdium-1_2.6.24-gdium-1_mipsel.deb">http://lebesgue.cowpig.ca/~philippe/gdium/linux-2.6.24-gdium-1_2.6.24-gdium-1_mipsel.deb</a></span></code></p>
<p><code><span style="background-color: #ffffff;">dpkg -i linux-2.6.24-gdium-1_2.6.24-gdium-1_mipsel.deb</span></code></p></blockquote>
<p><code>Change /etc/modules to the following:</code></p>
<blockquote><p>gdium_laptop<br />
ipv6<br />
i2c_gpio<br />
sm501_gpio<br />
lm75<br />
hwmon_vid<br />
hwmon<br />
eeprom<br />
i2c_dev</p></blockquote>
<p><code>Install udev in debian. Otherwise the debian will complain about rtc after rebooting.<br />
</code></p>
<blockquote><p><code>apt-get install udev</code></p></blockquote>
<p><code>(4) Reboot your gdium and set the env parameters pf PMON</code></p>
<p><code>Reboot the gdium and press DEL on the keyboard when gdium powers up to enter the PMON console. Set the env parameters of PMON to let it loads the correct kernel image and find the correct root file system.</code></p>
<blockquote><p><code><span style="background-color: #ffffff;">set al <a>/dev/fs/ext2@usbg0/boot/vmlinuz-2.6.24-gdium-1</a></span></code></p>
<p><code><span style="background-color: #ffffff;">set karg console=tty0 root=/dev/sda1 rootwait video=sm501fb:1024x600 init=/sbin/init</span></code></p>
<p><code><span style="background-color: #ffffff;">reboot</span></code></p></blockquote>
<p><code>Please change root=/dev/sda1 according to your USB disk's partition setting.</code></p>
<p><code>(5) Install software in debian</code></p>
<blockquote><p><code><span style="background-color: #ffffff;">apt-get install lm-sensors</span></code></p></blockquote>
<p><code><span style="background-color: #ffffff;">Change the /etc/sensors3.conf to the following:</span></code></p>
<blockquote><p>chip "lm75-*"<br />
set temp1_max      40<br />
set temp1_max_hyst 35</p></blockquote>
<p>Install the video card driver.</p>
<blockquote><p><span style="background-color: #ffffff;">apt-get install xorg</span></p>
<p><span style="background-color: #ffffff;">wget <a title="http://lebesgue.cowpig.ca/~philippe/gdium/xserver-xorg-video-siliconmotion_1.7.0-0_mipsel.deb" href="http://lebesgue.cowpig.ca/~philippe/gdium/xserver-xorg-video-siliconmotion_1.7.0-0_mipsel.deb">http://lebesgue.cowpig.ca/~philippe/gdium/xserver-xorg-video-siliconmotion_1.7.0-0_mipsel.deb</a></span></p>
<p><span style="background-color: #ffffff;">dpkg -i xserver-xorg-video-siliconmotion_1.7.0-0_mipsel.deb</span></p></blockquote>
<p>Install lxde desktop. Of course you can install xfce4 or gnome.</p>
<blockquote><p><span style="background-color: #ffffff;">apt-get install lxde</span></p></blockquote>
<p>Install the wireless card driver and wicd. Change the /etc/apt/sources.list to the following.</p>
<blockquote><p>deb <a href="http://ftp.us.debian.org/debian">http://ftp.us.debian.org/debian</a> lenny main non-free<br />
deb <a href="http://apt.wicd.net">http://apt.wicd.net</a> lenny extras</p></blockquote>
<blockquote><p>apt-get update</p>
<p>apt-get install firmware-ralink wicd wireless-tools</p>
<p>modprobe rt61pci</p></blockquote>
<p>Ok. Now you have a working debian lenny system with lxde desktop.</p>
<p>Issues &amp; solutions:</p>
<p>(1) portmap hangs and you can't turn off gdium</p>
<p>Add the following lines to /etc/network/interfaces.</p>
<blockquote><p>auto lo<br />
iface lo inet loopback</p></blockquote>
<p>(2)cannot access mtab: Input/output error</p>
<p>That's because /etc/fstab is not configured. Add the follow lines into your /etc/fstab. You can add or delete the partitions if you want.</p>
<blockquote><p>/dev/sda1 / ext3 noatime 1 1<br />
/dev/sda4 swap swap defaults 0 0<br />
none /tmp tmpfs defaults 0 0<br />
none /var/log tmpfs defaults 0 0<br />
none /proc proc defaults 0 0<br />
none /sys/kernel/debug debugfs defaults 0 0</p></blockquote>
<p>(3) Sound does not work on my system!!</p>
<p>Add you the the audio group.</p>
<blockquote><p>usermod -a - G audio yajin</p></blockquote>
<p>(4) The system can not display Chinese characters.</p>
<blockquote><p>apt-get install locales</p>
<p>dpkg-reconfigure locales</p></blockquote>
<p>Please make sure zh_CN locale is selected. You can install wqy fonts if you want.</p>
<blockquote><p>apt-get install xfonts-wqy ttf-wqy-zenhei</p></blockquote>
<p>(5) How to display the flash player in youtube</p>
<blockquote><p><span style="background-color: #ffffff;">apt-get install swfdec-mozilla</span></p></blockquote>
<p>The feedbacks are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/03/20/how-to-install-debian-lenny-on-gdium/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>My New Toy: Gdium Liberty 1000</title>
		<link>http://vm-kernel.org/blog/2009/03/16/my-new-toy-gdium-liberty-1000/</link>
		<comments>http://vm-kernel.org/blog/2009/03/16/my-new-toy-gdium-liberty-1000/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 07:40:03 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[ARM/MIPS]]></category>
		<category><![CDATA[loongson]]></category>
		<category><![CDATA[gdium]]></category>
		<category><![CDATA[OLPH]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/03/16/my-new-toy-gdium-liberty-1000/</guid>
		<description><![CDATA[This morning I eventually received my gdium liberty 1000 from zjs express, nearly 5 days after its shipping! Last time I use sf express to ship my mp4 player to Beijing in less than 2 days. I understand, because of the battery stuff can not be shipped by airline, but 5 days is excessive for [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">This morning I eventually received my gdium liberty 1000 from <a href="http://www.zjs.com.cn/eng/index.aspx">zjs express</a>, nearly 5 days after its shipping! Last time I use <a href="http://en.sf-express.com/">sf express</a> to ship my mp4 player to Beijing in less than 2 days. I understand, because of the battery stuff can not be shipped by airline, but 5 days is excessive for train and even for truck!</p>
<p>Although a little dissatisfied with the shipping express, gdium seems very attractive to me at my first glance for its smart size and its black color. It spend me a little time to make the battery work because I do not know how to assemble the battery at first. The speed of gdium is not as good as I had expected for a 900MHZ CPU. But there is room for optimization because of the N32 MIPS ABI. The screen resolution is excellent, 1024*600 is enough for most of the web sites. The Chinese fonts display very well when I visit the sina.com.cn, thanks to <a href="http://wenq.org/index.cgi">wqy fonts</a>. The Youtube videos can also display very well in Firefox. Awesome! I do not find which plugin does firefox use to display the flash, gnash maybe? The gtk desktop is not very fluent, but that's ok because I will replace it with a lightweight desktop.</p>
<p>Gdium, to me, is a development platform more than a notebook for daily use. I want a MIPS development platform for a long time and gdium is the very one. It is better than the <a href="http://www.lemote.com/english/yeeloong.html">yeeloong</a> notebook, which I planned to buy a few months ago, for gdium has an bigger LCD and good look.</p>
<p>I have too many plans on this new toy, porting android, porting lguest and kvm. But the issue is there is no uart interface on gdium. If you want the uart interface, you need to seal it by yourself. That is too hard to me, a hardware beginner.</p>
<p>If there is an emulator of gdium, life would be much easier. I can use the emulator to test the pmon/linux kernel and lguest porting. I know I can develop a gdium emulator based on qemu, but I have done too much about the emulator stuff, <a href="http://vm-kernel.org/qemu-omap3.htm">qemu-omap3</a>, <a href="http://code.google.com/p/jz-hacking/wiki/qemujz">qemu-jz</a>, virtualmips and a little fed up with emulator development. But emulator is really a big helper for kernel related development......</p>
<p>Following is my todo list these months.</p>
<ul>
<li>install debian and a lightweight desktop for gdium</li>
<li>develop an emulator of gdium based on qemu</li>
<li>port lguest and kvm to MIPS</li>
<li>port android to gdium and tune the performance of dalvik runtime on MIPS target</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/03/16/my-new-toy-gdium-liberty-1000/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Let&#039;s bring virtualization into MIPS&#039;s world</title>
		<link>http://vm-kernel.org/blog/2009/02/25/lets-bring-virtulization-into-mipss-world/</link>
		<comments>http://vm-kernel.org/blog/2009/02/25/lets-bring-virtulization-into-mipss-world/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 07:35:19 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[ARM/MIPS]]></category>
		<category><![CDATA[JZ]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[jz-hacking]]></category>
		<category><![CDATA[Links:Virtualization]]></category>
		<category><![CDATA[loongson]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/02/25/lets-bring-virtulization-into-mipss-world/</guid>
		<description><![CDATA[I have spent about 1 month in making linux run on onda vx747 and it works now. Although it is a achievement, it's not the end of project jz-hacking.
These days I am always thinking about bringing virtualization into MIPS's world. You know, xen has been ported into ARM by Samsung and kvm into PPC by [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">I have spent about 1 month in making <a href="http://vm-kernel.org/blog/2009/02/24/linux-on-onda-vx747/">linux run on onda vx747</a> and it works now. Although it is a achievement, it's not the end of project jz-hacking.</p>
<p align="justify">These days I am always thinking about bringing virtualization into MIPS's world. You know, <a href="http://www.youtube.com/watch?v=ylEy-WT3JF4">xen has been ported into ARM</a> by Samsung and <a href="http://kvm.qumranet.com/kvmwiki/KvmForum2008?action=AttachFile&amp;do=get&amp;target=kdf2008_10.pdf">kvm into PPC by IBM</a>. X86, not even to say,  has the most complete support of virtualization in hardware and software. But to MIPS, there is nothing. Neither there is no virtualization support in MIPS's world nor anyone wants to do this(at least I have NOT heard of that).</p>
<p align="justify">I think you may ask who needs virtualization or why we need virtualization in MIPS's world. Well, that's a good question which is not easy to answer. Let's divide MIPS's world into two parts: high performance computing and embedded devices. For the first part, the advantage of virtualization is obvious, for example, making better resource utilization.To the embedded world, let's use mobile phone as an example, using virtualization can make your device more secure by isolating the critical part, communicating protocol for example, from feature rich os(linux for example). Because of isolation, the virus on linux can not control your system's critical part.</p>
<p align="justify">Loongson has done great job in developing 2E and 2F, but that's not enough. I find that loongson has put many effort into x86 binary translation acceleration in last few years. That's a good point to get more market share. But we need to consider one thing first, if one customer wants to buy a MIPS translated x86 cpu, why does not he buy a x86 cpu directly? I think there is one area which loongson should put even more effort into. That is virtualization!</p>
<p align="justify">Virtualization can be achieved by hardware and/or software, with the better performance if hardware supports this feature. To the software virtualization, we already have xen/kvm/lguest and OKL4(it seems to focus on embedded world). Xen is a paravirtualization solution while kvm is a full virtualization solution. The most obvious difference between paravirtualization and full virtualization is prarvirtualization needs to modify the guest operation system while full virtualization needn't. Of course you can do this in full virtualization to achieve better performance.</p>
<p align="justify">According to MIPS, I think there should be a solution of virtualization. Either kvm or xen is ok. The important part is that we need to have one. That's what I was planned todo even in one year ago when I was busy developing virtualmips. I spent some days on porting <a href="http://lguest.ozlabs.org/">lguest</a> to jz4740 in last July. But at last I gave up. Now I want to do it again. I plan to port lguest to jz4740 and  loongson 2f first. With the help of this experience, I can gain some knowledge about virtualization on MIPS platform. And then kvm is planned to be ported to loongson 2f. Image that one day we can run five linux operating systems on loongson 2f at the same time, is it cool?</p>
<p align="justify">If you are interested in virtualization, let's work together to make this happen. Do not leave MIPS alone while other boys all have virtualization to play with. <img src='http://vm-kernel.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/02/25/lets-bring-virtulization-into-mipss-world/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Problems I meet when porting linux to onda vx747</title>
		<link>http://vm-kernel.org/blog/2009/02/24/problems-i-meet-when-porting-linux-to-onda-vx747/</link>
		<comments>http://vm-kernel.org/blog/2009/02/24/problems-i-meet-when-porting-linux-to-onda-vx747/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 06:20:25 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[JZ]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[frame buffer console]]></category>
		<category><![CDATA[jz4740]]></category>
		<category><![CDATA[qtopia]]></category>
		<category><![CDATA[vx747]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/02/24/problems-i-met-when-porting-linux-to-onda-vx747/</guid>
		<description><![CDATA[1. About jz4740 DMA
JZ4740 has 2 groups of DMA, 4 channels in each group. The default prority is channel 0 has the highest priority and channel 7 has the loweset priority.
Channel 0 is used for SLCD and channel 2/3 are used for MMC TX/RX. Because the SLCD DMA is busy transmitting data from frame buffer [...]]]></description>
			<content:encoded><![CDATA[<p>1. About jz4740 DMA</p>
<p>JZ4740 has 2 groups of DMA, 4 channels in each group. The default prority is channel 0 has the highest priority and channel 7 has the loweset priority.</p>
<p>Channel 0 is used for SLCD and channel 2/3 are used for MMC TX/RX. Because the SLCD DMA is busy transmitting data from frame buffer to LCD controller, so that MMC DMA is in hunger and the root filesystem can not be loaded from micro sd card.</p>
<p>In SLCD driver, set the DMA priority to round bin.</p>
<p>2. Issues about qtopia</p>
<p>(1)QWSServerSocket: could not bind to file /tmp/qtembedded-unknown/QtEmbedded-0</p>
<p>Error: File exists</p>
<p>Failed to bind to /tmp/qtembedded-unknown/QtEmbedded-0</p>
<p>Add networking support in linux kernel.</p>
<p>Networking support-&gt;Networking options-&gt;Unix domain sockets</p>
<p>(2)QServerSocket: failed to bind or listen to the socket<br />
Failed to bind to port 4243<br />
QServerSocket: failed to bind or listen to the socket<br />
Failed to bind to port 4242</p>
<p>According to <a title="http://osdir.com/ml/handhelds.opie/2002-10/msg00253.html" href="http://osdir.com/ml/handhelds.opie/2002-10/msg00253.html">http://osdir.com/ml/handhelds.opie/2002-10/msg00253.html</a>,</p>
<blockquote><p>Opie is binding to the ports 4242(ftp) and 4243(qcopbridge) this is needed for<br />
syncing.. Opie got terminated and restarted somehow and did not properly<br />
release the sockets..<br />
I guess this is a kernel security feature.</p></blockquote>
<p>That's because Opie can not bind to port 4242 and 4243. After enabling TCP/IP support in linux kernel, this problem is solved.</p>
<p>Networking support-&gt;Networking options-&gt;TCP/IP networking</p>
<p>(3)Unable to open /usr/share/zoneinfo/zone.tab</p>
<p>That's because zoneinfo directory is missed. Copy it from my debian and it works.</p>
<p>3. Issues about framebuffer console</p>
<p>When I pass console=fb0 to linux kernel, the framebuffer does not appear on LCD. I am sure the LCD driver is working because the qtopia can run successfully. And I have enabled framebuffer console support in linux kernel.</p>
<p>Pass console=tty0 to linux kernel can solve this problem.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/02/24/problems-i-meet-when-porting-linux-to-onda-vx747/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>linux on onda vx747(updated)</title>
		<link>http://vm-kernel.org/blog/2009/02/24/linux-on-onda-vx747/</link>
		<comments>http://vm-kernel.org/blog/2009/02/24/linux-on-onda-vx747/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 04:13:19 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[JZ]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[jz4740]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[onda]]></category>
		<category><![CDATA[qtopia]]></category>
		<category><![CDATA[vx747]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/02/24/linux-on-onda-vx747/</guid>
		<description><![CDATA[Before reading this article, please please visit the following website and help this little girl. She is the daughter of panjet, the core member of this project. Without him, this project can not even happen. 
http://yifanfund.com (English)
在阅读这篇文章前, 我恳请您花一点时间来帮助panjet的女儿怡帆. Panjet是这个项目的核心成员.如果没有他的参与,这个项目不可能成功地port linux到vx747上面. 赠人玫瑰,手留余香.  您的爱心一定能让小怡帆度过目前的困难.
http://help-yifan.org (中文)

Hi guys, a good news for you who are interested in running linux [...]]]></description>
			<content:encoded><![CDATA[<p align="justify"><strong>Before reading this article, please please visit the following website and help this little girl. She is the daughter of panjet, the core member of this project. Without him, this project can not even happen. </strong></p>
<p align="justify"><a href="http://yifanfund.com/">http://yifanfund.com</a> (English)</p>
<p align="justify"><strong>在阅读这篇文章前, 我恳请您花一点时间来帮助panjet的女儿怡帆. Panjet是这个项目的核心成员.如果没有他的参与,这个项目不可能成功地port linux到vx747上面. 赠人玫瑰,手留余香.  您的爱心一定能让小怡帆度过目前的困难.</strong></p>
<p align="justify"><a href="http://help-yifan.org/">http://help-yifan.org</a> (中文)</p>
<p align="justify"><img class="alignnone" title="Yifan" src="http://yifanfund.com/images/header/header.jpg" alt="" width="790" height="308" /></p>
<p align="justify">Hi guys, a good news for you who are interested in running linux on jz4740 based devices. First I would link to say it is not a very easy work although ingenic has released the linux source code. Secondly I would like to say thanks to many people who helped me a lot, vxworks,panjet,esoul of <a href="http://www.linuxforum.net/forum/postlist.php?Cat=&amp;Board=embedded&amp;page=0&amp;view=collapsed&amp;sb=5&amp;o=0">linuxforum</a> and Maurus Cuelenaere, the great rockbox guy.</p>
<p align="justify">Hey do not be so boring to say these useless words. Tell me how do you do that. Ok. Please be patient.</p>
<p align="justify">Currently linux can run on onda vx747 without writting any things to your nand flash. What you need is just a micro sd card  bigger than 128M bytes where you put linux kernel and root filesystem. Of course, if you want to replace the original firmware and write u-boot into nand flash, I can tell you how to do it. Even after writing u-boot into your nand flash you can still reinstall the original firmware. So please do not worry about your devices.  It won't be damaged.</p>
<p align="justify">1. Download the following files from jz_hacking.</p>
<p align="justify">(1)<a href="http://jz-hacking.googlecode.com/files/jz_tools_20090224.tar.bz2">jz_tools_20090224.tar.bz2</a>: It contains a tool called usbtool which uploads your program into jz4740's internal sram directly.</p>
<p align="justify">md5:1520851babe97da15651f9bef2c1ac5f</p>
<p align="justify">(2)<a href="http://jz-hacking.googlecode.com/files/jz_hacking_20090224.tar.bz2">jz_hacking_20090224.tar.bz2</a>: It contains u-boot image, jz_xloader and linux image.</p>
<p align="justify">md5:ac755b694f6e38224560a9051f1392e7</p>
<p align="justify">(3)<a href="http://jz-hacking.googlecode.com/files/root26.tar.bz2">root26.tar.bz2</a>: root file system of linux 2.6 kernel with qtopia</p>
<p align="justify">md5:738f6dfc648d36229a799d1d608655d1</p>
<p align="justify">Some guy says that this bz2 file is corrupted. I have tried downloading it using firefox in window and the file downloaded is corrupted!. But when I use other download tool it is ok. So if you can not unpack this package, you can try downloading it using other download tool. Wget in linux works well.</p>
<p align="justify">2. Make usbtool</p>
<p align="justify">Decompress the jz_tools_20090224.tar.bz2 and build the usbtool. It can be compiled in linux or minigw on windows. Please first read the README file in 'jz_tools_20090224/usb_tools'.</p>
<p align="justify">In linux, libusb-dev needs to be installed first. In windows, install MingW32 and LibUSB-Win32 and edit "Makefile" to make sure "WIN_DRIVERS_LIBUSB_DIR" is set correctly.</p>
<p align="justify">Type 'make linux' in linux platform and 'make win' on windows to build usbtool. After that copy jz_xloader.bin and u-boot-boot-linux.bin and u-boot-program-nand.bin from jz_hacking_20090224 into this directory.</p>
<p align="justify">3. Prepare your micro sd card</p>
<p align="justify">First you need to format sd card into <span style="text-decoration: line-through;">two </span>three partitions, one is fat and the other is ext2 and the third partition is swap. You do not know how to do it? Do not worry. <a href="http://code.google.com/p/beagleboard/wiki/LinuxBootDiskFormat">This wiki page</a> on beagle board tells you how to do it.  Please  to format your first partition to FAT16 format, not FAT32 referred on the wiki page. That mean you have to use 'mkfs.vfat -F 16' to format the first partition. Use mkswap command in linux to format the third partition into swap space. In xp, you can use partition magic to do this job.</p>
<p align="justify">Download the following files:</p>
<ul>
<li><a style="white-space: nowrap;" href="http://jz-hacking.googlecode.com/files/uImage-vx747-20090303">uImage-vx747-20090303</a> :this is the linux kernel with sound support</li>
<li><a style="white-space: nowrap;" href="http://jz-hacking.googlecode.com/files/rcS-vx747-20090303">rcS-vx747-20090303</a> :This is the init script for vx747.</li>
<li><a style="white-space: nowrap;" href="http://jz-hacking.googlecode.com/files/rcS-vx747-20090303"></a><a style="white-space: nowrap;" href="http://jz-hacking.googlecode.com/files/pointercal-vx747-20090302">pointercal-vx747-20090302</a> :This is the touch screen calibration data  for vx747.</li>
</ul>
<p align="justify">After you finish formatting your micro sd card, rename uImage-vx747-20090303 to uImage and copy it to your fat partition. Copy u-boot-nand.bin from jz_hacking_20090224 to your fat pattition. Do <strong>NOT</strong> copy uImage in jz_hacking_20090224 to your fat partition. It is the old linux kernel image. Now we have uImage-vx747-20090303 and we do not need it anymore. Copy all the files in root26 into the ext2 partition. Rename rcS-vx747-20090303 to rcS and copy it to directory 'ext/init.d/rcS' of the ext2 partition of your SD card. Rename pointercal-vx747-20090302 to pointercal and copy it to the directory 'ext/pointercal'.</p>
<p align="justify">4. Boot linux</p>
<p align="justify">Ok, it is time to boot linux. Insert the sd card into onda vx747. Press the reset button and hold the M button at the same time to enter usb boot mode. Run the usbtool using the following commands.</p>
<blockquote>
<p align="justify"><span style="background-color: #ffffff;">./usbtool 1 jz_xloader.bin 0x80000000</span></p>
<p align="justify"><span style="background-color: #ffffff;">./usbtool 1 u-boot-boot-linux.bin 0x80100000<br />
</span></p></blockquote>
<p align="justify">If that does not work in your system(some guy says it does that work on ubuntu), you can try the following commands:</p>
<blockquote>
<p align="justify"><span style="background-color: #ffffff;">sudo ./usbtool 12<br />
</span></p></blockquote>
<p align="justify">Then you can see the u-boot logo. It will load uImage from micro sd card into SDRAM automatically and then boot from SDRAM. After that, linux logo will appear on LCD with framebuffer console output. At last, qtopia is running and you can play with it.</p>
<p align="justify">5. Programing u-boot into nand flash(optional)</p>
<p align="justify">If you decide to replace the original firmware and write u-boot into nand flash, you can use u-boot-program-nand.bin to do that.</p>
<blockquote>
<p align="justify"><span style="background-color: #ffffff;">./usbtool 1 jz_xloader.bin 0x80000000</span></p>
<p><span style="background-color: #ffffff;">./usbtool 1 u-boot-program-nand.bin 0x80100000</span></p></blockquote>
<p align="justify">Also 'sudo ./usbtool 13' can work.</p>
<p align="justify">It will write u-boot into nand flash and reboot onda vx747 automatically.</p>
<p align="justify">If you want to restore the original firmware, <a href="http://www.rockbox.org/twiki/bin/view/Main/OndaVX747#Official_flash_recovery">this information may help you</a>.</p>
<p align="justify">I only test the linux kernel and u-boot on my 4G bytes onda vx747 with 16M SDRAM. Some guy says that there is another model of vx747 with 32M SDRAM, I have not tried on that device. If you have any suggestion, please wirte to me(yajin AT vm-kernel.org). Spams are not welcome. <img src='http://vm-kernel.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p align="justify">Current Issue:</p>
<ul>
<li><span style="text-decoration: line-through;">Touch screen is not accurate </span>(solved)</li>
<li><span style="text-decoration: line-through;">Sound is not working </span>(solved)</li>
<li><span style="text-decoration: line-through;">time and date setting </span>(solved)<span style="text-decoration: line-through;"><br />
</span></li>
<li>nand driver of u-boot is not working on 8G vx747 (not yet. I do not have the 8G version of vx747)</li>
</ul>
<p>Please be patient. I will solve these problems.</p>
<p align="justify">Also any donation of jz4740/4750 based device is appreciated.</p>
<p align="justify">For anyone interested, the source code of u-boot and linux-kernel is available here.</p>
<p align="justify">http://code.google.com/p/jz-hacking/wiki/Index?tm=6#source_code</p>
<p align="justify"><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="344" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/jbMxSP7_jqY&amp;hl=zh_CN&amp;fs=1" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="425" height="344" src="http://www.youtube.com/v/jbMxSP7_jqY&amp;hl=zh_CN&amp;fs=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/02/24/linux-on-onda-vx747/feed/</wfw:commentRss>
		<slash:comments>133</slash:comments>
		</item>
		<item>
		<title>Cause register bug in qemu-jz</title>
		<link>http://vm-kernel.org/blog/2009/01/16/cause-register-bug-in-qemu-jz/</link>
		<comments>http://vm-kernel.org/blog/2009/01/16/cause-register-bug-in-qemu-jz/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 11:24:39 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[JZ]]></category>
		<category><![CDATA[emulation]]></category>
		<category><![CDATA[MIPS]]></category>
		<category><![CDATA[qemu-jz]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/01/16/cause-register-bug-in-qemu-jz/</guid>
		<description><![CDATA[In MIPS, cause register is responsible for telling CPU which interrupt is happening. CPU read the IP bits in cause register and dispatch interrupt to interrupt service routine.
One question: who is responsible for clear IP bits in cause register? That is interrupt handler. Interrupt handler must clear the corresponding IP bit in cause register, othewise [...]]]></description>
			<content:encoded><![CDATA[<p>In MIPS, cause register is responsible for telling CPU which interrupt is happening. CPU read the IP bits in cause register and dispatch interrupt to interrupt service routine.</p>
<p>One question: who is responsible for clear IP bits in cause register? That is interrupt handler. Interrupt handler must clear the corresponding IP bit in cause register, othewise next time, interrupt is reenabled, CPU thinks the interrupt is still happening!</p>
<p>In linux, the function to clear IP bit in mask_and_ack_intc_irq. In JZ4740, it is:</p>
<blockquote><p>50 static void mask_and_ack_intc_irq(unsigned int irq)     <br />51 {      <br />52&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; __intc_mask_irq(irq);      <br />53&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; __intc_ack_irq(irq);      <br />54 }</p>
</blockquote>
<blockquote><p>1372 #define __intc_mask_irq(n)&#160;&#160;&#160;&#160;&#160; ( REG_INTC_IMSR = (1 &lt;&lt; (n)) )     <br />1373 #define __intc_ack_irq(n)&#160;&#160;&#160;&#160;&#160;&#160; ( REG_INTC_IPR = (1 &lt;&lt; (n)) )</p>
</blockquote>
<p>Linux writes to REG_INTC_IPR to clear pending interrupt and JZ4740 interrupt controller will clear the interrupt signal to MIPS CPU.</p>
<p>In qemu-jz, when writing to REG_INTC_IPR, the interrupt to MIPS cpu is not cleared and linux runs in a dead loop.</p>
<p>The following is the interrupt handling process in MIPS CPU.</p>
<p>1. Set ECP=PC and CPU jumps to 0x80000200 and then to handle_int. The interrupt is disabled.</p>
<p>2. Function handle_int will save all the register(including EPC so that interrupt can be nested) to stack and call plat_irq_dispatch. </p>
<p>3. After the irq is processed, it will reenable the in function __do_softirq. If a new interrupt is coming at this time(check the IP bits cause register), go to 1. otherwise go to 4.</p>
<p>4. Call ret_from_irq and restore all the register(including EPC) and using ERET to set PC=EPC.</p>
<p>5. Runs from PC.</p>
<p>Because of the IP bits in cause register is not cleared, linux will run into a dead loop between 1 and 3.</p>
<p>Thanks to the log function and remote gdb. Really hard to find this bug in qemu-jz.</p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/01/16/cause-register-bug-in-qemu-jz/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to run rockbox on vx747</title>
		<link>http://vm-kernel.org/blog/2009/01/12/how-to-run-rockbox-on-vx747/</link>
		<comments>http://vm-kernel.org/blog/2009/01/12/how-to-run-rockbox-on-vx747/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 03:55:44 +0000</pubDate>
		<dc:creator>yajin</dc:creator>
				<category><![CDATA[JZ]]></category>
		<category><![CDATA[jz4732]]></category>
		<category><![CDATA[jz4740]]></category>
		<category><![CDATA[rockbox]]></category>
		<category><![CDATA[vx747]]></category>

		<guid isPermaLink="false">http://vm-kernel.org/blog/2009/01/12/how-to-run-rockbox-on-vx747/</guid>
		<description><![CDATA[Caution: This article is out-dated. You can find the new how to in rockbox's wiki.
This article describes how to run rockbox on vx747 and vx747+.
1. Download rockbox from daily archive or svn. I use the svn version 19703.
2. build the toolchain. You can build the toolchain from ingenic or use the script in rockbox to [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Caution: This article is out-dated. You can find the new how to in <a href="http://www.rockbox.org/twiki/bin/view/Main/OndaVX747#How_to_upload_Rockbox_to_SDRAM">rockbox's wiki</a>.</strong></p>
<p>This article describes how to run rockbox on vx747 and vx747+.</p>
<p>1. Download rockbox from daily archive or svn. I use the svn version 19703.</p>
<p>2. build the toolchain. You can build the toolchain from ingenic or use the script in rockbox to build the toolchain.</p>
<p>Option 1) download the source code from <a href="ftp://ftp.ingenic.cn/3sw/01linux/00toolchain/mipseltools-gcc412-lnx26.tar.gz">ingenic ftp</a> and build it.</p>
<p>Option 2) use the rockboxdev.sh in rockbox/tools to build the toolchain.</p>
<p>Add the toolchain to your system's PATH.</p>
<p>3. build the rockbox. If you use the toolchain from ingenic, you should comment the following line in firmware/target/mips/ingenic_jz47xx/boot.lds</p>
<blockquote><p>#OUTPUT_FORMAT("elf32-littlemips")</p></blockquote>
<p>If you buile the toolchain from rockboxdev.sh, we do not need to change boot.lds.</p>
<blockquote><p><span style="background-color: #ffffff;">cd rockbox-19703</span></p>
<p><span style="background-color: #ffffff;">mkdir build</span></p>
<p><span style="background-color: #ffffff;">cd build</span></p>
<p>../tools/configure</p></blockquote>
<p>Choose 120 for vx747 and 122 for vx747+ and then choose B for buile rockbox for bootloader. It will create Makefile in build directory. Type make to build the rockbox. If everything goes ok, file rockboot.vx747 is created. Rename it to onda.bin.</p>
<p>4. Build and use the usbtool to upload onda.bin to vx747.</p>
<blockquote><p>cd utils/jz4740_tools/</p>
<p>make</p></blockquote>
<p>Libusb-dev is needed to build usbtool. You can read the README in jz4740_tools.</p>
<p>Downlaod <a href="http://www.rockbox.org/twiki/bin/viewfile/Main/OndaVX747?rev=1;filename=Log_Files.rar">Log_files.rar</a> and decompress it. Copy 1.bin to utils/jz4740_tools.</p>
<blockquote><p>./usbtool 10</p></blockquote>
<p>It will upload onda.bin to your vx747's SDRAM. Do not worry, it won't corrupt your device.</p>
<p>Following is the screenshot of rockbox on vx747.</p>
<p><a href="http://picasaweb.google.com/lh/photo/nxAGCQw1yUHSn2Q6RXpb2g?feat=embedwebsite"><img src="http://lh6.ggpht.com/_vf_uV7bji2A/SWq--oidmTI/AAAAAAAAAPQ/1P5hAZk1pf4/s400/rockbox-vx747.jpg" alt="" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://vm-kernel.org/blog/2009/01/12/how-to-run-rockbox-on-vx747/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
