我如何才能让操作系统在关机前等待一秒钟(nasm) [英] How can i make the os wait a second before shutdown ( nasm )
问题描述
powerCommand:
mov si, powerOFF
call printString
;sleep command here
mov ax, 0x1000
mov ax, ss
mov sp, 0xf000
mov ax, 0x5307
mov bx, 0x0001
mov cx, 0x0003
int 0x15
ret
我希望程序等待1秒钟,然后继续关闭.此刻,它会在关闭消息后立即关闭.我正在用nasm定制的操作系统运行它.
I want the program wait for 1 second then continue with shutdown. At the moment it shuts down instantly after the shutdown message. I am running it on my custom os made in nasm.
推荐答案
假定您的程序是通过ROM-BIOS(不是EFI)加载的,并且您正在(真实/虚拟)86模式下运行,并且遇到了中断启用(sti
),并且您没有重新配置PIC和PIT,也没有更改中断8(默认IRQ 0)处理程序,那么您可以在0_046Ch(相当于40h:6Ch)使用dword自午夜以来一直保持计时器滴答,并由ROM-BIOS的中断8处理程序每秒增加约18.2次(约18.2 Hz).
Assuming your program is loaded by the ROM-BIOS (not EFI), and you're running in (Real/Virtual) 86 Mode, and you have interrupts enabled (sti
), and you didn't reconfigure the PIC and the PIT, and also didn't change the interrupt 8 (default IRQ 0) handler, then you can use the dword at 0_046Ch (equivalently, 40h:6Ch) which holds the timer ticks since midnight, and is incremented circa 18.2 times per second (at circa 18.2 Hz) by the ROM-BIOS's interrupt 8 handler.
在我的程序中,我通常只检查计数器低位字的更改频率,通常这足够准确,并且不需要任何特殊的午夜翻转处理.
In my programs I generally just check for how often the lower word of the counter changes, which will usually be accurate enough, and doesn't need any special midnight rollover handling.
(幼稚的方法是获取当前的滴答声计数并添加要等待的任意多个滴答声,然后在循环时检查tick dword是否高于或等于计算值.但是,这需要午夜翻转处理在任何情况下都能正常工作.)
(The naive approach is to take the current tick count and add however many ticks you want to wait, then when looping check whether the tick dword is above-or-equal the calculated value. However, this requires midnight rollover handling to correctly work in all circumstances.)
以下是我的项目中某些计时器处理的源代码: https://hg.ulukai.org/ecm/ldebug/file/82570f7094b8/source/debug.asm#l1367
Here's the source part for some timer handling in a project of mine: https://hg.ulukai.org/ecm/ldebug/file/82570f7094b8/source/debug.asm#l1367
.timer:
push ax
push dx
push cx
push es
mov dx, 40h
mov es, dx
mov cx, word [getline_timer_count]
mov dx, word [getline_timer_last]
cmp dx, word [es:6Ch]
je .timer_next
mov dx, word [es:6Ch]
inc cx
mov al, 18
mul byte [serial_keep_timeout]
test ax, ax
jz .timer_next
cmp cx, ax
jb .timer_next
pop es
mov dx, msg.serial_no_keep_timer
jmp .no_keep
.timer_next:
mov word [getline_timer_count], cx
mov word [getline_timer_last], dx
pop es
pop cx
pop dx
pop ax
retn
这是该计时器的设置:
xor ax, ax
mov word [getline_timer_count], ax
mov word [getline_timer_last], ax
mov word [getline_timer_func], .timer
call getline00
如果输入是从串行端口完成的,则
getline00在等待输入时会反复调用word [getline_timer_func]
中的函数指针(在我们使用此计时器的情况下就是这种情况).在 https://hg.ulukai.org/ecm/ldebug/file/82570f7094b8/source/lineio.asm#l814 :
getline00 repeatedly calls the function pointer in word [getline_timer_func]
while waiting for input, if input is done from the serial port (which is the case whenever we use this timer). That's at https://hg.ulukai.org/ecm/ldebug/file/82570f7094b8/source/lineio.asm#l814 :
call near word [getline_timer_func]
下面的行通过指向一个空函数(只是一个retn
)来禁用计时器:
And the following line disables the timer by pointing at an empty function (that's just a single retn
):
mov word [getline_timer_func], dmycmd
将它们放在一起,这是您的睡眠处理程序:
Putting it all together, here's your sleep handler:
%assign SLEEP_SECONDS 1
sleep:
xor cx, cx ; initialise counter to zero
xor dx, dx ; initialise "prior value" to zero
; (any value will do, at worst it is a match to the
; tick low word and we will wait one tick longer)
mov ax, 40h
mov es, ax ; => ROM-BIOS data area
.loop:
cmp word [es:6Ch], dx
; still same ?
je .next ; yes, just wait for next -->
mov dx, word [es:6Ch]
; update our last-seen low tick word value
inc cx ; increment our counter
cmp cx, SLEEP_SECONDS * 18
; as many ticks elapsed as we want ?
jae .end ; yes, end the loop -->
; (fall through to .next)
.next:
sti ; insure interrupts are enabled for the hlt
hlt ; idle the machine while waiting for IRQs
jmp .loop ; continue the loop -->
.end:
从我的程序源进行的更改:
Changes from my program's source:
- sleep 滴答超时是在组装时根据预处理器定义的秒数计算的,而不是在运行时使用变量.
- 计数器和最后一次看到的值不在两次迭代之间存储在变量中,而是始终保存在
cx
和dx
中. - 不使用函数指针框架,因为在睡眠处理期间指针将是一个常量.
- 我们没有从计时器函数返回直到再次调用它,而是跳回到了
.loop
本地标签.这也意味着我们不必使用push
和pop
保留寄存器内容. - 我们没有检查按键(在我的程序中也最终使机器空闲了),我们只是在这里处于一个紧密的循环中.
hlt
使它可以闲置.
- The sleep tick timeout is calculated at assembling time from a preprocessor define for the seconds, instead of using a variable at run time.
- The counter and last seen value are not stored in variables between the iterations, rather they are always kept in
cx
anddx
. - The function pointer framing is not used, as the pointer would be a constant during the sleep handling.
- Instead of returning from the timer function until it is called again, we just jump back to the
.loop
local label. This also means we do not have to preserve the register contents withpush
andpop
. - Instead of checking for a keypress (which in my program eventually idles the machine too), we just sit in a tight loop here. The
hlt
makes it so that the machine can idle.
这篇关于我如何才能让操作系统在关机前等待一秒钟(nasm)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!