﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-快乐生活，感受人生-随笔分类-技术文档</title><link>http://www.cnitblog.com/yuhensong/category/3036.html</link><description>New Life, Old Face
&lt;bgsound src=http://www.ht.com.cn/bbu/attachments/month_0510/kh0n_10.wma loop="-1"&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 20 Sep 2016 12:24:52 GMT</lastBuildDate><pubDate>Tue, 20 Sep 2016 12:24:52 GMT</pubDate><ttl>60</ttl><item><title>利用bochs调试内核（转载）</title><link>http://www.cnitblog.com/yuhensong/archive/2016/09/20/90485.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Tue, 20 Sep 2016 09:23:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2016/09/20/90485.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/90485.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2016/09/20/90485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/90485.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/90485.html</trackback:ping><description><![CDATA[<span style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">Bochs具有非常强大的操作系统内核调试功能。这也是本文选择Bochs作为首选实验环境的主要原因之一。有关Bochs调试功能的说明参见前面14.2节，这里基于Linux 0.11内核来说明Windows环境下Bochs系统调试操作的基本方法。</span><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">14.8.1 运行Bochs调试程序<br />我们假设Bochs系统已被安装在目录&#8220;C:\Program Files\Bochs-2.1.1\&#8221;中，并且Linux 0.11系统的Bochs配置文件名称是bochsrc-hd.bxrc。现在在包含内核Image文件的目录下建立一个简单的批处理文件run.bat，其内容如下：</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">"C:\Program Files\Bochs-2.1.1\bochsdbg" -q -f bochsrc-hd.bxrc</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">其中bochsdbg是Bochs系统的调试执行程序。运行该批处理命令即可进入调试环境。此时Bochs的主显示窗口空白，而控制窗口将显示以下类似内容：</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">C:\Documents and Settings\john1\桌面\Linux-0.11&gt;"C:\Program Files\Bochs-2.1.1\bo<br />chsdbg" -q -f bochsrc-hd.bxrc<br />========================================================================<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Bochs x86 Emulator 2.1.1<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; February 08, 2004<br />========================================================================<br />00000000000i[ &nbsp; &nbsp; ] reading configuration from bochsrc-hd.bxrc<br />00000000000i[ &nbsp; &nbsp; ] installing win32 module as the Bochs GUI<br />00000000000i[ &nbsp; &nbsp; ] Warning: no rc file specified.<br />00000000000i[ &nbsp; &nbsp; ] using log file bochsout.txt<br />Next at t=0<br />(0) context not implemented because BX_HAVE_HASH_MAP=0<br />[0x000ffff0] f000:fff0 (unk. ctxt): jmp f000:e05b &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ea5be000f0<br />&lt;bochs:1&gt;</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">此时Bochs调试系统已经准备好开始运行，CPU执行指针已指向ROM BIOS中地址0x000fffff0处的指令处。其中'&lt;bochs:1&gt;'是命令输入提示符，其中的数字表示当前的命令序列号。在命令提示符'&lt;bochs:1&gt;'后面键入'help'命令，可以列出调试系统的基本命令。若要了解某个命令的具体使用方法，可以键入'help'命令并且后面跟随一个用单引号括住的具体命令，例如：&#8220;help 'vbreak'&#8221;，如下面所示。</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">&lt;bochs:1&gt; help<br />help - show list of debugger commands<br />help 'command'- show short command description<br />-*- Debugger control -*-<br />&nbsp; &nbsp;help, q|quit|exit, set, instrument, show, trace-on, trace-off,<br />&nbsp; &nbsp;record, playback, load-symbols, slist<br />-*- Execution control -*-<br />&nbsp; &nbsp;c|cont, s|step|stepi, p|n|next, modebp<br />-*- Breakpoint management -*-<br />&nbsp; &nbsp;v|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist,<br />&nbsp; &nbsp;bpe, bpd, d|del|delete<br />-*- CPU and memory contents -*-<br />&nbsp; &nbsp;x, xp, u|disas|disassemble, r|reg|registers, setpmem, crc, info, dump_cpu,<br />&nbsp; &nbsp;set_cpu, ptime, print-stack, watch, unwatch, ?|calc<br />&lt;bochs:2&gt; help 'vbreak'<br />help vbreak<br />vbreak seg:off - set a virtual address instruction breakpoint<br />&lt;bochs:3&gt;</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">为了让Bochs直接模拟执行到Linux的引导启动程序开始处，我们可以先使用断点命令在0x7c00处设置一个断点，然后让系统连续运行到0x7c00处停下来。执行的命令序列如下：</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">&lt;bochs:3&gt;&nbsp;<span style="color: #ff0000;">vbreak 0x0000:0x7c00</span><br />&lt;bochs:4&gt;&nbsp;<span style="color: #ff0000;">c</span><br />(0) Breakpoint 1, 0x7c00 (0x0:0x7c00)<br />Next at t=4409138<br />(0) [0x00007c00] 0000:7c00 (unk. ctxt): mov ax, 0x7c0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; b8c007<br />&lt;bochs:5&gt;</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">此时，CPU执行到boot.s程序开始处的第1条指令处，Bochs主窗口将显示出&#8220;Boot From floppy...&#8221;等一些信息。现在，<span style="color: #ff0000;">我们可以利用单步执行命令's'或'n'</span>（<span style="color: #ff0000;">不跟踪进入子程序</span>）来跟踪调试程序了。在调试时可以使用Bochs的断点设置命令、反汇编命令、信息显示命令等来辅助我们的调试操作。下面是一些常用命令的示例：</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #ff0000;">&lt;bochs:8&gt; u /10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;"># 反汇编从当前地址开始的10条指令。</span><br />00007c00: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov ax, 0x7c0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; b8c007<br />00007c03: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov ds, ax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 8ed8<br />00007c05: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov ax, 0x9000 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; b80090<br />00007c08: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov es, ax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 8ec0<br />00007c0a: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov cx, 0x100 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; b90001<br />00007c0d: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): sub si, si &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 29f6<br />00007c0f: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): sub di, di &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 29ff<br />00007c11: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): rep movs word ptr [di], word ptr [si] ; f3a5<br />00007c13: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): jmp 9000:0018 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; ea18000090<br />00007c18: ( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;): mov ax, cs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 8cc8<br />&lt;bochs:9&gt;&nbsp;<span style="color: #ff0000;">info r &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 查看当前CPU寄存器的内容</span><br />eax &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xaa55 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 43605<br />ecx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x110001 &nbsp; &nbsp; &nbsp; &nbsp; 1114113<br />edx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />ebx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />esp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xfffe &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xfffe<br />ebp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0<br />esi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />edi &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xffe4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 65508<br />eip &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x7c00 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x7c00<br />eflags &nbsp; &nbsp; &nbsp; &nbsp; 0x282 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;642<br />cs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />ss &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />ds &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />es &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />fs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />gs &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br />&lt;bochs:10&gt;&nbsp;<span style="color: #ff0000;">print-stack &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 显示当前堆栈的内容</span><br />&nbsp; 0000fffe [0000fffe] &nbsp;0000<br />&nbsp; 00010000 [00010000] &nbsp;0000<br />&nbsp; 00010002 [00010002] &nbsp;0000<br />&nbsp; 00010004 [00010004] &nbsp;0000<br />&nbsp; 00010006 [00010006] &nbsp;0000<br />&nbsp; 00010008 [00010008] &nbsp;0000<br />&nbsp; 0001000a [0001000a] &nbsp;0000<br />...<br />&lt;bochs:11&gt;&nbsp;<span style="color: #ff0000;">dump_cpu &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # 显示CPU中的所有寄存器和状态值。</span><br />eax:0xaa55<br />ebx:0x0<br />ecx:0x110001<br />edx:0x0<br />ebp:0x0<br />esi:0x0<br />edi:0xffe4<br />esp:0xfffe<br />eflags:0x282<br />eip:0x7c00<br />cs:s=0x0, dl=0xffff, dh=0x9b00, valid=1<br />ss:s=0x0, dl=0xffff, dh=0x9300, valid=7<br />ds:s=0x0, dl=0xffff, dh=0x9300, valid=1<br />es:s=0x0, dl=0xffff, dh=0x9300, valid=1<br />fs:s=0x0, dl=0xffff, dh=0x9300, valid=1<br />gs:s=0x0, dl=0xffff, dh=0x9300, valid=1<br />ldtr:s=0x0, dl=0x0, dh=0x0, valid=0<br />tr:s=0x0, dl=0x0, dh=0x0, valid=0<br />gdtr:base=0x0, limit=0x0<br />idtr:base=0x0, limit=0x3ff<br />dr0:0x0<br />dr1:0x0<br />dr2:0x0<br />dr3:0x0<br />dr6:0xffff0ff0<br />dr7:0x400<br />tr3:0x0<br />tr4:0x0<br />tr5:0x0<br />tr6:0x0<br />tr7:0x0<br />cr0:0x60000010<br />cr1:0x0<br />cr2:0x0<br />cr3:0x0<br />cr4:0x0<br />inhibit_mask:0<br />done<br />&lt;bochs:12&gt;</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">由于Linux 0.11内核的32位代码是从绝对物理地址0处开始存放的，因此若想直接执行到32位代码开始处，即head.s程序开始处，我们可以在线性地址0x0000处设置一个断点并运行命令'c'执行到那个位置处。<br />另外，当直接在命令提示符下打回车键时会重复执行上一个命令；按向上方向键会显示上一命令。其他命令的使用方法请参考'help'命令。</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">14.8.2 定位内核中的变量或数据结构<br />在编译内核时会产生一个system.map文件。该文件列出了内核Image (bootimage)文件中全局变量和各个模块中的局部变量的偏移地址位置。在内核编译完成后可以使用前面介绍的文件导出方法把system.map文件抽取到主机环境（windows）中。有关system.map文件的详细功能和作用请参见2.10.3节。system.map样例文件中的部分内容见如下所示。利用这个文件，我们可以在Bochs调试系统中快速地定位某个变量或跳转到指定的函数代码处。</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">...<br />Global symbols:</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">&nbsp;_dup: 0x16e2c<br />&nbsp;_nmi: 0x8e08<br />&nbsp;_bmap: 0xc364<br />&nbsp;_iput: 0xc3b4<br />&nbsp;_blk_dev_init: 0x10ed0<br />&nbsp;_open: 0x16dbc<br />&nbsp;_do_execve: 0xe3d4<br />&nbsp;_con_init: 0x15ccc<br />&nbsp;_put_super: 0xd394<br />&nbsp;_sys_setgid: 0x9b54<br />&nbsp;_sys_umask: 0x9f54<br />&nbsp;_con_write: 0x14f64<br />&nbsp;_show_task: 0x6a54<br />&nbsp;_buffer_init: 0xd1ec<br />&nbsp;_sys_settimeofday: 0x9f4c<br />&nbsp;_sys_getgroups: 0x9edc<br />...</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">同样，由于Linux 0.11内核的32位代码是从绝对物理地址0处开始存放的，system.map中全局变量的偏移位置值就是CPU中线性地址位置，因此我们可以直接在感兴趣的变量或函数名位置处设置断点，并让程序连续执行到指定的位置处。例如若我们想调试函数buffer_init()，那么从system.map文件中可以知道它位于0xd1ec处。此时我们可以在该处设置一个线性地址断点，并执行命令'c'让CPU执行到这个指定的函数开始处，见如下所示。</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">&lt;bochs:12&gt;&nbsp;<span style="color: #ff0000;">lb 0xd1ec &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 设置线性地址断点。</span><br />&lt;bochs:13&gt;&nbsp;<span style="color: #ff0000;">c &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 连续执行。</span><br />(0) Breakpoint 2, 0xd1ec in ?? ()<br />Next at t=16689666<br />(0) [0x0000d1ec] 0008:0000d1ec (unk. ctxt): push ebx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; 53<br />&lt;bochs:14&gt;&nbsp;<span style="color: #ff0000;">n &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 执行下一指令。</span><br />Next at t=16689667<br />(0) [0x0000d1ed] 0008:0000d1ed (unk. ctxt): mov eax, dword ptr ss:[esp+0x8] ; 8b442408<br />&lt;bochs:15&gt; n &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 执行下一指令。<br />Next at t=16689668<br />(0) [0x0000d1f1] 0008:0000d1f1 (unk. ctxt): mov edx, dword ptr [ds:0x19958] ; 8b1558990100<br />&lt;bochs:16&gt;</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">程序调试是一种技能，需要多练习才能熟能生巧。上面介绍的一些基本命令需要组合在一起使用才能灵活地观察到内核代码执行的整体环境情况。</p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">Bochs使用简单教程&nbsp;</span><br /><span style="color: #0000ff;">Bochs是一个开源的虚拟机。它可以实现vpc和vmware的大部分功能。你也可以像使用vmware一样的在Bochs里面安装操作系统。但是，由于它是全模拟的。所以，速度要远远慢于vmware.这样看来Bochs好像没有什么优势.是这样吗？在应用方面的确如此。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">但是,在其他一个方面它是处于绝对优势的。那就是它具有调试功能!这是一个让人振奋的功能。这个功能在你调试操作系统或者其他一些在裸机上运行的程序时候，会让你有一种在写windows下运行的应用程序的感觉。有时候它是我们的救命稻草。没了它，也能活，但是肯定要糟糕的多。好了我们开始切入正题。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">一、 配置Bochs&nbsp;</span><br /><span style="color: #0000ff;">实际上配置Bochs是很简单的，为什么很多人不会配置呢？我觉的就是因为他使用和配置方式和普通程序不一样&#8212;&#8212;配置文件。实际上配置文件是和ini文件、bat文件类似的。Bochs没有给我们提供图形界面的配置工具。这就需要我们自己来修改配置文件。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">简单的配置就可以让你的操作系统在Bochs里面跑起来。用Bochs跑完整的linux和windows是不现实的。实在是太慢了。一般我们也只能把他当成调试器来使用。现在，我们先看一下如何让dos在他里面跑起来。如果你细心的话你会发现在Bochs文件夹里面有一个Bochsrc-sample.txt的文本文件。里面包含了所有了Bochs参数的信息。这个是官方的教程。可惜是英文的，而且我也没有找到有中文的教程（不然也没有我这篇文章）。在这里我们仅仅介绍最简单的配置选项。好了，废话就不多说了。我们现在就开始。&nbsp;</span><br /><span style="color: #0000ff;">我们以一个例子来说明，这个例子是我用来跑dos以及我自己的小操作系统的。下面就是我们要用到的最基本的选项：&nbsp;</span><br /><span style="color: #0000ff;"># 在一行的最前面加上&#8220;#&#8221;表示这一行是注释行。&nbsp;</span><br /><span style="color: #0000ff;"># 内存，以MB为单位，对于dos来说最大可以访问16MB&nbsp;</span><br /><span style="color: #0000ff;"># 的内存，所以我就给了他16MB，你可以根据自己的机器来调整&nbsp;</span><br /><span style="color: #0000ff;">megs: 16&nbsp;</span><br /><span style="color: #0000ff;"># 下面两句一般是不可以改的，至于干什么用的就不用我说&nbsp;</span><br /><span style="color: #0000ff;"># 了。从他们的文件名就可以看出来。&nbsp;</span><br /><span style="color: #0000ff;">romimage: file=../BIOS-Bochs-latest, address=0xf0000&nbsp;</span><br /><span style="color: #0000ff;">vgaromimage: file=../VGABIOS-lgpl-latest&nbsp;</span><br /><span style="color: #0000ff;"># 这个还用说吗？当然是软驱了，我想我们写操作系统肯定是先&nbsp;</span><br /><span style="color: #0000ff;"># 把操作系统放在软盘（或映像）里面吧？在Bochs里面是可&nbsp;</span><br /><span style="color: #0000ff;"># 以使用任意大小的软驱映像的。可以是1.44或2.88，我一般使&nbsp;</span><br /><span style="color: #0000ff;"># 用2.88。还有就是Bochs里面可以使用两个软驱。不过好像&nbsp;</span><br /><span style="color: #0000ff;"># 我们并不经常这样做。&nbsp;</span><br /><span style="color: #0000ff;">floppya: 2_88=test.img, status=inserted&nbsp;</span><br /><span style="color: #0000ff;">#floppyb: 1_44=floppyb.img, status=inserted&nbsp;</span><br /><span style="color: #0000ff;"># 下面是硬盘，很简单，还有就是Bochs也是可以支持多个硬&nbsp;</span><br /><span style="color: #0000ff;"># 盘的。那么，硬盘文件是怎么生成的呢？我们可以发现硬盘是&nbsp;</span><br /><span style="color: #0000ff;"># img格式的。你注意没有在Bochs文件夹里有一个工具叫&nbsp;</span><br /><span style="color: #0000ff;"># bximage.exe，我想你应该猜出来了。他就是用来生成这个硬盘&nbsp;</span><br /><span style="color: #0000ff;"># 文件的工具。我在这儿还想说的是硬盘分三种格式的，最好选&nbsp;</span><br /><span style="color: #0000ff;">#用growing类型。这种有一个好处就是节省硬盘空间，不过使用&nbsp;</span><br /><span style="color: #0000ff;">#这种类型的硬盘还需要在下面加上mode = growing这个选项。&nbsp;</span><br /><span style="color: #0000ff;">ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14&nbsp;</span><br /><span style="color: #0000ff;">ata0-master: type=disk, path="dos.img", cylinders=306, heads=4, spt=17&nbsp;</span><br /><span style="color: #0000ff;"># 下面这个就是光驱，没什么好说的。如果你想使用物理光驱，&nbsp;</span><br /><span style="color: #0000ff;"># 只要让path=E:（我们假设E盘是光驱）&nbsp;</span><br /><span style="color: #0000ff;">ata0-slave: type=cdrom, path="dos.iso", status=inserted&nbsp;</span><br /><span style="color: #0000ff;"># 这个是启动设备，可以使用cdrom（光驱）、c（硬盘）或floppy（软&nbsp;</span><br /><span style="color: #0000ff;"># 驱）。&nbsp;</span><br /><span style="color: #0000ff;">#boot: cdrom&nbsp;</span><br /><span style="color: #0000ff;">boot: c&nbsp;</span><br /><span style="color: #0000ff;">#boot: floppy&nbsp;</span><br /><span style="color: #0000ff;"># 这一句可以不要，他只是指定用来保存日志的文件。如果不指定的&nbsp;</span><br /><span style="color: #0000ff;"># 话他就会输出到命令控制台上。&nbsp;</span><br /><span style="color: #0000ff;">log: Bochsout.txt&nbsp;</span><br /><span style="color: #0000ff;"># 这一句是设置在开机时是否激活鼠标，Bochs对于鼠标的控制不是# 很好。建议如果不是特别需要的话不要激活他。在运行期间也可以点窗口右上角的鼠标图标来激活他。&nbsp;</span><br /><span style="color: #0000ff;">mouse: enabled=0&nbsp;</span><br /><span style="color: #0000ff;">以上这些设置就可以让你的DOS或自己的小操作系统在Bochs里面跑起来了。至于其他的一些高级支持，你可以查看Bochsrc-sample.txt里面的说明。不要害怕他，其实很简单。关键是抛弃恐惧。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">二、 启动Bochs&nbsp;</span><br /><span style="color: #0000ff;">配置文件已经写好了，硬盘文件等也都已经弄好了。那么我们如何来启动Bochs呢？很简单，你右击一下上面写的那个配置文件（例如myos.bxrc，注意：扩展名要是.bxrc。）选择&#8220;运行&#8221;或双击即可。不过我一般都不这样做，我一般是写一个批处理文件。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">很简单，如下所示：&nbsp;</span><br /><span style="color: #0000ff;">cd "d:\Bochs-2.2.1\dos"&nbsp;</span><br /><span style="color: #0000ff;">..\Bochs.exe -q -f Bochsrc.bxrc&nbsp;</span><br /><span style="color: #0000ff;">这样做的好处就是无论这个启动脚本放在哪儿都是可以使用的。那么，我们如何进入调试状态呢？下面我们就来讨论这个问题。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">三、 调试功能&nbsp;</span><br /><span style="color: #0000ff;">新建一个批处理文件，写入一下内容：&nbsp;</span><br /><span style="color: #0000ff;">cd "d:\Bochs-2.2.1\dos"&nbsp;</span><br /><span style="color: #0000ff;">..\Bochsdbg.exe -q -f Bochsrc.bxrc&nbsp;</span><br /><span style="color: #0000ff;">运行这个批处理文件，你就可以进入调试状态了。不过你会发现，程序卡住了。没有想普通运行状态一样进入你的dos操作系统。为什么？因为调试在等待你的命令。你只有给他一个命令他才会继续。我们输入&#8220;c&#8221;，然后回车。是不是dos已经可是运行了？</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">如果没有运行说明你输入的窗口不对，你不会把c输入到那个没有光标的窗口了吧？如果真是那样我真是服了你了。真的！但是，dos运行起来了，如何在返回调试状态？很简单，按ctrl+c。什么你正在运行的程序被结束了？谁让你在操作系统窗口中按了，我是说在调试窗口按。至于哪个是调试窗口，哪个是操作系统窗口，我就不说了。如果你不知道你就干脆别使用Bochs了，也不要写什么程序了，更不要开发什么操作系统了。为什么？因为你不可能成功。从这儿就可以看出来。最好是找块豆腐撞死，这样你会很幸福的死去，不然你就会成为教育后代的典范&#8212;&#8212;看到了吗XXX是怎么死的，笨死的。呵呵！开个玩笑。你真要不知道&nbsp;</span><br /><span style="color: #0000ff;">千万不要来找我，找我我也不告诉你。不好意思，我也不知道。那么，在调试状态下我们可以干哪些事呢？你用过debug吗？它能做的Bochs都能做，它不能做的Bochs也可以做。下面就是一些常用的调试命令。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">help</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">我最想告诉大家的是这个指令，因为他可以告诉我们一切。古语说：&#8220;授之以鱼，不若授之以渔&#8221;。我觉的很有道理。但是，有些人就是不想学这种一劳永逸的方法。所以，我还要继续写下去。&nbsp;</span><br /><span style="color: #0000ff;">输入help，回车。你会得到以下信息：&nbsp;</span><br /><span style="color: #0000ff;">help - show list of debugger commands&nbsp;</span><br /><span style="color: #0000ff;">help 'command'- show short command description&nbsp;</span><br /><span style="color: #0000ff;">-*- Debugger control -*-&nbsp;</span><br /><span style="color: #0000ff;">help, q|quit|exit, set, instrument, show, trace-on, trace-off,&nbsp;</span><br /><span style="color: #0000ff;">record, playback, load-symbols, slist&nbsp;</span><br /><span style="color: #0000ff;">-*- Execution control -*-&nbsp;</span><br /><span style="color: #0000ff;">c|cont, s|step|stepi, p|n|next, modebp&nbsp;</span><br /><span style="color: #0000ff;">-*- Breakpoint management -*-&nbsp;</span><br /><span style="color: #0000ff;">vb|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist,&nbsp;</span><br /><span style="color: #0000ff;">bpe, bpd, d|del|delete&nbsp;</span><br /><span style="color: #0000ff;">-*- CPU and memory contents -*-&nbsp;</span><br /><span style="color: #0000ff;">x, xp, u|disas|disassemble, r|reg|registers, setpmem, crc, info, dump_cpu,&nbsp;</span><br /><span style="color: #0000ff;">set_cpu, ptime, print-stack, watch, unwatch, ?|calc&nbsp;</span><br /><span style="color: #0000ff;">需不需要我翻译一下前两句？那好吧。&nbsp;</span><br /><span style="color: #0000ff;">help － 现实调试命令列表&nbsp;</span><br /><span style="color: #0000ff;">help '命令' － 显示某条命令的详细用法。&nbsp;</span><br /><span style="color: #0000ff;">命令分为哪些？很明显，四类：调试控制，运行控制，断点管理，CPU和内存控制。我不想在这儿一一介绍了。没有必要，我只介绍一下最常用的就可以了。&nbsp;</span><br /><span style="color: #0000ff;">c：继续，前面我们已经用过了。&nbsp;</span><br /><span style="color: #0000ff;">s：单步执行。他还有一个扩展用法。&nbsp;</span><br /><span style="color: #0000ff;">s n ：执行n步。&nbsp;</span><br /><span style="color: #0000ff;">b 0x7c00：在内存0x7c00处设置一个断点.当程序执行到0x7c00处就自动进入到调试状态.后面的这个数指的是内存的线性地址</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">。也可以使用10进制的数，但是好像没有人会这样做。&nbsp;</span><br /><span style="color: #0000ff;">x /20 0x7c00: 以16进制的形式从内存的0x7c00开始显示20个字的数据。这个是很常用的命令，但是需要注意的是他的显示顺序和16进制编辑器中的显示顺序有一点小的区别。他的显示是以字为单位的，而且在字中是从低到高显示的.不过也没有什么大不了的。你只要稍微注意一下就可以了。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">dump_cpu：这个是我最长用的三个指令之一。他的功能是显示现在的寄存器的状态，详细内容类似于：&nbsp;</span><br /><span style="color: #0000ff;">eax:0x00000000, ebx:0x00000000, ecx:0x00000000, edx:0x00000683&nbsp;</span><br /><span style="color: #0000ff;">ebp:0x00000000, esp:0x00000000, esi:0x00000000, edi:0x00000000&nbsp;</span><br /><span style="color: #0000ff;">eip:0x0000fff0, eflags:0x00000002, inhibit_mask:0&nbsp;</span><br /><span style="color: #0000ff;">cs:s=0xf000, dl=0x0000ffff, dh=0xff009bff, valid=1&nbsp;</span><br /><span style="color: #0000ff;">ss:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1&nbsp;</span><br /><span style="color: #0000ff;">ds:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1&nbsp;</span><br /><span style="color: #0000ff;">es:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1&nbsp;</span><br /><span style="color: #0000ff;">fs:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1&nbsp;</span><br /><span style="color: #0000ff;">gs:s=0x0000, dl=0x0000ffff, dh=0x00009300, valid=1&nbsp;</span><br /><span style="color: #0000ff;">ldtr:s=0x0000, dl=0x00000000, dh=0x00000000, valid=0&nbsp;</span><br /><span style="color: #0000ff;">tr:s=0x0000, dl=0x00000000, dh=0x00000000, valid=0&nbsp;</span><br /><span style="color: #0000ff;">gdtr:base=0x00000000, limit=0xffff&nbsp;</span><br /><span style="color: #0000ff;">idtr:base=0x00000000, limit=0xffff&nbsp;</span><br /><span style="color: #0000ff;">dr0:0x00000000, dr1:0x00000000, dr2:0x00000000&nbsp;</span><br /><span style="color: #0000ff;">dr3:0x00000000, dr6:0xffff0ff0, dr7:0x00000400&nbsp;</span><br /><span style="color: #0000ff;">cr0:0x00000010, cr1:0x00000000, cr2:0x00000000&nbsp;</span><br /><span style="color: #0000ff;">cr3:0x00000000, cr4:0x00000000&nbsp;</span><br /><span style="color: #0000ff;">u /20 0x7c00 :反汇编内存0x7c00处，反汇编的长度是20。你想不想知道dos的引导程序是什么样子的？执行一下这个命令就可以了。你还可以使用这样的命令 u /20 cs:0x120a，至于什么意思，我也不说了。</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="color: #0000ff;">现在，我们已经介绍了6条命令了。够了。对于日常应用已经完全够用了。如果你想了解其他命令的用法只要执行一下help &#8220;命令名&#8221;就可以了（注意，命令上要带有引号）。好了。现在已经把Bochs的基本功能介绍完了。你是不是感觉Bochs很简单？对于简单的应用来说，确实如此。但是，想让他支持一些高级功能就有点麻烦了。毕竟它是全模拟的虚拟机，所以在有些方面实现起来并不容易。但是，向网络之类的功能还是可以支持的。你只要看一下Bochsrc-sample.txt就知道了。我在这儿就不说了。我还要说的是Bochs不仅仅可以调试操作系统，还可以调试dos下的程序。我们知道dos没有多少好的调试器。那么我们完全可以使用Bochs来调试。你知道在程序的开头输出一下程序的段地址和偏移地址，然后暂定一下，在虚拟机里面设置一下断点就可以了。我一般都是在在程序里面潜入一句汇编：&nbsp;</span><br /><span style="color: #0000ff;">jmp $&nbsp;</span><br /><span style="color: #0000ff;">这样在程序死循环的时候在调试窗口按下ctrl+c就可以看到他的段地址和偏移地址了。然后，在去掉这一句，设置一下断点，运行这个程序。是不是在指定位置中断了？</span></p><p style="margin: 10px auto; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;"><span style="font-family: 宋体;"><span style="font-size: x-small;">一：配置<br /></span><span style="line-height: 1.3em;">bochs.exe是执行模式，不能调试的。<span style="line-height: 1.3em; font-size: x-small;">Bochs的调试工具是Bochsdbg.exe。同样，调试的时候你仍然需要进行配置。此时如果我们还使用双击.bxrc配置文件的方法显然是不行的（因为此时会运行Bochs.exe而不是Bochsdbg.exe）。所以我copy了《自己动手写操作系统》作者于渊的方法&#8212;&#8212;使用bat批处理文件。</span></span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">新建一个批处理文件然后进行编辑。以下内容为我的bat文件：</span></span><br /><span style="text-decoration: underline;"><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">D:\Develop\Bochs-2.2.1\bochsdbg.exe&nbsp;-q&nbsp;-f&nbsp;config.bxrc</span></span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">显然，首先要指定调试程序的位置，后面&nbsp;&#8211;q&nbsp;&#8211;f表示退出配置选择文件配置，后面的config.bxrc就是刚才运行Bochs所使用的配置文件。下面重点看看如何进行调试。</span></span><br /><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">二：调试</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">感觉Bochs的调试和DOS提供的Debug很相似&#8212;&#8212;毕竟都是命令行式的调试。如果有一个像TurboDebugger这样的可视化调试工具就好了。（这段文章也是我从网上copy下来的，最后总结为表格的形式，以方便以后查阅）</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">说明：下面的&#8220;[]&#8221;表示可有可无的参数在写的时候不要写。</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><strong><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">执行控制命令</span></span></strong><br /><span style="line-height: 1.3em; font-family: 宋体;">Help&nbsp;帮助命令，以下的命令都可以通过help命令查到。</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">c&nbsp;继续执行，遇到断点将停止</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">stepi&nbsp;[count]&nbsp;执行count条指令,&nbsp;默认为1条</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">si&nbsp;[count]&nbsp;stepi的缩写</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">step&nbsp;[count]&nbsp;执行count条指令,&nbsp;默认为1条</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">s&nbsp;[count]&nbsp;step的缩写</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">Ctrl-C&nbsp;停止执行，返回命令行</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">Ctrl-D&nbsp;执行完所有命令后，退出</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">quit&nbsp;退出调试器</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">q&nbsp;quit缩写</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><strong><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">设置断点</span></span></strong><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">vbreak&nbsp;seg:off&nbsp;在指定的虚拟地址（段+偏移）设置断点，在保护模式下也可以使用</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">vb&nbsp;seg:off</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">lbreak&nbsp;addr&nbsp;在一个线性地址设置断点</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">lb&nbsp;addr</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">pbreak&nbsp;[*]&nbsp;addr&nbsp;在一个物理地址设置断点</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">pb&nbsp;[*]&nbsp;addr&nbsp;</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">break&nbsp;[*]&nbsp;addr</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">b&nbsp;[*]&nbsp;addr</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;break&nbsp;显示所有断点状态</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">例如：</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">--------------------------------------</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">Num&nbsp;Type&nbsp;Disp&nbsp;Enb&nbsp;Address</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">1&nbsp;pbreakpoint&nbsp;keep&nbsp;y&nbsp;0x00007c00</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">表示在物理地址0x00007c00设置一个断点，该断点目前有效</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">---------------------------------------</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">delete&nbsp;n&nbsp;删除一个断点</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">del&nbsp;n</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">d&nbsp;n</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">关于物理地址，线性地址和虚拟地址的区别，我只能凭我的理解简单说说，可能不准确。物理地址在什么时候都存在，但是在采用分页技术和虚拟内存技术后，你很难确定物理地址在那里，所以建议在实模式下采用物理地址和线性地址形式，这时候物理地址和线性地址其实是一致的。最常用的，比方说，计算机启动后的地址是0xfff0:0000，装载BIOS，然后转移到0x07C0:0000，所以总可以设置一个物理断点0x7C00，开始调试你的bootloader。</span></span><br /><strong><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">查看内存</span></span></strong><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">x&nbsp;/nuf&nbsp;addr&nbsp;查看一个线性地址的内存</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">xp&nbsp;/nuf&nbsp;addr&nbsp;查看一个物理地址的内存</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">n&nbsp;显示多少个单位的内存</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">u&nbsp;内存单位大小，可以是</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">b&nbsp;字节</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">h&nbsp;字（2个字节）</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">w&nbsp;双字（4个字节）</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">g&nbsp;4字(8字节)</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">注意:&nbsp;它们不太符合Intel字节命名格式，但是遵守GDB约定。</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">f&nbsp;打印格式，可以是</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">x&nbsp;16进制格式打印</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">d&nbsp;10进制格式打印</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">u&nbsp;无符号10进制格式打印</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">o&nbsp;8进制格式打印</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">t&nbsp;2进制格式打印</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">n，f，和u是可选参数。U和f默认为你最后使用的参数,&nbsp;如果是第一次使用，u默认为w，f默认为x，&nbsp;n默认为1。如果没有指定nuf，那么/也可以不要。setpmem&nbsp;addr&nbsp;datasize&nbsp;val&nbsp;设置物理地址addr，大小datasize的内存单元的值为val.</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">crc&nbsp;addr1&nbsp;addr2&nbsp;对物理地址范围addr1到addr2进行CRC校验？（没用过）info&nbsp;dirty&nbsp;显示写过的页？（没用过）</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><strong><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">Info</span></span></strong><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;program&nbsp;查看程序的执行状态</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;registers&nbsp;列举CPU整型寄存器遗迹它们的内容</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;break&nbsp;显示当前断点信息</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">where&nbsp;打印当前call&nbsp;stack</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><strong><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">寄存器操作</span></span></strong><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">set&nbsp;$reg&nbsp;=&nbsp;val&nbsp;改变寄存器的内容。可改变的寄存器有:</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">eax,&nbsp;ecx,&nbsp;edx,&nbsp;ebx,&nbsp;esp,&nbsp;ebp,&nbsp;esi,&nbsp;edi.</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">不可改变的寄存器有：</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">eflags,&nbsp;cs,&nbsp;ss,&nbsp;ds,&nbsp;es,&nbsp;fs,&nbsp;gs.</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">例如&nbsp;set&nbsp;$eax&nbsp;=&nbsp;0x01234567</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">set&nbsp;$edx&nbsp;=&nbsp;25</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;">&nbsp;</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;registers&nbsp;显示寄存器内容</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">dump_cpu&nbsp;查看所有与CPU相关的寄存器状态</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">set_cpu&nbsp;设置所有与CPU相关的寄存器状态</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">dump_cpu和set_cpu格式如下：</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"eax:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ebx:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ecx:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"edx:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ebp:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"esi:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"edi:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"esp:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"eflags:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"eip:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cs:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ss:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ds:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"es:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"fs:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"gs:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"ldtr:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr:s=0x%x,&nbsp;dl=0x%x,&nbsp;dh=0x%x,&nbsp;valid=%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"gdtr:base=0x%x,&nbsp;limit=0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"idtr:base=0x%x,&nbsp;limit=0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr0:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr1:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr2:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr3:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr4:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr5:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr6:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"dr7:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr3:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr4:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr5:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr6:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"tr7:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cr0:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cr1:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cr2:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cr3:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"cr4:0x%x\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"inhibit_int:%u\n"</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">"done\n"</span></span><br /><strong><br /><br />命令<br />说明<br />断<br />点<br />相<br />关<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">vb&nbsp;seg:off&nbsp;&nbsp;vbreak</span></span><br />在指定的虚拟地址（段<span style="line-height: 1.3em; font-family: 宋体;">+偏移）设置断点，在保护模式下也可以使用</span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">lb&nbsp;addr&nbsp;&nbsp;&nbsp;lbreak</span></span><br />在一个线性地址设置断点<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">Pb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pbreak</span></span><br />在一个物理地址设置断点<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;break</span></span><br />显示所有断点状态<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">del&nbsp;n&nbsp;&nbsp;delete&nbsp;n&nbsp;&nbsp;&nbsp;d&nbsp;n</span></span><br />删除一个断点<br />步<br />进<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">C</span></span><br />继续执行，遇到断点将停止<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">step&nbsp;[count]</span></span><br />执行<span style="line-height: 1.3em; font-family: 宋体;">count条指令,&nbsp;默认为1条</span><br />内<br />存<br />&nbsp;<br />寄<br />存<br />器<br />&nbsp;<br />查<br />看<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">x&nbsp;/nuf&nbsp;addr</span></span><br />查看一个线性地址的内存<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;"><strong>n&nbsp;</strong><strong>显示多少个单位的内存</strong></span></span><strong><br /><span style="line-height: 1.3em; font-family: 宋体; font-size: x-small;">u&nbsp;</span></strong><span style="line-height: 1.3em; font-size: x-small;"><strong>内存单位大小：</strong></span><br /><span style="line-height: 1.3em; font-size: x-small;">可以是，<span style="line-height: 1.3em; font-family: 宋体;">b字节，h字，w&nbsp;双字，g&nbsp;4字</span></span><br /><strong><span style="line-height: 1.3em; font-family: 宋体; font-size: x-small;">f&nbsp;</span></strong><span style="line-height: 1.3em; font-size: x-small;"><strong>打印格式：</strong></span><br /><span style="line-height: 1.3em; font-size: x-small;">可以是：<span style="line-height: 1.3em; font-family: 宋体;">16进制，d&nbsp;10进制，u&nbsp;无符号10进制，o&nbsp;8进制，t&nbsp;2进制</span></span><br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">xp&nbsp;/nuf&nbsp;addr</span></span><br />查看一个物理地址的内存<br /><span style="line-height: 1.3em; font-family: 宋体;"><span style="line-height: 1.3em; font-size: x-small;">info&nbsp;registers</span></span><br />列举<span style="line-height: 1.3em; font-family: 宋体;">CPU整型寄存器遗迹它们的内容</span><br />&nbsp;<br /><span style="line-height: 1.3em; font-size: x-small;"><strong>反汇编</strong></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 1.3em; font-size: x-small;">disassemble&nbsp;start&nbsp;end&nbsp;反汇编的地址范围<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;$disassemble_size&nbsp;=&nbsp;n&nbsp;告诉调试器，反汇编段的属性（16位或32位，默认32位）。</span><br />---http://blog.chinaunix.net/u/15262/showart_411540.html</strong></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/90485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2016-09-20 17:23 <a href="http://www.cnitblog.com/yuhensong/archive/2016/09/20/90485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux下如何查看多核负载情况</title><link>http://www.cnitblog.com/yuhensong/archive/2016/06/22/90457.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Wed, 22 Jun 2016 02:39:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2016/06/22/90457.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/90457.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2016/06/22/90457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/90457.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/90457.html</trackback:ping><description><![CDATA[<p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">首先声明出处：sam的技术blog<a href="http://blog.sina.com.cn/samzhen1977" style="color: #ca0000;">http://blog.sina.com.cn/samzhen1977</a></p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">1. Linux下，如何看每个CPU的使用率：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">#top -d 1</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">（此时会显示以1s的频率刷新系统负载显示，可以看到总的CPU的负载情况，以及占CPU最高的进程id，进程名字等信息）</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">（切换按下数字1，则可以在显示多个CPU和总CPU中切换）</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">之后按下数字1. 则显示多个CPU&nbsp;&nbsp; （top后按1也一样）</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">Cpu0&nbsp; :&nbsp; 1.0%us,&nbsp; 3.0%sy,&nbsp; 0.0%ni, 96.0%id,&nbsp; 0.0%wa,&nbsp; 0.0%hi,&nbsp; 0.0%si,&nbsp; 0.0%st<br />Cpu1&nbsp; :&nbsp; 0.0%us,&nbsp; 0.0%sy,&nbsp; 0.0%ni,100.0%id,&nbsp; 0.0%wa,&nbsp; 0.0%hi,&nbsp; 0.0%si,&nbsp; 0.0%st</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;这里对us,sy,ni,id,wa,hi,si,st进行分别说明：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">us 列显示了用户模式下所花费 CPU 时间的百分比。us的值比较高时，说明用户进程消耗的cpu时间多，但是如果长期大于50%，需要考虑优化用户的程序。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">sy 列显示了内核进程所花费的cpu时间的百分比。这里us + sy的参考值为80%，如果us+sy 大于 80%说明可能存在CPU不足。<br />ni&nbsp; 列显示了用户进程空间内改变过优先级的进程占用CPU百分比。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">id&nbsp; 列显示了cpu处在空闲状态的时间百分比。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">wa 列显示了IO等待所占用的CPU时间的百分比。这里wa的参考值为30%，如果wa超过30%，说明IO等待严重，这可能是磁盘大量随机访问造成的，也可能磁盘或者磁盘访问控制器的带宽瓶颈造成的(主要是块操作)。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">hi</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">si</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">st</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">2. 在Linux下，如何确认是多核或多CPU:</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">#cat /proc/cpuinfo</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">如果有多个类似以下的项目，则为多核或多CPU:</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">processor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 0</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">......</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">processor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 1</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">3. 如何察看某个进程在哪个CPU上运行：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">#top -d 1</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">之后按下f.进入top Current Fields设置页面：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">选中：j: P&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = Last used cpu (SMP)</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">则多了一项：P 显示此进程使用哪个CPU。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">Sam经过试验发现：同一个进程，在不同时刻，会使用不同CPU Core.这应该是Linux Kernel SMP处理的。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">4. 配置Linux Kernel使之支持多Core：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">内核配置期间必须启用 CONFIG_SMP 选项，以使内核感知 SMP。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">Processor type and features&nbsp; ---&gt; Symmetric multi-processing support</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">察看当前Linux Kernel是否支持（或者使用）SMP</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">#uname -a</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">5. Kernel 2.6的SMP负载平衡：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">在 SMP 系统中创建任务时，这些任务都被放到一个给定的 CPU 运行队列中。通常来说，我们无法知道一个任务何时是短期存在的，何时需要长期运行。因此，最初任务到 CPU 的分配可能并不理想。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">为了在 CPU 之间维护任务负载的均衡，任务可以重新进行分发：将任务从负载重的 CPU 上移动到负载轻的 CPU 上。Linux 2.6 版本的调度器使用负载均衡（load balancing） 提供了这种功能。每隔 200ms，处理器都会检查 CPU 的负载是否不均衡；如果不均衡，处理器就会在 CPU 之间进行一次任务均衡操作。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">这个过程的一点负面影响是新 CPU 的缓存对于迁移过来的任务来说是冷的（需要将数据读入缓存中）。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">记住 CPU 缓存是一个本地（片上）内存，提供了比系统内存更快的访问能力。如果一个任务是在某个 CPU 上执行的，与这个任务有关的数据都会被放到这个 CPU 的本地缓存中，这就称为热的。如果对于某个任务来说，CPU 的本地缓存中没有任何数据，那么这个缓存就称为冷的。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">不幸的是，保持 CPU 繁忙会出现 CPU 缓存对于迁移过来的任务为冷的情况。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">6. 应用程序如何利用多Core :</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">开发人员可将可并行的代码写入线程，而这些线程会被SMP操作系统安排并发运行。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">另外，Sam设想，对于必须顺序执行的代码。可以将其分为多个节点，每个节点为一个thread.并在节点间放置channel.节点间形如流水线。这样也可以大大增强CPU利用率。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">例如：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">游戏可以分为3个节点。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">1.接受外部信息，声称数据 （1ms）</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">2.利用数据，物理运算（3ms）</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">3.将物理运算的结果展示出来。(2ms)</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">如果线性编程，整个流程需要6ms.</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">但如果将每个节点作为一个thread。但thread间又同步执行。则整个流程只需要3ms.</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/90457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2016-06-22 10:39 <a href="http://www.cnitblog.com/yuhensong/archive/2016/06/22/90457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gdb break 断点设置（一）</title><link>http://www.cnitblog.com/yuhensong/archive/2014/12/12/89891.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 12 Dec 2014 09:40:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/12/12/89891.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89891.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/12/12/89891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89891.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89891.html</trackback:ping><description><![CDATA[<p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">断点设置</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">gdb断点分类：</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">以设置断点的命令分类：</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">breakpoint</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">可以根据行号、函数、条件生成断点。</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;"><dfn>watchpoint</dfn></p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;"><dfn>监测变量或者表达式的值发生变化时产生断点。</dfn></p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">catchpoint</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">监测信号的产生。例如c++的throw，或者加载库的时候。</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">gdb中的变量从1开始标号，不同的断点采用变量标号同一管理，可以 用enable、disable等命令管理，同时支持断点范围的操作，比如有些命令接受断点范围作为参数。</p><p dir="ltr" style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">例如：disable 5-8</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">1、break及break变种详解：</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">相关命令有break，tbreak，rbreak,hbreak，thbreak，后两种是基于硬件的，先不介绍。</p><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&gt;&gt;break 与 tbeak</p><blockquote dir="ltr" style="font-family: Arial; font-size: 14px; line-height: 26px; margin-right: 0px;"><p style="padding-top: 0px; padding-bottom: 0px;">break，tbreak可以根据行号、函数、条件生成断点。tbreak设置方法与break相同，只不过tbreak只在断点停一次，过后会自动将断点删除，break需要手动控制断点的删除和使能。</p><p style="padding-top: 0px; padding-bottom: 0px;">break 可带如下参数：</p><p style="padding-top: 0px; padding-bottom: 0px;">linenum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本地行号，即list命令可见的行号</p><p style="padding-top: 0px; padding-bottom: 0px;">filename:linenum&nbsp; 制定个文件的行号</p><p style="padding-top: 0px; padding-bottom: 0px;">function&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 函数，可以是自定义函数也可是库函数，如open</p><p style="padding-top: 0px; padding-bottom: 0px;">filename:function&nbsp; 制定文件中的函数</p><p style="padding-top: 0px; padding-bottom: 0px;">condtion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 条件</p><p style="padding-top: 0px; padding-bottom: 0px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px;">*address&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 地址，可是函数，变量的地址，此地址可以通过info add命令得到。</p><p style="padding-top: 0px; padding-bottom: 0px;">例如：</p><p style="padding-top: 0px; padding-bottom: 0px;">break 10&nbsp;&nbsp;&nbsp;&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px;">break test.c:10</p><p style="padding-top: 0px; padding-bottom: 0px;">break main</p><p style="padding-top: 0px; padding-bottom: 0px;">break test.c:main</p><p style="padding-top: 0px; padding-bottom: 0px;">break system</p><p style="padding-top: 0px; padding-bottom: 0px;">break open</p><p style="padding-top: 0px; padding-bottom: 0px;">如果想在指定的地址设置断点，比如在main函数的地址出设断点。</p><p style="padding-top: 0px; padding-bottom: 0px;">可用info add main 获得main的地址如0x80484624，然后用break *0x80484624.</p><p style="padding-top: 0px; padding-bottom: 0px;">条件断点就是在如上述指定断点的同时指定进入断点的条件。</p><p style="padding-top: 0px; padding-bottom: 0px;">例如：（假如有int 类型变量 index）</p><p style="padding-top: 0px; padding-bottom: 0px;">break 10 if index == 3</p><p style="padding-top: 0px; padding-bottom: 0px;">tbreak 12 if index == 5</p></blockquote><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&gt;&gt;rbreak</p><blockquote dir="ltr" style="font-family: Arial; font-size: 14px; line-height: 26px; margin-right: 0px;"><p style="padding-top: 0px; padding-bottom: 0px;">rbreak 可以跟一个规则表达式。rbreak + 表达式的用法与grep + 表达式相似。即在所有与表达式匹配的函数入口都设置断点。</p><p style="padding-top: 0px; padding-bottom: 0px;">&nbsp;</p><p style="padding-top: 0px; padding-bottom: 0px;">rbreak list_* 即在所有以 list_ 为开头字符的函数地方都设置断点。</p><p style="padding-top: 0px; padding-bottom: 0px;">rbreak ^list_ 功能与上同。</p></blockquote><p style="padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14px; line-height: 26px;">&gt;&gt;查看断点信息</p><blockquote dir="ltr" style="font-family: Arial; font-size: 14px; line-height: 26px; margin-right: 0px;"><p style="padding-top: 0px; padding-bottom: 0px;">info break [break num ]</p><p style="padding-top: 0px; padding-bottom: 0px;">info break 可列出所有断点信息，info break 后也可设置要查看的break num如：</p><p style="padding-top: 0px; padding-bottom: 0px;">info break 1 列出断点号是1的断点信息</p></blockquote><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp; Num&nbsp;&nbsp;&nbsp;&nbsp; Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Disp Enb&nbsp; Address&nbsp;&nbsp;&nbsp; What</pre><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; breakpoint&nbsp;&nbsp;&nbsp;&nbsp; keep y&nbsp;&nbsp;&nbsp; &lt;MULTIPLE&gt;</pre><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stop only if i==1</pre><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; breakpoint already hit 1 time</pre><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y&nbsp;&nbsp;&nbsp; 0x080486a2 in void foo&lt;int&gt;() at t.cc:8</pre><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp; 1.2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y&nbsp;&nbsp;&nbsp; 0x080486ca in void foo&lt;double&gt;() at t.cc:8</pre><img src ="http://www.cnitblog.com/yuhensong/aggbug/89891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-12-12 17:40 <a href="http://www.cnitblog.com/yuhensong/archive/2014/12/12/89891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ubuntu下玩转EDKII+OVMF</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/25/89779.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 25 Sep 2014 06:18:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/25/89779.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89779.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/25/89779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89779.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89779.html</trackback:ping><description><![CDATA[<p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">[原文地址：<a rel="nofollow" href="https://wiki.ubuntu.com/UEFI-howto" style="color: #e75263;">https://wiki.ubuntu.com/UEFI-howto</a>]</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">1. Introduction</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">&nbsp;&nbsp; 本文介绍了如何在Ubuntu下建立EDKII编译环境，使用QEMU运行EDKII BIOS.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">2. 建立EDKII编译环境</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Note: EDKII (12/1/2011 SVN checkout) builds cleanly on 11.10 (with packages in proposed repo installed).</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Note: EDKII is known to build correctly on Natty (11.04) but has compilation issues with the more pedantic gcc 4.6.1 ,</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;so it fails to build on Oneiric (as of 20 Oct 2011). However, upsteam are aware of this and are working on a fix.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">(1) Install required packages<br /><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sudo&nbsp;apt-get&nbsp;install&nbsp;build-essential&nbsp;subversion&nbsp;uuid-dev&nbsp;iasl</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) Get the latest source for EDKII<br /></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp; In a suitable working directory extract the latest EDKII source. Note there is no password for guest account, so hit enter.</p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">      $ mkdir ~/src        $ cd ~/src        $ git clone git://github.com/tianocore/edk2.git</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4) Compile base tools<br /></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp; For MS Windows, prebuilt binaries of the base tools are shipped with the source;</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp; on Ubuntu the base tools required for building EDKII need to be built first.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">      $ cd ~/src        $ make -C edk2/BaseTools</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">(5) Set up build environment<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; You need to set EDK_TOOLS_PATH and set up the build environment by running the edksetup.sh script provided in the</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source. This script will copy template and configuration files to edk2/Conf directory.</p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">       $ cd ~/src/edk2         $ export EDK_TOOLS_PATH=$HOME/src/edk2/BaseTools         $ . edksetup.sh BaseTools</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(6) Set up build target<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; To set up the build target you need to modify the conf file Conf/target.txt.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp;&nbsp; This will enable the firmware package to be built and set up the compiler version used.</p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">     $ vi ~/src/edk2/Conf/target.txt</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Find</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;ACTIVE_PLATFORM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;Nt32Pkg/Nt32Pkg.dsc&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">and replace it with</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;ACTIVE_PLATFORM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;MdeModulePkg/MdeModulePkg.dsc&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Find</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;TOOL_CHAIN_TAG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;MYTOOLS&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">and replace it with your version on GCC here for example GCC 4.4 will be used.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;TOOL_CHAIN_TAG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;GCC44&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Find</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;TARGET_ARCH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;IA32&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">and replace it with 'X64' for 64bit or 'IA32 X64' to build both architectures.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;TARGET_ARCH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;X64&nbsp;</tt></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">3. 编译MdeModulePkg</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp; This will build the&nbsp;<a rel="nofollow" href="https://wiki.ubuntu.com/MdeModulePkg" style="color: #e75263;">MdeModulePkg</a>&nbsp;and helloworld program that we can use later when we launch the UEFI shell from emulator...&nbsp;&nbsp;&nbsp;&nbsp;</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">&nbsp;&nbsp;&nbsp; Just type build...</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">  $ cd ~/src/edk2/    $ build</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">  On a Core i5 with 4GB of RAM the total build time is two minutes. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">4. Build a full system firmware image (OVMF)</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">   The Open Virtual Machine Firmware (or "OVMF") can be used to enable UEFI within virtual machines. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">   It provides libraries and drivers related to virtual machines. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">   Currently OVMF support QEMU for emulating UEFI on IA32 and X86-64 based systems. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">   You could also build OVMF with source level debugging enabled. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><br />   <strong>Set up build target<br /></strong>   You can build OVMF for IA32 or X64 architechtures. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">In this example we will build OVMF for X64 architecture. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">You will need to modify Conf/target.txt and replace ACTIVE_PLATFORM with the right dsc file. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">$ vi ~/src/edk2/Conf/target.txt</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Find </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;ACTIVE_PLATFORM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;MdeModulePkg/MdeModulePkg.dsc&nbsp;</tt> </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">replace with </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><tt>&nbsp;ACTIVE_PLATFORM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;OvmfPkg/OvmfPkgX64.dsc&nbsp;</tt> </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">This will set the Target Arch to X64, PEI code to X64 and DXE/UEFI code to X64. </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Build the OvmfPkg<br />    $ cd ~/src/edk2      $ build</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">On an i5 with 4GB RAM the total build time is less than two minutes. The files built will be located </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">under ~/src/Build/ </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;"><strong>Building the OvmfPkg with Secure Boot support<br /></strong>    If you wish to build OVMF with Secure Boot, you must follow the openssl installation instructions </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">found in:- </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">~/src/edk2/CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">and build like this instead:- </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">$ cd ~/src/edk2     $ build &#8211;D SECURE_BOOT_ENABLE</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">If you see an error that "the required fv image size exceeds the set fv image size" consult <a rel="nofollow" href="http://feishare.com/efimail/messages/20110324-1024-Re__edk2__Error_about_building_OVMF_on_Fedora_8-Bei_Guan.html" style="color: #e75263;">this mailing list post.</a> </pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; text-indent: 2em; background-color: #fafafa;">But note that the rest of this guide currently assumes you build WITHOUT Secure Boot. </pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">5. Running UEFI in QEMU</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ sudo apt-get install qemu</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Initial setup<br /></p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">create a directory where you will set up firmware, a directory to use as hard disk image for QEMU.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">    $ mkdir ~/ovmf-qemu      $ cd ~/ovmf-qemu      $ mkdir hda-contents</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Copy the firmware to your working directory.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">    $ cd ~/ovmf-qemu      $ cp ~/src/edk2/Build/OvmfX64/DEBUG_GCC45/FV/OVMF.fd ./bios.bin      $ cp ~/src/edk2/Build/OvmfX64/DEBUG_GCC45/FV/OvmfVideo.rom ./vgabios-cirrus.bin</pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">Run UEFI image in QEMU<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This will launch UEFI firmware image on QEMU and drop to UEFI shell.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp; You can type exit and get to the UEFI menus or work with the shell.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">&nbsp;&nbsp; Note: to release mouse grab from QEMU hit CTRL+ALT</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">     $ qemu-system-x86_64 -L . -hda fat:hda-contents</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">6. Running HelloWorld.efi</pre><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">    <p style="margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; text-indent: 2em;">As part of the <a rel="nofollow" href="https://wiki.ubuntu.com/MdeModule" style="color: #e75263;">MdeModule</a> build, you also built a <a rel="nofollow" href="https://wiki.ubuntu.com/HelloWorld" style="color: #e75263;">HelloWorld</a>.efi. Exit any QEMU sessions you are running and copy the hello world program to your QEMU hard disk. </p><p style="margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; text-indent: 2em;"></p><pre style="white-space: pre-wrap;">$ cp ~/src/edk2/Build/MdeModule/DEBUG_GCC45/X64/HelloWorld.efi ~/ovmf-qemu/hda-contents/.</pre><p style="margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; text-indent: 2em;">Launch UEFI firmware in QEMU, and run the hello world program. </p></pre><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; background-color: #fafafa;">7. 在QEMU上利用OVMF启动Ubuntu 12.04</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;">You can boot the Ubuntu live CD image using OVMF as your firmware. Please note that splash screen does not work, and you might not be able to get a network connection, but the OS will boot and will be fully functional. I have precise-desktop-amd64.iso downloaded to ~/Downloads/iso/12.04/, I change directory to where I copied the firmware I built and run QEMU with the following options.</p><p style="line-height: 28px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: #595959; font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53; font-size: 16px; text-indent: 2em; background-color: #fafafa;"></p><pre style="line-height: 28px; white-space: pre-wrap; color: #595959; font-size: 16px; background-color: #fafafa;">$ cd ~/ovmf-qemu  $ qemu-system-x86_64 -L . -m 1024 -cdrom ~/Downloads/iso/12.04/precise-desktop-amd64.iso -vga cirrus -enable-kvm</pre><img src ="http://www.cnitblog.com/yuhensong/aggbug/89779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-25 14:18 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/25/89779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>qemu源码分析之五-- TCG动态翻译技术</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89751.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 11 Sep 2014 02:50:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89751.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89751.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89751.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89751.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">1. TCG简单介绍</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">TCG（Tiny Code Generator）最早被用于C编译器的后端。在TCG相关的代码中，target指的是我们通常说的host，这一点需要注意，并不是我们理解的被仿真的平台。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">2. TCG动态翻译技术的几个概念</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">（1）与dyngen一样，TCG的&#8220;function&#8221;与qemu的TBs（Translated Block）相对应，即以分支跳转指令结束的代码段。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">（2）TCG中有三种变量：temporary， local temporary， global。这三种变量有着不同的生命周期，temporary变量的声明周期是TBs，local temporary变量的声明周期是functions，global变量的声明周期是所有的functions，类似C语言的全局变量。temporary和local temporary变量通常在function内定义，global变量通常在function外定义。全局变量通常被映射到某个内存地址或某个固定的寄存器。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">3. TCG operations</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">就像dyngen动态翻译技术中的micro-operations一样，TCG也采用中间表示的形式(TCG instructions)，TCG至中间表示支持的三种变量有两种数据类型：32 bit整型和64 bit整型。另外，指针类型被实现为整型的别名。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">TCG指令有固定的形式：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">TCG 操作码 输出变量域，输入变量域，常量域</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">比较特殊的是call指令，其后只跟一个变量，同时作为输出和输入变量域。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">举个例子：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">add_i32 t0, t1, t2 (t0 &lt;- t1 + t2)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">操作码 输出变量域 输入变量域 常量域（输入）</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">4. TCG是qemu的核心，主要实现了以下翻译流程：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;"></p><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">guest binary instructions -&gt; TCG IR -&gt; host binary instructions TCG 定义了一组IR(intermediate representation),这些IR大致可以分为以下几类：</div><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;"></p><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- Mov类操作: mov, movi, ...</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- 逻辑操作: and, or, xor, shl, shr, ...</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- 算术操作: add, sub, mul, div, ...</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- 分支跳转操作: jmp, br, brcond</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- 函数调用: call - 内存操作: ld, st</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">- QEMU的特殊操作: tb_exit, goto_tb, qemu_ld/qemu_st</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">这里仅对TCG中间表示做一下简单分类，至于每条TCG指令的具体用法，参见qemu源码tcg/readme。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">5. TCG 动态翻译过程</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">前面也提到TCG主要实现以下翻译过程：</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">guest binary instructions -&gt; TCG IR -&gt; host binary instructions</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">在qemu源码中，target-ARCH/* 定义了如何将guest binary instructions 反汇编成 TCG IR，tcg/ARCH 定义了如何將 TCG IR 翻译成 host binary instructions。</div><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 18.2000007629395px;">在下一篇文章中，将会从qemu源码的角度详细分析x86--&gt;x86平台的TCG动态翻译技术的执行过程。</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/89751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-11 10:50 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/11/89751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>qemu源码分析之四--dyngen动态翻译技术</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89750.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 11 Sep 2014 02:49:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89750.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89750.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89750.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89750.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp; &nbsp;由于刚刚接触qemu，所以前面几篇文章仅仅是肤浅的介绍qemu的一些背景知识，今天突然感觉前面说的太没有条理了，而且大部分是读别人的文章，一知半解，没有自己的总结体会，今天感觉稍微有点心得，敬请指教。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">1. 明确guest和host</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 对于qemu而言，被仿真的平台成为guest或者说target；很明显，运行qemu的平台就称为host。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2. 了解qemu动态翻译技术的发展</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu运用动态翻译的技术将guest binary instructions动态翻译成host binary instructions，之后由host运行翻译后的指令。在qemu-0.9之前的版本都采用dyngen的动态翻译技术，而从qemu-0.10开始的版本开始采用TCG（Tiny&nbsp; Code Generator）的翻译技术。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp; &nbsp; 采用dyngen&nbsp; 动态翻译技术的资料主要有以下两篇文章，是了解动态翻译技术入门的好文章（在后续的分析中，会简单介绍dyngen技术）：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>&nbsp; QEMU, a Fast and Portable Dynamic Translator</li><li><pre style="white-space: pre-wrap; word-wrap: break-word;">&nbsp;Porting QEMU to Plan 9: QEMU Internals and Port Strategy</pre></li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 介绍TCG技术的文章则相对较少，主要是阅读qemu源码和qemu官网上的相关资料。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">3. dyngen简单介绍</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp;&nbsp;图1简单说明了qemu采用dyngen动态翻译技术将目标平台指令翻译成主机平台指令的简单过程。<br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><img alt="" src="http://hi.csdn.net/attachment/201110/11/0_13183399538lT7.gif" style="border: none; max-width: 100%;" /><br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">假设target为PowerPC，host为x86，说明整个翻译过程：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><img alt="" src="http://hi.csdn.net/attachment/201110/11/0_1318342373l7fb.gif" style="border: none; max-width: 100%;" /></p><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><div bg_html"="" style="width: 700.90625px;"><div><div><strong>[html]</strong>&nbsp;<a href="http://blog.csdn.net/ustc_dylan/article/details/6857014#" title="view plain" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_plain.gif); background-position: 0% 0%; background-repeat: no-repeat;">view plain</a><a href="http://blog.csdn.net/ustc_dylan/article/details/6857014#" title="copy" style="padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px; background-image: url(http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/images/default/ico_copy.gif); background-position: 0% 0%; background-repeat: no-repeat;">copy</a><div style="position: absolute; left: 517px; top: 1920px; width: 18px; height: 18px; z-index: 99;"></div></div></div><ol start="1"><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span>&nbsp;<span style="color: red;">style</span>=<span style="color: blue;">"BACKGROUND-COLOR:&nbsp;#f0f0f0;&nbsp;MARGIN:&nbsp;4px&nbsp;0px"</span>&nbsp;<span style="color: red;">class</span>=<span style="color: blue;">"html"</span>&nbsp;<span style="color: red;">name</span>=<span style="color: blue;">"code"</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span>&nbsp;<span style="color: red;">class</span>=<span style="color: blue;">"html"</span>&nbsp;<span style="color: red;">name</span>=<span style="color: blue;">"code"</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li><li style="line-height: 18px;"><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span><span style="color: #993300; font-weight: bold;">&lt;/</span><span style="color: #993300; font-weight: bold;">pre</span><span style="color: #993300; font-weight: bold;">&gt;</span>&nbsp;&nbsp;</li></ol></div></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp;dyngen在整个过程中扮演了非常重要的角色，其详细功能在这里不再详述，但是有一个疑问，希望与大家讨论：</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">在将目标平台指令集向micro-operations这一步的转化中，《QEMU, a Fast and Portable Dynamic Translator》一文中提到采用了hand coded code的方式，我理解是我们说的&#8220;硬编码&#8221;，即目标平台指令到micro-op是预先写好的一一映射的关系，我的疑问就是这种一一映射的关系是怎么实现的，因为没有看过qemu-0.9之前版本的代码，所以很想知道是怎么hand coded 的。另外，该文还提到&#8220;When QEMU first encounters a piece of target code, it&nbsp;translates it to host code ... ....&#8221;, 我的问题是qemu怎么处理目标平台的objective file的， 比方说qemu怎么分析一个ELF文件，怎么从中读取指令，怎么来进行后面的hand coded ？？？？</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp;在dyngen动态翻译技术中，还涉及到几个比较重要的地方，比如：</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp;（1）TBs，Translated Blocks</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;qemu将TB定义为碰到下一个jump指令或修改CPU state的指令之前的所有代码称为一个TB<br />&nbsp;&nbsp; &nbsp;（2）寄存器分配</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;target平台的寄存器被映射到host的固定寄存器或指定的内存地址</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">&nbsp;&nbsp; &nbsp;（3）条件代码的优化</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">&nbsp;&nbsp; &nbsp;（4）TB块以hash表的形式组织</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">&nbsp;&nbsp; &nbsp;（5）mmap()系统调用仿真target的MMU</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">&nbsp;&nbsp; &nbsp;（6）longjmp()实现异常仿真</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">&nbsp;&nbsp; &nbsp;（7）异步轮询的方式实现中断的仿真</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp; &nbsp;至于<span style="color: #ff0000;">（3）~（7）</span>的具体实现方式，现在还比较模糊，希望与大家交流！！！！！！！！！</div><img src ="http://www.cnitblog.com/yuhensong/aggbug/89750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-11 10:49 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/11/89750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>qemu源码分析系列(二)</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89748.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 11 Sep 2014 02:48:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89748.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89748.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89748.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89748.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89748.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">在qemu源码分析系列(一)简单介绍了下qemu相关的背景知识，本文将详细分析qemu的核心 -- 动态翻译器。</span><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">为了更容易理解动态翻译技术，我们暂时忽略掉qemu的其他模块，如用户交互模块，硬件模拟等模块，而是从数据结构的设计，数据结构之间的操作及其应用等方面来进行详细地分析，重点关注动态翻译器和微操作库(micro-ops library)的原理，至于细节的东西可以放在以后去深入分析。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">qemu利用了一种可移植的动态代码翻译器以快速地完成客户代码的仿真。qemu本身并不能识别它主机体系结构的指令集，作为替代，每一个客户机指定一个c语言实现的微操作库以及一个客户机代码反汇编器和翻译器，用来将客户代码转换成微操作表，这些微操作可以被认为是一种虚拟机，尽管仅仅是对客户系统模拟的一种优化而已。另外，这些操作本身包括寄存器转化，显示的条件代码更新代码，按位操作，整型和浮点型数学函数，内存加载和存储操作等。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.1 翻译</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.1.1 基本块的翻译</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">图1描述了一小段带条件跳转x86代码以及其对应的微操作指令表示，每一条op_开头的微操作指令都将被拷贝到翻译缓冲区中，微操作指令中看起来像参数的常量被称为折叠常量(const folding)，在2.3.4接将会进行详细的解释，现在只要把它看成是qemu中定义的微操作指令的参数就可以了。微操作指令的参数中，tb是比较特殊的，它指向与当前翻译缓冲区相关的元数据。另外，JNZ指令对应的微操作指令看起来比较怪异，控制流处理相关的细节将会在2.2.3节和2.2.4节详细介绍。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><a href="http://blog.chinaunix.net/link.php?url=http://blog.chinaunix.net%2Fattachment%2F201109%2F23%2F20940095_1316789491n7Nz.png" target="_blank" style="color: #336699;"><img title="image" border="0" alt="image" src="http://blog.chinaunix.net/attachment/201109/23/20940095_1316789491RBw4.png" width="515" height="223" style="border: 0px none; max-width: 100%; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" /></a></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.1.2 同步的错误安全舱口</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">严格的按照&#8220;基本块&#8221;（basic block）的方式译码将会使得翻译缓冲区中包含一条或多条客户机指令，同时几乎每一条指令都可能产生同步的fault(比方说MMU fault)。为了便于理解，在翻译的时候我们重点考虑比较直接的客户机控制流（比方说，分支跳转：条件跳转和非条件跳转），毕竟，同步的错误(fault)很少出现。对于同步错误(fault)需要一种恢复机制，用来处理翻译缓冲区中的fault。qemu使用longjmp()从翻译缓冲区中跳到仿真器核心代码中。这里描述的意思是：当在执行翻译缓冲区的代码时，遇到了fault，就需要将执行路径切换到qemu的代码中，另外，当qemu处理完fault后，会重新创建一个翻译缓冲区。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.1 翻译缓冲区的高超技巧</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">qemu采用了一些不同寻常的技巧来提高性能：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>冗长的、额外开销大的主机操作（如仿真客户的MMU操作）并不会被直接放进翻译缓冲区，而是以可以从微操作中调用的帮助函数的形式存在<ul><li>一方面减少了对翻译缓冲区的占用，另一方面简化了翻译的过程（qemu中事先保存某些固定指令的翻译结果，当动态翻译器碰到这些指令时，直接跳过去执行就行了）</li></ul></li><li>翻译后的微操作指令序列的优化</li><li>启发式的译码和翻译</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.2.1 通过函数调用来达到节省翻译缓冲区的技术</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">目前操作系统中的MMU操作指令自身非常复杂。对于MMU操作会产生大量的访存操作，通常的解决方法是增加一个cache，但这进一步增加代码的复杂度。如果将每一次访存操作的这些复杂代码都放入翻译缓冲区中，其代价将会非常的昂贵。除了MMU操作指令，一些特殊的客户机指令也是非常复杂的，如CPUID指令，即使在简化的qemu的实现中，一条x86的CPUID指令都需要75行C代码来实现。与ARPL指令相比，CPUID对于不同的寄存器内容将会表现是完全不同的行为，因此，必须需要一大串冗长的微操作指令来实现CPUID的功能。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">为了优化这种代价昂贵，需要冗长的微操作指令来实现的客户机指令，qemu采用能够实现类似函数调用功能的微操作指令的机制来实现，比如ldl_kernel，实现了内核模式的大量数据的读功能；helper_cpuid，这个微操作包含了CPUID指令的实现。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">2.2.2 惰性赋值</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">每一条指令都会隐含性修改指令指针(EIP)，并且每一条指令都会修改处理器条件码（比如零标志位，溢出标志位、进位标志位等），但实际的情况是，只要指令按照正确的顺序执行，其实客户代码很少去关心这些状态的变化。对于这些条件码除了条件跳转状态位外，我们很少去关注其他的状态位。图1中一段小小的客户代码都会引起指令指针的修改和条件码修改的大量操作：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>ADDL操作会修改条件码的零和进位/借位标志位</li><li>SUBL操作会修改条件码的零和进位/借位标志位</li><li>ADDL和SUBL都会修改EIP，使其指向下一条指令</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">由于qemu是按照&#8220;基本代码块&#8221;为单位进行翻译的，所以只有在整个&#8220;基本代码块&#8221;翻译完成或显示的读取EIP的时候才会对EIP进行更新，这就避免了EIP的频繁更新的问题。在实际情况下，ADDL和SUBL都不会去读指令指针EIP，因此，可以优化掉翻译后的微操作指令中对EIP更新的微操作，具体描述如图2所示。图2中仅仅是在每个&#8220;基本代码块&#8221;的最后通过op_jmp_im微操作来进行EIP的更新，即每个&#8220;基本代码块&#8221;只做一次更新操作。</p><p align="center" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><img title="image" border="0" alt="image" src="http://blog.chinaunix.net/attachment/201109/23/20940095_13167894921y4i.png" width="486" height="264" style="border: 0px none; max-width: 100%; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-top: 0px;" /></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/89748.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-11 10:48 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/11/89748.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QEMU源码分析系列（三）</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89749.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 11 Sep 2014 02:48:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89749.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89749.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/11/89749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89749.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89749.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">从QEMU-0.10.0开始，<span style="color: #ff0000;">TCG成为QEMU新的翻译引擎，使QEMU不再依赖于GCC3.X版本，并且做到了&#8220;真正&#8221;的动态翻译（从某种意义上说，旧版本是从编译后的目标文件中复制二进制指令）。</span>TCG的全称为&#8220;<strong><span style="color: #ff0000;">Tiny Code Generator</span></strong>&#8221;，QEMU的作者Fabrice Bellard在TCG的说明文件中写到，TCG起源于一个C编译器后端，后来被简化为QEMU的动态代码生成器（Fabrice Bellard以前还写过一个很牛的编译器TinyCC）。实际上TCG的作用也和一个真正的编译器后端一样，主要负责分析、优化Target代码以及生成Host代码。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">Target指令 ----&gt; TCG ----&gt; Host指令</span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><strong>以下的讲述以X86平台为例（Host和Target都是X86）。</strong></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">我在上篇文章中讲到，<strong><span style="color: #ff0000;">动态翻译的基本思想就是把每一条Target指令切分成为若干条微指令，每条微指令由一段简单的C代码来实现，运行时通过一个动态代码生成器把这些微指令组合成一个函数，最后执行这个函数，就相当于执行了一条Target指令</span>。</strong></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">这种思想的基础是因为CPU指令都是很规则的，每条指令的长度、操作码、操作数都有固定格式，根据前面就可推导出后面，所以只需通过反汇编引擎分析出指令的操作码、输入参数、输出参数等，剩下的工作就是编码为目标指令了。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">那么现在的CPU指令这么多，怎么知道要分为哪些微指令呢？其实CPU指令看似名目繁多，异常复杂，实际上多数指令不外乎以下几大类：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #ff0000;">数据传送、算术运算、逻辑运算、程序控制；</span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">例如，数据传送包括：传送指令（如MOV）、堆栈操作（PUSH、POP）等</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">程序控制包括：函数调用（CALL）、转移指令（JMP）等；</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">基于此，<span style="color: #ff0000;">TCG就把微指令按以上几大类定义（见tcg/i386/tcg-target.c），</span>例如：其中一个最简单的函数 tcg_out_movi 如下：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">// tcg/tcg.c<br />static inline void tcg_out8(TCGContext *s, uint8_t v)<br />{<br />*s-&gt;code_ptr++ = v;<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void tcg_out32(TCGContext *s, uint32_t v)<br />{<br />*(uint32_t *)s-&gt;code_ptr = v;<br />s-&gt;code_ptr += 4;<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">// tcg/i386/tcg-target.c<br />static inline void tcg_out_movi(TCGContext *s, TCGType type,<br />int ret, int32_t arg)<br />{<br />if (arg == 0) {<br />/* xor r0,r0 */<br />tcg_out_modrm(s, 0x01 | (ARITH_XOR &lt;&lt; 3), ret, ret);<br />} else {<br />tcg_out8(s, 0xb8 + ret); // 输出操作码，ret是寄存器索引<br />tcg_out32(s, arg); // 输出操作数<br />}<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #cc0000;">0xb8 - 0xbf 正是x86指令中的 mov R, Iv 系列操作的16进制码，所以，tcg_out_movi 的功能就是输出 mov 操作的指令码到缓冲区中。</span><strong><span style="color: #ff0000;">可以看出，TCG在生成目标指令的过程中是采用硬编码的，因此，要让TCG运行在不同的Host平台上，就必须为不同的平台编写微操作函数。</span></strong></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">接下来，我还是以一条Target指令 jmp f000:e05b 来讲述它是如何被翻译成Host指令的。其中几个关键变量的定义如下：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">gen_opc_buf： 操作码缓冲区<br />gen_opparam_buf：参数缓冲区<br />gen_code_buf： 存放翻译后指令的缓冲区<br />gen_opc_ptr、gen_opparam_ptr、gen_code_ptr三个指针变量分别指向上述缓冲区。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">jmp f000:e05b 的编码是：EA 5B E0 00 F0，</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">首先是disas_insn()函数翻译指令，当碰到第1个字节EA，分析可知这是一条16位无条件跳转指令，因此依次从后续字节中得到offset和selector，然后分为如下微指令操作：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">gen_op_movl_T0_im(selector);<br />gen_op_movl_T1_imu(offset);<br />gen_op_movl_seg_T0_vm(R_CS);<br />gen_op_movl_T0_T1();<br />gen_op_jmp_T0();</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">这几个微指令函数的定义如下（功能可看注释）：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void gen_op_movl_T0_im(int32_t val)<br />{<br />tcg_gen_movi_tl(cpu_T[0], val); // 相当于 cpu_T[0] = val<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void gen_op_movl_T1_imu(uint32_t val)<br />{<br />tcg_gen_movi_tl(cpu_T[1], val); // 相当于 cpu_T[1] = val<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void gen_op_movl_seg_T0_vm(int seg_reg)<br />{<br />tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff); // cpu_T[0] = cpu_T[0]&amp;0xffff<br />tcg_gen_st32_tl(cpu_T[0], cpu_env,&nbsp;<br />offsetof(CPUX86State,segs[seg_reg].selector)); // the value of cpu_T[0] store to the 'offset' of cpu_env<br />tcg_gen_shli_tl(cpu_T[0], cpu_T[0], 4); // cpu_T[0] = cpu_T[0]&lt;&lt;4<br />tcg_gen_st_tl(cpu_T[0], cpu_env,&nbsp;<br />offsetof(CPUX86State,segs[seg_reg].base)); // the value of cpu_T[0] store to the 'offset' of cpu_env<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void gen_op_movl_T0_T1(void)<br />{<br />tcg_gen_mov_tl(cpu_T[0], cpu_T[1]); // cpu_T[0] = cpu_T[1]<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void gen_op_jmp_T0(void)<br />{<br />tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUState, eip)); // // the value of cpu_T[0] store to the 'offset' of cpu_env<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">其中，cpu_T[0]、cpu_T[1]和前面讲过的T0、T1功能一样，都是用来临时存储的变量。在32位目标机上，tcg_gen_movi_tl 就是 tcg_gen_op2i_i32 函数，它的定义如下：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void tcg_gen_op2i_i32(int opc, TCGv_i32 arg1, TCGArg arg2)<br />{<br />*gen_opc_ptr++ = opc;<br />*gen_opparam_ptr++ = GET_TCGV_I32(arg1);<br />*gen_opparam_ptr++ = arg2;<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg)<br />{<br />tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg);<br />}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">gen_opparam_buf 是用来存放操作数的缓冲区，它的存放顺序是：第1个4字节代表s-&gt;temps（用来存放目标值的数组，即输出参数）的索引，第2个4字节及之后字节代表输入参数，对它的具体解析过程可见 tcg_reg_alloc_movi 函数，示例代码如下：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">TCGTemp *ots;<br />tcg_target_ulong val;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">ots = &amp;s-&gt;temps[args[0]];<br />val = args[1];</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">ots-&gt;val_type = TEMP_VAL_CONST;<br />ots-&gt;val = val; // 把输入值暂时存放在ots结构中</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">接下来，根据 gen_opc_buf 保存的操作码列表，gen_opparam_buf 保存的参数列表，以及TCGContext结构，经过 tcg_gen_code_common 函数调用，jmp f000:e05b 生成的最终指令如下：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">099D0040 B8 00 F0 00 00 mov eax,0F000h&nbsp;<br />099D0045 81 E0 FF FF 00 00 and eax,0FFFFh&nbsp;<br />099D004B 89 45 50 mov dword ptr [ebp+50h],eax&nbsp;<br />099D004E C1 E0 04 shl eax,4&nbsp;<br />099D0051 89 45 54 mov dword ptr [ebp+54h],eax&nbsp;<br />099D0054 B8 5B E0 00 00 mov eax,0E05Bh&nbsp;<br />099D0059 89 45 20 mov dword ptr [ebp+20h],eax&nbsp;<br />099D005C 31 C0 xor eax,eax&nbsp;<br />099D005E E9 25 5D CA 06 jmp _code_gen_prologue+8 (10675D88h) /* 返回 */</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">从上面可以看出，生成的Host代码很简洁，<span style="font-size: 13px;"><span style="font-family: 宋体;">对于Target机的JMP，Host没有去执行真正的跳转指令，而只是简单的将目标地址放到EIP中而已。</span></span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #000000; widows: 2; border-collapse: separate; font-size: 16px; line-height: normal; font-family: simsun; orphans: 2;"><span style="font-size: 13px;">QEMU维护着一个称为&nbsp;<span style="color: #ff0000;">CPUState 的数据结构，</span>这个结构包括了<span style="color: #ff0000;">Target机CPU的所有寄存器，像EAX，EBP，ESP，CS，EIP，EFLAGS等。</span></span></span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #000000; widows: 2; border-collapse: separate; font-size: 16px; line-height: normal; font-family: simsun; orphans: 2;"><span style="font-size: 13px;"><span style="color: #ff0000;">它总是代表着Target机的当前状态，我用env变量来表示 CPUState 结构，</span></span></span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="color: #000000; widows: 2; border-collapse: separate; font-size: 16px; line-height: normal; font-family: simsun; orphans: 2;"><span style="font-size: 13px;"><span style="color: #ff0000;">QEMU每次解析Target指令时，总是以 env.cs+env.eip 为开始地址的。</span>&nbsp;<br /><br />像上面说的jmp f000:e05b指令，它分解为如下微操作：&nbsp;<br /><br />gen_op_movl_T0_im(selector);&nbsp;<br />gen_op_movl_T1_imu(offset);&nbsp;<br />gen_op_movl_seg_T0_vm(R_CS);&nbsp;<br />gen_op_movl_T0_T1();&nbsp;<br />gen_op_jmp_T0();&nbsp;<br /><br />这<span style="color: #ff0000;">几条微操作的意义概括起来很简单，就是把selector放到env.cs，把offset放到env.eip</span>。<span style="font-family: Arial; font-size: 16px;">在调试中，把QEMU执行Target指令的过程和Bochs比较是一件很有趣的事情，当然，这只是设计理念的不同，而并没有技术上的优劣之分。</span></span></span></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/89749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-11 10:48 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/11/89749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QEMU源码分析系列(一）</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/11/QEMU.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 11 Sep 2014 02:47:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/11/QEMU.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89747.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/11/QEMU.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89747.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89747.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">1 qemu概述</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu是一种快速的多体系结构仿真器，通过动态翻译的技术达到了优异的仿真速度。目前，qemu支持两种操作模式：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>全系统仿真模式。在这种模式下，qemu完整的仿真目标平台，此时，qemu就相当于一台完整的pc机，例如包括一个或多个处理器以及各种外围设备。这种模式可以用来运行不同的操作系统或调试操作系统的代码。</li><li>用户态仿真模式。在这种模式下，qemu能够运行不同于主机平台的其他平台的程序（比如，在x86平台上运行为arm平台编译的程序），其中典型的代表wine windows API emulator。另外，在这种模式下能够进行方便的交叉编译和调试。</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 对于全系统仿真模式，qemu目前可以支持的硬件列表如下：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>x86 or x86_64 体系结构处理器</li><li>ISA PC （没有PCI总线的PC）</li><li>PowerPC 处理器</li><li>32/64bit的SPARC 处理器</li><li>32/64bit的MIPS处理器</li><li>ARM体系结构的处理器</li><li>PXA 270、PXA 255</li><li>OMAP 310、OMAP 2420、OMAP 310</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 对于用户态仿真模式，qemu支持的硬件列表如下：x86 (32 and 64 bit), PowerPC (32 and 64 bit), ARM, MIPS (32 bit only), Sparc (32 and 64 bit), Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported.</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">1.1 qemu 的本质</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp;&nbsp; 众所周知，Bochs 是一款可移植的IA-32仿真器，它利用模拟的技术来仿真目标系统，具体来说，将是将目标系统的指令分解，然后模拟分解后的指令以达到同样的效果。这种方法将每一条目标指令分解成多条主机系统的指令，很明显会大大降低仿真的速度。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu则是采用动态翻译的技术，先将目标代码翻译成一系列等价的被称为&#8220;微操作&#8221;（micro-operations）的指令，然后再对这些指令进行拷贝，修改，连接，最后产生一块本地代码。这些微操作排列复杂，从简单的寄存器转换模拟到整数/浮点数学函数模拟再到load/store操作模拟，其中load/store操作的模拟需要目标操作系统分页机制的支持。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu对客户代码的翻译是按块进行的，并且翻译后的代码被缓存起来以便将来重用。在没有中断的情况下，翻译后的代码仅仅是被链接到一个全局的链表上，目的是保证整个控制流保持在目标代码中，当异步的中断产生时，中断处理函数就会遍历串连翻译后代码的全局链表来在主机上执行翻译后的代码，这就保证了控制流从目标代码跳转到qemu代码。简单概括下：指定某个中断来控制翻译代码的执行，即每当产生这个中断时才会去执行翻译后的代码，没有中断时仅仅只是个翻译过程而已。这样做的好处就是，代码是是按块翻译，按块执行的，不像Bochs翻译一条指令，马上就执行一条指令。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">1.2 qemu能够模拟的硬件</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; Bochs和qemu从非常低的层次对硬件进行模拟，对于像总线和外围设备如显卡，网卡，磁盘控制器等都有相对应的软件的表示，但是二者仅对有限的硬件集合进行精确的模拟，比如对中断控制器，总线驱动，磁盘驱动，键盘，鼠标，显卡以及网卡的模拟。随着时间的推移，可模拟的硬件集合将会扩展到客户操作系统能够支持的尽可能多的设备。Qemu和Bochs都利用运行在模拟机中的BIOSes来初始化硬件的某些部分，这种设计思想使得对设备的仿真忠于原始的硬件。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 除了模拟之外，设备驱动利用主机的功能来提供模拟和用户要求的功能，下面来看几个例子：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><li>帧缓冲区通过用户可选择的接口被暴露出来，对于qemu来说，帧缓冲有SDL window，VNC Server和无图形界面的输出三个可供选择的选项</li><li>qemu中的网络可以是被禁止的，可以是被桥接到主机的，可以使用虚拟以太网协议创建的Unix套接字，还可以是被在qemu中被完全模拟的</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">1.3 可移植性</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu采用了模块化的设计思想，仿真器中与目标平台相关的部分被分离到它们自己的文件和目录中。对于核心部分，驱动部分和动态翻译器来说，所有目标平台都声明相同的接口，在整个qemu的111，000行代码中，目标平台相关的组件代码大约占了1/3，特别地，x86目标平台的大约不超过8000行。与Bochs不同的是，qemu对目标平台的描述非常的紧凑，因此，可以模拟大量的目标平台。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; qemu要求公开有关编译执行的信息以便动态翻译器使用，幸运地是，这些信息中的绝大部分对于调试器，动态连接器和单独编译来说都是非常必要的。另外，qemu完全由C语言编写，在主机和目标平台环境之间创建了一个隔离层。值得一提的是动态翻译器使用了带GNU扩展的C编写，这种结构化的可移植性，再加上GCC对大量系统的支持，使得qemu在主机系统之间的可移植性大大增加。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;&nbsp;&nbsp; 本文仅仅简单介绍下了qemu的相关知识，下一篇文章将会深入分析qemu的实现原理。</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/89747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-11 10:47 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/11/QEMU.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Makefile常用函数总结</title><link>http://www.cnitblog.com/yuhensong/archive/2014/09/01/89731.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Mon, 01 Sep 2014 07:09:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/09/01/89731.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89731.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/09/01/89731.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89731.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89731.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">在Makefile中可以使用函数来处理变量，从而让我们的命令或是规则更为的灵活和具&nbsp;</span><br style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;" /><span style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">有智能。make所支持的函数也不算很多，不过已经足够我们的操作了。函数调用后，函&nbsp;</span><br style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;" /><span style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">数的返回值可以当做变量来使用。</span><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">一、函数的调用语法<br />函数调用，很像变量的使用，也是以&#8220;$&#8221;来标识的，其语法如下：<br />$(&lt;function&gt; &lt;arguments&gt; )&nbsp;<br />或是<br />${&lt;function&gt; &lt;arguments&gt;}</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />这里，&lt;function&gt;就是函数名，make支持的函数不多。&lt;arguments&gt;是函数的参数，参数&nbsp;<br />间以逗号&#8220;,&#8221;分隔，而函数名和参数之间以&#8220;空格&#8221;分隔。函数调用以&#8220;$&#8221;开头，以圆&nbsp;<br />括号或花括号把函数名和参数括起。感觉很像一个变量，是不是？函数中的参数可以使&nbsp;<br />用变量，为了风格的统一，函数和变量的括号最好一样，如使用&#8220;$(substa,b,$(x))&#8221;这&nbsp;<br />样的形式，而不是&#8220;$(substa,b,${x})&#8221;的形式。因为统一会更清楚，也会减少一些不必&nbsp;<br />要的麻烦。<br />还是来看一个示例：<br />comma:= ,&nbsp;<br />empty:=&nbsp;<br />space:= $(empty) $(empty)&nbsp;<br />foo:= a b c&nbsp;<br />bar:= $(subst $(space),$(comma),$(foo))<br />在这个示例中，$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格，&nbsp;<br />$(foo)的值是&#8220;a b c&#8221;，$(bar)的定义用，调用了函数&#8220;subst&#8221;，这是一个替换函数，这&nbsp;<br />个函数有三个参数，第一个参数是被替换字串，第二个参数是替换字串，第三个参数&nbsp;<br />是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号，所以$(bar)的值&nbsp;<br />是&#8220;a,b,c&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">二、字符串处理函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(subst &lt;from&gt;,&lt;to&gt;,&lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：字符串替换函数&#8212;&#8212;subst。&nbsp;<br />功能：把字串&lt;text&gt;中的&lt;from&gt;字符串替换成&lt;to&gt;。&nbsp;<br />返回：函数返回被替换过后的字符串。<br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">示例：<br />$(subst ee,EE,feet on the street)，<br />把&#8220;feetonthestreet&#8221;中的&#8220;ee&#8221;替换成&#8220;EE&#8221;，返回结果是&#8220;fEEtonthestrEEt&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">$(patsubst &lt;pattern&gt;,&lt;replacement&gt;,&lt;text&gt; )&nbsp;<br /><br />名称：模式字符串替换函数&#8212;&#8212;patsubst。&nbsp;<br />功能：查找&lt;text&gt;中的单词（单词以&#8220;空格&#8221;、&#8220;Tab&#8221;或&#8220;回车&#8221;&#8220;换行&#8221;分隔）是否&nbsp;<br />符合模式&lt;pattern&gt;，如果匹配的话，则以&lt;replacement&gt;替换。这里，&lt;pattern&gt;可以包括&nbsp;<br />通配符&#8220;%&#8221;，表示任意长度的字串。如果&lt;replacement&gt;中也包含&#8220;%&#8221;，那么，&nbsp;<br />&lt;replacement&gt;中的这个&#8220;%&#8221;将是&lt;pattern&gt;中的那个&#8220;%&#8221;所代表的字串。（可以用&#8220;\&#8221;&nbsp;<br />来转义，以&#8220;\%&#8221;来表示真实含义的&#8220;%&#8221;字符）&nbsp;<br />返回：函数返回被替换过后的字符串。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />示例：<br />$(patsubst %.c,%.o,x.c.c bar.c)<br />把字串&#8220;x.c.cbar.c&#8221;符合模式[%.c]的单词替换成[%.o]，返回结果是&#8220;x.c.obar.o&#8221;<br />备注：<br />这和我们前面&#8220;变量章节&#8221;说过的相关知识有点相似。如：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />&#8220;$(var:&lt;pattern&gt;=&lt;replacement&gt; )&#8221;&nbsp;<br />相当于&nbsp;<br />&#8220;$(patsubst &lt;pattern&gt;,&lt;replacement&gt;,$(var))&#8221;，</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />而&#8220;$(var:&lt;suffix&gt;=&lt;replacement&gt;)&#8221;&nbsp;<br />则相当于&nbsp;<br />&#8220;$(patsubst %&lt;suffix&gt;,%&lt;replacement&gt;,$(var))&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />例如有：objects=foo.obar.obaz.o，&nbsp;<br />那么，&#8220;$(objects:.o=.c)&#8221;和&#8220;$(patsubst%.o,%.c,$(objects))&#8221;是一样的。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(strip &lt;string&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：去空格函数&#8212;&#8212;strip。&nbsp;<br />功能：去掉&lt;string&gt;字串中开头和结尾的空字符。&nbsp;<br />返回：返回被去掉空格的字符串值。&nbsp;<br />示例：<br />$(strip a b c )<br />把字串&#8220;abc&#8221;去到开头和结尾的空格，结果是&#8220;abc&#8221;。<br />$(findstring &lt;find&gt;,&lt;in&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：查找字符串函数&#8212;&#8212;findstring。&nbsp;<br /><br />功能：在字串&lt;in&gt;中查找&lt;find&gt;字串。&nbsp;<br />返回：如果找到，那么返回&lt;find&gt;，否则返回空字符串。&nbsp;<br />示例：<br />$(findstring a,a b c)&nbsp;<br />$(findstring a,b c)<br />第一个函数返回&#8220;a&#8221;字符串，第二个返回&#8220;&#8221;字符串（空字符串）<br />$(filter &lt;pattern...&gt;,&lt;text&gt; )<br />名称：过滤函数&#8212;&#8212;filter。&nbsp;<br />功能：以&lt;pattern&gt;模式过滤&lt;text&gt;字符串中的单词，保留符合模式&lt;pattern&gt;的单词。可&nbsp;<br />以有多个模式。&nbsp;<br />返回：返回符合模式&lt;pattern&gt;的字串。&nbsp;<br />示例：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />sources := foo.c bar.c baz.s ugh.h&nbsp;<br />foo: $(sources)&nbsp;<br />cc $(filter %.c %.s,$(sources)) -o foo</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(filter %.c %.s,$(sources))返回的值是&#8220;foo.c bar.c baz.s&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(filter-out &lt;pattern...&gt;,&lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：反过滤函数&#8212;&#8212;filter-out。&nbsp;<br />功能：以&lt;pattern&gt;模式过滤&lt;text&gt;字符串中的单词，去除符合模式&lt;pattern&gt;的单词。可&nbsp;<br />以有多个模式。&nbsp;<br />返回：返回不符合模式&lt;pattern&gt;的字串。&nbsp;<br />示例：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />objects=main1.o foo.o main2.o bar.o&nbsp;<br />mains=main1.o main2.o</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(filter-out $(mains),$(objects)) 返回值是&#8220;foo.o bar.o&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(sort &lt;list&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：排序函数&#8212;&#8212;sort。&nbsp;<br />功能：给字符串&lt;list&gt;中的单词排序（升序）。&nbsp;<br />返回：返回排序后的字符串。&nbsp;<br />示例：$(sortfoobarlose)返回&#8220;barfoolose&#8221;。&nbsp;<br />备注：sort函数会去掉&lt;list&gt;中相同的单词。&nbsp;<br /><br />$(word &lt;n&gt;,&lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：取单词函数&#8212;&#8212;word。&nbsp;<br />功能：取字符串&lt;text&gt;中第&lt;n&gt;个单词。（从一开始）&nbsp;<br />返回：返回字符串&lt;text&gt;中第&lt;n&gt;个单词。如果&lt;n&gt;比&lt;text&gt;中的单词数要大，那么返回&nbsp;<br />空字符串。&nbsp;<br />示例：$(word2,foobarbaz)返回值是&#8220;bar&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(wordlist &lt;s&gt;,&lt;e&gt;,&lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：取单词串函数&#8212;&#8212;wordlist。&nbsp;<br />功能：从字符串&lt;text&gt;中取从&lt;s&gt;开始到&lt;e&gt;的单词串。&lt;s&gt;和&lt;e&gt;是一个数字。&nbsp;<br />返回：返回字符串&lt;text&gt;中从&lt;s&gt;到&lt;e&gt;的单词字串。如果&lt;s&gt;比&lt;text&gt;中的单词数要大，&nbsp;<br />那么返回空字符串。如果&lt;e&gt;大于&lt;text&gt;的单词数，那么返回从&lt;s&gt;开始，到&lt;text&gt;结束&nbsp;<br />的单词串。&nbsp;<br />示例：$(wordlist2,3,foobarbaz)返回值是&#8220;barbaz&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(words &lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：单词个数统计函数&#8212;&#8212;words。&nbsp;<br />功能：统计&lt;text&gt;中字符串中的单词个数。&nbsp;<br />返回：返回&lt;text&gt;中的单词数。&nbsp;<br />示例：$(words,foobarbaz)返回值是&#8220;3&#8221;。&nbsp;<br />备注：如果我们要取&lt;text&gt;中最后的一个单词，我们可以这样：$(word $(words&nbsp;<br />&lt;text&gt; ),&lt;text&gt; )。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(firstword &lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：首单词函数&#8212;&#8212;firstword。&nbsp;<br />功能：取字符串&lt;text&gt;中的第一个单词。&nbsp;<br />返回：返回字符串&lt;text&gt;的第一个单词。&nbsp;<br />示例：$(firstwordfoobar)返回值是&#8220;foo&#8221;。&nbsp;<br />备注：这个函数可以用word函数来实现：$(word1,&lt;text&gt;)。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />以上，是所有的字符串操作函数，如果搭配混合使用，可以完成比较复杂的功能。这里，&nbsp;<br />举一个现实中应用的例子。我们知道，make使用&#8220;VPATH&#8221;变量来指定&#8220;依赖文件&#8221;的&nbsp;<br />搜索路径。于是，我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数&nbsp;<br />CFLAGS，如：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />如果我们的&#8220;$(VPATH)&#8221;值是&#8220;src:../headers&#8221;，那么&#8220;$(patsubst %,-I%,$(subst :, ,&nbsp;<br />$(VPATH)))&#8221;将返回&#8220;-Isrc -I../headers&#8221;，这正是 cc 或 gcc 搜索头文件路径的参数。&nbsp;<br /><br />三、文件名操作函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或&nbsp;<br />是一系列的文件名来对待。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">$(dir &lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">名称：取目录函数&#8212;&#8212;dir。&nbsp;<br />功能：从文件名序列&lt;names&gt;中取出目录部分。目录部分是指最后一个反斜杠（&#8220;/&#8221;）&nbsp;<br />之前的部分。如果没有反斜杠，那么返回&#8220;./&#8221;。&nbsp;<br />返回：返回文件名序列&lt;names&gt;的目录部分。&nbsp;<br />示例：$(dirsrc/foo.chacks)返回值是&#8220;src/./&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">$(notdir &lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">名称：取文件函数&#8212;&#8212;notdir。&nbsp;<br />功能：从文件名序列&lt;names&gt;中取出非目录部分。非目录部分是指最后一个反斜杠（&#8220;/&nbsp;<br />&#8221;）之后的部分。&nbsp;<br />返回：返回文件名序列&lt;names&gt;的非目录部分。&nbsp;<br />示例：$(notdirsrc/foo.chacks)返回值是&#8220;foo.chacks&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(suffix &lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：取后缀函数&#8212;&#8212;suffix。&nbsp;<br />功能：从文件名序列&lt;names&gt;中取出各个文件名的后缀。&nbsp;<br />返回：返回文件名序列&lt;names&gt;的后缀序列，如果文件没有后缀，则返回空字串。&nbsp;<br />示例：$(suffixsrc/foo.csrc-1.0/bar.chacks)返回值是&#8220;.c.c&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(basename &lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：取前缀函数&#8212;&#8212;basename。&nbsp;<br />功能：从文件名序列&lt;names&gt;中取出各个文件名的前缀部分。&nbsp;<br />返回：返回文件名序列&lt;names&gt;的前缀序列，如果文件没有前缀，则返回空字串。&nbsp;<br />示例：$(basenamesrc/foo.csrc-1.0/bar.chacks)返回值是&#8220;src/foosrc-1.0/barhacks&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(addsuffix &lt;suffix&gt;,&lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：加后缀函数&#8212;&#8212;addsuffix。&nbsp;<br />功能：把后缀&lt;suffix&gt;加到&lt;names&gt;中的每个单词后面。&nbsp;<br />返回：返回加过后缀的文件名序列。&nbsp;<br />示例：$(addsuffix.c,foobar)返回值是&#8220;foo.cbar.c&#8221;。&nbsp;<br /><br />$(addprefix &lt;prefix&gt;,&lt;names...&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：加前缀函数&#8212;&#8212;addprefix。&nbsp;<br />功能：把前缀&lt;prefix&gt;加到&lt;names&gt;中的每个单词后面。&nbsp;<br />返回：返回加过前缀的文件名序列。&nbsp;<br />示例：$(addprefixsrc/,foobar)返回值是&#8220;src/foosrc/bar&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(join &lt;list1&gt;,&lt;list2&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />名称：连接函数&#8212;&#8212;join。&nbsp;<br />功能：把&lt;list2&gt;中的单词对应地加到&lt;list1&gt;的单词后面。如果&lt;list1&gt;的单词个数要比&nbsp;<br />&lt;list2&gt;的多，那么，&lt;list1&gt;中的多出来的单词将保持原样。如果&lt;list2&gt;的单词个数要比&nbsp;<br />&lt;list1&gt;多，那么，&lt;list2&gt;多出来的单词将被复制到&lt;list2&gt;中。&nbsp;<br />返回：返回连接过后的字符串。&nbsp;<br />示例：$(joinaaabbb,111222333)返回值是&#8220;aaa111bbb222333&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;<br />四、foreach函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的，Makefile 中的&nbsp;<br />foreach 函数几乎是仿照于 Unix 标准 Shell（/bin/sh）中的 for 语句，或是 C-Shell&nbsp;<br />（/bin/csh）中的foreach语句而构建的。它的语法是：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(foreach &lt;var&gt;,&lt;list&gt;,&lt;text&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />这个函数的意思是，把参数&lt;list&gt;中的单词逐一取出放到参数&lt;var&gt;所指定的变量中，&nbsp;<br />然后再执行&lt;text&gt;所包含的表达式。每一次&lt;text&gt;会返回一个字符串，循环过程中，&nbsp;<br />&lt;text&gt;的所返回的每个字符串会以空格分隔，最后当整个循环结束时，&lt;text&gt;所返回的&nbsp;<br />每个字符串所组成的整个字符串（以空格分隔）将会是foreach函数的返回值。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />所以，&lt;var&gt;最好是一个变量名，&lt;list&gt;可以是一个表达式，而&lt;text&gt;中一般会使用&nbsp;<br />&lt;var&gt;这个参数来依次枚举&lt;list&gt;中的单词。举个例子：&nbsp;<br /><br />names := a b c d</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />files := $(foreach n,$(names),$(n).o)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />上面的例子中，$(name)中的单词会被挨个取出，并存到变量&#8220;n&#8221;中，&#8220;$(n).o&#8221;每次根&nbsp;<br />据&#8220;$(n)&#8221;计算出一个值，这些值以空格分隔，最后作为foreach函数的返回，所以，&nbsp;<br />$(files)的值是&#8220;a.o b.o c.o d.o&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />注意，foreach中的&lt;var&gt;参数是一个临时的局部变量，foreach函数执行完后，参数&nbsp;<br />&lt;var&gt;的变量将不在作用，其作用域只在 foreach 函数当中。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />五、if函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">if 函数很像 GNU 的 make 所支持的条件语句&#8212;&#8212;ifeq（参见前面所述的章节），if 函数&nbsp;<br />的语法是：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(if &lt;condition&gt;,&lt;then-part&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />或是</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(if &lt;condition&gt;,&lt;then-part&gt;,&lt;else-part&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />可见，if函数可以包含&#8220;else&#8221;部分，或是不含。即if函数的参数可以是两个，也可以是&nbsp;<br />三个。&lt;condition&gt;参数是if的表达式，如果其返回的为非空字符串，那么这个表达式就&nbsp;<br /><br />相当于返回真，于是，&lt;then-part&gt;会被计算，否则&lt;else-part&gt;会被计算。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;<br />而if函数的返回值是，如果&lt;condition&gt;为真（非空字符串），那个&lt;then-part&gt;会是整&nbsp;<br />个函数的返回值，如果&lt;condition&gt;为假（空字符串），那么&lt;else-part&gt;会是整个函数的&nbsp;<br />返回值，此时如果&lt;else-part&gt;没有被定义，那么，整个函数返回空字串。&nbsp;<br />所以，&lt;then-part&gt;和&lt;else-part&gt;只会有一个被计算。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />六、call函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">call 函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式，&nbsp;<br />这个表达式中，你可以定义许多参数，然后你可以用call函数来向这个表达式传递参&nbsp;<br />数。其语法是：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />$(call &lt;expression&gt;,&lt;parm1&gt;,&lt;parm2&gt;,&lt;parm3&gt;...)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />当make执行这个函数时，&lt;expression&gt;参数中的变量，如$(1)，$(2)，$(3)等，会被参&nbsp;<br />数&lt;parm1&gt;，&lt;parm2&gt;，&lt;parm3&gt;依次取代。而&lt;expression&gt;的返回值就是call函数的返&nbsp;<br />回值。例如：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />reverse = $(1) $(2)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />foo = $(call reverse,a,b)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />那么，foo的值就是&#8220;ab&#8221;。当然，参数的次序是可以自定义的，不一定是顺序的，如：&nbsp;<br /><br />reverse = $(2) $(1)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />foo = $(call reverse,a,b)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />此时的foo的值就是&#8220;ba&#8221;。&nbsp;<br />七、origin函数&nbsp;<br />origin 函数不像其它的函数，他并不操作变量的值，他只是告诉你你的这个变量是哪里&nbsp;<br />来的？其语法是：&nbsp;<br />$(origin &lt;variable&gt; )</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />注意，&lt;variable&gt;是变量的名字，不应该是引用。所以你最好不要在&lt;variable&gt;中使用&#8220;&nbsp;<br />$&#8221;字符。Origin 函数会以其返回值来告诉你这个变量的&#8220;出生情况&#8221;，下面，是 origin&nbsp;<br />函数的返回值:</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />&#8220;undefined&#8221;&nbsp;<br />如果&lt;variable&gt;从来没有定义过，origin函数返回这个值&#8220;undefined&#8221;。&nbsp;<br />&#8220;default&#8221;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />如果&lt;variable&gt;是一个默认的定义，比如&#8220;CC&#8221;这个变量，这种变量我们将在后面讲述。&nbsp;<br /><br />&#8220;environment&#8221;&nbsp;<br />如果&lt;variable&gt;是一个环境变量，并且当Makefile被执行时，&#8220;-e&#8221;参数没有被打开。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />&#8220;file&#8221;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />如果&lt;variable&gt;这个变量被定义在Makefile中。&nbsp;<br />&#8220;command line&#8221;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />如果&lt;variable&gt;这个变量是被命令行定义的。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;<br />&#8220;override&#8221;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />如果&lt;variable&gt;是被override指示符重新定义的。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;<br />&#8220;automatic&#8221;&nbsp;<br />如果&lt;variable&gt;是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。&nbsp;<br />这些信息对于我们编写Makefile是非常有用的，例如，假设我们有一个Makefile其包&nbsp;<br />了一个定义文件Make.def，在Make.def中定义了一个变量&#8220;bletch&#8221;，而我们的环境中&nbsp;<br />也有一个环境变量&#8220;bletch&#8221;，此时，我们想判断一下，如果变量来源于环境，那么我&nbsp;<br />们就把之重定义了，如果来源于Make.def或是命令行等非环境的，那么我们就不重新&nbsp;<br />定义它。于是，在我们的Makefile中，我们可以这样写：&nbsp;<br />ifdef bletch&nbsp;<br /><br />ifeq "$(origin bletch)" "environment"&nbsp;<br />bletch = barf, gag, etc.&nbsp;<br />endif&nbsp;<br />endif&nbsp;<br />当然，你也许会说，使用override关键字不就可以重新定义环境中的变量了吗？为什&nbsp;<br />么需要使用这样的步骤？是的，我们用override是可以达到这样的效果，可是override&nbsp;<br />过于粗暴，它同时会把从命令行定义的变量也覆盖了，而我们只想重新定义环境传来&nbsp;<br />的，而不想重新定义命令行传来的。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />八、shell函数</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">shell 函数也不像其它的函数。顾名思义，它的参数应该就是操作系统 Shell 的命令。它和&nbsp;<br />反引号&#8220;`&#8221;是相同的功能。这就是说，shell函数把执行操作系统命令后的输出作为函数&nbsp;<br />返回。于是，我们可以用操作系统命令以及字符串处理命令awk，sed等等命令来生成&nbsp;<br />一个变量，如：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />contents := $(shell cat foo)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />files := $(shell echo *.c)</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><br />注意，这个函数会新生成一个Shell程序来执行命令，所以你要注意其运行性能，如果&nbsp;<br />你的Makefile中有一些比较复杂的规则，并大量使用了这个函数，那么对于你的系统&nbsp;<br />性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你&nbsp;<br />想像的多得多。</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/89731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-09-01 15:09 <a href="http://www.cnitblog.com/yuhensong/archive/2014/09/01/89731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】Windows下用Python你会几种copy文件的方法？</title><link>http://www.cnitblog.com/yuhensong/archive/2014/08/14/89706.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 14 Aug 2014 07:14:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/08/14/89706.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89706.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/08/14/89706.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89706.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89706.html</trackback:ping><description><![CDATA[<p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><strong style="margin: 0px; padding: 0px;">1. os.system</strong></p><dl style="margin: 0px; padding: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> os<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.txt</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />open (filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">w</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">).close ()<br style="margin: 0px; padding: 0px;" />filename2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, filename2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷文件</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">os.system (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">copy %s %s</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span> <span style="margin: 0px; padding: 0px; color: #000000;">%</span><span style="margin: 0px; padding: 0px; color: #000000;"> (filename1, filename2))<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isfile (filename2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.dir</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />os.mkdir (dirname1)<br style="margin: 0px; padding: 0px;" />dirname2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, dirname2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷目录</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">os.system (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">xcopy /s %s %s</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span> <span style="margin: 0px; padding: 0px; color: #000000;">%</span><span style="margin: 0px; padding: 0px; color: #000000;"> (dirname1, dirname2))<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isdir (dirname2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span></div></pre></dd></dl><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><strong style="margin: 0px; padding: 0px;">2. shutil.copy和shutil.copytree</strong></p><dl style="margin: 0px; padding: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> os<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> shutil<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.txt</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />open (filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">w</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">).close ()<br style="margin: 0px; padding: 0px;" />filename2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, filename2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷文件</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">shutil.copy (filename1, filename2)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isfile (filename2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.dir</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />os.mkdir (dirname1)<br style="margin: 0px; padding: 0px;" />dirname2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, dirname2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷目录</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">shutil.copytree (dirname1, dirname2)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isdir (dirname2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span></div></pre></dd></dl><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><strong style="margin: 0px; padding: 0px;">3.&nbsp; win32file.CopyFile</strong></p><dl style="margin: 0px; padding: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> os<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> win32file<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.txt</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />open (filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">w</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">).close ()<br style="margin: 0px; padding: 0px;" />filename2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, filename2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷文件</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" />#</span><span style="margin: 0px; padding: 0px; color: #008000;">文件已存在时，1为不覆盖，0为覆盖</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">win32file.CopyFile (filename1, filename2, </span><span style="margin: 0px; padding: 0px; color: #000000;">1</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />win32file.CopyFile (filename1, filename2, 0)<br style="margin: 0px; padding: 0px;" />win32file.CopyFile (filename1, filename2, </span><span style="margin: 0px; padding: 0px; color: #000000;">1</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isfile (filename2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.dir</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />os.mkdir (dirname1)<br style="margin: 0px; padding: 0px;" />dirname2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, dirname2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷目录</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">win32file.CopyFile (dirname1, dirname2, </span><span style="margin: 0px; padding: 0px; color: #000000;">1</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isdir (dirname2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span></div></pre></dd></dl><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><strong style="margin: 0px; padding: 0px;">4. SHFileOperation&nbsp;<br style="margin: 0px; padding: 0px;" /></strong></p><dl style="margin: 0px; padding: 0px; color: #111111; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23.399999618530273px;"><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> os<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">from</span><span style="margin: 0px; padding: 0px; color: #000000;"> win32com.shell </span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> shell, shellcon<br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">import</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.txt</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />open (filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">w</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">).close ()<br style="margin: 0px; padding: 0px;" />filename2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> filename1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, filename2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷文件</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" />#</span><span style="margin: 0px; padding: 0px; color: #008000;">文件已存在时，shellcon.FOF_RENAMEONCOLLISION会指示重命名文件</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">shell.SHFileOperation (<br style="margin: 0px; padding: 0px;" />  (0, shellcon.FO_COPY, filename1, filename2, 0, None, None)<br style="margin: 0px; padding: 0px;" />)<br style="margin: 0px; padding: 0px;" />shell.SHFileOperation (<br style="margin: 0px; padding: 0px;" />  (0, shellcon.FO_COPY, filename1, filename2, shellcon.FOF_RENAMEONCOLLISION, None, None)<br style="margin: 0px; padding: 0px;" />)<br style="margin: 0px; padding: 0px;" />shell.SHFileOperation (<br style="margin: 0px; padding: 0px;" />  (0, shellcon.FO_COPY, filename1, filename2, 0, None, None)<br style="margin: 0px; padding: 0px;" />)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isfile (filename2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> tempfile.mktemp (</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.dir</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">)<br style="margin: 0px; padding: 0px;" />os.mkdir (dirname1)<br style="margin: 0px; padding: 0px;" />dirname2 </span><span style="margin: 0px; padding: 0px; color: #000000;">=</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1 </span><span style="margin: 0px; padding: 0px; color: #000000;">+</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">.copy</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span><span style="margin: 0px; padding: 0px; color: #000000;"> dirname1, </span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">=&gt;</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #000000;">, dirname2<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #008000;">#</span><span style="margin: 0px; padding: 0px; color: #008000;">拷目录</span><span style="margin: 0px; padding: 0px; color: #008000;"><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #000000;">shell.SHFileOperation (<br style="margin: 0px; padding: 0px;" />  (0, shellcon.FO_COPY, dirname1, dirname2, 0, None, None)<br style="margin: 0px; padding: 0px;" />)<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /></span><span style="margin: 0px; padding: 0px; color: #0000ff;">if</span><span style="margin: 0px; padding: 0px; color: #000000;"> os.path.isdir (dirname2): </span><span style="margin: 0px; padding: 0px; color: #0000ff;">print</span> <span style="margin: 0px; padding: 0px; color: #800000;">"</span><span style="margin: 0px; padding: 0px; color: #800000;">Success</span><span style="margin: 0px; padding: 0px; color: #800000;">"</span></div></pre></dd><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;">不知道有没有其它的了，os.rename不算，那个是移动文件。另外我在测试它们的性能如何。</div>http://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html <br style="margin: 0px; padding: 0px;" />这里和楼主列出的都一样，没有更多的了 <br style="margin: 0px; padding: 0px;" />或者使用Chilkat  http://www.chilkatsoft.com/refdoc/pythonCkFileAccessRef.html<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />测试结果出来了： <br style="margin: 0px; padding: 0px;" /> 测试环境：系统&#8212;&#8212;Win7 RTM，CPU&#8212;&#8212;P4 3.0，MEM&#8212;&#8212;1.5G DDR400，U盘&#8212;&#8212;Kingston 4G <br style="margin: 0px; padding: 0px;" />  <br style="margin: 0px; padding: 0px;" /> 用4种不同的方法从硬盘拷贝MSDN 2008 SP1（2.37G）到U盘： <br style="margin: 0px; padding: 0px;" />  <br style="margin: 0px; padding: 0px;" /> os System&nbsp; &nbsp; &nbsp; 的方法耗时903.218秒 <br style="margin: 0px; padding: 0px;" /> shutil&nbsp; &nbsp; &nbsp; &nbsp;  的方法耗时1850.634秒 <br style="margin: 0px; padding: 0px;" /> win32file&nbsp; &nbsp; &nbsp; 的方法耗时861.438秒 <br style="margin: 0px; padding: 0px;" /> SHFileOperation的方法耗时794.023秒 <br style="margin: 0px; padding: 0px;" />  <br style="margin: 0px; padding: 0px;" /> 另外SHFileOperation是显示对话框的，可以这样用 </pre><dl style="margin: 0px; padding: 0px;"><dd style="margin: 0px; padding: 0px;"><pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;"><div style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #000000;">shell.SHFileOperation (<br style="margin: 0px; padding: 0px;" />  (0, shellcon.FO_COPY, filename1, filename2, <br style="margin: 0px; padding: 0px;" />   shellcon.FOF_RENAMEONCOLLISION </span><span style="margin: 0px; padding: 0px; color: #000000;">|</span><span style="margin: 0px; padding: 0px; color: #000000;"> \<br style="margin: 0px; padding: 0px;" />   shellcon.FOF_NOCONFIRMATION </span><span style="margin: 0px; padding: 0px; color: #000000;">|</span><span style="margin: 0px; padding: 0px; color: #000000;">\<br style="margin: 0px; padding: 0px;" />   shellcon.FOF_NOERRORUI </span><span style="margin: 0px; padding: 0px; color: #000000;">|</span><span style="margin: 0px; padding: 0px; color: #000000;"> \<br style="margin: 0px; padding: 0px;" />   shellcon.FOF_SILENT, None, None)<br style="margin: 0px; padding: 0px;" />)</span></div></pre></dd></dl></dd></dl><img src ="http://www.cnitblog.com/yuhensong/aggbug/89706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-08-14 15:14 <a href="http://www.cnitblog.com/yuhensong/archive/2014/08/14/89706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分析YUV数据</title><link>http://www.cnitblog.com/yuhensong/archive/2014/06/25/89621.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Wed, 25 Jun 2014 07:30:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2014/06/25/89621.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/89621.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2014/06/25/89621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/89621.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/89621.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 做视频采集与处理，自然少不了要学会分析YUV数据。因为从采集的角度来说，一般的视频采集芯片输出的码流一般都是YUV数据流的形式，而从视频处理（例如H.264、MPEG视频编解码）的角度来说，也是在原始YUV码流进行编码和解析，所以，了解如何分析YUV数据流对于做视频领域的人而言，至关重要。本文就是根据我的学习和了解，简单地介绍如何分析YUV数据流。&nbsp;&nbsp;&nbsp; YUV，分为...&nbsp;&nbsp;<a href='http://www.cnitblog.com/yuhensong/archive/2014/06/25/89621.html'>阅读全文</a><img src ="http://www.cnitblog.com/yuhensong/aggbug/89621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2014-06-25 15:30 <a href="http://www.cnitblog.com/yuhensong/archive/2014/06/25/89621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM uboot中的.lds</title><link>http://www.cnitblog.com/yuhensong/archive/2012/11/19/86782.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Mon, 19 Nov 2012 08:30:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2012/11/19/86782.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/86782.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2012/11/19/86782.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/86782.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/86782.html</trackback:ping><description><![CDATA[<div id="article_content" class="article_content">
<div style="text-indent: 21pt">对于.lds文件，它定义了整个程序编译之后的连接过程，决定了一个可执行程序的各个段的存储位置。虽然现在我还没怎么用它，但感觉还是挺重要的，有必要了解一下。</div>
<div style="text-indent: 21pt">先看一下<a href="http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_node/ld_21.html" target="_blank"><u><font color="#0000ff">GNU官方网站上</font></u></a>对.lds文件形式的完整描述：</div>
<p style="text-indent: 21pt"></p>
<table style="border-collapse: collapse" border="1" width="95%">
<tbody>
<tr>
<td>
<div style="line-height: 150%; margin: 5px">SECTIONS {<br />...<br />secname <em>start</em> BLOCK(<em>align</em>) (NOLOAD) : AT ( <em>ldadr</em> )<br />&nbsp;&nbsp;{ <em>contents</em> } &gt;<em>region</em> :<em>phdr</em> =<em>fill</em><br />...<br />}</div></td></tr></tbody></table>
<p>&nbsp;</p><pre style="text-indent: 16.5pt">secname和contents是必须的，其他的都是可选的。下面挑几个常用的看看：</pre>
<div style="text-indent: 21pt">1、secname：段名</div>
<div style="text-indent: 21pt">2、contents：决定哪些内容放在本段，可以是整个目标文件，也可以是目标文件中的某段（代码段、数据段等）</div>
<div style="text-indent: 21pt">3、start：本段连接（运行）的地址，如果没有使用AT（ldadr），本段存储的地址也是start。GNU网站上说start可以用任意一种描述地址的符号来描述。</div>
<div style="text-indent: 21pt">4、AT（ldadr）：定义本段存储（加载）的地址。</div>
<div style="text-indent: 21pt">看一个简单的例子：（摘自《2410完全开发》）</div>
<p>&nbsp;</p>
<table style="border-collapse: collapse" border="1" width="95%">
<tbody>
<tr>
<td>
<div style="line-height: 150%; margin: 5px">/* nand.lds */<br />SECTIONS { <br />firtst 0x00000000 : { head.o init.o } <br />second 0x30000000 : AT(4096) { main.o } <br />}</div></td></tr></tbody></table>
<p>&nbsp;</p>
<div>&nbsp;&nbsp;&nbsp; 以上，head.o放在0x00000000地址开始处，init.o放在head.o后面，他们的运行地址也是0x00000000，即连接和存储地址相同（没有AT指定）；main.o放在4096（0x1000，是AT指定的，存储地址）开始处，但是它的运行地址在0x30000000，运行之前需要从0x1000（加载处）复制到0x30000000（运行处），此过程也就用到了读取Nand flash。</div>
<div style="text-indent: 21pt">这就是存储地址和连接（运行）地址的不同，称为加载时域和运行时域，可以在.lds连接脚本文件中分别指定。</div>
<div style="text-indent: 21pt">编写好的.lds文件，在用arm-linux-ld连接命令时带-Tfilename来调用执行，如<br />arm-linux-ld &#8211;Tnand.lds x.o y.o &#8211;o xy.o。也用-Ttext参数直接指定连接地址，如<br />arm-linux-ld &#8211;Ttext 0x30000000 x.o y.o &#8211;o xy.o。</div>
<div style="text-indent: 21pt">&nbsp;既然程序有了两种地址，就涉及到一些跳转指令的区别，这里正好写下来，以后万一忘记了也可查看，以前不少东西没记下来现在忘得差不多了。。。</div>
<div style="text-indent: 21pt">ARM汇编中，常有两种跳转方法：b跳转指令、ldr指令向PC赋值。</div>
<div style="text-indent: 21pt">我自己经过归纳如下：</div>
<div style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt">（1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b step1 ：b跳转指令是相对跳转，依赖当前PC的值，偏移量是通过该指令本身的bit[23:0]算出来的，这使得使用b指令的程序不依赖于要跳到的代码的位置，只看指令本身。</div>
<div style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt">（2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ldr pc, =step1 ：该指令是从内存中的某个位置（step1）读出数据并赋给PC，同样依赖当前PC的值，但是偏移量是那个位置（step1）的连接地址（运行时的地址），所以可以用它实现从Flash到RAM的程序跳转。</div>
<div style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt">（3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此外，有必要回味一下adr伪指令，U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中。仍然用我当时的注释：</div>
<p>&nbsp;</p>
<table style="border-collapse: collapse" border="1" width="95%">
<tbody>
<tr>
<td>
<div style="line-height: 150%; margin: 5px">relocate: /* 把U-Boot重新定位到RAM */<br />&nbsp;&nbsp;&nbsp; adr r0, _start /* r0是代码的当前位置 */ <br />/* adr伪指令，汇编器自动通过当前PC的值算出 如果执行到_start时PC的值，放到r0中：<br />当此段在flash中执行时r0 = _start = 0；当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000，即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */<br />&nbsp;&nbsp;&nbsp; ldr r1, _TEXT_BASE /* 测试判断是从Flash启动，还是RAM */ <br />/* 此句执行的结果r1始终是0x33FF80000，因为此值是又编译器指定的(ads中设置，或-D设置编译器参数) */<br />&nbsp;&nbsp;&nbsp; cmp r0, r1 /* 比较r0和r1，调试的时候不要执行重定位 */</div></td></tr></tbody></table>
<p>&nbsp;</p>
<div>&nbsp;&nbsp;&nbsp; 下面，结合u-boot.lds看看一个正式的连接脚本文件。这个文件的基本功能还能看明白，虽然上面分析了好多，但其中那些GNU风格的符号还是着实让我感到迷惑，好菜啊，怪不得连被3家公司鄙视，自己鄙视自己。。。</div>
<div style="line-height: 150%; margin: 5px">OUTPUT_FORMAT("elf32&amp;shy;littlearm", "elf32&amp;shy;littlearm", "elf32&amp;shy;littlearm")<br />&nbsp;&nbsp;;指定输出可执行文件是elf格式,32位ARM指令,小端<br />OUTPUT_ARCH(arm)<br />&nbsp;&nbsp;;指定输出可执行文件的平台为ARM<br />ENTRY(_start)<br />&nbsp;&nbsp;;指定输出可执行文件的起始代码段为_start.<br />SECTIONS<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = 0x00000000 ; 从0x0位置开始<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = ALIGN(4) ; 代码以4字节对齐<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.text : ;指定代码段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpu/arm920t/start.o (.text) ; 代码的第一个代码部分<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(.text) ;其它代码部分<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = ALIGN(4) <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.rodata : { *(.rodata) } ;指定只读数据段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = ALIGN(4);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.data : { *(.data) } ;指定读/写数据段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = ALIGN(4);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.got : { *(.got) } ;指定got段, got段式是uboot自定义的一个段, 非标准段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__u_boot_cmd_start = . ;把__u_boot_cmd_start赋值为当前位置, 即起始位置<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.u_boot_cmd : { *(.u_boot_cmd) } ;指定u_boot_cmd段, uboot把所有的uboot命令放在该段.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__u_boot_cmd_end = .;把__u_boot_cmd_end赋值为当前位置,即结束位置<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;. = ALIGN(4);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__bss_start = .; 把__bss_start赋值为当前位置,即bss段的开始位置<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.bss : { *(.bss) }; 指定bss段<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_end = .; 把_end赋值为当前位置,即bss段的结束位置<br />}</div>
<p><br />&nbsp;</p>
<p>88888888**********************************</p>
<p>r与adr的区别 </p>
<p style="text-indent: 2em">转自：<a href="http://coon.blogbus.com/logs/2738861.html" rel="nofollow"><u><font color="#0000ff">http://coon.blogbus.com/logs/2738861.html</font></u></a></p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, _start</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adr&nbsp;&nbsp;&nbsp;&nbsp; r0, _start</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, =_start</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nop</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; pc, lr </p>
<p style="text-indent: 2em">_start:</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nop</p>
<p style="text-indent: 2em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p style="text-indent: 2em">编译的时候设置 RO 为 0x0c008000</p>
<p style="text-indent: 2em">&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;&#8595;</p>
<p style="text-indent: 2em">0c008000 &lt;_start-0x14&gt;:</p>
<p style="text-indent: 2em">c008000:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e59f000c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, [pc, #12]&nbsp;&nbsp; ; c008014 &lt;_start&gt;</p>
<p style="text-indent: 2em">c008004:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e28f0008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;&nbsp;&nbsp;&nbsp; r0, pc, #8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; 0x8</p>
<p style="text-indent: 2em">c008008:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e59f0008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, [pc, #8]&nbsp;&nbsp;&nbsp;&nbsp;; c008018 &lt;_start+0x4&gt;</p>
<p style="text-indent: 2em">c00800c:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e1a00000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (mov r0,r0)</p>
<p style="text-indent: 2em">c008010:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e1a0f00e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; pc, lr</p>
<p style="text-indent: 2em">0c008014 &lt;_start&gt;:</p>
<p style="text-indent: 2em">c008014:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e1a00000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (mov r0,r0)</p>
<p style="text-indent: 2em">c008018:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0c008014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stceq&nbsp;&nbsp; 0, cr8, [r0], -#80</p>
<p style="text-indent: 2em">分析：</p>
<p style="text-indent: 2em">ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, _start</p>
<p style="text-indent: 2em">从内存地址 _start 的地方把值读入。执行这个后，r0 = 0xe1a00000</p>
<p style="text-indent: 2em">adr&nbsp;&nbsp;&nbsp;&nbsp; r0, _start</p>
<p style="text-indent: 2em">取得 _start 的地址到 r0，但是请看反编译的结果，它是与位置无关的。其实取得的时相对的位置。例如这段代码在 0x0c008000 运行，那么 adr r0, _start 得到 r0 = 0x0c008014；如果在地址 0 运行，就是 0x00000014 了。</p>
<p style="text-indent: 2em">ldr&nbsp;&nbsp;&nbsp;&nbsp; r0, =_start</p>
<p style="text-indent: 2em">这个取得标号 _start 的绝对地址。这个绝对地址是在 link 的时候确定的。看上去这只是一个指令，但是它要占用 2 个 32bit 的空间，一条是指令，另一条是 _start 的数据（因为在编译的时候不能确定 _start 的值，而且也不能用 mov 指令来给 r0 赋一个 32bit 的常量，所以需要多出一个空间存放 _start 的真正数据，在这里就是 0x0c008014）。</p>
<p style="text-indent: 2em">因此可以看出，这个是绝对的寻址，不管这段代码在什么地方运行，它的结果都是 r0 = 0x0c008014</p><br /></div><img src ="http://www.cnitblog.com/yuhensong/aggbug/86782.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2012-11-19 16:30 <a href="http://www.cnitblog.com/yuhensong/archive/2012/11/19/86782.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最全的uboot start.S分析</title><link>http://www.cnitblog.com/yuhensong/archive/2012/10/30/86709.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Tue, 30 Oct 2012 08:49:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2012/10/30/86709.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/86709.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2012/10/30/86709.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/86709.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/86709.html</trackback:ping><description><![CDATA[<pre>#include &lt;config.h&gt;
#include &lt;version.h&gt;

#if defined(CONFIG_S3C2410)
#include &lt;s3c2410.h&gt;
#elif defined(CONFIG_S3C2440)//include\configs\smdk2440.h中定义。
#include &lt;s3c2440.h&gt;
#endif

#include &lt;status_led.h&gt;

/*************************************************************************
  Jump vector table as in table 3.1 in [1]
 *************************************************************************/
//.global声明一个符号可被其它文件引用，相当于声明了一个
//全局变量，.globl与.global相同。
//该部分为处理器的异常处理向量表。地址范围为
//0x0000 0000 ~ 0x0000 0020,刚好8条指令。

//声明全局变量 _start
.globl _start     /*系统复位位置,整个程序入口*/
_start:	b       start_code    /*各个异常向量对应的相对跳转代码,0x00*/
     /*start_code用b，就是因为start_code在MMU建立前后都有可能发生*/
     /*其他的异常只有在MMU建立之后才会发生*/
	ldr	pc, _undefined_instruction  //未定义指令异常,0x04
	ldr	pc, _software_interrupt    //软中断异常,0x08
	ldr	pc, _prefetch_abort  //内存操作异常,0x0c
	ldr	pc, _data_abort     //数据异常,0x10
	ldr	pc, _not_used      //未适用,0x14
	ldr	pc, _irq          //慢速中断异常,0x18 
	ldr	pc, _fiq         //快速中断异常,0x1c

//.word伪操作用于分配一段字内存单元（分配的单元都是字对齐的），并
//用伪操作中的expr初始化。.long与.int作用与之相同。
/*.word 表达式 ==&gt; 就是在当前位置放一个word型的值，这个值就是"表达式"
;rWTCON: .word 0x15300000 就是在当前地址，即_rWTCON处放一个值0x15300000*/ 

_undefined_instruction:	.word undefined_instruction
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word irq
_fiq:			.word fiq


/*.balign[wl] abs-expr, abs-expr, abs-expr
;增加位置计数器(在当前子段)使它指向规定的存储边界。
;第一个表达式参数(结果必须是纯粹的数字)是必需参数：边界基准,单位
为字节。
;例如， '.balign 8'向后移动位置计数器直至计数器的值等于8的倍数。
;如果位置计数器已经是8的倍数，则无需移动。
;第2个表达式参数(结果必须是纯粹的数字)给出填充字节的值，用这个值
填充位置计数器越过的地方。
;第2个参数(和逗点)可以省略。如果省略它，填充字节的值通常是0。
;但在某些系统上，如果本段标识为包含代码，而填充值被省略,则使用
no-op指令填充空白区。
;第3个参数的结果也必须是纯粹的数字，这个参数是可选的。如果存在第
3个参数，
;它代表本对齐命令允许跳过字节数的最大值。如果完成这个对齐需要跳
过的字节数比规定的最大值还多,
;则根本无法完成对齐。您可以在边界基准参数后简单地使用两个逗号，
以省略填充值参数(第二参数)；
;如果您在想在适当的时候，对齐操作自动使用no-op指令填充

balignw和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。
.balignl使用4字节来填充。例如,.balignw 4,0x368d将地址对齐到4的倍数，如果它跳
过2个字节，GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理器
的存储方式而定)。
如果它跳过1或3个字节,则填充值不明确。


//它的含义是以16字节边界对齐，为了对齐而越过的地址以字为单位填冲
//值0xdeadbeef。我猜0xdeadbeef可能NOP指令。
	.balignl 16,0xdeadbeef  //对齐内存为16的倍数
/*************************************************************************
 *
 * Startup Code (called from the ARM reset exception vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************/

// TEXT_BASE在开发板相关的目录中的config.mk文件中定义, 它定义了
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
/*
 *保存变量的数据区,保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者
 其它的使用。
 *还有一些变量的长度是通过连接脚本里得到,实际上由编译器算出来的
 */
//TEXT_BASE定义在\board\smdk2410\config.mk中。

/*TEXT_BASE是代码执行的起始地址.编译产生的二进制文件必需下载到该地
址,因为所有的函数,全局变量等等定位都是以这个地址为参照的.
如果uboot中是TEXT_BASE就是设的0x33F80000, 那么必需download到这个地址的ram中才
能正常运行.
*/  
_TEXT_BASE:  //_TEXT_BASE=TEXT_BASE.
			.word	TEXT_BASE   /*uboot映像在SDRAM中的重定位地址*/

// 标号_start在前面有定义
	
.globl _armboot_start   // /*在_armboot_start标号处，保存了_start的值*/
_armboot_start:     //_armboot_start=_start。
				.word _start    /*_start是程序入口，链接完毕它的值应该是TEXT_BASE*/ 

/*
 * These are defined in the board-specific linker script.
 */
//__bss_start是uboot 的bss段起始地址，那么uboot映像的大小就是__bss_start - _start；
//实际上，_armboot_start并没有实际意义，它只是在"ldr r2, _armboot_start"中用來寻
//址_start的值而已，_bss_start也是一样的道理，真正有意义的应该是_start和 
//__bss_start本身。 

.globl _bss_start  /*__bss_start是uboot 的bss段起始地址，*/
_bss_start:         /*uboot映像的大小就是__bss_start - _start*/
		.word __bss_start

.globl _bss_end
_bss_end:
		.word _end

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
				.word	0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
				.word 0x0badc0de
#endif


/* the actual start code*/
start_code:/*复位启动子程序*/
	/*设置cpu运行在SVC32模式。共有7种模式*/	
	mrs	r0,cpsr  /*复制当前程序状态寄存器cpsr到r0*/
	bic	r0,r0,#0x1f  //这里使用位清除指令,把中断全部清除,只置位模式控制位
	                          //7种异常，共占0x00 - 0x16空间
	/*ORR{条件}{S}  &lt;dest&gt;, &lt;op 1&gt;, &lt;op 2&gt;*/
       /*OR 将在两个操作数上进行逻辑或，把结果放置到目的寄存器中*/
	orr	r0,r0,#0xd3 /*选择新模式，(现在设为超级保护模式)*/
	
	msr	cpsr,r0  /*设置cpsr为超级保护模式*/
   /*通过设置ARM的CPSR寄存器,让CPU运行在操作系统模式,为后面进行其它操作作好准备*/

//如果定义了CONFIG_AT91RM9200DK,CONFIG_AT91RM9200EK,CONFIG_AT91RM9200DF中的任意一个
//,就会执行其中的语句.这里没有用。
#if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
	/* relocate exception table*/
	ldr		r0, =_start
	ldr		r1, =0x0
	mov		r2, #16
copyex:
	subs	r2, r2,   #1
	ldr		r3, [r0], #4
	str		r3, [r1], #4
	bne		copyex
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)

#if defined(CONFIG_S3C2400)
#define pWTCON	0x15300000
#define INTMSK	0x14400008	/* Interupt-Controller base addresses */
#define CLKDIVN	0x14800014	/* clock divisor register */
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#define pWTCON	0x53000000  /*"看门狗定时器控制寄存器"的地址0x53000000*/  
#define INTMSK	0x4A000008 /*"中断屏蔽寄存器"的地址:0x4A000008 */
#define INTSUBMSK	0x4A00001C /*针对INTMAK具体化的一个中断请求屏蔽寄存器,其地
                                                             址0x4A00001C */  
#define LOCKTIME	0x4c000000  //锁时计数寄存器    
#define MPLLCON 	0x4c000004  //MPLL寄存器
#define UPLLCON 	0x4c000008  //UPLL寄存器
#define CLKDIVN	0x4C000014	/*CPU时钟分频控制寄存器,地址0x4C000014*/  
#endif

#if defined(CONFIG_S3C2410)
#define INTSUBMSK_val	0x7ff
#define MPLLCON_val	((0x90 &lt;&lt; 12) + (0x7 &lt;&lt; 4) + 0x0)	/* 202 MHz */
#define UPLLCON_val	((0x78 &lt;&lt; 12) + (0x2 &lt;&lt; 4) + 0x3)
#define CLKDIVN_val	3 /* FCLK:HCLK:PCLK = 1:2:4 */
#elif defined(CONFIG_S3C2440)
#define INTSUBMSK_val	0xffff  //以便屏蔽INTSUBMSK的bit[15:0]对应的中断请求
#if (CONFIG_SYS_CLK_FREQ == 16934400)//晶振=16.9344M在include\configs\smdk2440.h中定义。
/*
Mpll = (2 * m * Fin) / (p * 2s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV

Upll = (m * Fin) / (p * 2s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV

MDIV =PLLCON[19:12];  PDIV=PLLCON[9:4];  SDIV=PLLCON[1:0];
*/
//# define MPLLCON_val	((0x61 &lt;&lt; 12) + (0x1 &lt;&lt; 4) + 0x2)	/* 296.35 MHz */
//# define UPLLCON_val	((0x3c &lt;&lt; 12) + (0x4 &lt;&lt; 4) + 0x2)	/*  47.98 MHz */
                                //MDIV=184        PDIV=2     SDIV=2                                 
#define MPLLCON_val	((184 &lt;&lt; 12) + (2 &lt;&lt; 4) + 2)	/*406M*/
                                //MDIV=60        PDIV=4     SDIV=2  
#define UPLLCON_val 	((60 &lt;&lt; 12) + (4 &lt;&lt; 4) + 2)   /*  47M */
#elif (CONFIG_SYS_CLK_FREQ == 12000000)
#define MPLLCON_val	((0x44 &lt;&lt; 12) + (0x1 &lt;&lt; 4) + 0x1)	/* 304.00 MHz */
#define UPLLCON_val	((0x38 &lt;&lt; 12) + (0x2 &lt;&lt; 4) + 0x2)	/*  48.00 MHz */
#endif
#define CLKDIVN_val	7 /* FCLK:HCLK:PCLK = 1:3:6   CLKDIVN=7  */
                       //CPU  : 高速设备:  低速设备
#define CAMDIVN	0x4C000018
#endif

        //禁用看门狗
	ldr       r0, =pWTCON
	mov     r1, #0x0
	str       r1, [r0]

	/* mask all IRQs by setting all bits in the INTMR - default*/
	/*在SVC模式下，屏蔽所有中断发生*/
	mov	  r1, #0xffffffff
	ldr	  r0, =INTMSK
	str	  r1, [r0]
	
#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
	ldr	r1, =INTSUBMSK_val  /*子中断同样屏蔽INTSUBMSK_val=0xffff*/
	ldr	r0, =INTSUBMSK
	str	r1, [r0]

/*To reduce PLL lock time, adjust the LOCKTIME register. */
        ldr     r0,=LOCKTIME
        ldr     r1,=0xffffff
        str     r1,[r0]	
#endif

    /* FCLK:HCLK:PCLK = 1:3:6*//* default FCLK is 406M MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #CLKDIVN_val
	str	r1, [r0]

#if defined(CONFIG_S3C2440)
      /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */
        ldr        r0, =CAMDIVN
        mov     r1, #0
        str       r1, [r0]

        /* Clock asynchronous mode */
        mrc     p15, 0, r1, c1, c0, 0
        orr      r1,   r1, #0xc0000000
        mcr     p15, 0, r1, c1, c0, 0

	ldr	r0,=UPLLCON
	ldr	r1,=UPLLCON_val
	str	r1,[r0]
	
	nop	
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	
	ldr	r0,=MPLLCON
	ldr	r1,=MPLLCON_val
	str	r1,[r0]
//
#define GPJCON      0x560000D0
#define GPJDAT       0x560000D4
#define GPJUP		0x560000D8
/*
        LDR   R0,   = GPJCON
        LDR   R1,   = 0x15555
        STR   R1,   [R0]
        LDR   R0,   = GPJUP
        LDR   R1,   = 0x1f
        STR   R1,   [R0]
        LDR   R0,   = GPJDAT  
//    LDR   R1,   = 0xffff
        LDR   R1,   = 0x00
        STR   R1,   [R0]
*/
#endif

#endif	/* CONFIG_S3C2400 || CONFIG_S3C2410 */

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */
	//bl      LED_FLASH
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*这些初始化代码在系统重启的时候执行，运行时热复位从RAM中启动不执行*/
	bl	cpu_init_crit
#endif
#if 1
        LDR   R0,   = GPJCON
        LDR   R1,   = 0x15555
        STR   R1,   [R0]
        LDR   R0,   = GPJUP
        LDR   R1,   = 0x1f
        STR   R1,   [R0]
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x00
        STR   R1,   [R0]
#endif
	
#if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
#ifndef CONFIG_S3C2410_NAND_BOOT
//NOR_BOOT :
relocate:	/* 把U-BOOT重新定位到RAM*/
         //r0=0;
	adr	r0, _start		/* r0是代码的当前位置*/
	//r1=TEXT_BASE = 0x33F80000
	ldr	r1, _TEXT_BASE	/*测试判断是从FLASH启动，还是RAM  */
	cmp     r0, r1     /*比较R0、R1，调试的时候不需要重定位。 */
	beq     stack_setup  /*如果R0等于R1，跳到重定位代码。*/

	//如果不是从RAM运行的话，则将代码拷贝到_TEXT_BASE标识的RAM中。
	/*准备重新定义代码。*/
	ldr	r2, _armboot_start//_armboot_start=_start
	ldr	r3, _bss_start  //
	sub	r2, r3, r2		/* r2得到armboot的大小*/
	add	r2, r0, r2		/* r2得到要复制代码的末尾地址*/
//kaobei guo cheng
copy_loop:/*重新定位代码*/
	ldmia	r0!, {r3-r10}		/*从源地址[r0]复制,r0指向_start(=0)*/
	stmia	r1!, {r3-r10}		/*复制到目的地址[r1],r1指向_TEXT_BASE(=0x33F80000)*/
	cmp	r0, r2			/* 复制数据块直到源数据末尾地址[r2]*/
	ble	copy_loop
#else /* NAND_BOOT */
//relocate:
copy_myself:
	/* mov	r10, lr */
#if defined(CONFIG_S3C2410)
	@ reset NAND
	mov	r1, #S3C2410_NAND_BASE
	ldr	r2, =0xf842		@ initial value enable tacls=3,rph0=6,rph1=0
	str	r2, [r1, #oNFCONF]
	ldr	r2, [r1, #oNFCONF]
	bic	r2, r2, #0x800		@ enable chip
	str	r2, [r1, #oNFCONF]
	mov	r2, #0xff		@ RESET command
	strb	r2, [r1, #oNFCMD]
	mov	r3, #0			@ wait
1:	add	r3, r3, #0x1
	cmp	r3, #0xa
	blt	1b
2:	ldr	r2, [r1, #oNFSTAT]	@ wait ready
	tst	r2, #0x1
	beq	2b
	ldr	r2, [r1, #oNFCONF]
	orr	r2, r2, #0x800		@ disable chip
	str	r2, [r1, #oNFCONF]
#elif defined(CONFIG_S3C2440)
        /*从NAND闪存中把U-BOOT拷贝到RAM*/
	mov	r1, #S3C2440_NAND_BASE //S3C2440_NAND_BASE=0x4E000000
	ldr	r2, =0xfff0		@ initial value tacls=3,rph0=7,rph1=7
	ldr	r3, [r1, #oNFCONF] //oNFCONF=0x00
	orr	r3, r3, r2
	str	r3, [r1, #oNFCONF]//oNFCONF=0x00

	ldr	r3, [r1, #oNFCONT] //oNFCONT=0x04
	orr	r3, r3, #1		@ enable nand controller
	str	r3, [r1, #oNFCONT]//oNFCONT=0x04
#endif  //if defined(CONFIG_S3C2410)

#if 0
	@ get ready to call C functions (for nand_read())
	ldr	sp, DW_STACK_START	@ setup stack pointer
	mov	fp, #0			@ no previous frame, so fp=0
#else
	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
	
        /* CFG_MALLOC_LEN=(CFG_ENV_SIZE + 2048*1024) =0x210000 ;   CFG_ENV_SIZE	= 0x10000
             CFG_GBL_DATA_SIZE=128	*/
	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
	sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ  /*include/configs/smdk2440.h*/
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  //8K+4K
#endif
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
#endif   //#if 0

	@ copy u-boot to RAM
	ldr	r0, _TEXT_BASE //置第1个参数: UBOOT在RAM中的起始地址
	mov     r1, #0x0   //设置第2个参数:NAND闪存的起始地址
	//CFG_UBOOT_SIZE=0x40000=256k
	mov	r2, #CFG_UBOOT_SIZE  // 设置第3个参数: U-BOOT的长度(256KB)
	bl	nand_read_ll   //调用nand_read_whole(),把NAND闪存中的数据读入到RAM中

	tst	r0, #0x0 // 如果函数的返回值为0,表示执行成功
	beq	ok_nand_read  //执行内存比较，把RAM中的前4K内容与NAND闪存中的前4K内容进行比较, 如果完全相同, 则表示搬移成功
#ifdef CONFIG_DEBUG_LL
bad_nand_read:
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
1:	b	1b		@ infinite loop
#endif

ok_nand_read:
#ifdef CONFIG_DEBUG_LL
	ldr	r0, STR_OK
	ldr	r1, SerBase
	bl	PrintWord
#endif

	@ verify
	mov	r0, #0
	@ldr	r1, =0x33f00000
	ldr	r1, _TEXT_BASE
	mov	r2, #0x400	@ 4 bytes * 1024 = 4K-bytes
go_next:
	ldr	r3, [r0], #4
	ldr	r4, [r1], #4
	teq	r3, r4
	bne	notmatch
	subs	r2, r2, #4
	beq	done_nand_read
	bne	go_next
notmatch:
#ifdef CONFIG_DEBUG_LL
	sub	r0, r0, #4
	ldr	r1, SerBase
	bl	PrintHexWord
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
#endif

#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x4
        STR   R1,   [R0]
#endif
1:	b	1b
done_nand_read:
#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x2
        STR   R1,   [R0]
#endif

#endif /* NAND_BOOT */
#endif	/* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
	/* 初始化堆栈*/
stack_setup:
	ldr	r0, _TEXT_BASE		/*上面是128kib重定位的u-boot*/
	/*在smdk244.h中定义 #define CFG_MALLOC_LEN		(CFG_ENV_SIZE + 2048*1024)
	                    #define CFG_ENV_SIZE	    0x10000 
			   #define CFG_GBL_DATA_SIZE	128	*/
	sub	r0, r0, #CFG_MALLOC_LEN	/*向下是内存分配空间*/
	sub	r0, r0, #CFG_GBL_DATA_SIZE /*然后是bdinfo结构体地址空间*/
#ifdef CONFIG_USE_IRQ  //在 smdk2440.h中定义。
    /*在smdk244.h中定义#define CONFIG_STACKSIZE_IRQ	(8*1024)	
                                                 #define CONFIG_STACKSIZE_FIQ	(4*1024)	 */
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
	sub	sp, r0, #12		/*为 abort-stack 预留3个字,得到最终sp指针初始值*/

clear_bss:
	ldr	r0, _bss_start		/*找到bss 段起始地址。*/
	ldr	r1, _bss_end		/* bss 段末尾地址。*/
	mov r2, #0x00000000		/* 清零。*/

clbss_l:str	r2, [r0]		/*bss 段地址空间清零循环。。。*/
	add	r0, r0, #4
	cmp	r0, r1
	ble	clbss_l
#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x1
        STR   R1,   [R0]
#endif
     /*跳转到start_armboot函数入口，_start_armboot字保存函数入口指针*/
	ldr	pc, _start_armboot

//_start_armboot=start_armboot
//pc=start_armboot;
//去执行void start_armboot (void)，在lib_arm/boarb.c中。
_start_armboot:	.word start_armboot


/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */

//功能:设置CP15寄存器 这里完成的功能:失效Icache和Dcache,禁能MMU和cache 
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
//关键的初始化子程序。
cpu_init_crit:
	 /*  flush v4 I/D caches  | 失效指令cache和数据cache       */
	mov	r0, #0
	//使I/D cache失效：将寄存器r0的数据传送到协处理器p15的c7中。C7寄存器
	//位对应cp15中的cache控制寄存器
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	//使TLB操作寄存器失效：将r0数据送到cp15的c8、c7中。C8对应TLB操作
	//寄存器
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

	/*
	 * disable MMU stuff and caches
	 */
	 /*   disable MMU stuff and caches |   禁能MMU和cache       */ 
	mrc	p15, 0, r0, c1, c0, 0 //先把c1和c0寄存器的各位置0(r0 = 0)
	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
	mcr	p15, 0, r0, c1, c0, 0

	/*
	 * before relocating, we have to setup RAM timing
	 * because memory timing is board-dependend, you will
	 * find a lowlevel_init.S in your board directory.
	 */
	mov	ip, lr
#if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)

#else
	bl	lowlevel_init  //位于board/smdk2440/lowlevel_init.S：用于完成芯片存储器的初始化，
	                             //执行完成后返回
#endif
	mov	lr, ip
	mov	pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE	72

#define S_OLD_R0	68
#define S_PSR		64
#define S_PC		60
#define S_LR		56
#define S_SP		52

#define S_IP		48
#define S_FP		44
#define S_R10		40
#define S_R9		36
#define S_R8		32
#define S_R7		28
#define S_R6		24
#define S_R5		20
#define S_R4		16
#define S_R3		12
#define S_R2		8
#define S_R1		4
#define S_R0		0

#define MODE_SVC 0x13
#define I_BIT	 0x80

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */

	.macro	bad_save_user_regs
	sub	sp, sp, #S_FRAME_SIZE
	stmia	sp, {r0 - r12}			@ Calling r0-r12
	ldr	r2, _armboot_start
	sub	r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
	sub	r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
	ldmia	r2, {r2 - r3}			@ get pc, cpsr
	add	r0, sp, #S_FRAME_SIZE		@ restore sp_SVC

	add	r5, sp, #S_SP
	mov	r1, lr
	stmia	r5, {r0 - r3}			@ save sp_SVC, lr_SVC, pc, cpsr
	mov	r0, sp
	.endm

	.macro	irq_save_user_regs
	sub	sp, sp, #S_FRAME_SIZE
	stmia	sp, {r0 - r12}			@ Calling r0-r12
	add     r8, sp, #S_PC
	stmdb   r8, {sp, lr}^                   @ Calling SP, LR
	str     lr, [r8, #0]                    @ Save calling PC
	mrs     r6, spsr
	str     r6, [r8, #4]                    @ Save CPSR
	str     r0, [r8, #8]                    @ Save OLD_R0
	mov	r0, sp
	.endm

	.macro	irq_restore_user_regs
	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
	mov	r0, r0
	ldr	lr, [sp, #S_PC]			@ Get PC
	add	sp, sp, #S_FRAME_SIZE
	subs	pc, lr, #4			@ return &amp; move spsr_svc into cpsr
	.endm

	.macro get_bad_stack
	ldr	r13, _armboot_start		@ setup our mode stack
	sub	r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
	sub	r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

	str	lr, [r13]			@ save caller lr / spsr
	mrs	lr, spsr
	str     lr, [r13, #4]

	mov	r13, #MODE_SVC			@ prepare SVC-Mode
	@ msr	spsr_c, r13
	msr	spsr, r13
	mov	lr, pc
	movs	pc, lr
	.endm

	.macro get_irq_stack			@ setup IRQ stack
	ldr	sp, IRQ_STACK_START
	.endm

	.macro get_fiq_stack			@ setup FIQ stack
	ldr	sp, FIQ_STACK_START
	.endm

/*
 * exception handlers
 */
	.align  5
undefined_instruction:
	get_bad_stack
	bad_save_user_regs
	bl 	do_undefined_instruction

	.align	5
software_interrupt:
	get_bad_stack
	bad_save_user_regs
	bl 	do_software_interrupt

	.align	5
prefetch_abort:
	get_bad_stack
	bad_save_user_regs
	bl 	do_prefetch_abort

	.align	5
data_abort:
	get_bad_stack
	bad_save_user_regs
	bl 	do_data_abort

	.align	5
not_used:
	get_bad_stack
	bad_save_user_regs
	bl 	do_not_used

#ifdef CONFIG_USE_IRQ

	.align	5
irq:
	get_irq_stack
	irq_save_user_regs
	bl 	do_irq
	irq_restore_user_regs

	.align	5
fiq:
	get_fiq_stack
	/* someone ought to write a more effiction fiq_save_user_regs */
	irq_save_user_regs
	bl 	do_fiq
	irq_restore_user_regs

#else

	.align	5
irq:
	get_bad_stack
	bad_save_user_regs
	bl 	do_irq

	.align	5
fiq:
	get_bad_stack
	bad_save_user_regs
	bl 	do_fiq

#endif
</pre><img src ="http://www.cnitblog.com/yuhensong/aggbug/86709.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2012-10-30 16:49 <a href="http://www.cnitblog.com/yuhensong/archive/2012/10/30/86709.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Win7]Powercfg 命令 </title><link>http://www.cnitblog.com/yuhensong/archive/2012/06/05/80854.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Tue, 05 Jun 2012 07:27:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2012/06/05/80854.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/80854.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2012/06/05/80854.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/80854.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/80854.html</trackback:ping><description><![CDATA[<p>最近遇到一个设置系统sleep状态的case，最后从客户那里得到了设置方法~就是用Powercfg 命令</p>
<p><span style="background-color: #99cc00">powercfg -energy</span></p>
<p>顺便找了一些powercfg的其他命令行选项在下面：</p>
<p><strong>powercfg</strong> [<strong>-l</strong>] [<strong>-q </strong>] [<strong>-x</strong>] [<strong>-changename</strong>] [<strong>-duplicatescheme</strong>] [<strong>-d</strong>] [<strong>-deletesetting</strong>] [<strong>-setactive</strong>] [<strong>-getactivescheme</strong>] [<strong>-setacvalueindex</strong>] [<strong>-setdcvalueindex</strong>] [<strong>-h</strong>] [<strong>-a</strong>] [<strong>-devicequery</strong>] [<strong>-deviceenablewake</strong>] [<strong>-devicedisablewake</strong>] [<strong>-import</strong>] [<strong>-export</strong>] [<strong>-lastwake</strong>] [<strong>-?</strong>][<strong>-aliases</strong>] [<strong>-setsecuritydescriptor</strong>] [<strong>-getsecuritydescriptor</strong>]</p>
<table><br />
<tbody>
<tr>
<th style="text-align: left">选项&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </th>
<th style="text-align: left">描述&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </th></tr>
<tr>
<td>
<p><strong>-</strong><strong>list</strong></p>
<p><strong>-</strong><strong>l</strong></p></td>
<td>
<p>列出当前用户环境中的所有电源方案。</p>
<p>例如： </p>
<p><strong>powercfg -list</strong></p></td></tr>
<tr>
<td>
<p><strong>-</strong><strong>query</strong> [<em>Scheme_GUID</em>] [<em>Sub_GUID</em>]</p>
<p><strong>-</strong><strong>q</strong> [<em>Scheme_GUID</em>] [<em>Sub_GUID</em>]</p></td>
<td>
<p>显示指定的电源方案的内容。</p>
<p>用法： </p>
<p><strong>powercfg -query</strong> [<em>Scheme_GUID</em>] [<em>Sub_GUID</em>]</p>
<p><em>SCHEME_GUID</em></p>
<p>（可选）指定要显示的电源方案的 GUID。可以使用 <strong>powercfg -l</strong> 命令获取。</p>
<p><em>SUB_GUID</em></p>
<p>（可选）指定要显示的子组的 GUID。要求提供 <em>SCHEME_GUID</em>。</p>
<p>如果未提供 <em>SCHEME_GUID</em> 和 <em>SUB_GUID</em>，则显示当前用户的活动电源方案的设置。</p>
<p>如果未指定 <em>SUB_GUID</em>，则显示指定电源方案中的所有设置。</p></td></tr>
<tr>
<td>
<p><strong>-</strong><strong>change</strong><em>setting</em><em>value</em></p>
<p><strong>-</strong><strong>x</strong><em>setting value</em></p></td>
<td>
<p>修改当前电源方案中的设置值。</p>
<p>用法： </p>
<p><strong>powercfg</strong><strong>-x</strong><em>setting value</em></p>
<p><em>设置</em></p>
<p>指定以下设置之一：</p>
<p><strong>-</strong><strong>monitor-timeout-ac</strong><em>分钟</em></p>
<p><strong>-</strong><strong>monitor-timeout-dc</strong><em>分钟</em></p>
<p><strong>-</strong><strong>disk-timeout-ac</strong><em>分钟</em></p>
<p><strong>-</strong><strong>disk-timeout-dc</strong><em>分钟</em></p>
<p><strong>-</strong><strong>standby-timeout-ac</strong><em>minutes</em></p>
<p><strong>-</strong><strong>standby-timeout-dc</strong><em>分钟</em></p>
<p><strong>-</strong><strong>hibernate-timeout-ac</strong><em>分钟</em></p>
<p><strong>-</strong><strong>hibernate-timeout-dc</strong><em>分钟</em></p>
<p><em>值</em></p>
<p>指定值，以分钟为单位。</p>
<p>例如：</p>
<p><strong>powercfg</strong><strong>-change</strong><strong>-monitor-timeout-ac</strong><strong>5</strong></p>
<p>这将监视器使用交流电源时的空闲超时值设置为五分钟。</p></td></tr>
<tr>
<td>
<p><strong>-</strong><strong>changename</strong><em>GUID name</em> [<em>scheme_description</em>]</p></td>
<td>
<p>修改电源方案的名称，也可以修改方案描述。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-changename</strong><em>GUID name</em><em>scheme_description</em></p>
<p><em>GUID</em></p>
<p>指定电源方案的 GUID</p>
<p><em>名称</em></p>
<p>指定电源方案的名称。</p>
<p><em>scheme_description</em></p>
<p>描述电源方案。</p>
<p>如果忽略描述，将仅更改名称。</p></td></tr>
<tr>
<td>
<p><strong>-</strong><strong>duplicatescheme</strong><em>GUID</em> [<em>DestinationGUID</em>]</p></td>
<td>
<p>复制指定的电源方案。将显示产生的 GUID（表示新方案）。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-duplicatescheme</strong><em>GUID</em> [<em>DestinationGUID</em>]</p>
<p><em>GUID</em></p>
<p>指定方案 GUID。通过使用 <strong>powercfg</strong><strong>-l</strong> 命令获取。</p>
<p><em>DestinationGUID</em></p>
<p>指定将在其中复制方案的 GUID。</p>
<p>如果省略 <em>DestinationGUID</em>，则将为重复方案创建新 GUID。</p></td></tr>
<tr>
<td>
<p><strong>-delete</strong><em>GUID</em></p>
<p><strong>-d</strong><em>GUID</em></p></td>
<td>
<p>删除带有指定 GUID 的电源方案。</p>
<p>用法： </p>
<p><strong>Powercfg</strong><strong>-delete</strong><em>GUID</em></p>
<p><em>GUID</em></p>
<p>指定方案的 GUID。使用 <strong>-list</strong> 选项获取。</p></td></tr>
<tr>
<td>
<p><strong>-deletesetting</strong><em>Sub_GUID Setting_GUID</em></p></td>
<td>
<p>删除电源设置。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-deletesetting</strong><em>Sub_GUID Setting_GUID</em></p>
<p><em>Sub_GUID</em></p>
<p>指定子组 GUID。</p>
<p><em>Setting_GUID</em></p>
<p>指定电源设置 GUID。</p></td></tr>
<tr>
<td>
<p><strong>-setactive</strong><em>Scheme_GUID</em></p>
<p><strong>-s </strong><em>Scheme_GUID</em></p></td>
<td>
<p>使计算机上指定的电源方案成为活动的方案。</p>
<p>用法： </p>
<p><strong>Powercfg</strong><strong>-setactive</strong><em>Scheme_GUID</em></p>
<p><em>Scheme_GUID</em></p>
<p>指定方案 GUID。</p></td></tr>
<tr>
<td>
<p><strong>-getactivescheme</strong></p></td>
<td>
<p>检索当前活动的电源方案。</p>
<p>用法： </p>
<p><strong>Powercfg</strong><strong>-getactivescheme</strong></p></td></tr>
<tr>
<td>
<p><strong>-setacvalueindex</strong><em>Scheme_GUID Sub_GUID Setting_GUID SettingIndex</em></p></td>
<td>
<p>设置在计算机使用交流电源供电时与指定电源设置相关联的值。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-setacvalueindex</strong><em>Scheme_GUID</em><em>Sub_GUID</em><em>Setting_GUID</em><em>SettingIndex</em></p>
<p><em>Scheme_GUID</em></p>
<p>指定电源方案 GUID。使用 <strong>-l</strong> 选项获取。</p>
<p><em>Sub_GUID</em></p>
<p>指定电源设置 GUID 的子组。使用 <strong>-q</strong> 选项获取。</p>
<p><em>Setting_GUID</em></p>
<p>指定单个电源设置 GUID。通过使用 <strong>-q</strong> 选项获取。</p>
<p><em>SettingIndex</em></p>
<p>指定此电源设置将会设置为可能值列表中的哪个。</p>
<p>例如：</p>
<p><strong>powercfg</strong><strong>-setacvalueindex</strong><em>Scheme_GUID Sub_GUID Setting_GUID </em><strong>5</strong></p>
<p>这会将电源设置的交流电源值设置为此电源设置可能值列表中的第五项。</p></td></tr>
<tr>
<td>
<p><strong>-setdcvalueindex</strong><em>Scheme_GUID Sub_GUID Setting_GUID SettingIndex</em></p></td>
<td>
<p>设置在计算机使用直流电源供电时与指定电源设置相关联的值。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-setdcvalueindex</strong><em>Scheme_GUID Sub_GUID Setting_GUID SettingIndex</em></p>
<p><em>Scheme_GUID</em></p>
<p>指定电源方案 GUID。通过使用 <strong>-l</strong> 选项获取。</p>
<p><em>Sub_GUID</em></p>
<p>指定电源设置 GUID 的子组。通过使用 <strong>-q</strong> 选项获取。</p>
<p><em>Setting_GUID</em></p>
<p>指定单个电源设置 GUID。通过使用 <strong>-q</strong> 选项获取。</p>
<p><em>SettingIndex</em></p>
<p>指定此电源设置将设置为可能值的列表中的哪一个。</p>
<p>例如：</p>
<p><strong>powercfg</strong><strong>-setdcvalueindex</strong><em>Scheme_GUID Sub_GUID Setting_GUID </em><strong>5</strong></p>
<p>这会将电源设置的直流电源值设置为此电源设置可能值列表中的第五项。</p></td></tr>
<tr>
<td>
<p><strong>-hibernate</strong> [<strong>on</strong>|<strong>off</strong>]</p>
<p><strong>-h</strong> [<strong>on</strong>|<strong>off</strong>]</p></td>
<td>
<p>启用或禁用休眠功能。所有计算机上均不支持休眠超时。</p>
<p>例如：<strong>powercfg</strong><strong>-h on</strong></p></td></tr>
<tr>
<td>
<p><strong>-availablesleepstates</strong></p>
<p><strong>-a</strong></p></td>
<td>
<p>报告计算机上可用的睡眠状态。尝试报告睡眠状态不可用的原因。</p></td></tr>
<tr>
<td>
<p><strong>-devicequery</strong><em>query_flags</em></p></td>
<td>
<p>返回符合指定条件的设备。</p>
<p>用法： </p>
<p><strong>powercfg</strong><strong>-devicequery</strong><em>query_flags</em></p>
<p><em>query_flags</em></p>
<p>指定以下条件之一：</p>
<p><strong>wake_from_S1_supported</strong> - 返回支持将计算机从轻度睡眠状态中唤醒的所有设备。</p>
<p>例如：</p>
<p><strong>powercfg -devicequery wake_armed</strong></p></td></tr>
<tr>
<td>
<p><strong>-deviceenablewake</strong><em>devicename</em></p></td>
<td>
<p>使设备可以将计算机从睡眠状态中唤醒。</p>
<p>用法： </p>
<p><strong>powercfg</strong><strong>-deviceenablewake</strong><em>devicename</em></p>
<p><em>devicename</em></p>
<p>指定通过使用 <strong>powercfg</strong><strong>-devicequery</strong><strong>wake_programmable</strong> 命令检索的设备。</p>
<p>例如：</p>
<p><strong>powercfg</strong><strong>-deviceenablewake</strong><strong>"Microsoft USB IntelliMouse Explorer"</strong></p></td></tr>
<tr>
<td>
<p><strong>-devicedisablewake</strong><em>devicename</em></p></td>
<td>
<p>使设备不能将计算机从睡眠状态中唤醒。</p>
<p>用法：</p>
<p><strong>powercfg</strong><strong>-devicedisablewake</strong><em>devicename</em></p>
<p><em>devicename</em></p>
<p>指定通过使用 <strong>powercfg</strong><strong>-devicequery</strong><strong>wake_armed</strong> 命令检索的设备。</p></td></tr>
<tr>
<td>
<p><strong>-import </strong><em>filename</em> [<em>GUID</em>]</p></td>
<td>
<p>从指定的文件导入所有电源设置。</p>
<p>用法： </p>
<p><strong>powercfg</strong><strong>-import</strong><em>filename</em> [<em>GUID</em>]</p>
<p><em>filename</em></p>
<p>指定通过使用 <strong>powercfg</strong><strong>-export</strong> 选项生成的文件的完全限定路径。</p>
<p><em>GUID</em></p>
<p>（可选）表示加载到电源方案的设置。如果未提供，则 Powercfg 将生成并使用新的 GUID</p>
<p>例如：</p>
<p><strong>powercfg</strong><strong>-import</strong><strong>c:\scheme.pow</strong></p></td></tr>
<tr>
<td>
<p><strong>-export </strong><em>filename GUID</em></p></td>
<td>
<p>将指定 GUID 表示的电源方案导出到指定文件。</p>
<p>用法： </p>
<p><strong>powercfg -export </strong><em>filename GUID</em></p>
<p><em>filename</em></p>
<p>指定目标文件的完全限定路径。</p>
<p><em>GUID</em></p>
<p>指定电源方案 GUID。使用 <strong>-/l</strong> 选项获取。</p>
<p>例如：</p>
<p><strong>powercfg -export c:\scheme.pow 381b4222-f694-41f0-9685-ff5bb260df2e</strong></p></td></tr>
<tr>
<td>
<p><strong>-lastwake</strong></p></td>
<td>
<p>报告有关将计算机从最后一个睡眠转换中唤醒的事件的信息。</p></td></tr>
<tr>
<td>
<p><strong>-help</strong></p>
<p><strong>-?</strong></p></td>
<td>
<p>显示有关 Powercfg 命令行选项的信息。</p></td></tr>
<tr>
<td>
<p><strong>-aliases</strong></p></td>
<td>
<p>显示所有别名及其相应的 GUID。用户可能在命令提示符处使用这些别名来代替任意 GUID</p></td></tr>
<tr>
<td>
<p><strong>-setsecruitydescriptor </strong>[<em>GUID</em>|<em>Action</em>] <em>SDDL</em></p></td>
<td>
<p>设置与指定的电源设置、电源方案或操作相关联的安全描述符。</p>
<p>用法：</p>
<p><strong>powercfg -setsecuritydescriptor</strong> [<em>GUID</em>|<em>Action</em>] <em>SDDL</em></p>
<p><em>GUID</em></p>
<p>指定电源方案或电源设置 GUID。</p>
<p><em>Action</em></p>
<p>指定以下字符串之一：<strong>ActionSetActive</strong>、<strong>ActionCreate</strong>、<strong>ActionDefault</strong></p>
<p><em>SDDL</em></p>
<p>指定 SDD 格式的有效的安全描述符字符串。调用 <strong>powercfg -getsecuritydescriptor</strong> 来查看示例 SDDL STRING。</p></td></tr>
<tr>
<td>
<p><strong>-getsecuritydescriptor </strong>[<em>GUID</em>|<em>Action</em>]</p></td>
<td>
<p>获取与指定的电源设置、电源方案或操作相关联的安全描述符。</p>
<p>用法： </p>
<p><strong>powercfg -getsecuritydescriptor </strong>[<em>GUID</em>|<em>Action</em>]</p>
<p><em>GUID</em></p>
<p>指定电源方案或电源设置 GUID。</p>
<p><em>Action</em></p>
<p>指定以下一个字符串：<strong>ActionSetActive</strong>、<strong>ActionCreate</strong>、<strong>ActionDefault</strong></p></td></tr></tbody></table><img src ="http://www.cnitblog.com/yuhensong/aggbug/80854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2012-06-05 15:27 <a href="http://www.cnitblog.com/yuhensong/archive/2012/06/05/80854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>64-bit EFI和SMM</title><link>http://www.cnitblog.com/yuhensong/archive/2009/11/09/62491.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Mon, 09 Nov 2009 10:26:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2009/11/09/62491.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/62491.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2009/11/09/62491.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/62491.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/62491.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果EFI支持64-bit的话，那么就可以启动Windows 7, 还不是因为MS不好好支持32-bit，这样就不需要CSM module了<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么如果EFI支持64-bit的话，SMM driver也就变成64-bit了，这个时候SMM就必须从Real mode 转成64-bit protect mode，其实主要的问题就是CPU的mode是IA-32e mode，这是由CPU的一个寄存器来决定的，具体的就是MSR（C0000080h）的bit8，所以在SMI handler中就需要load 64-bit的GDT，然后切成保护模式之前，设置CPU的这个寄存器，使之变成64-bit，其他的和32-bit的一模一样，就可以去执行64-bit的C程序了<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要强调的是，64-bit汇编code中，eax就用rax了，等等。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 贴一张图吧，说明一下CPU的不同模式：<br><img style="WIDTH: 911px; HEIGHT: 616px" height=616 src="http://www.cnitblog.com/images/cnitblog_com/yuhensong/mode.JPG" width=911 border=0></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/62491.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2009-11-09 18:26 <a href="http://www.cnitblog.com/yuhensong/archive/2009/11/09/62491.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于ACPI table的基本概念和图示</title><link>http://www.cnitblog.com/yuhensong/archive/2009/10/21/62042.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Wed, 21 Oct 2009 08:04:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2009/10/21/62042.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/62042.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2009/10/21/62042.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/62042.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/62042.html</trackback:ping><description><![CDATA[&nbsp;
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ACPI Table</span><span>是</span><span>BIOS</span><span>提供给</span><span>OSPM</span><span>的硬件配置数据，包括系统硬件的电源管理和配置管理，</span><span>ACPI Table</span><span>有很多表，根据存储的位置，可以分为：</span></p>
<p><span><span>1）&nbsp;</span></span><span>RSDP</span><span>位于</span><span>F</span><span>段，用于</span><span>OSPM</span><span>搜索</span><span>ACPI Table</span><span>，</span><span>RSDP</span><span>可以定位其他所有</span><span>ACPI Table</span></p>
<p><span><span>2）&nbsp;</span></span><span>FACS</span><span>位于</span><span>ACPI NVS</span><span>内存，用于系统进行</span><span>S3</span><span>保存的恢复指针，内存为</span><span>NV Store</span></p>
<p><span><span>3）&nbsp;</span></span><span>剩下所有</span><span>ACPI Table</span><span>都位于</span><span>ACPI Reclaim</span><span>内存，进入</span><span>OS</span><span>后，内存可以释放</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ACPI Table</span><span>根据版本又分为</span><span>1.0B</span><span>，</span><span>2.0</span><span>，</span><span>3.0，4.0</span><span>。</span><span>2.0</span><span>以后，支持了</span><span>64-bit</span><span>的地址空间，因此几个重要的</span><span>Table</span><span>会不大一样，比如：</span><span>RSDP</span><span>，</span><span>RSDT</span><span>，</span><span>FADT</span><span>，</span><span>FACS</span><span>。简单的列举一下不同版本的</span><span>ACPI Table</span><span>：</span></p>
<p><span><span>1）&nbsp;</span></span><span>ACPI 1.0B</span><span>：</span><span>RSDP1</span><span>，</span><span>RSDT</span><span>，</span><span>FADT1</span><span>，</span><span>FACS1</span><span>，</span><span>DSDT</span><span>，</span><span>MADT</span><span>，</span><span>SSDT</span><span>，</span><span>HPET</span><span>，</span><span>MCFG</span><span>等</span></p>
<p><span><span>2）&nbsp;</span></span><span>ACPI 3.0 </span><span>：</span><span>RSDP3</span><span>，</span><span>RSDT</span><span>，</span><span>XSDT</span><span>，</span><span>FADT3</span><span>，</span><span>FACS3</span><span>，</span><span>DSDT</span><span>，</span><span>MADT</span><span>，</span><span>HPET</span><span>，</span><span>MCFG</span><span>，</span><span>SSDT</span><span>等</span></p>
<p><span>以系统支持</span><span>ACPI3.0</span><span>为例子，说明系统中</span><span>ACPI table</span><span>之间的关系如图：<br></span></p>
<p>&nbsp;</p>
<p><img style="WIDTH: 556px; HEIGHT: 363px" height=363 src="http://www.cnitblog.com/images/cnitblog_com/yuhensong/acpitable.JPG" width=556 border=0>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;<span>其中绿色代表在内存</span><span>F</span><span>段，蓝色是</span><span>ACPI Reclaim</span><span>内存，红色是</span><span>NV store</span><span>内存</span></p>
<span><br clear=all></span>
<p>&nbsp;</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/62042.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2009-10-21 16:04 <a href="http://www.cnitblog.com/yuhensong/archive/2009/10/21/62042.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于C语言中+和|的区别 （原创）</title><link>http://www.cnitblog.com/yuhensong/archive/2009/05/22/58700.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 22 May 2009 05:18:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2009/05/22/58700.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/58700.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2009/05/22/58700.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/58700.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/58700.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 当我们在coding的时候，使用两个变量相加的情况，或者用 +，或者用 | ，都是没有问题，比如：<br>&nbsp;&nbsp;&nbsp; 0x1000 + 0x55 = 0x1055<br>&nbsp;&nbsp;&nbsp; 0x1000 | 0x55&nbsp;&nbsp;= 0x1055<br>&nbsp;&nbsp;&nbsp; 介于以前这种固有的思维，因此没有把其中不同仔细考虑，直到这几天的bug，才恍然大悟，还是因为基础知识的不扎实和习惯性的思维导致这个bug，不过也给我了一个机会，彻底的搞清楚这两个运算符在变量相加的时候的区别。<br>&nbsp;&nbsp;&nbsp; 因为code是这么定义的：<br>#define PCI_ADDR(bus,device,func,reg)&nbsp; (UINT64)(bus&lt;&lt;24 + device&lt;&lt;16 + func&lt;&lt;8 + reg ) &amp; 0x00000000FFFFFFFF<br>#define DRAM_PCI&nbsp;&nbsp;&nbsp; PCI_ADDR(0,0,3,0)<br>&nbsp;&nbsp;&nbsp;&nbsp;UINT64 Addr；<br>&nbsp;&nbsp;&nbsp;&nbsp;假如我要访问寄存器0x55<br>&nbsp;&nbsp;&nbsp; （1） Addr = DRAM_PCI + 0x55;<br>&nbsp;&nbsp;&nbsp;&nbsp;（2） Addr = DRAM_PCI&nbsp; | 0x55;<br>&nbsp;&nbsp;&nbsp;&nbsp; 那么请问（1）和（2）相等吗？ <br>&nbsp;&nbsp;&nbsp;&nbsp; 答案是： （1） Addr = 0；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2） Addr = RealValue;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; 那么为什么在（1）中，Addr = 0呢，问题还是出在PCI_ADDR这个宏定义上：<br>&nbsp;&nbsp;&nbsp;&nbsp; 因为宏定义最后做了一个与运算，所以在之后的运算中就需要和 + 或者 | 进行优先级的比较，由于+&nbsp; 》 &amp;&nbsp; 》 | ，因此当使用 | 的时候，就不会出现问题，能够和我们想要的运算一致；当使用 + 的时候，由于 + 比 &amp; 优先级高，因此就率先计算了 0x00000000FFFFFFFF + 0x55，导致得到了新值 0x0000000100000054，然后和之前的数值进行 &amp;， 不就得到了 0 嘛<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #0000ff">所以得到的经验教训：<br></span>&nbsp;&nbsp;&nbsp;&nbsp; 1）在复杂的定义面前不能想当然的去使用自己认为没有问题的运算符，因为检查这个问题可不是这么容易找到根源的。<br>&nbsp;&nbsp;&nbsp;&nbsp; 2）在进行宏定义的时候最好给整个宏加上括号，那么就可以避免很多优先级的问题，因为调用这个宏的人可能多种多样。<br>&nbsp;&nbsp;&nbsp;&nbsp; 3）尽可能的使用最简单的运算符进行coding，可以避免一些问题，当然如果反复调用的情况下，还是需要定义宏，当然定义要慎重，参考2）<br>&nbsp;&nbsp;&nbsp;&nbsp; 4）基础很重要啊，要能快速的找到问题的根源还是需要熟悉各种运算符的优先级，这次又好好的复习了一下。<br><br><span style="COLOR: red">顺便附上C语言中常用运算符的优先级：</span><br>1 () [] -&gt; .&nbsp;&nbsp; ::&nbsp; ! ~ ++ -- <br>2 - (unary) * (dereference)&nbsp; &amp; (address of) sizeof <br>3 -&gt;* .* <br>4 * (multiply) / % <br>5 + - <br>6 &lt;&lt; &gt;&gt; <br>7 &lt; &lt;= &gt; &gt;= <br>8 == != <br>9 &amp; (bitwise AND) <br>10 ^ <br>11 | <br>12 &amp;&amp; <br>13 || <br>14 ? : <br>15 = += -= etc. <br>16 , <br></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/58700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2009-05-22 13:18 <a href="http://www.cnitblog.com/yuhensong/archive/2009/05/22/58700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Standby Suspend Sleep and Hibernate</title><link>http://www.cnitblog.com/yuhensong/archive/2008/06/18/45849.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Wed, 18 Jun 2008 06:54:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2008/06/18/45849.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/45849.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2008/06/18/45849.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/45849.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/45849.html</trackback:ping><description><![CDATA[<div>USER ISSUE<br>What is the difference between sleep, standby, suspend, and hibernate?</div>
<div>GENERAL INFORMATION<br>&nbsp; Computers typically offer various power saving modes. The names for these modes will be something like standby, suspend, sleep, and hibernate. Typically the standby, suspend and sleep modes require that the computer be left on to some degree, and that it <font color=#ff0000>stay connected to power</font> (battery or AC). While in these modes, the hard drive usually stops running, the display turns off, and the fans might even turn off. However, the computer is still keeping in <font color=#ff0000>active memory </font>everything that was running and open just prior to being put in a low power mode. The hibernate mode allows you to turn off the computer completely and even unplug it from power. When it turns back on, the screen should show you exactly what you were were working on just prior to putting it in hibernate mode.</div>
<div>&nbsp;&nbsp; Because standby, suspend and sleep modes keep all the information <font color=#ff0000>in memory</font>, it is typically <font color=#ff0000>quicker</font> to start working again after being in these modes. Resuming work from the hibernate mode typically takes more time because it requires starting up the computer and loading everything <font color=#ff0000>into memory from the hard drive </font>again (although you don't need to manually start the programs and load the files because the computer will restore everything to the state it was in previously).</div>
<div>&nbsp;&nbsp; Depending on the computer and configuration, some cleanup tasks may be performed at system startup and shut down. So, some people prefer to simply shut down a computer when the are done using it. Some people suggest that it is best to leave computers on. However, if we consider the computer to be like any other appliance, then it makes sense to simply turn it off when it is not in use just as we would with a television set, dish washer, microwave, coffee pot, or any other appliance.</div>
<div><font color=#333399>休眠功能的特点 </font></div>
<div>与普通开机过程比较，休眠状态有以下的特点： <br>　　1.可以随时进入休眠状态，无须将所有工作储存起来，并关闭一个又一个的应用软件。因为休眠所保存的是当前的&#8220;状态&#8221;，所有打开的程序、设置及窗口排列等都不会改变。 <br>　　2.开机和关机的过程很快，相对正常关机和开机，休眠到硬盘（STD）至唤醒所需的时间可以快20%以上，而休眠到内存（STR）的关机和开机过程只需5秒钟。 <br>　　3.对笔记本电脑来说，当电池即将耗尽而又不能得到外接电源补给的时候，迅速进入休眠状态是保证当前工作不会丢失的唯一自保方法。 </div>
<div><font color=#333399>休眠功能的分类</font> </div>
<div>&nbsp;　　台式电脑和笔记本电脑的休眠模式也各有特色，一般而言后者的休眠方式比较全面和复杂。但总体来说都可分为STD和STR方式，而后者又细分成S1、S3及S1&amp;&amp;S3模式。 <br>（一）ＳＴＤ模式（Ｓｕｓｐｅｎｄ ｔｏ Ｄｉｓｋ，休眠到磁盘） <br>　　STD的特点是将电脑内存中的状态复制到硬盘，因为内存中的资料就是电脑当前状态的写照，所以保存这些资料就完整保留了电脑中的状态。STD在Windows中称为&#8220;Hibernate&#8221;（休眠），要在控制面板的电源管理中进行设置（开始&#8594;设置&#8594;控制面板&#8594;电源管理&#8594;休眠&#8594;启用休眠功能）。其特点是会在硬盘中永久占用空间作为保存内存资料之用。很明显，内存容量有多大，需要占用的硬盘空间就有多大。 <br>　　看到这里，大家一定会联想到，在STD状态下，电脑内存容量越大，进入休眠和唤醒的过程也就越慢。当然，对于内存中没有资料的部分，硬盘也不会全部读写，所以时间比完全读写要快一些，但总的来说速度仍然较慢。 <br>　　不过STD也有优点，就是当资料复制到硬盘后，即使电源完全中断，资料也不会丢失。因此对笔记本电脑来说，STD是最好的选择。 <br>（二）ＳＴＲ模式：（Ｓｕｓｐｅｎｄ ｔｏ ＲＡＭ，休眠到内存） <br>　　STR是在进入休眠状态时，只保留内存和主板芯片组的供电，而关闭其他部分。由于所有资料本来就在内存中，因此速度之快超乎想像。无论是台式电脑或笔记本电脑都可以利用此方式作休眠，它在Windows中被称为&#8220;Suspend&#8221;。 <br>　　其中Suspend状态又可分为S1与S3。S1模式的休眠程度较浅，当休眠时，硬盘、处理器和其他设备都会停止工作，但处理器和显示卡的风扇仍然会运转，机箱电源也仍然在工作。因此S1的省电程度较低，但进入和唤醒速度最快，兼容性也比较好(我的机器就是这个，suspend以后机箱里还有风扇的声音并且洞口有风进入说明电源风扇还在转)。而S3就仿佛彻底关机一样，除了电源指示灯会闪烁之外，所有风扇全部停转。此模式的耗电最少，速度也够快。笔记本电脑通常都以此模式运作，达到最省电和无噪音的效果。而台式电脑采用此模式后，基本上无须关机，不用电脑的时候直接在关机菜单中选择&#8220;Standby&#8221;就行了。 <br>　　STR的缺点就是很容易因为第三方驱动程序的兼容性问题使得系统无法正常进入Suspend状态。此外，如果主板BIOS对ACPI的支持不完善，也会使STR功能无法使用。其中S3模式出现问题的几率比S1模式多，因此很多主板都具备S1&amp;&amp;S3模式，并可让操作系统自动选择。但另外一个重要的前提就是机箱电源的+5V Standby插头必须能输出750mA以上电流，否则计算机将&#8220;长眠不醒&#8221;。</div>
<div>　　绝大多数笔记本电脑同时支持多种电源管理模式，通常当用户在Windows中选择&#8220;Standby&#8221;或者按下电源开关，就会进入Suspend状态。而当用户合上屏幕，则会进入Hibernate状态。当然，不管使用哪种模式，即使电脑不进入休眠或待机状态，我们都可以设置当某种设备闲置一定时间后就自动关闭，以便省电。 <br>　　只要大家充分了解和应用电脑的休眠功能，既能达到省电的目的，又可以让电脑在开机和关机时更加迅速，不是有一举两得的功效吗？ <br><br>缩写：<br>S1 or S3&nbsp;&nbsp;= standby&nbsp;&nbsp;&nbsp; = 待机&nbsp; = STR<br>S4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= Hibernate&nbsp; = 休眠 = STD<br></div><img src ="http://www.cnitblog.com/yuhensong/aggbug/45849.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2008-06-18 14:54 <a href="http://www.cnitblog.com/yuhensong/archive/2008/06/18/45849.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数指针和指针函数的基本概念（ZZ）</title><link>http://www.cnitblog.com/yuhensong/archive/2008/06/13/45663.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 13 Jun 2008 07:12:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2008/06/13/45663.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/45663.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2008/06/13/45663.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/45663.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/45663.html</trackback:ping><description><![CDATA[<p><font size=2><font color=#0000ff>【函数指针】</font><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在程序运行中，函数代码是程序的算法指令部分，它们和数组一样也占用存储空间，都有相应的地址。可以使用指针变量指向数组的首地址，也可以使用指针变量指向函数代码的首地址，指向函数代码首地址的指针变量称为函数指针。</font></p>
<p><font size=2>1．函数指针定义</font></p>
<p><font size=2>函数类型 （*指针变量名）(形参列表)；</font></p>
<p><font size=2>&#8220;函数类型&#8221;说明函数的返回类型，由于&#8220;()&#8221;的优先级高于&#8220;*&#8221;,所以指针变量名外的括号必不可少，后面的&#8220;形参列表&#8221;表示指针变量指向的函数所带的参数列表。</font></p>
<p><font size=2>例如：</font></p>
<p><font size=2>int (*f)(int x);</font></p>
<p><font size=2>double (*ptr)(double x);</font></p>
<p><font size=2>在定义函数指针时请注意：<br>&nbsp;&nbsp;&nbsp; <br>函数指针和它指向的函数的参数个数和类型都应该是—致的；</font></p>
<p><font size=2>函数指针的类型和函数的返回值类型也必须是一致的。</font></p>
<p><font size=2>2．函数指针的赋值</font></p>
<p><font size=2>函数名和数组名一样代表了函数代码的首地址，因此在赋值时，直接将函数指针指向函数名就行了。</font></p>
<p><font size=2>例如，</font></p>
<p><font size=2>int func(int x);&nbsp;&nbsp; /* 声明一个函数 */</font></p>
<p><font size=2>int (*f) (int x);&nbsp;&nbsp;&nbsp; /* 声明一个函数指针 */</font></p>
<p><font size=2>f=func;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 将func函数的首地址赋给指针f */</font></p>
<p><font size=2>赋值时函数func不带括号，也不带参数，由于func代表函数的首地址，因此经过赋值以后，指针f就指向函数func(x)的代码的首地址。</font></p>
<p><font size=2>3．通过函数指针调用函数</font></p>
<p><font size=2>函数指针是通过函数名及有关参数进行调用的。</font></p>
<p><font size=2>与其他指针变量相类似，如果指针变量pi是指向某整型变量i的指针，则*p等于它所指的变量i；如果pf是指向某浮点型变量f的指针，则*pf就等价于它所指的变量f。同样地，*f是指向函数func(x)的指针，则*f就代表它所指向的函数func。所以在执行了f=func;之后，(*f)和func代表同一函数。</font></p>
<p><font size=2>由于函数指针指向存储区中的某个函数，因此可以通过函数指针调用相应的函数。现在我们就讨论如何用函数指针调用函数，它应执行下面三步：</font></p>
<p><font size=2>首先，要说明函数指针变量。</font></p>
<p><font size=2>例如：int (*f)(int x);</font></p>
<p><font size=2>其次，要对函数指针变量赋值。</font></p>
<p><font size=2>例如： f=func;&nbsp;&nbsp;&nbsp; (func(x)必须先要有定义)</font></p>
<p><font size=2>最后，要用 (*指针变量)(参数表);调用函数。</font></p>
<p><font size=2>例如：&nbsp;&nbsp;&nbsp; (*f)(x);(x必须先赋值)</font></p>
<p><br><font size=2>【例】任意输入n个数，找出其中最大数，并且输出最大数值。</font></p>
<p><font size=2>main()</font></p>
<p><font size=2>{</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int f();</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i，a，b;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*p)();&nbsp;&nbsp;&nbsp; /* 定义函数指针 */</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scanf("%d"，&amp;a);</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p=f;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 给函数指针p赋值，使它指向函数f */</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i＝1;i&lt;9;i++)</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scanf("%d"，&amp;b);</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a＝(*p)(a，b);&nbsp;&nbsp;&nbsp; /* 通过指针p调用函数f */</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("The Max Number is:%d"，a)</font></p>
<p><font size=2>}</font></p>
<p><br><font size=2>f(int x，int y)</font></p>
<p><font size=2>{</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; int z;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; z＝(x&gt;y)?x:y;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; return(z);</font></p>
<p><font size=2>}</font></p>
<p><font size=2>运行结果为：</font></p>
<p><font size=2>343 -45 4389 4235 1 -534 988 555 789↙</font></p>
<p><font size=2>The Max Number is：4389</font></p>
<p><br><font color=#0000ff size=2>【指针函数】</font></p>
<p><font size=2>一个函数不仅可以带回一个整型数据的值，字符类型值和实型类型的值，还可以带回指针类型的数据，使其指向某个地址单元。</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回指针的函数，一般定义格式为：</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型标识符&nbsp;&nbsp;&nbsp; *函数名(参数表)</font></p>
<p><font size=2>int *f(x，y);</font></p>
<p><font size=2>其中x，y是形式参数，f是函数名，调用后返回一个指向整型数据的地址指针。f(x，y)是函数，其值是指针。</font></p>
<p><font size=2>如：char *ch();表示的就是一个返回字符型指针的函数，请看下面的例题：</font></p>
<p><font size=2>【例】将字符串1(str1)复制到字符串2(str2)，并输出字符串2.</font></p>
<p><font size=2>#include "stdio.h"</font></p>
<p><font size=2>main()</font></p>
<p><font size=2>{</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; char *ch(char *，char *);</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; char str1[]="I am glad to meet you!";</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; char str2[]="Welcom to study C!";</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; printf("%s"，ch(str1，str2));</font></p>
<p><font size=2>}</font></p>
<p><font size=2>char *ch(char *str1，char *str2)</font></p>
<p><font size=2>{</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; int i;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; char *p;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; p=str2<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; if(*str2==NULL) exit(-1);</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; do</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; { </font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *str2=*str1;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str1++;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str2++;</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; }while(*str1!=NULL);</font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; return(p);</font></p>
<p><font size=2>}</font></p>
<p><br><font size=2>通过分析可得</font></p>
<p><font size=2>函数指针是一个指向函数的指针，而指针函数只是说明他是一个返回值为指针的函数，</font></p>
<p><font size=2>函数指针可以用来指向一个函数。<br></font></p><img src ="http://www.cnitblog.com/yuhensong/aggbug/45663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2008-06-13 15:12 <a href="http://www.cnitblog.com/yuhensong/archive/2008/06/13/45663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BDA - BIOS Data Area - PC Memory Map[ZZ]</title><link>http://www.cnitblog.com/yuhensong/archive/2007/10/25/35322.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Thu, 25 Oct 2007 07:38:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/10/25/35322.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/35322.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/10/25/35322.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/35322.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/35322.html</trackback:ping><description><![CDATA[<pre>	Address Size	   Description
00:00 256dwords Interrupt vector table
30:00 256bytes	Stack area used during post and bootstrap
40:00	word	COM1 port address
40:02	word	COM2 port address
40:04	word	COM3 port address
40:06	word	COM4 port address
40:08	word	LPT1 port address
40:0A	word	LPT2 port address
40:0C	word	LPT3 port address
40:0E	word	LPT4 port address (except PS/2)
Extended BIOS Data Area segment (PS/2, see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/ebda.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/ebda.html"><font color=#a70002>EBDA</font></a>)
40:10  2 bytes	Equipment list flags (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int11.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int11.html"><font color=#a70002>INT 11</font></a>)
|7|6|5|4|3|2|1|0| 40:10 (value in INT 11 register AL)
| | | | | | | `- IPL diskette installed
| | | | | | `-- math coprocessor
| | | | |-+-- old PC system board RAM &lt; 256K
| | | | | `-- pointing device installed (PS/2)
| | | | `--- not used on PS/2
| | `------ initial video mode
`--------- # of diskette drives, less 1
|7|6|5|4|3|2|1|0| 40:11  (value in INT 11 register AH)
| | | | | | | `- 0 if DMA installed
| | | | `------ number of serial ports
| | | `------- game adapter
| | `-------- not used, internal modem (PS/2)
`----------- number of printer ports
40:12	byte	PCjr: infrared keyboard link error count
40:13	word	Memory size in Kbytes  (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int12.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int12.html"><font color=#a70002>INT 12</font></a>)
40:15	byte	Reserved
40:16	byte	PS/2 BIOS control flags
40:17	byte	Keyboard flag byte 0 (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/kbflags.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/kbflags.html"><font color=#a70002>KB FLAGS</font></a>)
|7|6|5|4|3|2|1|0| keyboard flag byte 0
| | | | | | | `--- right shift key depressed
| | | | | | `---- left shift key depressed
| | | | | `----- CTRL key depressed
| | | | `------ ALT key depressed
| | | `------- scroll-lock is active
| | `-------- num-lock is active
| `--------- caps-lock is active
`---------- insert is active
40:18	byte	Keyboard flag byte 1 (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/kbflags.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/kbflags.html"><font color=#a70002>KB FLAGS</font></a>)
|7|6|5|4|3|2|1|0| keyboard flag byte
| | | | | | | `--- left CTRL key depressed
| | | | | | `---- left ALT key depressed
| | | | | `----- system key depressed and held
| | | | `------ suspend key has been toggled
| | | `------- scroll lock key is depressed
| | `-------- num-lock key is depressed
| `--------- caps-lock key is depressed
`---------- insert key is depressed
40:19	byte	Storage for alternate keypad entry
40:1A	word	Offset from 40:00 to keyboard buffer head
40:1C	word	Offset from 40:00 to keyboard buffer tail
40:1E  32bytes	Keyboard buffer (circular queue buffer)
40:3E	byte	Drive recalibration status
|7|6|5|4|3|2|1|0| drive recalibration status
| | | | | | | `-- 1=recalibrate drive 0
| | | | | | `--- 1=recalibrate drive 1
| | | | | `---- 1=recalibrate drive 2
| | | | `----- 1=recalibrate drive 3
| `---------- unused
`----------- 1=working interrupt flag
40:3F	byte	Diskette motor status
|7|6|5|4|3|2|1|0| diskette motor status
| | | | | | | `-- 1=drive 0 motor on
| | | | | | `--- 1=drive 1 motor on
| | | | | `---- 1=drive 2 motor on
| | | | `----- 1=drive 3 motor on
| `---------- unused
`----------- 1=write operation
40:40	byte	Motor shutoff counter (decremented by <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int8.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int8.html"><font color=#a70002>INT 8</font></a>)
40:41	byte	Status of last diskette operation (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int13-1.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int13-1.html"><font color=#a70002>INT 13,1</font></a>)
|7|6|5|4|3|2|1|0| status of last diskette operation
| | | | | | | `--- invalid diskette command
| | | | | | `---- diskette address mark not found
| | | | | `----- sector not found
| | | | `------ diskette DMA error
| | | `------- CRC check / data error
| | `-------- diskette controller failure
| `--------- seek to track failed
`---------- diskette time-out
40:42  7 bytes	NEC diskette controller status (see <a href="http://quby.bokee.com/java%20script:if(confirm('http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/765.html%20%20/n/nThis%20file%20was%20not%20retrieved%20by%20Teleport%20Pro,%20because%20the%20server%20reports%20that%20this%20file%20cannot%20be%20found.%20%20/n/nDo%20you%20want%20to%20open%20it%20from%20the%20server?'))window.location='http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/765.html'" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/765.html"><font color=#a70002>FDC</font></a>)
40:49	byte	Current video mode  (see VIDEO MODE)
40:4A	word	Number of screen columns
40:4C	word	Size of current video regen buffer in bytes
40:4E	word	Offset of current video page in video regen buffer
40:50  8 words	Cursor position of pages 1-8, high order byte=row
low order byte=column; changing this data isn't
reflected immediately on the display
40:60	byte	Cursor ending (bottom) scan line (don't modify)
40:61	byte	Cursor starting (top) scan line (don't modify)
40:62	byte	Active display page number
40:63	word	Base port address for active <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/6845.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/6845.html"><font color=#a70002>6845</font></a> CRT controller
3B4h = mono, 3D4h = color
40:65	byte	6845 CRT mode control register value (port 3x8h)
EGA/VGA values emulate those of the MDA/CGA
40:66	byte	CGA current color palette mask setting (port 3d9h)
EGA and VGA values emulate the CGA
40:67	dword	CS:IP for 286 return from protected mode
dword	Temp storage for SS:SP during shutdown
dword	Day counter on all products after AT
dword	PS/2 Pointer to reset code with memory preserved
5 bytes	Cassette tape control (before AT)
40:6C	dword	Daily timer counter, equal to zero at midnight;
incremented by INT 8; read/set by <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int1a.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int1a.html"><font color=#a70002>INT 1A</font></a>
40:70	byte	Clock rollover flag, set when 40:6C exceeds 24hrs
40:71	byte	BIOS break flag, bit 7 is set if <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int1b.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int1b.html"><font color=#a70002>Ctrl-Break</font></a> was
*ever* hit; set by <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int9.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int9.html"><font color=#a70002>INT 9</font></a>
40:72	word	Soft reset flag via Ctl-Alt-Del or JMP FFFF:0
1234h  Bypass memory tests &amp; CRT initialization
4321h  Preserve memory
5678h  System suspend
9ABCh  Manufacturer test
ABCDh  Convertible POST loop
????h  many other values are used during POST
40:74	byte	Status of last hard disk operation (see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int13-1.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int13-1.html"><font color=#a70002>INT 13,1</font></a>)
40:75	byte	Number of hard disks attached
40:76	byte	XT fixed disk drive control byte
40:77	byte	Port offset to current fixed disk adapter
40:78  4 bytes	Time-Out value for LPT1,LPT2,LPT3(,LPT4 except PS/2)
40:7C  4 bytes	Time-Out value for COM1,COM2,COM3,COM4
40:80	word	Keyboard buffer start offset (seg=40h,BIOS 10-27-82)
40:82	word	Keyboard buffer end offset (seg=40h,BIOS 10-27-82)
40:84	byte	Rows on the screen (less 1, EGA)
40:85	word	Point height of character matrix (EGA)
byte	PCjr: character to be repeated if the typematic
repeat key takes effect
40:86	byte	PCjr: initial delay before repeat key action begins
40:87	byte	PCjr: current Fn function key number
byte	Video mode options (EGA)
|7|6|5|4|3|2|1|0| Video mode options (EGA)
| | | | | | | `-- 1=alphanumeric cursor emulation enabled
| | | | | | `--- 1=video subsystem attached to monochrome
| | | | | `---- reserved
| | | | `----- 1=video subsystem is inactive
| | | `------ reserved
| `--------- video RAM  00-64K  10-192K  01-128K  11-256K
`---------- video mode number passed to <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int10.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int10.html"><font color=#a70002>INT 10</font></a>, function 0
40:88	byte	PCjr: third keyboard status byte
EGA feature bit switches, emulated on VGA
|7|6|5|4|3|2|1|0| EGA feature bit switches (EGA)
| | | | | | | `-- EGA SW1 config (1=off)
| | | | | | `--- EGA SW2 config (1=off)
| | | | | `---- EGA SW3 config (1=off)
| | | | `----- EGA SW4 config (1=off)
| | | `------ Input FEAT0 (ISR0 bit 5) after output on FCR0
| | `------- Input FEAT0 (ISR0 bit 6) after output on FCR0
| `-------- Input FEAT1 (ISR0 bit 5) after output on FCR1
`--------- Input FEAT1 (ISR0 bit 6) after output on FCR1
40:89	byte	Video display data area (MCGA and VGA)
|7|6|5|4|3|2|1|0| Video display data area (MCGA and VGA)
| | | | | | | `-- 1=VGA is active
| | | | | | `--- 1=gray scale is enabled
| | | | | `---- 1=using monochrome monitor
| | | | `----- 1=default palette loading is disabled
| | | `------ see table below
| | `------- reserved
| `--------  1=display switching enabled
`--------- alphanumeric scan lines (see table below)
Bit7    Bit4	Scan Lines
0	0	350 line mode
0	1	400 line mode
1	0	200 line mode
1	1	reserved
40:8A	byte	Display Combination Code (DCC) table index (EGA)
40:8B	byte	Last diskette data rate selected
|7|6|5|4|3|2|1|0| last diskette data rate selected
| | | | `--------- reserved
| | `------------ last floppy drive step rate selected
`-------------- last floppy data rate selected
Data Rate 			Step Rate
00  500K bps		00  step rate time of 0C
01  300K bps		01  step rate time of 0D
10  250K bps		10  step rate time of 0A
11  reserved		11  reserved
40:8C	byte	Hard disk status returned by controller
40:8D	byte	Hard disk error returned by controller
40:8E	byte	Hard disk interrupt control flag(bit 7=working int)
40:8F	byte	Combination hard/floppy disk card when bit 0 set
40:90  4 bytes	Drive 0,1,2,3 media state
|7|6|5|4|3|2|1|0| drive media state (4 copies)
| | | | | `------- drive/media state (see below)
| | | | `------- reserved
| | | `------- 1=media/drive established
| | `------- double stepping required
`--------- data rate:	00=500K bps    01=300K bps
10=250K bps    11=reserved
Bits
210  Drive Media State
000  360Kb diskette/360Kb drive not established
001  360Kb diskette/1.2Mb drive not established
010  1.2Mb diskette/1.2Mb drive not established
011  360Kb diskette/360Kb drive established
100  360Kb diskette/1.2Mb drive established
101  1.2Mb diskette/1.2Mb drive established
110  Reserved
111  None of the above
40:94	byte	Track currently seeked to on drive 0
40:95	byte	Track currently seeked to on drive 1
40:96	byte	Keyboard mode/type
|7|6|5|4|3|2|1|0| Keyboard mode/type
| | | | | | | `--- last code was the E1 hidden code
| | | | | | `---- last code was the E0 hidden code
| | | | | `----- right CTRL key depressed
| | | | `------ right ALT key depressed
| | | `------- 101/102 enhanced keyboard installed
| | `-------- force num-lock if Rd ID &amp; KBX
| `--------- last char was first ID char
`---------- read ID in process
40:97	byte	Keyboard LED flags
|7|6|5|4|3|2|1|0| Keyboard LED flags
| | | | | | | `--- scroll lock indicator
| | | | | | `---- num-lock indicator
| | | | | `----- caps-lock indicator
| | | | `------ circus system indicator
| | | `------- ACK received
| | `-------- re-send received flag
| `--------- mode indicator update
`---------- keyboard transmit error flag
40:98	dword	Pointer to user wait complete flag
40:9C	dword	User wait Time-Out value in microseconds
40:A0	byte	RTC wait function flag
|7|6|5|4|3|2|1|0| <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int15-86.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int15-86.html"><font color=#a70002>INT 15,86</font></a> RTC wait function flag
| | | | | | | `--- 1= wait pending
| `-------------- not used
`--------------- 1=INT 15,86 wait time elapsed
40:A1	byte	LANA DMA channel flags
40:A2  2 bytes	Status of LANA 0,1
40:A4	dword	Saved hard disk interrupt vector
40:A8	dword	BIOS Video Save/Override Pointer Table address
(see <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/videoinformation.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/videoinformation.html"><font color=#a70002>VIDEO TABLES</font></a>)
40:AC  8 bytes	Reserved
40:B4	byte	Keyboard NMI control flags (convertible)
40:B5	dword	Keyboard break pending flags (convertible)
40:B9	byte	Port 60 single byte queue (convertible)
40:BA	byte	Scan code of last key (convertible)
40:BB	byte	NMI buffer head pointer (convertible)
40:BC	byte	NMI buffer tail pointer (convertible)
40:BD  16bytes	NMI scan code buffer (convertible)
40:CE	word	Day counter (convertible and after)
40:F0  16bytes	Intra-Applications Communications Area (IBM Technical
Reference incorrectly locates this at 50:F0-50:FF)
Address Size	   Description	 (BIOS/DOS Data Area)
50:00	byte	Print screen status byte
00 = PrtSc not active,
01 = PrtSc in progress
FF = error
50:01  3 bytes	Used by BASIC
50:04	byte	DOS single diskette mode flag, 0=A:, 1=B:
50:05  10bytes	POST work area
50:0F	byte	BASIC shell flag; set to 2 if current shell
50:10	word	BASICs default DS value (DEF SEG)
50:12	dword	Pointer to BASIC <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int1c.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int1c.html"><font color=#a70002>INT 1C</font></a> interrupt handler
50:16	dword	Pointer to BASIC <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int23.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int23.html"><font color=#a70002>INT 23</font></a> interrupt handler
50:1A	dword	Pointer to BASIC <a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int24.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int24.html"><font color=#a70002>INT 24</font></a> disk error handler
50:20	word	DOS dynamic storage
50:22  14bytes	DOS diskette initialization table (<a href="http://cs.uns.edu.ar/~jechaiz/organizacion/assembly/int1e.html" tppabs="http://www.iro.umontreal.ca/~feeley/cours/ift2240/doc/assembly/int1e.html"><font color=#a70002>INT 1E</font></a>)
50:30	4bytes	MODE command
70:00		I/O drivers from IO.SYS/IBMBIO.COM
</pre>
<h1 align=center>The following map varies in size and locus</h1>
<pre>	07C0:0		Boot code is loaded here at startup (31k mark)
A000:0		EGA/VGA RAM for graphics display mode 0Dh &amp; above
B000:0		MDA RAM, Hercules graphics display RAM
B800:0		CGA display RAM
C000:0		EGA/VGA BIOS ROM (thru C7FF)
C400:0		Video adapter ROM space
C600:0 256bytes PGA communication area
C800:0	 16K	Hard disk adapter BIOS ROM
C800:5		XT Hard disk ROM format, AH=Drive, AL=Interleave
D000:0	 32K	Cluster adapter BIOS ROM
D800:0		PCjr conventionalsoftware cartridge address
E000:0	 64K	Expansion ROM space (hardwired on AT)
128K	PS/2 System ROM (thru F000)
F000:0		System monitor ROM
PCjr: software cartridge override address
F400:0		System expansion ROMs
F600:0		IBM ROM BASIC (AT)
F800:0		PCjr software cartridge override address
FC00:0		BIOS ROM
FF00:0		System ROM
FFA6:E		ROM graphics character table
FFFF:0		ROM bootstrap code
FFFF:5 8 bytes	ROM date (not applicable for all clones)
FFFF:E	byte	ROM machine id	(see MACHINE ID)
</pre><img src ="http://www.cnitblog.com/yuhensong/aggbug/35322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-10-25 15:38 <a href="http://www.cnitblog.com/yuhensong/archive/2007/10/25/35322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CPU中和标志寄存器</title><link>http://www.cnitblog.com/yuhensong/archive/2007/10/12/34774.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 12 Oct 2007 08:40:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/10/12/34774.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/34774.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/10/12/34774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/34774.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/34774.html</trackback:ping><description><![CDATA[<ul>
    <li><font size=4><strong>ZF </strong>(<em>Zero Flag</em>): 零标志位。它记录相关指令执行后，其结果是否为0。 </font>
    <li><font size=4><strong>PF </strong>(<em>Parity Flag</em>): 奇偶标志位。它记录相关指令执行后，其结果的所有二进制位中1的个数是否为偶数。 </font>
    <li><font size=4><strong>SF </strong>(<em>Sign Flag</em>): 符号标志位。它记录相关指令执行后，其结果是否为负。 </font>
    <li><font size=4><strong>CF </strong>(<em>Carry Flag</em>): 进位标志位。它记录了无符号数运算结果的最高位向更高位的进位值，或从更高位的借位值。 </font>
    <li><font size=4><strong>OF </strong>(<em>Overflow Flag</em>): 溢出标志位。它记录了有符号数运算的结果是否发生了溢出。 </font>
    <li><font size=4><strong>CF</strong>和<strong>OF</strong>的区别:&nbsp;CF对无符号数运算有意义，而OF对有符号数运算有意义。 </font>
    <li><font size=4><strong>adc </strong>(<em>c - carry</em>)&nbsp;&nbsp;带进位加法指令。它利用了CF位上记录的进位值。 </font>
    <li><font size=4><strong>sbb </strong>(<em>b - borrow</em>)&nbsp;&nbsp;带借位减法指令。它利用了CF位上记录的借位值。 </font>
    <li><font size=4><strong>cmp </strong>(<em>compare</em>)&nbsp;&nbsp;比较指令。它的功能相当于减法指令，只是不保存结果。 </font>
    <li><font size=4><strong>je </strong>(<em>e - equal</em>)&nbsp;&nbsp;ZF=1则转移 <br><strong>jne </strong>(<em>ne - not equal</em>)&nbsp;ZF=0则转移 <br><strong>jb </strong>(<em>b - below</em>)&nbsp;&nbsp;CF=1则转移 <br><strong>jnb </strong>(<em>nb - not below</em>)&nbsp;CF=0则转移 <br><strong>ja </strong>(<em>a - above</em>)&nbsp;&nbsp;CF=0且ZF=0则转移 <br><strong>jna </strong>(<em>na - not above</em>)&nbsp;CF=1或ZF=1则转移 </font>
    <li><font size=4>将<strong>cmp</strong>指令和<strong>je</strong>等条件转移指令配合使用，可以实现根据比较结果进行转移的功能。 </font>
    <li><font size=4><strong>DF </strong>(<em>Direction Flag</em>)&nbsp;&nbsp;方向标志位。在串处理指令中，控制每次操作后si，di的增减，0增1减。 </font>
    <li><font size=4><strong>movesb </strong>(<em>b - byte</em>)&nbsp;&nbsp;传送一个字节。 <br><strong>movesw </strong>(<em>w - word</em>)&nbsp;传送一个字。 <br><strong>rep movesb </strong>(<em>rep - repeat</em>)&nbsp;循环执行字节串传送指令。 <br><strong>rep movesw </strong>(<em>rep - repeat</em>)&nbsp;循环执行字串传送指令。 </font>
    <li><font size=4><strong>cld </strong>(<em>clear DF</em>)&nbsp;&nbsp;将DF置0。 <br><strong>std </strong>(<em>set DF</em>)&nbsp;&nbsp;将DF置1。 </font>
    <li><font size=4><strong>pushf </strong>(<em>push flag</em>)&nbsp;&nbsp;将标志寄存器的值压栈。 </font>
    <li><font size=4><strong>popf </strong>(<em>pop flag</em>)&nbsp;&nbsp;从栈中弹出数据送入标志寄存器。 </font>
    <li><font size=4><strong>Debug</strong>中标志位的表示： </font></li>
</ul>
<blockquote dir=ltr>
<p><font size=4>标志位&nbsp;&nbsp; 值为1&nbsp;&nbsp;&nbsp; 值为0 <br>OF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OV&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NV <br>SF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PL <br>ZF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NZ <br>PF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PO <br>CF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NC <br>DF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UP</font></p>
</blockquote><img src ="http://www.cnitblog.com/yuhensong/aggbug/34774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-10-12 16:40 <a href="http://www.cnitblog.com/yuhensong/archive/2007/10/12/34774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zz]Switch to Protected Mode </title><link>http://www.cnitblog.com/yuhensong/archive/2007/08/24/32387.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 24 Aug 2007 08:39:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/08/24/32387.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/32387.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/08/24/32387.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/32387.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/32387.html</trackback:ping><description><![CDATA[<p>在8086/8088时代，处理器只存在一种操作模式（Operation Mode），当时由于不存在其它操作模式，因此这种模式也没有被命名。自从80286到80386开始，处理器增加了另外两种操作模式——保护模式PM（Protected Mode）和系统管理模式SMM（System Management Mode），因此，8086/8088的模式被命名为实地址模式RM（Real-address Mode）。 </p>
<p>PM是处理器的native模式，在这种模式下，处理器支持所有的指令和所有的体系结构特性，提供最高的性能和兼容性。对于所有的新型应用程序和操作系统来说，建议都使用这种模式。为了保证PM的兼容性，处理器允许在受保护的，多任务的环境下执行RM程序。这个特性被称做虚拟8086模式（Virtual-8086 Mode），尽管它并不是一个真正的处理器模式。Virtual-8086模式实际上是一个PM的属性，任何任务都可以使用它。</p>
<p>RM提供了Intel 8086处理器的编程环境，另外有一些扩展（比如切换到PM或SMM的能力）。当主机被Power-up或Reset后，处理器处于RM下。</p>
<p>SMM是一个对所有Intel处理器都统一的标准体系结构特性。出现于Intel386 SL芯片。这个模式为OS实现平台指定的功能（比如电源管理或系统安全）提供了一种透明的机制。当外部的SMM interrupt pin（SMI#）被激活或者从APIC（Advanced Programming Interrupt Controller）收到一个SMI，处理器将进入SMM。在SMM下，当保存当前正在运行程序的整个上下文（Context）时，处理器切换到一个分离的地址空间。然后SMM指定的代码或许被透明的执行。当从SMM返回时，处理器将回到被系统管理中断之前的状态。</p>
<p align=center><img height=232 src="http://www.xemean.net/resource/image/mode.gif" width=351></p>
<p>由于机器在Power-up或Reset之后，处理器处于RM状态，而对于Intel 80386以及其后的芯片，只有使用PM才能发挥出最大的作用。所以我们就面临着一个从RM切换到PM的问题。</p>
<p>本文不讨论SMM，本节的重点集中于在Booting阶段如何从RM切换到PM，这里不会过多的讨论PM的细节，因为《Intel Architecture Software Developer&#8217;s Manual Volume 3: System Programming》中有非常详尽和准确的介绍。</p>
<p><strong>1. What is GDT</strong></p>
<p>&#160;</p>
<p>在Protected Mode下，一个重要的必不可少的数据结构就是GDT（Global Descriptor Table）。 <br>为什么要有GDT？我们首先考虑一下在Real Mode下的编程模型：</p>
<p>在Real Mode下，我们对一个内存地址的访问是通过Segment:Offset的方式来进行的，其中Segment是一个段的Base Address，一个Segment的最大长度是64 KB，这是16-bit系统所能表示的最大长度。而Offset则是相对于此Segment Base Address的偏移量。Base Address+Offset就是一个内存绝对地址。由此，我们可以看出，一个段具备两个因素：Base Address和Limit（段的最大长度），而对一个内存地址的访问，则是需要指出：使用哪个段？以及相对于这个段Base Address的Offset，这个Offset应该小于此段的Limit。当然对于16-bit系统，Limit不要指定，默认为最大长度64KB，而16-bit的Offset也永远不可能大于此Limit。我们在实际编程的时候，使用16-bit段寄存器CS（Code Segment），DS（Data Segment），SS（Stack Segment）来指定Segment，CPU将段积存器中的数值向左偏移4-bit，放到20-bit的地址线上就成为20-bit的Base Address。</p>
<p>到了Protected Mode，内存的管理模式分为两种，段模式和页模式，其中页模式也是基于段模式的。也就是说，Protected Mode的内存管理模式事实上是：纯段模式和段页式。进一步说，段模式是必不可少的，而页模式则是可选的——如果使用页模式，则是段页式；否则这是纯段模式。</p>
<p>既然是这样，我们就先不去考虑页模式。对于段模式来讲，访问一个内存地址仍然使用Segment:Offset的方式，这是很自然的。由于Protected Mode运行在32-bit系统上，那么Segment的两个因素：Base Address和Limit也都是32位的。IA-32允许将一个段的Base Address设为32-bit所能表示的任何值（Limit则可以被设为32-bit所能表示的，以2^12为倍数的任何指），而不象Real Mode下，一个段的Base Address只能是16的倍数（因为其低4-bit是通过左移运算得来的，只能为0，从而达到使用16-bit段寄存器表示20-bit Base Address的目的），而一个段的Limit只能为固定值64 KB。另外，Protected Mode，顾名思义，又为段模式提供了保护机制，也就说一个段的描述符需要规定对自身的访问权限（Access）。所以，在Protected Mode下，对一个段的描述则包括3方面因素：[Base Address, Limit, Access]，它们加在一起被放在一个64-bit长的数据结构中，被称为段描述符。这种情况下，如果我们直接通过一个64-bit段描述符来引用一个段的时候，就必须使用一个64-bit长的段积存器装入这个段描述符。但Intel为了保持向后兼容，将段积存器仍然规定为16-bit（尽管每个段积存器事实上有一个64-bit长的不可见部分，但对于程序员来说，段积存器就是16-bit的），那么很明显，我们无法通过16-bit长度的段积存器来直接引用64-bit的段描述符。</p>
<p>怎么办？解决的方法就是把这些长度为64-bit的段描述符放入一个数组中，而将段寄存器中的值作为下标索引来间接引用（事实上，是将段寄存器中的高13-bit的内容作为索引）。这个全局的数组就是GDT。事实上，在GDT中存放的不仅仅是段描述符，还有其它描述符，它们都是64-bit长，我们随后再讨论。</p>
<p>GDT可以被放在内存的任何位置，那么当程序员通过段寄存器来引用一个段描述符时，CPU必须知道GDT的入口，也就是基地址放在哪里，所以Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址，程序员将GDT设定在内存中某个位置之后，可以通过LGDT指令将GDT的入口地址装入此积存器，从此以后，CPU就根据此积存器中的内容作为GDT的入口来访问GDT了。</p>
<p>GDT是Protected Mode所必须的数据结构，也是唯一的——不应该，也不可能有多个。另外，正象它的名字（Global Descriptor Table）所揭示的，它是全局可见的，对任何一个任务而言都是这样。</p>
<p>除了GDT之外，IA-32还允许程序员构建与GDT类似的数据结构，它们被称作LDT（Local Descriptor Table），但与GDT不同的是，LDT在系统中可以存在多个，并且从LDT的名字可以得知，LDT不是全局可见的，它们只对引用它们的任务可见，每个任务最多可以拥有一个LDT。另外，每一个LDT自身作为一个段存在，它们的段描述符被放在GDT中。</p>
<p>IA-32为LDT的入口地址也提供了一个寄存器LDTR，因为在任何时刻只能有一个任务在运行，所以LDT寄存器全局也只需要有一个。如果一个任务拥有自身的LDT，那么当它需要引用自身的LDT时，它需要通过LLDT将其LDT的段描述符装入此寄存器。LLDT指令与LGDT指令不同的时，LGDT指令的操作数是一个32-bit的内存地址，这个内存地址处存放的是一个32-bit GDT的入口地址，以及16-bit的GDT Limit。而LLDT指令的操作数是一个16-bit的选择子，这个选择子主要内容是：被装入的LDT的段描述符在GDT中的索引值——这一点和刚才所讨论的通过段积存器引用段的模式是一样的。</p>
<p align=center><img height=153 src="http://www.xemean.net/resource/image/gdtr.gif" width=463></p>
<p>LDT只是一个可选的数据结构，你完全可以不用它。使用它或许可以带来一些方便性，但同时也带来复杂性，如果你想让你的OS内核保持简洁性，以及可移植性，则最好不要使用它。 </p>
<p>引用GDT和LDT中的段描述符所描述的段，是通过一个16-bit的数据结构来实现的，这个数据结构叫做Segment Selector——段选择子。它的高13位作为被引用的段描述符在GDT/LDT中的下标索引，bit 2用来指定被引用段描述符被放在GDT中还是到LDT中，bit 0和bit 1是RPL——请求特权等级，被用来做保护目的，我们这里不详细讨论它。</p>
<p align=center><img height=120 src="http://www.xemean.net/resource/image/segment-selector.gif" width=261></p>
<p>前面所讨论的装入段寄存器中作为GDT/LDT索引的就是Segment Selector，当需要引用一个内存地址时，使用的仍然是Segment:Offset模式，具体操作是：在相应的段寄存器装入Segment Selector，按照这个Segment Selector可以到GDT或LDT中找到相应的Segment Descriptor，这个Segment Descriptor中记录了此段的Base Address，然后加上Offset，就得到了最后的内存地址。如下图所示：</p>
<p align=center><img height=209 src="http://www.xemean.net/resource/image/gdt.gif" width=364></p>
<p><strong>2. Setup GDT </strong><br></p>
<p>由上一节的讨论得知，GDT是Protected Mode所必须的数据结构，那么我们在进入Protected Mode之前，必须设定好GDT，并通过LGDT将其装入相应的寄存器。</p>
<p>尽管GDT允许被放在内存的任何位置，但由于GDT中的元素——描述符——都是64-bit长，也就是说都是8个字节，所以为了让CPU对GDT的访问速度达到最快，我们应该将GDT的入口地址放在以8个字节对齐，也就是说是8的倍数的地址位置。</p>
<p>GDT中第一个描述符必须是一个空描述符，也就是它的内容应该全部为0。如果引用这个描述符进行内存访问，则是产生General Protection异常。</p>
<p>如果一个OS不使用虚拟内存，段模式会是一个不错的选择。但现代OS没有不使用虚拟内存的，而实现虚拟内存的比较方便和有效的内存管理方式是页式管理。但是在IA-32上如果我们想使用页式管理，我们只能使用段页式——没有方法可以完全禁止段模式。但我们可以尽力让段的效果降低的最小。</p>
<p>IA-32提供了一种被称作&#8220;Basic Flat Model&#8221;的分段模式可以达到这种效果。这种模式要求在GDT中至少要定义两个段描述符，一个用来引用Data Segment，另一个用来引用Code Segment。这2个Segment都包含整个线性空间，即Segment Limit = 4 GB，即使实际的物理内存远没有那么多，但这个空间定义是为了将来由页式管理来实现虚拟内存。</p>
<p>在这里，我们只是处于Booting阶段，所以我们只需要初步设置一下GDT，等真正进入Protected Mode，启动了OS Kernel之后，具体OS打算如何设置GDT，使用何种内存管理模式，由Kernel自身来设置，Booting只需要给Kernel的数据段和代码段设置全部线性空间就可以了。 </p>
<p>段描述符的格式如下图所示：</p>
<p align=center><img height=258 src="http://www.xemean.net/resource/image/segment-descriptor.gif" width=381></p>
<p>具体到代码段和数据段，它们的格式如下图所示：</p>
<p align=center><img height=275 src="http://www.xemean.net/resource/image/cd-sd.gif" width=372></p>
<p>下面就是在Booting阶段为进入Protected Mode而设置的临时的gdt。这里定义了3个段描述符：第一个是系统规定的空描述符，第2个是引用4 GB线性空间的代码段，第3个是引用4 GB线性空间的数据段。这是"Basic Flat Model"所要求的最下GDT设置，但就booting阶段，只是为了进入Protected Mode，并为内核提供一个连续的，最大的线性空间这个目的而言，已经足够了。 </p>
<p># Descriptor tables</p>
<p>gdt:<br>.word 0, 0, 0, 0 # dummy </p>
<p>.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)<br>.word 0 # base address = 0<br>.word 0x9A00 # code read/exec<br>.word 0x00CF # granularity = 4096, 386<br># (+5th nibble of limit) </p>
<p>.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)<br>.word 0 # base address = 0<br>.word 0x9200 # data read/write<br>.word 0x00CF # granularity = 4096, 386<br># (+5th nibble of limit)</p>
<p>&#160;</p>
<p><strong>3. Load GDT</strong> <br></p>
<p>设置好GDT之后，我们需要通过LGDT指令将设定的gdt的入口地址和gdt表的大小装入GDTR寄存器。</p>
<p>&#160;</p>
<p>GDTR寄存器包括两部分：32-bit的线性基地址，以及16-bit的GDT大小（以字节为单位）。需要注意的是，对于32-bit线性基地址，必须是32-bit绝对物理地址，而不是相对于某个段的偏移量。而我们在Booting阶段，在进入Protected Mode之前，我们CS和DS设置很可能不是0，所以我们必须计算出gdt的绝对物理地址。</p>
<p>&#160;</p>
<p>为了执行LGDT指令，你需要把这两部分内容放在内存的某个位置，然后将这个位置的内存地址作为操作数传递给LGDT指令。然后LGDT指令会自动将保存在这个位置的这两部分值装入GDTR寄存器。</p>
<p># 这是存放GDTR所需的两部分内容的位置</p>
<p>gdt_48:<br>.word 0x8000 # gdt limit=2048,<br></p>
<p># 256 GDT entries</p>
<p>.word 0, 0 # gdt base (filled in later)</p>
<p># 下面这段代码用来计算GDT的32-bit线性地址，并将其装入GDTR寄存器。</p>
<p>xorl %eax, %eax # Compute gdt_base<br>movw %ds, %ax # (Convert %ds:gdt to a linear ptr)<br>shll $4, %eax<br>addl $gdt, %eax<br>movl %eax, (gdt_48+2)<br>lgdt gdt_48 # load gdt with whatever is appropriate</p>
<p><strong>4. Other Preparing Stuff</strong></p>
<p>&#160;</p>
<p>在进入Protected Mode之前，除了需要设置和装入GDT之外，还需要做如下一些事情： <br>屏蔽所有可屏蔽中断； <br>装入IDTR； <br>所有协处理器被正确的Reset。 <br>由于在Real Mode和Protected Mode下的中断处理机制有一些不同，所以在进入Protected Mode之前，务必禁止所有可屏蔽中断，这可以通过下面两种方法之一：</p>
<p>使用CLI指令； <br>对8259A可编程中断控制器编程以屏蔽所有中断。 <br>即使当我们进入Protected Mode之后，也不能马上将中断打开，这时因为我们必须在OS Kernel中对相关的Protected Mode中断处理所需的数据结构正确的初始化之后，才能打开中断，否则会产生处理器异常。</p>
<p>在Real Mode下，中断处理使用IVT(Interrupt Vector Table)，在Protected Mode下，中断处理使用IDT（Interrupt Descriptor Table），所以，我们必须在进入Protected Mode之前设置IDTR。</p>
<p>IDTR的格式和GDTR相同，IDTR的装入方式和GDTR也相同。由于IDT中相关的中断处理程序需要让OS Kernel来设定，所以在Booting阶段，我们只需要将IDTR中IDT的基地址和Size都设为0就可以了，随后，等进入Protected Mode之后，由OS Kernel来真正设置它。</p>
<p>关于中断机制和中断处理，请参考 <a href="http://www.pagoda-ooos.org/book/interrupt_and_exception.htm" target=_blank><u><font color=#0000ff>Interrupt &amp; Exception</font></u></a> ，这里不再赘述。</p>
<p>&#160;</p>
<p>#</p>
<p># 这是存放IDTR所需的两部分内容的位置</p>
<p>#</p>
<p>idt_48:<br>.word 0 # idt limit = 0<br>.word 0, 0 # idt base = 0L</p>
<p>&#160;</p>
<p># 对于IDTR的处理，只需要这一条指令即可</p>
<p>lidt idt_48 # load idt with 0,0</p>
<p>&#160;</p>
<p>#</p>
<p># 通过设置8259A PIC，屏蔽所有可屏蔽中断</p>
<p>#</p>
<p>movb $0xFF, %al # mask all interrupts for now<br>outb %al, $0xA1<br>call delay<br><br>movb $0xFB, %al # mask all irq's but irq2 which<br>outb %al, $0x21 # is cascaded</p>
<p>&#160;</p>
<p># 保证所有的协处理都被正确的Reset</p>
<p>xorw %ax, %ax<br>outb %al, $0xf0<br>call delay</p>
<p>outb %al, $0xf1<br>call delay</p>
<p>&#160;</p>
<p># Delay is needed after doing I/O</p>
<p>delay:<br>outb %al,$0x80<br>ret</p>
<p><br><strong>5. Let's Go</strong> <br></p>
<p>好了，一切准备就绪，Fire!:)</p>
<p>进入Protected Mode，还是进入Real Mode，完全靠CR0寄存器的PE标志位来控制：如果PE=1，则CPU切换到PM，否则，则进入RM。</p>
<p align=center><img height=86 src="http://www.xemean.net/resource/image/cr0.gif" width=378></p>
<p>设置CR0-PE位的方法有两种：</p>
<p>第一种是80286所使用的LMSW指令，后来的80386及更高型号的CPU为了保持向后兼容，都保留了这个指令。这个指令只能影响最低的4 bit，即PE，MP，EM和TS，对其它的没有影响。</p>
<p>&#160;</p>
<p>#</p>
<p>#通过LMSW指令进入Protected Mode</p>
<p>#</p>
<p>movw $1, %ax # protected mode (PE) bit</p>
<p>lmsw %ax # This is it!</p>
<p>&#160;</p>
<p>第二种是Intel所建议的在80386以后的CPU上使用的进入PM的方式，即通过MOV指令。MOV指令可以设置CR0寄存器的所有域的值。 </p>
<p>#</p>
<p>#通过MOV指令进入Protected Mode</p>
<p>#</p>
<p>movl %cr0, %eax</p>
<p>xorb $1, %al # set PE = 1</p>
<p>movl %eax, %cr0 # go!!</p>
<p>&#160;</p>
<p>OK，现在已经进入Protected Mode了。</p>
<p>&#160;</p>
<p>很简单，right？But It's not over yet! </p>
<p>&#160;</p>
<p><br></p>
<p><strong>6. Start Kernel </strong><br></p>
<p>我们已经从Real Mode进入Protected Mode，现在我们马上就要启动OS Kernel了。</p>
<p>OS Kernel运行在32-bit段模式，而当前我们却仍然处于16-bit段模式。这是怎么回事？为了了解这个问题，我们需要仔细探讨一下IA-32的段模式的实现方法。</p>
<p>IA-32共提供了6个16-bit段寄存器：CS，DS，SS，ES，FS，GS。但事实上，这16-bit只是对程序员可见的部分，但每个寄存器仍然包括64-bit的不可见部分。</p>
<p align=center><img height=200 src="http://www.xemean.net/resource/image/segment-register.gif" width=524></p>
<p>可见部分是为了供程序员装载段寄存器，但一旦装载完成，CPU真正使用的就只是不可见部分，可见部分就完全没有用了。 </p>
<p>不可见部分存放的内容是什么？具体格式我没有看到相关资料，但可以确定的是隐藏部分的内容和段描述符的内容是一致的（请参考段描述的格式），只不过格式可能不完全相同。但格式对我们理解这一点并不重要，因为程序员不可能能够直接操作它。</p>
<p>我们以CS寄存器为例，对于其它寄存器也是一样的：</p>
<p>在Real Mode下，当我们执行一个装载CS寄存器的指令的时候（jmp，call，ret等），相关的值会被装入CS寄存器的可见部分，但同时CPU也会根据可见部分的内容来设置不可见部分。比如我们执行"ljmp $0x1234, $go "之后，CS寄存器的可见部分的内容就是1234h，同时，不可见部分的32-bit Base Address域被设置为00001234h，20-bit的Limit域被设置为固定值10000h，也就是64 KB，Access Information部分的其它值我们不去考虑，只考虑其D/B位，由于执行此指令时处于Real Mode模式，所以D/B被设置为0，表示此段是一个16-bit段。当对CS寄存器的可见部分和不可见部分的内容都被设置之后，CS寄存器的装载工作完成。随后当CPU需要通过CS的内容进行地址运算的时候，则仅仅引用不可见部分。</p>
<p>在Protected Mode下，当我们执行一个装载CS寄存器的指令的时候，段选择子（Segment Selector）被装入CS寄存器的可见部分，同时CPU根据此选择子到相应的描述符表中（GDT或LDT）找到相应的段描述符并将其内容装载入CS寄存器的不可见部分。随后CPU当需要通过CS的内容进行地址运算的时候，也仅仅引用不可见部分。</p>
<p>从上面的描述可以看出，事实上CPU在引用段寄存器的内容进行地址运算时，Real Mode和Protected Mode是一致的。另外，也明白了为什么我们在Real Mode下设置的段寄存器的内容到了Protected Mode下仍然引用的是16-bit段。</p>
<p>那么我们如何将CS设置为引用32-bit段？方法就像我们前面所讨论的，使用jmp或call指令，引用一个段选择子，到GDT中装载一个引用32-bit段的段描述符。</p>
<p>需要注意的是，如果CS寄存器的内容指出当前是一个16-bit段，那么当前的地址模式也就是16-bit地址模式，这与你当前是出于Real Mode还是Protected Mode无关。而我们装载32-bit段的jmp指令或call指令必须使用的是32-bit地址模式。而我们当前的boot部分代码是16-bit代码，所以我们必须在此jmp/call指令前加上地址转换前缀代码66h。</p>
<p>下面的例子就是使用jmp指令装入32-bit段。Jmpi指令的含义是段间跳转，其Opcode为Eah，其格式为：jmpi Offset, Segment Selector。</p>
<p># 由于当前的代码是16-bit代码，而我们要执行32-bit地址模式的指令，指令前</p>
<p># 需要有地址模式切换前缀66h，如果我们直接写jmp指令，由编译器来生成代码</p>
<p># 的话，是无法作到这一点的，所以我们直接写相关数据。</p>
<p>　 .byte 0x66, 0xea # prefix + jmpi-opcode</p>
<p>　 .long 0x1000 　# Offset<br>　 .word __KERNEL_CS　# CS segment selector </p>
<p>上面的代码相当于32-bit指令： </p>
<p>jmpi 0x1000,__KERNEL_CS</p>
<p>如果__KERNEL_CS段选择子所引用的段描述符设置的段空间为线形地址[0，4 GB]，而我们将OS Kernel放在物理地址1000h，那么此jmpi指令就跳转到OS Kernel的入口处，并开始执行它。</p>
<p>此时，Booting阶段结束，OS正式开始运行！</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/32387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-08-24 16:39 <a href="http://www.cnitblog.com/yuhensong/archive/2007/08/24/32387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>初始化IO APIC时，发现的汇编指令Mfence</title><link>http://www.cnitblog.com/yuhensong/archive/2007/07/31/30994.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Tue, 31 Jul 2007 06:40:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/07/31/30994.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/30994.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/07/31/30994.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/30994.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/30994.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 当系统在做Memory IO操作的时候，用Index和Data间接方式访问寄存器（比如APIC 寄存器），这个时候需要加入写延时，否则，数据就会错位，因为系统硬件做流水操作，导致程序不能严格的顺序执行。而以前的延时值都是自己在实际中进行测试，选择一个比较合适的值，比较笨的方法！后来同事发现了mfence这个指令，可以正好使用在这个地方。mfence保证系统在后面的memory访问之前，先前的memory访问都已经结束。这是mfence是X86cpu家族中的新指令。<br><br>SFENCE,LFENCE,MFENCE指令提供了高效的方式来保证读写内存的排序,这种操作发生在产生弱排序数据的程序和读取这个数据的程序之间。&nbsp;<br>&nbsp;&nbsp;&nbsp;SFENCE——串行化发生在SFENCE指令之前的写操作但是不影响读操作。&nbsp;<br>&nbsp;&nbsp;&nbsp;LFENCE——串行化发生在SFENCE指令之前的读操作但是不影响写操作。&nbsp;<br>&nbsp;&nbsp;&nbsp;MFENCE——串行化发生在MFENCE指令之前的读写操作。 <br>sfence:在sfence指令前的写操作当必须在sfence指令后的写操作前完成。 <br>lfence：在lfence指令前的读操作当必须在lfence指令后的读操作前完成。 <br>mfence：在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。 <br><br>注意：SFENCE,LFENCE,MFENCE指令提供了比CPUID指令更灵活有效的控制内存排序的方式。<br><br>mfence&nbsp;is&nbsp;a&nbsp;memory&nbsp;barrier&nbsp;supported&nbsp;by&nbsp;hardware,&nbsp;and&nbsp;it&nbsp;only&nbsp;makes&nbsp;sense&nbsp;for&nbsp;shared&nbsp;memory&nbsp;systems. <br><br>For&nbsp;example,&nbsp;you&nbsp;have&nbsp;the&nbsp;following&nbsp;codes <br>&lt;codes1&gt; <br>mfence <br>&lt;codes2&gt; <br><br>mfence&nbsp;or&nbsp;other&nbsp;memory&nbsp;barriers&nbsp;techniques&nbsp;disallows&nbsp;the&nbsp;code&nbsp;motion&nbsp;(load/store)from&nbsp;codes2&nbsp;to&nbsp;codes1&nbsp;done&nbsp;by&nbsp;_hardware_&nbsp;.&nbsp;Some&nbsp;machines&nbsp;like&nbsp;P4&nbsp;can&nbsp;move&nbsp;loads&nbsp;in&nbsp;codes&nbsp;2&nbsp;before&nbsp;stores&nbsp;in&nbsp;codes1,&nbsp;which&nbsp;is&nbsp;out-of-order. <br><br>Another&nbsp;memory&nbsp;barrier&nbsp;is&nbsp;something&nbsp;like ("":::"memory"), which&nbsp;disallows&nbsp;the&nbsp;code&nbsp;motion&nbsp;done&nbsp;by&nbsp;_compiler_.&nbsp;But&nbsp;IMO&nbsp;memory&nbsp;access&nbsp;order&nbsp;is&nbsp;not&nbsp;always&nbsp;guaranteed&nbsp;in&nbsp;this&nbsp;case. <br><img src ="http://www.cnitblog.com/yuhensong/aggbug/30994.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-07-31 14:40 <a href="http://www.cnitblog.com/yuhensong/archive/2007/07/31/30994.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zz]System Management Mode (SMM) Memory Range</title><link>http://www.cnitblog.com/yuhensong/archive/2007/05/15/27030.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Tue, 15 May 2007 05:08:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/05/15/27030.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/27030.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/05/15/27030.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/27030.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/27030.html</trackback:ping><description><![CDATA[&nbsp; The Northbridge supports the use of main memory as System Management RAM (SMRAM) enabling the use of System Management Mode (SMM).<br>&nbsp; The Northbridge supports three SMM options :<br>&nbsp;&nbsp;&nbsp; - Compatible SMRAM (AB segment enabled)<br>&nbsp;&nbsp;&nbsp; - High Segment (HSEG)<br>&nbsp;&nbsp;&nbsp; - Top of Memory Segment (TSEG)<br>&nbsp; System Management RAM (SMRAM) space provides a memory area that is available for the SMI handler&#8217;s code and data storage. This memory resource is normally hidden from the operating system so that the processor has immediate access to this memory space upon entry to SMM.<br>&nbsp; The GMCH provides three SMRAM options :<br>&nbsp;&nbsp;&nbsp; &#8226; Below 1 MB option that supports compatible SMI handlers.<br>&nbsp;&nbsp;&nbsp; &#8226; Above 1 MB option that allows new SMI handlers to execute with write-back cacheable SMRAM.<br>&nbsp;&nbsp;&nbsp; &#8226; Optional larger write-back cacheable T_SEG area of either 512 KB or 1MB in size above 1 MB that is reserved from the highest area in system DRAM memory.<br>&nbsp; The above 1 MB solutions require changes to compatible SMRAM handler&#8217;s code to properly execute above 1 MB.<br>&nbsp; The HSEG and TSEG SMM transaction address spaces reside in this extended memory area.<br>HSEG ($000A_0000 &#8211; 000B_FFFF)<br>&nbsp; SMM-mode processor accesses to enabled HSEG are remapped to $000A_0000 &#8211; 000B_FFFF. Non-SMM-mode processor accesses to enabled HSEG are considered invalid are terminated immediately on the FSB. The exception to this is non-SMM-mode write-back cycles. They are remapped to SMM space to maintain cache coherency. AGP and hub interface originated cycles to enabled SMM space are not allowed. Physical DRAM behind the HSEG transaction address is not remapped and is not accessible.<br>TSEG (Top of Main Memory&#8211;TSEG)<br>&nbsp; TSEG can be up to 1 MB and is at the top of memory. SMM-mode processor accesses to enabled TSEG access the physical DRAM at the same address. Non-SMM-mode processor accesses to enabled TSEG are considered invalid and are terminated immediately on the FSB. The exception is non-SMM-mode write-back cycles. They are directed to the physical SMM space to maintain cache coherency. AGP and hub interface originated cycle toenabled SMM space are not allowed.<img src ="http://www.cnitblog.com/yuhensong/aggbug/27030.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-05-15 13:08 <a href="http://www.cnitblog.com/yuhensong/archive/2007/05/15/27030.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zz几个常用的 WinDbg 命令 </title><link>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24103.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 16 Mar 2007 03:34:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24103.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/24103.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24103.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/24103.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/24103.html</trackback:ping><description><![CDATA[<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">1. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">查询符号</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">kd&gt; x nt!KeServiceDescriptorTable*</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">8046e100 nt!KeServiceDescriptorTableShadow = &lt;no type information&gt;</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">8046e0c0 nt!KeServiceDescriptorTable = &lt;no type information&gt;</span>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">kd&gt; ln 8046e100</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">(8046e100)   nt!KeServiceDescriptorTableShadow   | (8046e140)   nt!MmSectionExtendResource</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">Exact matches:</span>
		</div>
		<div style="TEXT-INDENT: 21pt">
				<span style="FONT-FAMILY: Verdana">nt!KeServiceDescriptorTableShadow = &lt;no type information&gt;</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">2. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">下载系统文件的符号</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">symchk c:\winnt\system32\ntoskrnl.exe /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols</span>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">SYMCHK: FAILED files = 0</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">SYMCHK: PASSED + IGNORED files = 1</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">3. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">查看</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: Verdana"> event </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">对象的信号状态</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">!object \BaseNamedObjects</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">dt -b nt!_KEVENT xxxxxxxx</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">4. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">查看</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: Verdana"> LastError </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">值</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">!gle</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">5. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">指定进制形式，</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: Verdana">0x/0n/0t/0y </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">分别表示</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: Verdana"> 16/10/8/2 </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">进制</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">? 0x12345678+0n10</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">Evaluate expression: 305419906 = 12345682</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">6. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">过滤命令窗口输出信息</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">.prompt_allow -reg +dis -ea -src -sym</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">7. .formats </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">命令</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: 宋体">以多种格式显示表达式的值</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">0:000&gt; .formats @eax</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">Evaluate expression:</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Hex:     00181eb4</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Decimal: 1580724</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Octal:   00006017264</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Binary: 00000000 00011000 00011110 10110100</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Chars:   ....</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Time:    Mon Jan 19 15:05:24 1970</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Float:   low 2.21507e-039 high 0</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana"> Double: 7.80981e-318</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">8. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">异常处理相关</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: 宋体">有</span>
				<span style="FONT-FAMILY: Verdana"> sx, sxd, sxe, sxi, sxn, sxr </span>
				<span style="FONT-FAMILY: 宋体">几条命令可用来设置异常和事件的处理方式。比如：</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">0:000&gt; sxe ld</span>
		</div>
		<div>
				<span style="FONT-FAMILY: 宋体">可以在加载</span>
				<span style="FONT-FAMILY: Verdana"> dll </span>
				<span style="FONT-FAMILY: 宋体">时中断下来。</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">9. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">内核调试时切换进程</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">lkd&gt; !process 0 0</span>
		</div>
		<div>
				<span style="FONT-FAMILY: Verdana">lkd&gt; .process xxxxxxxx</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">10. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">可在桌面上建立一个</span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: Verdana"> WinDbg.exe </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">的快捷方式，然后在该快捷方式的属性力设置如下命令行</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: Verdana">C:\WinDBG\windbg.exe -c ".prompt_allow +dis -reg -ea -src -sym; .enable_unicode 1; .enable_long_status 1; .logopen /t c:\dbglog\dbglog.txt"</span>
		</div>
		<div> </div>
		<div>
				<strong>
						<span style="FONT-FAMILY: Verdana">11. </span>
				</strong>
				<strong>
						<span style="FONT-FAMILY: 宋体">本机内核调试</span>
				</strong>
		</div>
		<div> </div>
		<div>
				<span style="FONT-FAMILY: 宋体">通过</span>
				<span style="FONT-FAMILY: Verdana">File/Kernel Debug… </span>
				<span style="FONT-FAMILY: 宋体">菜单可以打开内核调试选择窗口，选择最后一个</span>
				<span style="FONT-FAMILY: Verdana"> Local </span>
				<span style="FONT-FAMILY: 宋体">选项页，确定后可以以内核方式调试本地机器。这时所有会挂起系统的命令都用不了了，但可以读写系统内存。另外，有一个方便的用途是用来查看系统结构，比如：</span>
				<span style="FONT-FAMILY: Verdana">dt nt!_EPROCESS</span>
				<span style="FONT-FAMILY: 宋体">。<br /><br />12. 其他命令<br /><h3 class="title">windbg中常用的命令</h3>~ - list threads in current process context<br />~* - list detail information of threads in current process context<br />lm - list all loaded modules<br />!sym noice/quiet - symbol prompts on/off<br />.srcpath - set source code path<br />k - display current stack<br />~*kb - display current stack for all threads<br />dv - display current local variable (ctrl + alt + v to switch mode)<br />.Frame - call stack<br />dt xxx - display data structure for xxx such as PEB<br />!gle/!error - display last error for current thread.<br />!teb - diplay current thread execution block<br />!peb - diplay current process execution block<br />r [@register] - display value of all register<br />ln [Address] - display the object type in Address<br />x [] - search address for global variable or global function, such as "x kernel32!*"<br />!locks - display dead lock<br />!handle - get current handle usage<br />!htrace [enable] - display and trace handles.<br />u - disassemble<br />bp [Kernel!SetLastError] [value] - set break pointer<br />bl - display break pointer information.<br />for example:<br />bp `mysource.cpp:143` "j (poi(MyVar)”0n20) ''; 'g' "<br />when MyVar is exceed 0x20, g command will be invoked. NOTE: "j" is to set conditional break pointer.<br />ba - data break pointer<br />ba w4 0x4000000 "kb;g" - list all modify 0x40000's call stack.<br /><br />p,pa,t,ta - control command<br /></span>
		</div><img src ="http://www.cnitblog.com/yuhensong/aggbug/24103.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-03-16 11:34 <a href="http://www.cnitblog.com/yuhensong/archive/2007/03/16/24103.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>0x000000A5:ACPI_BIOS_ERROR 详细分析 </title><link>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24094.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 16 Mar 2007 02:34:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24094.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/24094.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/03/16/24094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/24094.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/24094.html</trackback:ping><description><![CDATA[您可以使用下面的信息来帮助调试 Stop 0x000000A5 错误。 
<table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text">导致此 Stop 消息的原因始终是 ACPI BIOS 中的错误。在操作系统级别，您无法修复任何错误。</td></tr><tr><td class="bullet">•</td><td class="text">在其他情况下也可能会出现此 Stop 消息。例如，您可能会在安装 Windows XP 并随后进行硬件更改（如添加设备）时收到此 Stop 错误。可以正常运行 Microsoft Windows 98 的计算机可能无法正常运行 Windows XP。Windows 98 不一定使用 Windows XP 所使用的全部 ACPI 功能。Windows 98 可能会允许使用 Windows XP 由于其严格的系统稳定性要求而无法使用的替代方法。</td></tr></tbody></table>以下信息列出了 Stop 0x000000A5 错误的可能原因。要确定此 Stop 错误的原因，请记下 <var>Parameter1</var> 并将其与以下段落中列出的数字进行比较，以便大概了解问题所在。 <br /><br />本文不讨论其他参数。您只能通过将系统连接到内核调试程序来查看这些其他参数。本文介绍此 Stop 错误可能涉及到的问题，而不需要更高级的调试。有关更多信息，请参考 Acpidbg.h。<br /><br /><b>(0x00000001, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />此参数被定义为 ACPI 根资源故障。更具体地说就是，ACPI 在启动时收到的任何资源中都找不到系统控制中断 (SCI) 矢量。SCI 是一个特殊的中断类型，它提供了一个更为高效的方法，以处理通常需要由系统管理中断 (SMI) 处理的问题。如果 SCI 无法初始化，ACPI 将无法工作。如果列表中没有此 IRQ 的条目，或者根本找不到任何 IRQ 资源列表，就可能会发生此问题。<br /><br /><b>(0x00000002, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />此错误被定义为 ACPI 根 PCI 资源故障。要了解 PCI 设备当前使用了哪些资源，ACPI 必须能够在 ACPI 名称空间中查询 CRS 描述符。如果 BIOS 缺少指向列表的指针，或者列表为空，或者列表包含错误或冲突，将发生此错误。<br /><br /><b>(0x00000003, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />此错误被定义为“故障 ACPI 必须成功方法”。如果 ACPI 无法生成控制方法以引用 ACPI 名称空间，将发生此错误。此错误的其他参数引用正在运行的 ACPI 对象以及控制方法的名称。一种更为简单的解释（可能并不完全准确）是，系统找不到定义系统的即插即用和电源管理功能的 ACPI 表。<br /><br /><b>(0x00000004, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />发生此错误的原因是：系统在 ACPI 名称空间中定义 _PRW 方法时收到的某种数据类型不是所需的要用作其数据包元素的类型。_PRW 仅为能够将系统从休眠模式中唤醒的系统定义。除其他部分外，_PRW 还定义系统可以进入并能够从中恢复的最低电源系统状态。<br /><br /><b>(0x00000005, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />引用的 _PRW 必须至少包含两个元素。在被查询时，_PRW 指示它不完整。<br /><br /><b>(0x00000006, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />命名了电源资源，但是名称空间中没有可用于该资源的信息。<br /><br /><b>(0x00000007, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />当系统引用了 ACPI 名称空间中的方法时，系统需要 BUFFER 数据类型，但是收到了某种其他数据类型。<br /><br /><b>(0x00000008, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />系统需要 INTEGER 数据类型，但是收到了某种其他数据类型。<br /><br /><b>(0x00000009, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />系统需要 PACKAGE 数据类型，但是收到了某种其他数据类型。<br /><br /><b>(0x0000000A, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />系统需要 STRING 数据类型，但是收到了某种其他数据类型。<br /><br /><b>(0x0000000B, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />_EJD 字符串引用了不存在的对象。_EJD 对象定义依赖于特定弹出设备的对象。例如，如果插接站中有一个附加适配器，并且您尝试弹出便携式计算机，则 ACPI 将引用此名称空间，以确定插接站中的从属适配器是否支持弹出操作。发生此错误的原因是没有用于定义 _EJD 字符串中引用的名称的对象。<br /><br /><b>(0x0000000C, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />此名称空间定义对插接的支持，但是没有足够的信息来实现它。这可能是因为定义不正确，或者定义了重复的服务。<br /><br /><b>(0x0000000D, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 名称空间中必须定义许多对象，但其中一个或多个对象找不到。如果缺少 _HID 或 _ADR 对象，通常会出现此错误。_ADR 用于定义设备在其父级总线上的地址。_ADR 是一个静态地址，它定义设备的插槽编号，这些设备可以位于任意数量的总线类型上，其中包括 EISA、软驱、IDE 控制器、IDE 通道、PCI、PCMCIA 和 CardBus。_HID 包含向操作系统提供设备的即插即用硬件 ID 的对象。从技术角度上讲，这些对象是可选的，但是要描述 ACPI 驱动程序所枚举的任意设备，就必须使用它们。<br /><br /><b>(0x0000000E, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />发生此错误的原因是系统无法在电源资源名称空间中找到所需的方法或对象。电源资源是“设备”以外的任何对象。如果 BIOS 不为电源资源提供 ON、OFF 或 STA 中的任何一个，系统将停止并生成此错误。<br /><br /><b>(0x0000000F, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />当即插即用资源描述符小于其定义的大小时，将出现此错误，因为这表明该描述符不完整或已损坏。资源描述符描述计算机正在使用的、可以使用的或想要使用的系统资源。每个描述符条目都有一个预定义的大小，该大小必须与返回的数据相符。<br /><br /><b>(0x000000010, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />当系统从一个电源状态转换到另一个状态时，它会将整个系统都支持的状态与系统中个别设备所支持的状态进行比较。如果电源资源映射到不存在的系统范围资源，将发生此错误。您可以使用内核调试程序来查看此错误的具体信息，包括导致出现问题的系统电源状态。<br /><br /><b>(0x000000011, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />系统无法进入 ACPI 模式。发生此问题的原因有多个，其中包括： 
<table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text">系统无法初始化 AML 解释器。</td></tr><tr><td class="bullet">•</td><td class="text">系统找不到根系统描述表。</td></tr><tr><td class="bullet">•</td><td class="text">系统无法分配关键驱动程序。</td></tr><tr><td class="bullet">•</td><td class="text">系统无法加载根系统描述表。</td></tr><tr><td class="bullet">•</td><td class="text">系统无法加载设备描述符块。</td></tr><tr><td class="bullet">•</td><td class="text">系统无法连接中断矢量。</td></tr><tr><td class="bullet">•</td><td class="text">无法设置 SCI_EN（系统控制中断启用请求）（请参见 0x00000001）。</td></tr><tr><td class="bullet">•</td><td class="text">ACPI 表的校验和不正确。</td></tr></tbody></table>ACPI 是表的分层排列，每个表都构建在下一个表之上，以定义系统以及系统中各台设备的完整功能。ACPI 首先查找根系统描述表，该表指向下一个表，下一个表又指向它的下一个表，依此类推。通常，发生 0x000000011 错误的原因是这些表被损坏或丢失。<br /><br /><b>(0x000000012, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 需要一个电源资源对象，但是它找不到该对象。您可以通过内核调试程序来查看此错误，以准确了解该对象。<br /><br /><b>(0x00002001, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 试图评估特定类型的可编程中断控制器的控制方法，但没有成功。<br /><br /><b>(0x00010001, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 试图执行中断路由，但没有成功。发生此错误的原因通常是中断路由表已损坏。<br /><br /><b>(0x00010002, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 找不到中断路由表中引用的链接节点。<br /><br /><b>(0x00010003, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />系统中存在某个设备，但是 IRQ 路由表中没有对应该设备的条目。 <br /><br /><b>(0x00010005, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />此错误与定义如何写入 PCI 路由表的规则有关。为了避免出现含糊不清的情况，必须在表中指定设备编号，但是绝对不能指定函数编号。为此，必须将函数字段全部设置为 F。当函数编号没有全部为 F 时，将发生此错误。<br /><br /><b>(0x00010006, <var>Parameter2</var>, <var>Parameter3</var>, <var>Parameter4</var>)：</b><br /><br />ACPI 必须能够禁用链接节点，才能对其进行重新编程。如果 ACPI 无法禁用链接节点，将会发生此错误。<img src ="http://www.cnitblog.com/yuhensong/aggbug/24094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-03-16 10:34 <a href="http://www.cnitblog.com/yuhensong/archive/2007/03/16/24094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Blocked I/O Port Addresses and System Board Resources </title><link>http://www.cnitblog.com/yuhensong/archive/2007/03/12/23919.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Mon, 12 Mar 2007 09:23:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/03/12/23919.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/23919.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/03/12/23919.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/23919.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/23919.html</trackback:ping><description><![CDATA[<h2>Affected System Resources and Addresses </h2>
		<p>
		</p>
		<p>Table 1 lists the system resources and associated I/O addresses that should not be directly accessed by BIOS AML code (the "blocked ports" list).</p>
		<p>
				<b>Table 1 Blocked I/O Port Addresses and System Board Resources </b>
		</p>
		<table class="dataTable" id="EHD" cellspacing="0" cellpadding="0">
				<thead>
						<tr class="stdHeader" valign="top">
								<td id="colEJD">Address</td>
								<td id="colEMD">Function</td>
								<td id="colEPD" style="BORDER-RIGHT: #cccccc 1px solid">Comments</td>
						</tr>
				</thead>
				<tbody>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x000 0x00F</p>
								</td>
								<td>
										<p class="lastInCell">DMA Controller 1</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x020 0x021</p>
								</td>
								<td>
										<p class="lastInCell">Programmable Interrupt Controller</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell">Access is never allowed*</p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x040 0x043</p>
								</td>
								<td>
										<p class="lastInCell">System Timer 1</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x048 0x04B</p>
								</td>
								<td>
										<p class="lastInCell">Timer 2 Failsafe</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x070 0x071</p>
								</td>
								<td>
										<p class="lastInCell">System CMOS, RTC</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x074 0x076</p>
								</td>
								<td>
										<p class="lastInCell">Extended CMOS</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x081 0x083</p>
								</td>
								<td>
										<p class="lastInCell">DMA1 Page Registers</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x087</p>
								</td>
								<td>
										<p class="lastInCell">DMA1 CH0 Low Page</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x089</p>
								</td>
								<td>
										<p class="lastInCell">DMA2 CH2 Low Page</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x08A 0x08B</p>
								</td>
								<td>
										<p class="lastInCell">DMA2 CH3 Low Page,</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x08F</p>
								</td>
								<td>
										<p class="lastInCell">DMA2 Low Page Refresh</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x090 0x091</p>
								</td>
								<td>
										<p class="lastInCell">Arbitration Control Port Card Select Feedback</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x093 0x094</p>
								</td>
								<td>
										<p class="lastInCell">Reserved System Board Setup</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x096 0x097</p>
								</td>
								<td>
										<p class="lastInCell">POS Channel Select</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x0A0 0x0A1</p>
								</td>
								<td>
										<p class="lastInCell">Cascaded Programmable Interrupt Controller</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell">Access is never allowed*</p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0x0C0 0x0DF</p>
								</td>
								<td>
										<p class="lastInCell">ISA DMA</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
						<tr class="record" valign="top">
								<td>
										<p class="lastInCell">0x4D0 0x4D1</p>
								</td>
								<td>
										<p class="lastInCell">PIC Edge/Level Control Registers</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell">Access is never allowed*</p>
								</td>
						</tr>
						<tr class="evenRecord" valign="top">
								<td>
										<p class="lastInCell">0xCF8 0xD00</p>
								</td>
								<td>
										<p class="lastInCell">PCI Configuration Space Access</p>
								</td>
								<td style="BORDER-RIGHT: #cccccc 1px solid">
										<p class="lastInCell"> </p>
								</td>
						</tr>
				</tbody>
		</table>
		<div class="dataTableBottomMargin">
		</div>
		<p>*Read or write accesses to these ports are always blocked, regardless of the BIOS use of the _OSI method.</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/23919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-03-12 17:23 <a href="http://www.cnitblog.com/yuhensong/archive/2007/03/12/23919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How to debug Windows XP kernel?</title><link>http://www.cnitblog.com/yuhensong/archive/2007/03/05/23614.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Mon, 05 Mar 2007 09:34:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/03/05/23614.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/23614.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/03/05/23614.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/23614.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/23614.html</trackback:ping><description><![CDATA[I want to know how to debug Windows kernel, but can not know how to do.<br />Should I use some useful tool such as Windbg?<br />Then, I do not know how to print every boot information of OS to COM.<br />Have you some useful way to do it, please help me, thank you:)<img src ="http://www.cnitblog.com/yuhensong/aggbug/23614.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-03-05 17:34 <a href="http://www.cnitblog.com/yuhensong/archive/2007/03/05/23614.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>比较常见的windows蓝屏代码分析</title><link>http://www.cnitblog.com/yuhensong/archive/2007/03/02/23462.html</link><dc:creator>yuhen</dc:creator><author>yuhen</author><pubDate>Fri, 02 Mar 2007 02:03:00 GMT</pubDate><guid>http://www.cnitblog.com/yuhensong/archive/2007/03/02/23462.html</guid><wfw:comment>http://www.cnitblog.com/yuhensong/comments/23462.html</wfw:comment><comments>http://www.cnitblog.com/yuhensong/archive/2007/03/02/23462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/yuhensong/comments/commentRss/23462.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/yuhensong/services/trackbacks/23462.html</trackback:ping><description><![CDATA[<p>
				<span class="tpc_content">
						<font face="Times New Roman" size="2">┌─┐<br />│ 1 │<br />└─┘0x0000000A:IRQL_NOT_LESS_OR_EQUAL<br />◆错误分析:主要是由问题的驱动程序、有缺陷或不兼容的硬件与软件造成的. 从技术角度讲. 表明在内核模式中存在以太高的进程内部请求级别(IRQL)访问其没有权限访问的内存地址.<br />◇解决方案:请用前面介绍的解决方案中的2、3、5、8、9方案尝试排除. <br /><br />┌─┐<br />│ 2 │<br />└─┘0x00000012:TRAP_CAUSE_UNKNOWN<br />◆错误分析:如果遇到这个错误信息, 那么很不幸, 应为KeBudCheck分析的结果是错误原因未知.<br />◇解决方案:既然微软都帮不上忙, 就得靠自己了, 请仔细回想这个错误是什么时候出现的; 第一次发生时你对系统做了哪些操作; 发生时正在进行什么操作. 从这些信息中找出可能的原因, 从而选择相应解决方案尝试排除. <br /><br />┌─┐<br />│ 3 │<br />└─┘0x0000001A:MEMORY_MANAGEMENT<br />◆错误分析:这个内存管理错误往往是由硬件引起的, 比如: 新安装的硬件、内存本身有问题等.<br />◇解决方案:如果是在安装Windows时出现, 有可能是由于你的电脑达不到安装Windows的最小内存和磁盘要求. <br /><br />┌─┐<br />│ 4 │<br />└─┘0x0000001E:KMODE_EXCEPTION_NOT_HANDLED<br />◆错误分析:Windows内核检查到一个非法或者未知的进程指令, 这个停机码一般是由问题的内存或是<br />与前面0x0000000A相似的原因造成的.<br />◇解决方案:<br />(1)硬件兼容有问题:请对照前面提到的最新硬件兼容性列表, 查看所有硬件是否包含在该列表中.<br />(2)有问题的设备驱动、系统服务或内存冲突和中断冲突: 如果在蓝屏信息中出现了驱动程序的名字, 请试着在安装模式或者故障恢复控制台中禁用或删除驱动程序, 并禁用所有刚安装的驱动和软件. 如果错误出现在系统启动过程中, 请进入安全模式, 将蓝屏信息中所标明的文件重命名或者删除.<br />(3)如果错误信息中明确指出Win32K.sys: 很有可能是第三方远程控制软件造成的, 需要从故障恢复控制台中将对该软件的服务关闭.<br />(4)在安装Windows后第一次重启时出现:最大嫌疑可能时系统分区的磁盘空间不足或BIOS兼容有问题.<br />(5)如果是在关闭某个软件时出现的:很有可能时软件本省存在设计缺陷, 请升级或卸载它. <br /><br />┌─┐<br />│ 5 │0x00000023:FAT_FILE_SYSTEM<br />└─┘0x00000024:NTFS_FILE_SYSTEM<br />◆错误分析:0x00000023通常发生在读写FAT16或者FAT32文件系统的系统分区时, 而0x00000024则是由于NTFS.sys文件出现错误(这个驱动文件的作用是容许系统读写使用NTFS文件系统的磁盘). 这两个蓝屏错误很有可能是磁盘本身存在物理损坏, 或是中断要求封包(IRP)损坏而导致的. 其他原因还包括:硬盘磁盘碎片过多; 文件读写操作过于频繁, 并且数据量非常达或者是由于一些磁盘镜像软件或杀毒软件引起的<br />◇解决方案:<br />第一步:首先打开命令行提示符, 运行"Chkdsk /r"(注:不是CHKDISK, 感觉象这个, 但是……)命令检查并修复硬盘错误, 如果报告存在怀道(Bad Track), 请使用硬盘厂商提供的检查工具进行检查和修复.<br />第二步:接着禁用所有即使扫描文件的软件, 比如:杀毒软件、防火墙或备份工具.<br />第三步:右击C:\winnt\system32\drivers\fastfat.sys文件并选择"属性", 查看其版本是否与当前系统所使用的Windows版本相符.(注:如果是XP, 应该是C:\windows\system32\drivers\fastfat.sys)<br />第四步:安装最新的主板驱动程序, 特别IDE驱动. 如果你的光驱、可移动存储器也提供有驱动程序, 最好将它们升级至最新版. <br /><br />┌─┐<br />│ 6 │<br />└─┘0x00000027:RDR_FILE_SYSTEM<br />◆错误分析:这个错误产生的原因很难判断, 不过Windows内存管理出了问题很可能会导致这个停机码出现.<br />◇解决方案:如果是内存管理的缘故, 通常增加内存会解决问题. <br /><br />┌─┐<br />│ 7 │<br />└─┘0x0000002EATA_BUS_ERROR<br />◆错误分析:系统内存存储器奇偶校验产生错误, 通常是因为有缺陷的内存(包括物理内存、二级缓存或者显卡显存)时设备驱动程序访问不存在的内存地址等原因引起的. 另外, 硬盘被病毒或者其他问题所损伤, 以出现这个停机码.<br />◇解决方案:<br />(1)检查病毒<br />(2)使用"chkdsk /r"命令检查所有磁盘分区.<br />(3)用Memtest86等内存测试软件检查内存.<br />(4)检查硬件是否正确安装, 比如:是否牢固、金手指是否有污渍. <br /><br />┌─┐<br />│ 8 │<br />└─┘0x00000035:NO_MORE_IRP_STACK_LOCATIONS<br />◆错误分析:从字面上理解, 应该时驱动程序或某些软件出现堆栈问题. 其实这个故障的真正原因应该时驱动程序本省存在问题, 或是内存有质量问题.<br />◇解决方案:请使用前面介绍的常规解决方案中与驱动程序和内存相关的方案进行排除. <br /><br />┌─┐<br />│ 9 │<br />└─┘0x0000003F:NO_MORE_SYSTEM_PTES<br />◆错误分析:一个与系统内存管理相关的错误, 比如:由于执行了大量的输入/输出操作, 造成内存管理出现问题: 有缺陷的驱动程序不正确地使用内存资源; 某个应用程序(比如:备份软件)被分配了大量的内核内存等.<br />◇解决方案:卸载所有最新安装的软件(特别是哪些增强磁盘性能的应用程序和杀毒软件)和驱动程序. <br /><br />┌─┐<br />│10│<br />└─┘0x00000044:MULTIPLE_IRP_COMPLIETE_REQUESTS<br />◆错误分析:通常是由硬件驱动程序引起的.<br />◇解决方案:卸载最近安装的驱动程序. 这个故障很少出现, 目前已经知道的是, 在使用</font>
						<a href="http://www.in-system.com/" target="_blank">
								<font face="Times New Roman" size="2">http://www.in-system.com/</font>
						</a>
						<font face="Times New Roman" size="2">这家公司的某些软件时会出现, 其中的罪魁就是Falstaff.sys文件.(作者难道不怕吃官司嘛, 把公司网址公布) <br /><br />┌─┐<br />│11│<br />└─┘0x00000050AGE_FAULT_IN_NONPAGED+AREA<br />◆错误分析:有问题的内存(包括屋里内存、二级缓存、显存)、不兼容的软件(主要是远程控制和杀毒软件)、损坏的NTFS卷以及有问题的硬件(比如CI插卡本身已损坏)等都会引发这个错误.<br />◇解决方案:请使用前面介绍的常规解决方案中与内存、软件、硬件、硬盘等相关的方案进行排除. <br /><br />┌─┐<br />│12│<br />└─┘0x00000051:REGISTRY_ERROR<br />◆错误分析:这个停机码说明注册表或系统配置管理器出现错误, 由于硬盘本身有物理损坏或文件系统存在问题, 从而造成在读取注册文件时出现输入/输出错误.<br />◇解决方案:使用"chkdsk /r"检查并修复磁盘错误. <br /><br />┌─┐<br />│13│<br />└─┘0x00000058:FTDISK_INTERNAL_ERROR<br />◆错误分析:说明在容错集的主驱动发生错误.<br />◇解决方案:首先尝试重启电脑看是否能解决问题, 如果不行, 则尝试"最后一次正确配置"进行解决. <br /><br />┌─┐<br />│14│<br />└─┘0x0000005E:CRITICAL_SERVICE_FAILED<br />◆错误分析:某个非常重要的系统服务启动识别造成的.<br />◇解决方案:如果是在安装了某个新硬件后出新的, 可以先移除该硬件, 并通过网上列表检查它是否与Windows 2K/XP兼容, 接着启动电脑, 如果蓝屏还是出现, 请使用"最后一次正确配置"来启动Windows, 如果这样还是失败, 建议进行修复安装或是重装. <br /><br />┌─┐<br />│15│<br />└─┘0x0000006F:SESSION3_INITIALIZATION-FAILED<br />◆错误分析:这个错误通常出现在Windows启动时, 一般是由有问题的驱动程序或损坏的系统文件引起的.<br />◇解决方案:建议使用Windows安装光盘对系统进行修复安装. <br /><br />┌─┐<br />│16│<br />└─┘0x00000076ROCESS_HAS_LOCKED_PAGES<br />◆错误分析:通常是因为某个驱动程序在完成了一次输入/输出操作后, 没有正确释放所占有的内存<br />◇解决方案:<br />第一步:点击开始--&gt;运行:regedt32, 找到[HKLM\SYSTEM\Currentcontrol set\control\session manager\memory management], 在右侧新建双字节值"TrackLockedPages", 值为1. 这样Windows便会在错误再次出现时跟踪到是哪个驱动程序的问题.<br />第二步:如果再次出现蓝屏, 那么错误信息会变成:<br />STOP:0x0000000CB(0xY,0xY,0xY,0xY)DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS<br />其中第四个"0xY"会显示为问题驱动程序的名字, 接着对其进行更新或删除.<br />第三步:进入注册表, 删除添加的"TrackLockedPages". <br /><br />┌─┐<br />│17│<br />└─┘0x00000077:KERNEL_STACK_INPAGE_ERROR<br />◆错误分析:说明需要使用的内核数据没有在虚拟内存或物理内存中找到. 这个错误常常于是着磁盘有问题, 相应数据损坏或受到病毒侵蚀.<br />◇解决方案:使用杀毒软件扫描系统; 使用"chkdsk /r"命令检查并修复磁盘错误, 如不行则使用磁盘<br />厂商提供的工具检查修复. <br /><br />┌─┐<br />│18│<br />└─┘0x0000007A:KERNEL_DATA_INPAGE_ERROR<br />◆错误分析:这个错误往往是虚拟内存中的内核数据无法读入内存造成的. 原因可能是虚拟内存页面文件中存在坏簇、病毒、磁盘控制器出错、内存有问题.<br />◇解决方案:首先用升级为最新病毒库杀毒软件查杀病毒, 如果促无信息中还有0xC000009C或0xC000016A代码, 那么表示是坏簇造成的, 并且系统的磁盘检测工具无法自动修复, 这时要进入"故障恢复控制台", 用"chkdsk /r"命令进行手动修复. <br /><br />┌─┐<br />│19│<br />└─┘0x0000007B:INACESSIBLE_BOOT_DEVICE<br />◆错误分析:Windows在启动过程中无法访问系统分区或启动卷. 一般发生在更换主板后第一次启动时, 主要是因为新主板和旧主板的IDE控制器使用了不同芯片组造成的. 有时也可能是病毒或硬盘损伤所引起的.<br />◇解决方案:一般只要用安装光盘启动电脑, 然后执行修复安装即可解决问题. 对于病毒则可使用DOS版的杀毒软件进行查杀(主战有kv2005DOS版下载). 如果是硬盘本身存在问题, 请将其安装到其他电脑中, <br />然后使用"chkdsk /r"来检查并修复磁盘错误. <br /><br />┌─┐<br />│20│<br />└─┘0x0000007E:SYSTEM_THREAD_EXCEPTION_NOT_HANDLED<br />◆错误分析:系统进程产生错误, 但Windows错误处理器无法捕获. 其产生原因很多, 包括:硬件兼容性、有问题的驱动程序或系统服务、 或者是某些软件.<br />◇解决方案:请使用"事件查看器"来获取更多的信息, 从中发现错误根源.(发现好像不是解决哦, 看来这里大家要自力更生了!) <br /><br />┌─┐<br />│21│<br />└─┘0x0000007F:UNEXPECTED_KERNEL_MOED_TRAP<br />◆错误分析:一般是由于有问题的硬件(比如:内存)或某些软件引起的. 有时超频也会产生这个错误.<br />◇解决方案:用检测软件(比如:Memtest86)检查内存, 如果进行了超频, 请取消超频. 将PCI硬件插卡从主板插槽拔下来, 或更换插槽. 另外, 有些主板(比如:nForce2主板)在进行超频后, 南桥芯片过热也会导致蓝屏, 此时为该芯片单独增加散热片往往可以有效解决问题. <br /><br />┌─┐<br />│22│<br />└─┘0x00000080:NMI_HARDWARE_FAILURE<br />◆错误分析:通常是有硬件引起的.(似乎蓝屏与硬件错误有不解之缘)<br />◇解决方案:如果最近安装了新硬件, 请将其移除, 然后试试更换插槽和安装最新的驱动程序, 如果升级了驱动程序, 请恢复后原来的版本; 检查内存金手指是否有污染和损坏; 扫描病毒; 运行"chkdsk /r"检查并修复磁盘错误; 检查所有硬件插卡已经插牢. 如果以上尝试都无效果, 就得找专业的电脑维修公司请求帮助了. <br /><br />┌─┐<br />│23│<br />└─┘0x0000008E:KERNEL_MODE_EXCEPTION_NOT_HANDLED<br />◆错误分析:内核级应用程序产生了错误, 但Windows错误处理器没有捕获. 通常是硬件兼容性错误.<br />◇解决方案:升级驱动程序或升级BIOS. <br /><br />┌─┐<br />│24│<br />└─┘0x0000009C:MACHINE_CHECK_EXCEPTION<br />◆错误分析:通常是硬件引起的. 一般是因为超频或是硬件存在问题(内存、CPU、总线、电源).<br />◇解决方案:如果进行了超频, 请降会CPU原来频率, 检查硬件. <br /><br />┌─┐<br />│25│<br />└─┘0x0000009FRIVER_POWER_STATE_FAILURE<br />◆错误分析:往往与电源有关系, 常常发生在与电源相关的操作, 比如:关机、待机或休睡.<br />◇解决方案:重装系统, 如果不能解决, 请更换电源. <br /><br /><br /><br />┌─┐<br />│26│<br />└─┘0x000000A5:ACPI_BIOS_ERROR<br />◆错误分析:通常是因为主板BIOS不能全面支持ACPI规范.<br />◇解决方案:如果没有相应BIOS升级, 那么可在安装Windows 2K/XP时, 当出现"press F6 if you need to install a third-party SCSI or RAID driver"提示时, 按下F7键, 这样Windows便会自动禁止安装ACPI HAL, 而安装 Standard PC HAL. <br /><br /><br /><br /><br />┌─┐<br />│27│<br />└─┘0x000000B4:VIDEO_DRIVER_INIT_FAILURE<br />◆错误分析:这个停止信息表示Windows因为不能启动显卡驱动, 从而无法进入图形界面. 通常是显卡的问题, 或者是存在与显卡的硬件冲突(比如:与并行或串行端口冲突).<br />◇解决方案:进入安全模式查看问题是否解决, 如果可以, 请升级最新的显卡驱动程序, 如果还不行, 则很可能是显卡与并行端口存在冲突, 需要在安全模式按下WIN+break组合键打开"系统属性", 在硬件--&gt;设备管理器中找到并双击连接打印的LPT1端口的项, 在"资源"选项卡中取消"使用自动配置"的构选, 然后将"输入/输出范围"的"03BC"改为"0378". <br /><br /><br /><br /><br />┌─┐<br />│28│<br />└─┘0x000000BE:ATTEMPTED_WRITE_TO_READONLY_MEMORY<br />◆错误分析:某个驱动程序试图向只读内存写入数据造成的. 通常是在安装了新的驱动程序, 系统服务或升级了设备的固件程序后.<br />◇解决方案:如果在错误信息中包含有驱动程序或者服务文件名称, 请根据这个信息将新安装的驱动程序或软件卸载或禁用. <br /><br /><br /><br /><br />┌─┐<br />│29│<br />└─┘0x000000C2:BAD_POOL_CALLER<br />◆错误分析:一个内核层的进程或驱动程序错误地试图进入内存操作. 通常是驱动程序或存在BUG的软件造成的.<br />◇解决方案:请参考前面介绍的常规解决方案相关项目进行排除. <br /><br /><br /><br /><br /><br />┌─┐<br />│30│<br />└─┘0x000000CERIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS<br />◆错误分析:通常是由有问题的驱动程序或系统服务造成的.<br />◇解决方案:请参考前面介绍的常规解决方案相关项目进行排除. <br /><br /><br /><br /><br />┌─┐<br />│31│<br />└─┘0x000000D1RIVER_IRQL_NOT_LESS_OR_EQUAL<br />◆错误分析:通常是由有问题的驱动程序引起的(比如罗技鼠标的Logitech MouseWare 9.10和9.24版驱动程序会引发这个故障). 同时,有缺陷的内存、 损坏的虚拟内存文件、 某些软件(比如多媒体软件、杀毒软件、备份软件、DVD播放软件)等也会导致这个错误.<br />◇解决方案:检查最新安装或升级的驱动程序(如果蓝屏中出现"acpi.sys"等类似文件名, 可以非常肯定时驱动程序问题)和软件; 测试内存是否存在问题; 进入"故障恢复控制台", 转到虚拟内存页面文件Pagefile.sys所在分区, 执行"del pagefile.sys"命令, 将页面文件删除; 然后在页面文件所在分区执行"chkdsk /r"命令;进入Windows后重新设置虚拟内存.如果在上网时遇到这个蓝屏, 而你恰恰又在进行大量的数据下载和上传(比如:网络游戏、BT下载), 那么应该是网卡驱动的问题, 需要升级其驱动程序. <br /><br /><br /><br /><br />┌─┐<br />│32│<br />└─┘0x000000EA:THREAD_STUCK_IN_DEVICE_DRIVER<br />◆错误分析:通常是由显卡或显卡驱动程序引发的.<br />◇解决方案:先升级最新的显卡驱动, 如果不行, 则需要更换显卡测试故障是否依然发生. <br /><br /><br /><br /><br />┌─┐<br />│33│<br />└─┘0x000000ED:UNMOUNTABLE_BOOT_VOLUME<br />◆错误分析:一般是由于磁盘存在错误导致的, 有时也建议检查硬盘连线是否接触不良, 或是没有使用合乎该硬盘传输规格的连接线, 例如ATA-100仍使用ATA-33的连接线, 对低速硬盘无所谓, 但告诉硬盘(持ATA-66以上)的要求较严格, 规格不对的连线有时也会引起这类没办法开机的故障. 如果在修复后, 还是经常出现这个错误, 很可能是硬盘损坏的前兆.<br />◇解决方案:一般情况下, 重启会解决问题, 不管怎么样都建议执行"chkdsk /r"命令来检查修复硬盘 <br /><br /><br />┌─┐<br />│34│<br />└─┘0x000000F2:HARDWARE)INTERRUPT_STORM<br />◆错误分析:内核层检查到系统出现中断风暴, 比如:某个设备在完成操作后没有释放所占用的中断. 常这是由缺陷的驱动程序造成的.<br />◇解决方案:升级或卸载最新安装的硬件驱动程序. <br /><br /><br />┌─┐<br />│35│<br />└─┘0x00000135:UNABLE_TO_LOCATE_DLL<br />◆错误分析:通常表示某个文件丢失或已经损坏, 或者是注册表出现错误.<br />◇解决方案:如果是文件丢失或损坏, 在蓝屏信息中通常会显示相应的文件名, 你可以通过网络或是其他电脑找到相应的文件, 并将其复制到系统文件夹下的SYSTEM32子文件夹中. 如果没有显示文件名, 那就很有可能是注册表损坏, 请利用系统还原或是以前的注册表备份进行恢复. <br /><br /><br /><br />┌─┐<br />│36│<br />└─┘0x0000021A:STATUS_SYSTEM_PROCESS_TERMINATED<br />◆错误分析:用户模式子系统, 例如Winlogon或客服服务运行时子系统(CSRSS)已损坏, 所以无法再保证安全性, 导致系统无法启动. 有时, 当系统管理员错误地修改了用户帐号权限, 导致其无法访问系统文件和文件夹.<br />◇解决方案:使用"最后一次正确的配置", 如果无效, 可使用安装光盘进行修复安装. <br /><br /><br />┌─┐<br />│37│<br />└─┘STOP 0xC0000221 or STATUS_IMAGE_CHECKSUM_MISMATCH<br />◆错误分析:通常是由于驱动程序或系统DLL文件损坏造成的. 一般情况下, 在蓝屏中会出现文件名称.<br />◇解决方案:<br />(1)使用Windows安装光盘进行修复安装;<br />(2)如果还能进入安全模式, 可以"开始--&gt;运行": sfc /scannow<br />(3)还可以采用提取文件的方法来解决, 进入"故障恢复控制台", 使用copy或expand命令从光盘中复制或解压受损的文件. 不过, 蓝屏一般都是驱动程序文件的问题, 所以expand命令会用的都一些, 比如:蓝屏中提示tdi.sys文件, 因为驱动文件一般在i386\driver压缩包里, 所以使用: expand %CDROM:\i386\driver.cab \f:tdi.sys c:\winnt\system\drivers.(xp为expand %CDROM:\i386\driver.cab f:tdi.sys c:\windowns\system\drivers) <br /><br /><br />┌─┐<br />│38│<br />└─┘如果启动时出现这些蓝屏停机码<br />如果在Windows启动时出现蓝屏, 并出现附表一中的错误信息, 那么多半时硬件出现了问题, 请用硬件厂商提供的诊断工具来判断硬件是否存在问题, 并到其网站查看是否有最新的BIOS或固件更新程序. 如果硬件没有问题, 重装Windows 2K/XP, 若相同问题还是出现, 就只能求助专业的技术支持了.果遇到的时附表二中的错误信息, 也只有重装Windows了, 如果不能解决问题, 建议求救专业的技术支持.</font>
				</span>
		</p><img src ="http://www.cnitblog.com/yuhensong/aggbug/23462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/yuhensong/" target="_blank">yuhen</a> 2007-03-02 10:03 <a href="http://www.cnitblog.com/yuhensong/archive/2007/03/02/23462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>