Assembly 修改时钟中断处理程序xinu
今晚我有一个操作系统项目,需要澄清一个主题。我们正在使用操作系统XINU。我正在尝试更改默认的OS调度程序,以考虑某些进程的不足。我被引导到clkint.S文件,我认为它是时钟中断处理程序。我的问题是,我如何知道它多久中断一次?我如何设置每5秒进行一次函数调用的时间?我看过英特尔x86手册,但它们有大量的信息需要筛选,我的时间很短。如果有人能给我指出正确的方向,我将不胜感激 以下是我认为必要的几个文件:Assembly 修改时钟中断处理程序xinu,assembly,operating-system,x86,interrupt,Assembly,Operating System,X86,Interrupt,今晚我有一个操作系统项目,需要澄清一个主题。我们正在使用操作系统XINU。我正在尝试更改默认的OS调度程序,以考虑某些进程的不足。我被引导到clkint.S文件,我认为它是时钟中断处理程序。我的问题是,我如何知道它多久中断一次?我如何设置每5秒进行一次函数调用的时间?我看过英特尔x86手册,但它们有大量的信息需要筛选,我的时间很短。如果有人能给我指出正确的方向,我将不胜感激 以下是我认为必要的几个文件: clkint.S: /* clkint.s - _clkint */ #incl
clkint.S:
/* clkint.s - _clkint */
#include <icu.s>
.text
count1000: .word 1000
.globl sltop
.globl clkint
clkint:
pushal
cli
movb $EOI,%al
outb %al,$OCW1_2
incl ctr1000
subw $1,count1000
ja cl1
incl clktime
movw $1000,count1000
cl1:
cmpl $0,slnonempty # if no sleeping processes,
je clpreem # skip to preemption check
movl sltop,%eax # decrement key of first
decl (%eax) # sleeping process
jg clpreem # must use jg for signed int
call wakeup # if zero, call wakeup
clpreem: decl preempt # decrement preemption counter
jg clret # must use jg for signed int
call resched # if preemption, call resched
clret: # return from interrupt
sti
popal
iret
clkint.S:
/*clkint.s-\u clkint*/
#包括
.文本
count1000:。单词1000
.globl sltop
格洛比尔·克金特先生
clkint:
普沙尔
cli
movb$EOI,%al
支出%al,$OCW1_2
包括ctr1000
subw$1000
ja cl1
包括clktime
movw$1000,count1000
cl1:
cmpl$0,slnonempty#如果没有睡眠进程,
je CLPREEME#跳到抢占检查
movl sltop,%eax#第一个的减量键
decl(%eax)#睡眠过程
jg clpreem#必须将jg用于签名整数
呼叫唤醒#如果为零,则呼叫唤醒
CLPREEME:decl抢占#减量抢占计数器
jg clret#必须将jg用于有符号整数
调用resched#如果抢占,则调用resched
clret:#从中断返回
性病
波帕尔
艾雷特
clkinit.c:
/* clkinit.c - clkinit */
#include <xinu.h>
#include <interrupt.h>
#include <clock.h>
uint32 clktime; /* seconds since boot */
uint32 ctr1000 = 0; /* milliseconds since boot */
qid16 sleepq; /* queue of sleeping processes */
int32 slnempty; /* zero if the sleep queue is empty; */
/* non-zero otherwise */
int32 *sltop; /* ptr to key in first entry of sleepq */
/* if sleepq is not empty */
uint32 preempt; /* preemption counter */
/*------------------------------------------------------------------------
* clkinit - initialize the clock and sleep queue at startup
*------------------------------------------------------------------------
*/
void clkinit(void)
{
uint16 intv; /* clock rate in KHz */
/* Set interrupt vector for clock to invoke clkint */
set_evec(IRQBASE, (uint32)clkint);
/* clock rate is 1.190 Mhz; this is 10ms interrupt rate */
intv = 1190;
sleepq = newqueue(); /* allocate a queue to hold the delta */
/* list of sleeping processes */
preempt = QUANTUM; /* initial time quantum */
/* Specify that seepq is initially empty */
slnonempty = FALSE;
clktime = 0; /* start counting seconds */
/* set to: timer 0, 16-bit counter, rate generator mode,
counter is binary */
outb(CLKCNTL, 0x34);
/* must write LSB first, then MSB */
outb(CLOCK0, (char)intv);
outb(CLOCK0, intv>>8);
return;
}
/*clkinit.c-clkinit*/
#包括
#包括
#包括
uint32 clktime;/*开机后的秒数*/
uint32 ctr1000=0;/*启动后的毫秒数*/
qid16 sleepq;/*休眠进程队列*/
int32 slnempty;/*如果睡眠队列为空,则为零*/
/*否则为非零*/
int32*sltop;/*ptr输入sleepq的第一个条目*/
/*如果sleepq不是空的*/
uint32抢占;/*抢占计数器*/
/*------------------------------------------------------------------------
*clkinit-启动时初始化时钟和睡眠队列
*------------------------------------------------------------------------
*/
作废clkinit(作废)
{
uint16 intv;/*时钟频率,单位为KHz*/
/*为调用clkint的时钟设置中断向量*/
设定值(IRQBASE,(uint32)clkint);
/*时钟频率为1.190 Mhz;这是10毫秒的中断频率*/
intv=1190;
sleepq=newqueue();/*分配一个队列来保存增量*/
/*睡眠进程列表*/
抢占=量子;/*初始时间量子*/
/*指定seepq最初为空*/
slnonempty=FALSE;
clktime=0;/*开始计算秒数*/
/*设置为:定时器0,16位计数器,速率发生器模式,
计数器是二进制的*/
outb(CLKCNTL,0x34);
/*必须先写入LSB,然后写入MSB*/
outb(时钟0,(字符)intv);
outb(时钟0,intv>>8);
返回;
}
clkhandler.c:
/* clkhandler.c - clkhandler */
#include <xinu.h>
/*------------------------------------------------------------------------
* clkhandler - handle clock interrupt and process preemption events
* as well as awakening sleeping processes
*------------------------------------------------------------------------
*/
interrupt clkhandler(void)
{
clkupdate(CLKCYCS_PER_TICK);
/* record clock ticks */
clkticks++;
/* update global counter for seconds */
if (clkticks == CLKTICKS_PER_SEC) {
clktime++;
clkticks = 0;
}
/* If sleep queue is nonempty, decrement first key; when the */
/* key reaches zero, awaken a sleeping process */
if (nonempty(sleepq) && (--firstkey(sleepq) <= 0)) {
wakeup();
}
/* Check to see if this proc should be preempted */
if (--preempt <= 0) {
preempt = QUANTUM;
resched();
}
return;
}
/*clkhandler.c-clkhandler*/
#包括
/*------------------------------------------------------------------------
*clkhandler-处理时钟中断和处理抢占事件
*以及唤醒睡眠的过程
*------------------------------------------------------------------------
*/
中断clkhandler(无效)
{
clkupdate(每刻度CLKCYCS);
/*记录时钟滴答声*/
clkticks++;
/*更新全局计数器秒*/
如果(clkticks==clkticks\u/秒){
clktime++;
clkticks=0;
}
/*如果睡眠队列为非空,则减少第一个键;当*/
/*键达到零,唤醒一个睡眠过程*/
如果(nonempty(sleepq)&&(-firstkey(sleepq)intv
是用于调度的中断计时器的时间切片粒度(以Khz为单位)(至少在此代码中是如此)。每5秒听起来非常慢,可能会使系统几乎没有响应,请尝试毫秒的顺序
要计算新的间隔,您需要更改此值并对频率进行一点计算。您可能可以通过在intv
上进行的计算得出这一步,以获得10ms
在x86中,可以通过使用outb
汇编指令将计时器中断值(KHz)写入端口0x40
来建立计时器值。如代码所示,您必须先写入最低有效字节,然后再写入最高有效字节(outb
一次写入一个字节)。若要启用计时器,请将0x36
写入同一端口,并且必须将IRQ处理程序绑定到IRQ0才能接收中断。我尝试为您压缩一点信息,但这是x86特定的。我甚至不明白更改intv的值将如何影响任何事情。据我所知,它在其他任何地方都没有使用。我发现一个clkhandler.c,我可以计算所经过的时间并在那里调用我的函数吗?我在上面添加了它。@blackdemon619这是因为它是一个严格的中断计时。您可以通过更改中断计时器的值来更改计时。@blackdemon619如果您想了解更多,我已经编写了自己的操作系统,您可以看看我是如何做到的关于这一点(同样是针对x86的),我在提供的.S文件的comments部分看到clktime表示启动后的秒数。如果我检查(clktime%4==0),我能有效地在中断clkhandler中每4秒调用一次吗?@blackdemon619是的,我不建议只安排每4秒一次,但是,你必须记住USB设备是基于轮询的,如果事情长时间运行而没有中断,你就永远没有机会检查设备状态,因此你的系统看起来非常不正常海绵