Zarządzanie zasilaniem komputera

Jeśli zastanawialiście się kiedyś, jak wyłączać dyski twarde lub resetować komputer używając tylko oprogramowania (nie naciskając żadnych przycisków), to w tym artykule powinniście znaleźć odpowiedź na wszystkie wasze pytania.



Wyłączanie monitora


(przeskocz wyłączanie monitora)

Zajmijmy się najpierw teorią. Przerwanie, którym najpierw się zajmiemy, to.... int 10h, przerwanie sterowników karty graficznej. Co one mają wspólnego z energią? Otóż, można z użyciem int 10h wyłączyć monitor. Zajrzyjmy do RBIL, w opis funkcji numer 4F10h. Uruchomienie jej z BL=0 powinno nas upewnić, że odpowiednie funkcje są zainstalowane (zwróci AL=4Fh):


(przeskocz sprawdzanie funkcji)
	mov	ax, 4f10h
	mov	bl, 0
	xor	di, di
	mov	es, di		; przerwanie żąda ES:DI = 0
	int	10h

	cmp	al, 4fh
	jne	wychodzimy	; gdy klęska....

Teraz, jeśli wiemy, że ta funkcja działa, to patrzymy na kolejną. Wpisując 1 do BL możemy zmienić aktualny stan zasilania. W BH podajemy, co chcemy zrobić: 0-włączyć, 1-przełączyć w stan oczekiwania, 2-zawiesić, 4-wyłączyć monitor. Zanim jednak zaczniecie ochoczo pisać, dam wam radę: program należy napisać tak, aby po jakimś czasie monitor wracał jednak do stanu włączonego (bez resetowania komputera...). Wiem, że potrafilibyście coś takiego sami napisać, ale podam tutaj gotowe (i sprawdzone - działa nawet pod Win98) rozwiązanie:


(przeskocz program wyłączający monitor)
	; Program wyłącza monitor
	;
	; Autor: Bogdan D.
	; kontakt: bogdandr (at) op (dot) pl
	;
	; nasm -O999 -o mon_off.com -f bin mon_off.asm

	org 100h

	start:
		mov ax,4f10h		; wybranie numeru funkcji
		mov bx,0401h		; BL=1 - zmień stan. BH=4 - wyłącz
		int 10h

		xor ah,ah
		int 16h			; poczekaj na naciśnięcie klawisza

		mov ax,4f10h
		mov bx,1		; BL=1 - zmień stan. BH=0 - włącz
		int 10h

		mov ax,4c00h
		int 21h


Wyłączanie twardych dysków


(przeskocz wyłączanie twardych dysków)

Z dyskami twardymi jest nieco gorzej. Tutaj trzeba się znać na kontrolerze HDD - na jego portach i wysyłanych tam komendach. Dlatego posłużę się gotowcem. Ma on wyłączyć 2 pierwsze dyski twarde. Dla dokładniejszych opisów portów i ich komend spójrzcie do pliku ports.lst dołączonego do RBIL. Gotowiec ten jest częścią doskonałego programu FDAPM (FreeDOS Advanced Power Management), który wraz z kodem źródłowym można znaleźć na stronach projektu FreeDOS.


(przeskocz program wyłączający dyski)
	mov dx,1f6h     ; pierwszy kontroler IDE (drugi: 176)

	mov al,0a0h     ; bez LBA, dysk nadrzędny (Master)
        out dx,al
        inc dx		; DX = 1F7
        call miniWait	; chwila przerwy
        mov al,0e0h	; e0 = standby, e1 = włączony/idle
        out dx,al
        dec dx		; DX = 1F6
        call miniWait
        mov al,0b0h     ; bez LBA, dysk podrzędny (Slave)
        out dx,al
        inc dx		; DX = 1F7
        call miniWait
        mov al,0e0h	; e0 = standby, e1 = włączony/idle
        out dx,al

	mov ax,4c00h
	int 21h

	miniWait:	; bardzo krótki okres przerwy
	xchg ax, bx
	xchg bx, ax
	xchg ax, bx
	xchg bx, ax
	ret

Po zatrzymaniu twardego dysku można go uruchomić wykonując dowolną operację na systemie plików (na przykład wyświetlić zawartość bieżącego katalogu).

Parkowanie głowic twardego dysku jest sprawą prostszą, gdyż w tym przypadku pomaga nam BIOS. Aby zaparkować głowice pierwszego dysku twardego, użyj następującego kodu:

	mov	ah, 19h
	mov	dl, 80h
	int	13h

	jc	blad		; nie pokazuje błędów pod Windows 98

Jeśli chcecie zaparkować głowice drugiego dysku, zamiast 80h wpiszcie 81h, jeśli trzeciego - 82h itd.



Resetowanie i wyłączanie komputera

Teraz ciekawsze sprawy - resetowanie komputera lub wyłączanie go. Na początek grzecznie posłużymy się przerwaniem - będzie to int15h, numery funkcji 5300h i 5307h (po szczegółowe opisy tych funkcji posyłam oczywiście do RBIL). Najpierw sprawdźmy w ogóle, czy Advanced Power Management (APM) - bo o nim mowa - jest zainstalowane:


(przeskocz sprawdzanie APM)
	mov	ax, 5300h
	xor	bx, bx		; numer urządzenia = 0 = BIOS
	int	15h

	jc	niestety   ; gdy coś poszło nie tak (na przykład brak APM), to CF=1

Teraz spróbujmy wyłączyć system:


(przeskocz wyłączanie zasilania)
	mov	ax, 5307h	; funkcja APM
	mov	cx, 3		; wyłącz system. CX=2 - zawieś system, CX=1 -
				; przełącz system w stan oczekiwania stand-by
	mov	bx, 1		; wszystkie urządzenia
	int	15h		; spróbujemy wyłączyć...

Jeśli istnieje możliwość wyłączenia prądu w systemie, to powyższy kod powinien to załatwić.

Teraz przejdziemy do innych grzecznych sposobów na zresetowanie komputera. W RBIL znalazłem:


(przeskocz opis przerwań do resetowania)
	INT 16 - AMI BIOS - BIOS-FLASH Interface - GENERATE CPU RESET
	        AX = E0FFh

	INT 14 - FOSSIL - REBOOT SYSTEM
        AH = 17h
        AL = method
            00h = cold boot
            01h = warm boot

Jak widać, nie wygląda to skomplikowanie. Niestety, żaden z powyższych sposobów nie działa u mnie pod czystym DOS-em, a pod Windows98 działa jedynie sposób z APM (int15h).

A teraz pokażę kilka niegrzecznych (ale za to sprawdzonych przeze mnie i działających bez pudła) sposobów na zresetowanie komputera.

Pierwszym takim sposobem jest długi skok pod adres FFFF:0000 (tam znajduje się część BIOSu odpowiedzialna za operacje wykonywane przy starcie komputera). Wcześniej do segmentu danych BIOSu (segment 40h), pod adres 72h należy wpisać 0, gdy chcemy zimny reset (taki, co obejmuje testy pamięci i wszystko inne), a 1234h, gdy chcemy gorący reset.

Odpowiednie kawałki kodu wyglądają tak (przypominam, że adres 0040h:0072h = 0000:0472h - patrz część 2 mojego kursu):


(przeskocz kod do ręcznego resetowania)
	; zimny reset:

	mov	ax, 40h
	mov	ds, ax			; DS = 40h
	mov	word [ds:72h], 0	; zimny reset

	; niektóre kompilatory (na przykład TASM) nie lubią instrukcji w stylu
	; jmp 0FFFFh:0000h, więc zakoduję ją ręcznie
	db	0eah		; kod instrukcji wzięty z podręczników Intela
	dw	0		; offset
	dw	0ffffh		; segment


	; gorący reset:

	xor	ax, ax
	mov	ds, ax			; DS = 0
	mov	word [ds:472h], 1234h	; gorący reset

	db	0eah		; kod instrukcji wzięty z podręczników Intela
	dw	0		; offset
	dw	0ffffh		; segment

Drugim (i prostszym) sposobem jest zapisanie do jednego z portów klawiatury (64h) jednego z bajtów od F0 do FE, który ma bit0 = 0 (jest takich oczywiście kilka, najczęściej stosuje się FEh), chociaż ten sposób nie jest zalecany.
Kod jest wyjątkowo prosty i wygląda tak:

	mov	al, 0feh
	out	64h, al

Celowo nie wspominam tutaj o jednym: o przerwaniu int19h, które służy do ponownego przeczytania bootsektorów i przeładowania systemu od nowa. Gdy wkładacie niesystemową dyskietkę do stacji i resetujecie komputer, to (o ile macie możliwość uruchomienia systemu z dyskietki) pojawia się napis informujący o nieprawidłowym dysku systemowym. Po naciśnięciu Entera uruchamiane jest właśnie int19h, które nie wykonuje żadnych resetów, tylko czyta bootsektory od nowa.

Nie wspominałem o int19h, gdyż jest ono niebezpieczne. Jeżeli jakikolwiek program przejął przerwanie na przykład zegara, to int19h nie przywróci poprzedniej procedury, co jest nieprzewidywalne w skutkach!


Sposoby na wyłączanie urządzeń mogą się Wam przydać, gdy na przykład będziecie pisać własny wygaszacz ekranu, a możliwość zresetowania komputera przyda się, gdy Wasze oprogramowanie zostanie zainstalowane i musi zmienić na przykład zawartość pliku autoexec.bat.
Informacje, które tutaj podałem mogą się Wam też przydać przy pisaniu boot-sektorów do własnych mini-systemów operacyjnych.



Spis treści off-line (Alt+1)
Spis treści on-line (Alt+2)
Ułatwienia dla niepełnosprawnych (Alt+0)