我怎样才能让操作系统在关机前等待一秒钟(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) 加载的,并且你在 (Real/Virtual) 86 模式下运行,并且你有中断启用 (sti
),并且您没有重新配置 PIC 和 PIT,也没有更改中断 8(默认 IRQ 0)处理程序,那么您可以使用 0_046Ch 处的 dword(相当于, 40h:6Ch),它保持从午夜开始的计时器滴答声,并由 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.
(天真的方法是获取当前滴答计数并添加您想要等待的任何滴答,然后在循环时检查滴答 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屋!