<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=APIC_timer</id>
	<title>APIC timer - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=APIC_timer"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=APIC_timer&amp;action=history"/>
	<updated>2026-04-07T06:22:08Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=APIC_timer&amp;diff=1132&amp;oldid=prev</id>
		<title>2022年4月2日 (六) 08:25 Zhang3</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=APIC_timer&amp;diff=1132&amp;oldid=prev"/>
		<updated>2022-04-02T08:25:30Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2022年4月2日 (六) 08:25的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;第1行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第1行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;本地[[APIC]]定时器的最大好处是，它与每个CPU核心都是硬连线的，而[[PIT|PIT(Programmable Interval Timer - 可编程间隔定时器]]是一个单独的电路。 因此，不需要任何资源管理，这使得事情变得更容易。 缺点是它以CPU的频率之一振荡，该频率因机器而异，而PIT使用标准频率 (1,193,182Hz)。 要利用它，你必须知道它每秒能中断多少次。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;本地[[APIC]]定时器的最大好处是，它与每个CPU核心都是硬连线的，而[[PIT|PIT(Programmable Interval Timer - 可编程间隔定时器&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;)&lt;/ins&gt;]]是一个单独的电路。 因此，不需要任何资源管理，这使得事情变得更容易。 缺点是它以CPU的频率之一振荡，该频率因机器而异，而PIT使用标准频率 (1,193,182Hz)。 要利用它，你必须知道它每秒能中断多少次。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==APIC定时器模式==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==APIC定时器模式==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l11&quot;&gt;第11行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第11行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;例如，对于外部/总线频率为800兆赫兹的2.4GHzCPU，如果将分频配置寄存器设置为“除以4”并且将初始计数设置为123456； 然后，本地APIC定时器将以200 MHz的速率递减计数，并每617.28产生一个定时器IRQ，给出1620.01Hz的IRQs速率。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;例如，对于外部/总线频率为800兆赫兹的2.4GHzCPU，如果将分频配置寄存器设置为“除以4”并且将初始计数设置为123456； 然后，本地APIC定时器将以200 MHz的速率递减计数，并每617.28产生一个定时器IRQ，给出1620.01Hz的IRQs速率。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==One-Shot模式===&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;=&lt;/ins&gt;==One-Shot模式===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;对于One-Shot单触发模式，本地APIC以与周期模式相同的方式递减当前计数(并在计数达到零时生成定时器IRQ)； 但是，当当前计数达到零时，它不会将当前计数重置为初始计数。 相反，如果软件想要更多的定时器IRQ，它必须每次设置一个新的计数。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;对于One-Shot单触发模式，本地APIC以与周期模式相同的方式递减当前计数(并在计数达到零时生成定时器IRQ)； 但是，当当前计数达到零时，它不会将当前计数重置为初始计数。 相反，如果软件想要更多的定时器IRQ，它必须每次设置一个新的计数。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l19&quot;&gt;第19行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第19行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;缺点是，使用一次性模式更难实时跟踪，需要特别注意避免竞争条件；尤其是如果在旧计数到期之前设置了新计数。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;缺点是，使用一次性模式更难实时跟踪，需要特别注意避免竞争条件；尤其是如果在旧计数到期之前设置了新计数。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== TSC-Deadline 模式=&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== TSC-Deadline 模式 &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;==&lt;/ins&gt;=&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;TSC-Deadline模式与其他2种模式有很大不同。 &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;当CPU的时间戳计数器的值大于或等于截止日期时，软件设置“截止日期”，本地APIC生成定时器IRQ，而不是使用CPU的外部&lt;/del&gt;/&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;总线频率来减少计数。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;TSC-Deadline模式与其他2种模式有很大不同。 &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;该模式不是使用CPU的外部&lt;/ins&gt;/&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;总线频率来减少计数，而是软件设置“Deadline”，当CPU的时间戳计数器的值大于或等于Deadline时本地APIC生成定时器IRQ。&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;尽管有这些不同之处，但软件将/可以以与使用一次模式相同的方式使用它。 优点 (与 one-shot模式相比) 是你获得更高的精度 （因为CPU的时间戳计数器以CPU的（标称）内部频率而不是CPU的外部/总线频率运行）， 而且更容易避免/处理竞争条件。&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;尽管有这些不同之处，但软件将/可以以与使用一次模式相同的方式使用它。 优点 (与 one-shot模式相比) 是你获得更高的精度 （因为CPU的时间戳计数器以CPU的（标称）内部频率而不是CPU的外部/总线频率运行）， 而且更容易避免/处理竞争条件。&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l47&quot;&gt;第47行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第47行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;有几种方法可以做到这一点，但它们都使用不同的、独立于CPU总线频率的时钟源来做到这一点。 例如：[[RTC|实时时钟]]，[[TSC|时间戳计数器（TimeStamp Counter）]]，PIT或甚至轮询[[CMOS#&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;从RTC获得当前日期时间&lt;/del&gt;|CMOS寄存器]]获取。 在本教程中，我们将使用又老又好的PIT，因为它是最简单的。 需要完成的步骤:&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;有几种方法可以做到这一点，但它们都使用不同的、独立于CPU总线频率的时钟源来做到这一点。 例如：[[RTC|实时时钟]]，[[TSC|时间戳计数器（TimeStamp Counter）]]，PIT或甚至轮询[[CMOS#&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;从RTC获取当前日期和时间&lt;/ins&gt;|CMOS寄存器]]获取。 在本教程中，我们将使用又老又好的PIT，因为它是最简单的。 需要完成的步骤:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 将APIC重置为必要状态&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 将APIC重置为必要状态&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 启用APIC定时器&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* 启用APIC定时器&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l94&quot;&gt;第94行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第94行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		iret&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		iret&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;isr_spurious:	iret&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;isr_spurious:	iret&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;function to set a specific interrupt gate in IDT&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		; &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;在IDT中设置特定中断门（interrupt gate）的函数&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		;al=interrupt&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		;al=interrupt&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		;ebx=isr entry point&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		;ebx=isr entry point&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l217&quot;&gt;第217行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第217行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== C语言中的示例代码 ===&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;=== C语言中的示例代码 ===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;此代码是如何初始化APIC定时器以使其每10毫秒计时一次的示例。 这是通过让APIC定时器运行，使用PIT等待10毫秒，然后从APIC定时器获取滴答次数来完成的。 &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;它假设你拥有“写入”&lt;/del&gt;/&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;“读取”APIC寄存器和“pit_prepare_sleep”&lt;/del&gt;/&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;“pit_perform_sleep”功能，以尽可能准确地测量定时器的频率。&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;此代码是如何初始化APIC定时器以使其每10毫秒计时一次的示例。 这是通过让APIC定时器运行，使用PIT等待10毫秒，然后从APIC定时器获取滴答次数来完成的。 &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;它假设你拥有“write&lt;/ins&gt;/&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;read”APIC寄存器和“pit_prepare_sleep”&lt;/ins&gt;/&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;“pit_perform_sleep”函数，以尽可能准确地测量定时器的频率。&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;void apic_start_timer() {&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;void apic_start_timer() {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         //告诉APIC定时器使用divider16&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         // 告诉APIC定时器使用divider16&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         write(APIC_REGISTER_TIMER_DIV, 0x3);&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         write(APIC_REGISTER_TIMER_DIV, 0x3);&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;   &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;   &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=APIC_timer&amp;diff=1131&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“本地APIC定时器的最大好处是，它与每个CPU核心都是硬连线的，而PIT(Programmable Interval Timer - 可编程间隔定时器是一个单独的电路。 因此，不需要任何资源管理，这使得事情变得更容易。 缺点是它以CPU的频率之一振荡，该频率因机器而异，而PIT使用标准频率 (1,193,182Hz)。 要利用它，你必须知道它每秒能中断多少次。  ==APIC定时器模式==  定时器…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=APIC_timer&amp;diff=1131&amp;oldid=prev"/>
		<updated>2022-04-02T08:10:02Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“本地&lt;a href=&quot;/index.php?title=APIC&quot; title=&quot;APIC&quot;&gt;APIC&lt;/a&gt;定时器的最大好处是，它与每个CPU核心都是硬连线的，而&lt;a href=&quot;/index.php?title=PIT&quot; class=&quot;mw-redirect&quot; title=&quot;PIT&quot;&gt;PIT(Programmable Interval Timer - 可编程间隔定时器&lt;/a&gt;是一个单独的电路。 因此，不需要任何资源管理，这使得事情变得更容易。 缺点是它以CPU的频率之一振荡，该频率因机器而异，而PIT使用标准频率 (1,193,182Hz)。 要利用它，你必须知道它每秒能中断多少次。  ==APIC定时器模式==  定时器…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;本地[[APIC]]定时器的最大好处是，它与每个CPU核心都是硬连线的，而[[PIT|PIT(Programmable Interval Timer - 可编程间隔定时器]]是一个单独的电路。 因此，不需要任何资源管理，这使得事情变得更容易。 缺点是它以CPU的频率之一振荡，该频率因机器而异，而PIT使用标准频率 (1,193,182Hz)。 要利用它，你必须知道它每秒能中断多少次。&lt;br /&gt;
&lt;br /&gt;
==APIC定时器模式==&lt;br /&gt;
&lt;br /&gt;
定时器有2或3种模式。 前两种模式（周期性periodic和一次性one-shot）由所有本地APIC支持。 第三种模式(TSC-Deadline模式)是仅在最近的CPU上支持的扩展。&lt;br /&gt;
&lt;br /&gt;
=== 周期模式 ===&lt;br /&gt;
&lt;br /&gt;
对于周期模式，软件设置“初始计数”，本地APIC将其用于“当前计数”。 本地APIC递减当前计数直到其达到零，然后生成定时器IRQ并将当前计数重置为初始计数，并再次开始递减当前计数。 这样，本地APIC根据初始计数以固定速率生成IRQs。 当前计数的递减率取决于CPU的外部频率（“总线频率”）除以本地APIC的“除配置寄存器（Divide Configuration Register）”中的值。&lt;br /&gt;
&lt;br /&gt;
例如，对于外部/总线频率为800兆赫兹的2.4GHzCPU，如果将分频配置寄存器设置为“除以4”并且将初始计数设置为123456； 然后，本地APIC定时器将以200 MHz的速率递减计数，并每617.28产生一个定时器IRQ，给出1620.01Hz的IRQs速率。&lt;br /&gt;
&lt;br /&gt;
==One-Shot模式===&lt;br /&gt;
&lt;br /&gt;
对于One-Shot单触发模式，本地APIC以与周期模式相同的方式递减当前计数(并在计数达到零时生成定时器IRQ)； 但是，当当前计数达到零时，它不会将当前计数重置为初始计数。 相反，如果软件想要更多的定时器IRQ，它必须每次设置一个新的计数。&lt;br /&gt;
&lt;br /&gt;
这种模式的优点是，软件可以精确控制定时器IRQ何时发生。 例如，在任务切换期间，操作系统可以将计数设置为取决于新任务优先级的值 (以便某些任务运行少量时间而其他任务运行较长时间)， 而且不会有任何不必要的IRQ。 一些操作系统使用这种方法来实现通用的高精度定时器服务，其中本地APIC计数被设置为取决于哪个事件将最快发生的值。 例如，如果当前运行的任务开关应在1234纳秒内被抢先，则休眠任务需要在333纳秒内唤醒，并且必须在44444纳秒内发送警报信号， 然后定时器的计数将设置为333纳秒（所需的最早延迟） 当定时器IRQ发生时，OS知道在当前任务应该被抢占之前还有901纳秒，在需要发送报警信号之前还有441111纳秒 (并将下一个定时器IRQ的计数设置为901纳秒)。&lt;br /&gt;
&lt;br /&gt;
缺点是，使用一次性模式更难实时跟踪，需要特别注意避免竞争条件；尤其是如果在旧计数到期之前设置了新计数。&lt;br /&gt;
&lt;br /&gt;
=== TSC-Deadline 模式=&lt;br /&gt;
&lt;br /&gt;
TSC-Deadline模式与其他2种模式有很大不同。 当CPU的时间戳计数器的值大于或等于截止日期时，软件设置“截止日期”，本地APIC生成定时器IRQ，而不是使用CPU的外部/总线频率来减少计数。&lt;br /&gt;
&lt;br /&gt;
尽管有这些不同之处，但软件将/可以以与使用一次模式相同的方式使用它。 优点 (与 one-shot模式相比) 是你获得更高的精度 （因为CPU的时间戳计数器以CPU的（标称）内部频率而不是CPU的外部/总线频率运行）， 而且更容易避免/处理竞争条件。&lt;br /&gt;
&lt;br /&gt;
== 启用APIC定时器 ==&lt;br /&gt;
&lt;br /&gt;
在启用本地APIC定时器之前，应该设置本地APIC的其余部分。这包括：&lt;br /&gt;
&lt;br /&gt;
* 确定本地APIC的物理地址(通过ACPI表或多处理器规格表)&lt;br /&gt;
* 指定一个虚拟中断和软件启用APIC&lt;br /&gt;
* 确保TPR（任务优先级寄存器）已设置（因此它不会阻止/延迟低优先级IRQ）&lt;br /&gt;
&lt;br /&gt;
一旦完成此操作：&lt;br /&gt;
&lt;br /&gt;
* 设置本地APIC定时器的除法配置寄存器&lt;br /&gt;
* 配置本地APIC定时器的中断向量，并取消定时器的IRQ掩码&lt;br /&gt;
* 设置本地APIC定时器的初始计数&lt;br /&gt;
&lt;br /&gt;
注意: 建议遵循上面给出的顺序 (尤其是最后设置本地APIC定时器的初始计数)。 以不同的顺序进行操作（例如设置初始计数，然后启用定时器）可能会导致某些（真实或虚拟）机器出现问题 (例如，一切似乎都正确，计数器正在减少，但IRQ从不发送)。&lt;br /&gt;
&lt;br /&gt;
== 初始化 ==&lt;br /&gt;
“请注意，这是确定APIC定时器频率的推荐方法。”&lt;br /&gt;
&lt;br /&gt;
'''注意：''' 根据英特尔IA-32 (x86) 和英特尔64 (x86_64) 的文档，APIC定时器的频率等于总线的频率 '''或'''核心晶振的频率除以所选的分频器。 总线和核心晶体的频率可以在[[CPUID|CPUID]]函数中找到分别为[https://sandpile.org/x86/cpuid.htm#level_0000_0015h 0x15]和[https://sandpile.org/x86/cpuid.htm#level_0000_0016h 0x16]。 通过CPUID.0x15还可以确定TSC频率。 APIC定时器的频率取决于系统是使用本地APIC还是 “discrete” APIC ([https://en.wikipedia.org/wiki/advanced_programmale_interrupt_controller 82489DX])。 当本地APIC内置在核心晶振中时，APIC定时器使用核心的频率。 否则，它使用的是总线频率。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
有几种方法可以做到这一点，但它们都使用不同的、独立于CPU总线频率的时钟源来做到这一点。 例如：[[RTC|实时时钟]]，[[TSC|时间戳计数器（TimeStamp Counter）]]，PIT或甚至轮询[[CMOS#从RTC获得当前日期时间|CMOS寄存器]]获取。 在本教程中，我们将使用又老又好的PIT，因为它是最简单的。 需要完成的步骤:&lt;br /&gt;
* 将APIC重置为必要状态&lt;br /&gt;
* 启用APIC定时器&lt;br /&gt;
* 重置APIC定时器计数器&lt;br /&gt;
* 等待不同时钟测量的特定时间&lt;br /&gt;
* 从APIC定时器计数器获取滴答数&lt;br /&gt;
* 调整到一秒钟&lt;br /&gt;
* 除以你选择的数量（结果X）&lt;br /&gt;
* 使APIC定时器在每X个节拍时触发一个中断&lt;br /&gt;
&lt;br /&gt;
APIC定时器可以设置为在给定频率下进行tick (减小计数器)，称为 “分值”。 这意味着你必须将APIC定时器计数器tick数乘以这个除法值，才能得到真正的CPU总线频率。 你可以使用值1(每个总线周期上的tick)到128(每128个周期上的tick)。 有关详细信息，请参阅Intel手册vol3A第9.5.4章。 请注意，根据我的测试，Bochs似乎无法正确处理1的除除数，因此我将使用16。&lt;br /&gt;
&lt;br /&gt;
===先决条件===&lt;br /&gt;
在开始之前，让我们定义一些常量和函数。&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
APIC=映射APIC寄存器的线性地址&lt;br /&gt;
&lt;br /&gt;
APIC_APICID	= 20h&lt;br /&gt;
APIC_APICVER	= 30h&lt;br /&gt;
APIC_TASKPRIOR	= 80h&lt;br /&gt;
APIC_EOI	= 0B0h&lt;br /&gt;
APIC_LDR	= 0D0h&lt;br /&gt;
APIC_DFR	= 0E0h&lt;br /&gt;
APIC_SPURIOUS	= 0F0h&lt;br /&gt;
APIC_ESR	= 280h&lt;br /&gt;
APIC_ICRL	= 300h&lt;br /&gt;
APIC_ICRH	= 310h&lt;br /&gt;
APIC_LVT_TMR	= 320h&lt;br /&gt;
APIC_LVT_PERF	= 340h&lt;br /&gt;
APIC_LVT_LINT0	= 350h&lt;br /&gt;
APIC_LVT_LINT1	= 360h&lt;br /&gt;
APIC_LVT_ERR	= 370h&lt;br /&gt;
APIC_TMRINITCNT	= 380h&lt;br /&gt;
APIC_TMRCURRCNT	= 390h&lt;br /&gt;
APIC_TMRDIV	= 3E0h&lt;br /&gt;
APIC_LAST	= 38Fh&lt;br /&gt;
APIC_DISABLE	= 10000h&lt;br /&gt;
APIC_SW_ENABLE	= 100h&lt;br /&gt;
APIC_CPUFOCUS	= 200h&lt;br /&gt;
APIC_NMI	= (4&amp;lt;&amp;lt;8)&lt;br /&gt;
TMR_PERIODIC	= 20000h&lt;br /&gt;
TMR_BASEDIV	= (1&amp;lt;&amp;lt;20)&lt;br /&gt;
&lt;br /&gt;
		;Interrupt Service Routines&lt;br /&gt;
isr_dummytmr:	mov			dword [apic+APIC_EOI], 0&lt;br /&gt;
		iret&lt;br /&gt;
isr_spurious:	iret&lt;br /&gt;
		;function to set a specific interrupt gate in IDT&lt;br /&gt;
		;al=interrupt&lt;br /&gt;
		;ebx=isr entry point&lt;br /&gt;
writegate:	...&lt;br /&gt;
		ret&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
我还将假设你有一个工作的 [[IDT]]，并且你有一个函数可以为特定的中断编写一个门: writegate(intnumber，israddress)。&lt;br /&gt;
此外，为了简单起见，我假设你没有更改几乎每个教程中的默认中断映射：&lt;br /&gt;
*中断0-31：异常&lt;br /&gt;
* 中断32: 定时器，IRQ0&lt;br /&gt;
*中断39：虚拟irq，IRQ7&lt;br /&gt;
如果你已经对此进行了更改，请进行相应的修改。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ASM中的示例代码 ===&lt;br /&gt;
以下是在fasm语法程序集中初始化APIC定时器的一种可能方法：&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
		；你应该读取MSR，获得APIC基址，并映射到“APIC”&lt;br /&gt;
		;you should have used lidt properly&lt;br /&gt;
&lt;br /&gt;
		;set up isrs&lt;br /&gt;
		mov			al, 32&lt;br /&gt;
		mov			ebx, isr_dummytmr&lt;br /&gt;
		call			writegate&lt;br /&gt;
		mov			al, 39&lt;br /&gt;
		mov			ebx, isr_spurious&lt;br /&gt;
		call			writegate&lt;br /&gt;
&lt;br /&gt;
		; 将LAPIC初始化为合适的状态&lt;br /&gt;
		mov			dword [apic+APIC_DFR], 0FFFFFFFFh&lt;br /&gt;
		mov			eax, dword [apic+APIC_LDR]&lt;br /&gt;
		and			eax, 00FFFFFFh&lt;br /&gt;
		or			al, 1&lt;br /&gt;
		mov			dword [apic+APIC_LDR], eax&lt;br /&gt;
		mov			dword [apic+APIC_LVT_TMR], APIC_DISABLE&lt;br /&gt;
		mov			dword [apic+APIC_LVT_PERF], APIC_NMI&lt;br /&gt;
		mov			dword [apic+APIC_LVT_LINT0], APIC_DISABLE&lt;br /&gt;
		mov			dword [apic+APIC_LVT_LINT1], APIC_DISABLE&lt;br /&gt;
		mov			dword [apic+APIC_TASKPRIOR], 0&lt;br /&gt;
		;okay, now we can enable APIC&lt;br /&gt;
		;global enable&lt;br /&gt;
		mov			ecx, 1bh&lt;br /&gt;
		rdmsr&lt;br /&gt;
		bts			eax, 11&lt;br /&gt;
		wrmsr&lt;br /&gt;
		;软件启用，将虚拟中断映射到虚拟isr&lt;br /&gt;
		mov			dword [apic+APIC_SPURIOUS], 39+APIC_SW_ENABLE&lt;br /&gt;
		; 将APIC定时器映射到中断，并通过该中断在one-shot模式中启用它&lt;br /&gt;
		mov			dword [apic+APIC_LVT_TMR], 32&lt;br /&gt;
		; 将除数设置为16&lt;br /&gt;
		mov			dword [apic+APIC_TMRDIV], 03h&lt;br /&gt;
&lt;br /&gt;
		;ebx=0xFFFFFFFF;&lt;br /&gt;
		xor			ebx, ebx&lt;br /&gt;
		dec			ebx&lt;br /&gt;
&lt;br /&gt;
		; 在one-shot模式下初始化PIT Ch 2&lt;br /&gt;
		; 等待1秒可能会显著减慢引导时间，&lt;br /&gt;
		; 所以我们将等待1/100秒，并乘以计数的ticks&lt;br /&gt;
		mov			dx, 61h&lt;br /&gt;
		in			al, dx&lt;br /&gt;
		and			al, 0fdh&lt;br /&gt;
		or			al, 1&lt;br /&gt;
		out			dx, al&lt;br /&gt;
		mov			al, 10110010b&lt;br /&gt;
		out			43h, al&lt;br /&gt;
		;1193180/100 Hz = 11931 = 2e9bh&lt;br /&gt;
		mov			al, 9bh		;LSB&lt;br /&gt;
		out			42h, al&lt;br /&gt;
		in			al, 60h		;short delay&lt;br /&gt;
		mov			al, 2eh		;MSB&lt;br /&gt;
		out			42h, al&lt;br /&gt;
		;reset PIT one-shot counter (start counting)&lt;br /&gt;
		in			al, dx&lt;br /&gt;
		and			al, 0feh&lt;br /&gt;
		out			dx, al		;gate low&lt;br /&gt;
		or			al, 1&lt;br /&gt;
		out			dx, al		;gate high&lt;br /&gt;
		;reset APIC timer (set counter to -1)&lt;br /&gt;
		mov			dword [apic+APIC_TMRINITCNT], ebx&lt;br /&gt;
		;now wait until PIT counter reaches zero&lt;br /&gt;
@@:		in			al, dx&lt;br /&gt;
		and			al, 20h&lt;br /&gt;
		jz			@b&lt;br /&gt;
		;stop APIC timer&lt;br /&gt;
		mov			dword [apic+APIC_LVT_TMR], APIC_DISABLE&lt;br /&gt;
		;now do the math...&lt;br /&gt;
		xor			eax, eax&lt;br /&gt;
		xor			ebx, ebx&lt;br /&gt;
		dec			eax&lt;br /&gt;
		;get current counter value&lt;br /&gt;
		mov			ebx, dword [apic+APIC_TMRCURRCNT]&lt;br /&gt;
		;it is counted down from -1, make it positive&lt;br /&gt;
		sub			eax, ebx&lt;br /&gt;
		inc			eax&lt;br /&gt;
		;we used divide value different than 1, so now we have to multiply the result by 16&lt;br /&gt;
		shl			eax, 4		;*16&lt;br /&gt;
		xor			edx, edx&lt;br /&gt;
		;moreover, PIT did not wait a whole sec, only a fraction, so multiply by that too&lt;br /&gt;
		mov			ebx, 100	;*PITHz&lt;br /&gt;
		mul			ebx&lt;br /&gt;
	;-----edx:eax now holds the CPU bus frequency-----&lt;br /&gt;
		;now calculate timer counter value of your choice&lt;br /&gt;
		;this means that tasks will be preempted 1000 times in a second. 100 is popular too.&lt;br /&gt;
		mov			ebx, 1000&lt;br /&gt;
		xor			edx, edx&lt;br /&gt;
		div			ebx&lt;br /&gt;
		;again, we did not use divide value of 1&lt;br /&gt;
		shr			eax, 4		;/16&lt;br /&gt;
		;sanity check, min 16&lt;br /&gt;
		cmp			eax, 010h&lt;br /&gt;
		jae			@f&lt;br /&gt;
		mov			eax, 010h&lt;br /&gt;
		;now eax holds appropriate number of ticks, use it as APIC timer counter initializer&lt;br /&gt;
@@:		mov			dword [apic+APIC_TMRINITCNT], eax&lt;br /&gt;
		;finally re-enable timer in periodic mode&lt;br /&gt;
		mov			dword [apic+APIC_LVT_TMR], 32 or TMR_PERIODIC&lt;br /&gt;
		;setting divide value register again not needed by the manuals&lt;br /&gt;
		;although I have found buggy hardware that required it&lt;br /&gt;
		mov			dword [apic+APIC_TMRDIV], 03h&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== C语言中的示例代码 ===&lt;br /&gt;
此代码是如何初始化APIC定时器以使其每10毫秒计时一次的示例。 这是通过让APIC定时器运行，使用PIT等待10毫秒，然后从APIC定时器获取滴答次数来完成的。 它假设你拥有“写入”/“读取”APIC寄存器和“pit_prepare_sleep”/“pit_perform_sleep”功能，以尽可能准确地测量定时器的频率。&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void apic_start_timer() {&lt;br /&gt;
        //告诉APIC定时器使用divider16&lt;br /&gt;
        write(APIC_REGISTER_TIMER_DIV, 0x3);&lt;br /&gt;
 &lt;br /&gt;
        // 准备PIT休眠10ms (10000 µ s)&lt;br /&gt;
        pit_prepare_sleep(10000);&lt;br /&gt;
 &lt;br /&gt;
        // 将APIC init计数器设置为 -1&lt;br /&gt;
        write(APIC_REGISTER_TIMER_INITCNT, 0xFFFFFFFF);&lt;br /&gt;
 &lt;br /&gt;
        // 执行PIT支持的休眠&lt;br /&gt;
        pit_perform_sleep();&lt;br /&gt;
 &lt;br /&gt;
        // 停止APIC定时器&lt;br /&gt;
        write(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED);&lt;br /&gt;
 &lt;br /&gt;
        // 现在我们知道APIC计时器在10毫秒内ticked的频率&lt;br /&gt;
        uint32_t ticksIn10ms = 0xFFFFFFFF - read(APIC_REGISTER_TIMER_CURRCNT);&lt;br /&gt;
 &lt;br /&gt;
        // 在IRQ 0的divider16上启动计时器为周期定时器，计时时间为我们计算的时钟周期数&lt;br /&gt;
        write(APIC_REGISTER_LVT_TIMER, 32 | APIC_LVT_TIMER_MODE_PERIODIC);&lt;br /&gt;
        write(APIC_REGISTER_TIMER_DIV, 0x3);&lt;br /&gt;
        write(APIC_REGISTER_TIMER_INITCNT, ticksIn10ms);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==另见==&lt;br /&gt;
===文章===&lt;br /&gt;
* [[APIC]]&lt;br /&gt;
=== 论坛主题 ===&lt;br /&gt;
* [http://www.osdev.org/phpBB2/viewtopic.php?t=10686 APIC timer]&lt;br /&gt;
&lt;br /&gt;
===外部链接===&lt;br /&gt;
* [http://www.intel.com/products/processor/manuals/ Volume 3A:System Programming Guide, Part 1,manuals has a chapter on the APIC]&lt;br /&gt;
* [http://www.osdever.net/tutorials/view/advanced-programming-interrupt-controller Advanced Programmable Interrupt Controller by Mike Rieker]&lt;br /&gt;
&lt;br /&gt;
[[Category:Interrupts]]&lt;br /&gt;
[[Category:Time]]&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>