我怎样才能让 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 节拍超时是在汇编时根据预处理器定义的秒数计算的,而不是在 运行 时使用变量。
  • 计数器和最后一次看到的值不存储在迭代之间的变量中,而是始终保存在 cxdx.
  • 不使用函数指针框架,因为指针在睡眠处理期间将是常量。
  • 我们只是跳回到 .loop 局部标签,而不是从计时器函数返回直到再次调用它。这也意味着我们不必使用 pushpop.
  • 保留寄存器内容
  • 而不是检查按键(在我的程序中它最终也会使机器空闲),我们只是坐在一个紧密的循环中。 hlt 使机器可以空闲。