我怎样才能让 os 在关机前等待一秒钟 ( 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 中定制的 os。
假设您的程序由 ROM-BIOS(而非 EFI)加载,并且您 运行 处于 (Real/Virtual) 86 模式,并且您启用了中断 (sti
),并且你没有重新配置 PIC 和 PIT,也没有更改中断 8(默认 IRQ 0)处理程序,那么你可以使用 0_046Ch 处的双字(相当于,40h:6Ch) 从午夜开始保持计时器滴答,并由 ROM-BIOS 的中断 8 处理程序每秒增加大约 18.2 次(大约 18.2 Hz)。
在我的程序中,我通常只检查计数器的低位字多久更改一次,这通常足够准确,并且不需要任何特殊的午夜翻转处理。
(天真的方法是获取当前的滴答计数并添加您想要等待的滴答数,然后在循环时检查滴答 dword 是否高于或等于计算值。但是,这需要午夜翻转处理以在所有情况下正常工作。)
这是我的一个项目中一些定时器处理的源代码部分: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 :
call near word [getline_timer_func]
下面一行通过指向一个空函数(这只是一个 retn
)来禁用计时器:
mov word [getline_timer_func], dmycmd
综上所述,这是您的睡眠处理程序:
%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:
我的程序源的变化:
- sleep 节拍超时是在汇编时根据预处理器定义的秒数计算的,而不是在 运行 时使用变量。
- 计数器和最后一次看到的值不存储在迭代之间的变量中,而是始终保存在
cx
和 dx
. 中
- 不使用函数指针框架,因为指针在睡眠处理期间将是常量。
- 我们只是跳回到
.loop
局部标签,而不是从计时器函数返回直到再次调用它。这也意味着我们不必使用 push
和 pop
. 保留寄存器内容
- 而不是检查按键(在我的程序中它最终也会使机器空闲),我们只是坐在一个紧密的循环中。
hlt
使机器可以空闲。
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 中定制的 os。
假设您的程序由 ROM-BIOS(而非 EFI)加载,并且您 运行 处于 (Real/Virtual) 86 模式,并且您启用了中断 (sti
),并且你没有重新配置 PIC 和 PIT,也没有更改中断 8(默认 IRQ 0)处理程序,那么你可以使用 0_046Ch 处的双字(相当于,40h:6Ch) 从午夜开始保持计时器滴答,并由 ROM-BIOS 的中断 8 处理程序每秒增加大约 18.2 次(大约 18.2 Hz)。
在我的程序中,我通常只检查计数器的低位字多久更改一次,这通常足够准确,并且不需要任何特殊的午夜翻转处理。
(天真的方法是获取当前的滴答计数并添加您想要等待的滴答数,然后在循环时检查滴答 dword 是否高于或等于计算值。但是,这需要午夜翻转处理以在所有情况下正常工作。)
这是我的一个项目中一些定时器处理的源代码部分: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 :
call near word [getline_timer_func]
下面一行通过指向一个空函数(这只是一个 retn
)来禁用计时器:
mov word [getline_timer_func], dmycmd
综上所述,这是您的睡眠处理程序:
%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:
我的程序源的变化:
- sleep 节拍超时是在汇编时根据预处理器定义的秒数计算的,而不是在 运行 时使用变量。
- 计数器和最后一次看到的值不存储在迭代之间的变量中,而是始终保存在
cx
和dx
. 中
- 不使用函数指针框架,因为指针在睡眠处理期间将是常量。
- 我们只是跳回到
.loop
局部标签,而不是从计时器函数返回直到再次调用它。这也意味着我们不必使用push
和pop
. 保留寄存器内容
- 而不是检查按键(在我的程序中它最终也会使机器空闲),我们只是坐在一个紧密的循环中。
hlt
使机器可以空闲。