问题
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
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.
回答1:
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.
(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.)
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
Here's the setup of that timer:
xor ax, ax
mov word [getline_timer_count], ax
mov word [getline_timer_last], ax
mov word [getline_timer_func], .timer
call getline00
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]
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:
- 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.
来源:https://stackoverflow.com/questions/57596048/how-can-i-make-the-os-wait-a-second-before-shutdown-nasm