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.



Dyski twarde.


(przeskocz dyski twarde)

Oczywiście, jak na porządny system przystało, nie możemy operować bezpośrednio na dysku twardym. Ale umożliwi na to sam system, poprzez funkcję systemową sys_ioctl.

Poniżej przedstawiam działający (choć, aby otworzyć plik urządzenia dysku twardego, musiałem mieć uprawnienia roota) kod zatrzymujący dysk twardy. Kod ten napisałem dzięki analizie kodu źródłowego programu hdparm (i tam, oraz do stron podręcznika man: ioctl, ioctl_list, odsyłam po szczegóły). Dla tych, którzy nie korzystają z mojej biblioteki, podaję liczbowe odpowiedniki stałych.

Oto program (składnia NASM):


(przeskocz program zatrzymujący dysk twardy)
%include "bibl/incl/linuxbsd/nasm/n_system.inc"		; stałe systemowe

section .text

global _start

_start:
	mov	eax, sys_open			; =5. otwieramy plik....
	mov	ebx, dysk			; ....twardego dysku
	mov	ecx, O_RDONLY|O_NONBLOCK	; 04000q ósemkowo
	int	80h

	cmp	eax, 0
	jle	koniec				; jeśli wystąpił błąd,
						; wychodzimy od razu

	mov	ebx, eax		; zachowujemy deskryptor pliku

	mov	eax, sys_ioctl			; =54
	; EBX = deskryptor pliku
	mov	ecx, 0x031f			; komenda specjalna dysku
	mov	edx, args1			; pierwsze argumenty
	int	80h

	mov	eax, sys_ioctl
	; EBX = deskryptor pliku
	mov	ecx, 0x031f			; komenda specjalna dysku
	mov	edx, args2			; drugie argumenty
	int	80h

	mov	eax, sys_close			; =6
	; EBX = deskryptor pliku
	int	80h				; zamykamy otwarty plik

koniec:
	mov	eax, sys_exit			; =1
	xor	ebx, ebx
	int	80h				; wychodzimy z programu

section .data
args1	db	0e6h, 0, 0, 0			; skopiowane z hdparm.c
args2	db	99h, 0, 0, 0			; też skopiowane
dysk	db	"/dev/hda",0			; pierwszy dysk,hdb = drugi

UWAGA: należy odczekać chwilę, aż program się zakończy. Przez czas działania programu komputer może przestać reagować.
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).


Resetowanie komputera lub wyłączanie go.


(przeskocz resetowanie komputera)

Do zresetowania komputera posłuży nam funkcja systemowa sys_reboot, której podamy odpowiednie parametry. Oto program natychmiast resetujący komputer:


(przeskocz program resetujący komputer)
%include "bibl/incl/linuxbsd/nasm/n_system.inc"

section .text

global _start

_start:
	mov	eax, sys_reboot			; =88
	mov	ebx, 0fee1deadh			; wymagana stała
	mov	ecx, 672274793			; wymagana stała
				; EDX = tryb restartu. U nas: zwykły reset
	mov	edx, LINUX_REBOOT_CMD_RESTART	; =0x01234567
	int	80h

	; to, co jest poniżej nigdy nie zostanie wykonane.
	mov	eax, sys_exit			; =1
	xor	ebx, ebx
	int	80h

A oto program natychmiast wyłączający komputer:


(przeskocz program wyłączający komputer)
%include "bibl/incl/linuxbsd/nasm/n_system.inc"

section .text

global _start

_start:
	mov	eax, sys_reboot			; =88
	mov	ebx, 0fee1deadh			; wymagana stała
	mov	ecx, 672274793			; wymagana stała
			; EDX = tryb restartu. U nas: wyłączenie prądu
	mov	edx, LINUX_REBOOT_CMD_POWER_OFF	; =0x4321FEDC
	int	80h

	; to, co jest poniżej nigdy nie zostanie wykonane.
	mov	eax, sys_exit			; =1
	xor	ebx, ebx
	int	80h

UWAGA: ze względu na to, że podane programy wyłączają/resetują komputer natychmiast po uruchomieniu, NIE zalecam ich stosowania, gdyż może to być niezdrowe dla systemu plików.



Wyłączanie monitora.

No może nie zupełnie będzie to wyłączenie monitora, ale istotnie, obrazu nie będzie. Do wyłączenia obrazu wykorzystamy bibliotekę svgalib (do kompilacji potrzebny będzie też pakiet svgalib-devel).

Całość jest bardzo prosta: inicjujemy bibliotekę funkcją vga_init, wyłączamy obraz funkcją vga_screenoff, czekamy na klawisz (funkcja systemowa sys_read czytająca ze standardowego wejścia) i ponownie włączamy obraz funkcją vga_screenon. Funkcje vga nie przyjmują żadnych argumentów.

Cały program wygląda tak:


(przeskocz program wyłączający monitor)
; Program wyłączający monitor z wykorzystaniem SVGAlib
;
; Autor: Bogdan D., bogdandr (at) op.pl
; kompilacja:
;   nasm -O999 -f elf -o mon_off.o mon_off.asm
;   gcc -o mon_off mon_off.o -lvga

section .text
global	main

extern	vga_screenoff
extern	vga_screenon
extern	vga_init

%idefine	stdin		0
%idefine	sys_read	3

main:
	call	vga_init
	call	vga_screenoff

	mov	eax, sys_read	; funkcja czytania z pliku
	mov	ebx, stdin	; standardowe wejście
	mov	ecx, znak	; adres, dokąd czytać
	mov	edx, 1		; wczytaj 1 bajt
	int	80h

	call	vga_screenon

	ret

section .data

znak		db	0

Zwróćcie uwagę na sposób kompilacji. Skoro korzystamy z bibliotek języka C, to do kompilacji użyjemy GCC. Wtedy zaś funkcja główna musi się nazywać main - tak samo, jak w programach w języku C (i tak samo, jak w C, można ją zakończyć instrukcją RET). Potrzebne funkcje po prostu deklarujemy jako zewnętrzne (extern).

Program ten uruchomiłem też w środowisku graficznym. Nic złego się nie stało, ale po zakończeniu programu należy przejść na konsolę tekstową i wrócić na graficzną, aby odzyskać obraz.

Do działania programu pod X-ami potrzebne mogą być uprawnienia do pliku /dev/console a pod konsolą tekstową - do pliku /dev/mem.


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