środa, 9 lutego 2011

Własny bootloader w AT&T

Zaczęło się dosyć niewinnie - pewnego razu w celu sprawdzenia swojej pamięci RAM (coś nawalało) zaciągnąłem i odpaliłem program memtest86 na komputerze. Kiedy wykonywał on swoje testy zacząłem się zastanawiać w jaki sposób skonstruowany jest program typu bootloader. Całe te rozmyślania zaprowadziły mnie do szatańskiej idei napisania własnego bootloadera, czyli sprawdzenia tego po "kowbojsku".

Od początku byłem przekonany, że nie wyjdzie z tego nic bogatego - raczej taka studencka bieda. Skupiłem się więc na najprostszym zadaniu, czyli wyświechtany "Hello, world!". Z drugiej strony mimo swojej prostoty pisanie takiego bootloadera może dużo nauczyć. W sieci znalazłem kilka stron opisujących tworzenie systemów operacyjnych od podstaw (np. tu lub tu), ale wszystkie one przykłady podane były w składni NASM. Nie obchodziło mnie za bardzo co jest lepsze... znalazłem pustkę w polskim internecie i zamierzałem ją wypełnić. Co prawda wspomniany memtest86 i jak się później okazało bootloader Minixa używały składni AT&T - ale na szczęście nie wiedziałem o tym, popsuło by mi to zabawę.

Opis tego co się dzieje po uruchomieniu komputera znajdziecie na wymienionych stronach. Przydaje się również znienawidzony za czasów studiów, a doceniony po studiach using as. Bez tablicy przerwań BIOS też nie zbo(ot|j)ujemy za wiele, więc warto ją mieć pod ręką. Kończąc słowo wstępu, a zaczynając jednocześnie czyn, powstaje taki oto kod:
  1 .code16  
  2 _begin:  
  3   .section .text  
  4   .globl _start  
  5   
  6 _start:  
  7   movw  $0x07c0, %ax    # Tutaj startujemy (BIOS).  
  8   movw  %ax, %ds      # Ustawiamy stos (4K).  
  9   movw  %ax, %ss  
 10   
 11   movw  $message, %si    # Wkładamy wiadomość do rejestru.  
 12   movb  $0x0e, %ah  
 13   movb  $0x4f, %bh  
 14   
 15 _repeat:  
 16   lodsb  
 17   cmpb  $0, %al  
 18   je   _loop  
 19   int   $0x10  
 20   jmp   _repeat  
 21   
 22 _loop:  
 23   movb  $0x07, %ah  
 24   movb  $0, %al  
 25   jmp _loop #...  
 26   
 27 message:  
 28   .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13  
 29   .byte 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13, 10, 13  
 30   .ascii "Komputer zostal zablokowany\r\n"  
 31   .byte 10, 13  
 32   .ascii "Uzytkownik tego komputera odwiedzal zakazane przez prawo strony internetowe, na ktorych rozpowszechniane sa tresci nazistowskie. W celach prewencyjnych komputer zostal zablokowany, a identyfikator sprzetowy wyslany do jednostki EUROPOL Wroclaw.\r\n"  
 33   .byte 10, 13  
 34   .ascii "Jezeli uwazasz, ze komunikat pojawil sie na wskutek bledu, prosimy o kontakt z konsultantem pod numerem telefonu +48XXXYYYZZZ.\r\n"  
 35   .byte 10, 13  
 36   .byte 10, 13  
 37   .byte 10, 13, 0  
 38 message_len:  
 39   .long . - message  
 40   
 41   .section .text  
 42   
 43 _end:              # Dwa ostatnie bajty sektora MBR  
 44 .org 510            # muszą być ustawione na 0xaa55.  
 45  .byte 0xaa, 0x55  
 46   
 47   
Tak, też było mi ciężko w to uwierzyć - jak mogło wyjść tak krótko? Co tak właściwie się tutaj dzieje?

Pierwszą rzeczą jaką należy zrobić po uruchomieniu to nastawić stos i inne niezbędne segmenty pamięci (7-10). W następnych liniach stać się może wszystko. Dosłownie wszystko. W moim prostym przypadku wyświetlam stringa na ekranie (11-14). W tym celu do rejestru si podaję adres wiadomości, a następnie wywołuję przerwanie BIOS numer 16 podając jako parametr 14 (górny bajt rejestru A). I to wszystko, w zasadzie. Na koniec uzupełniamy plik, aby kończył się dwoma bajtami 0xaa55 i zajmował łącznie 512 bajtów (rozmiar sektora uruchomieniowego).

Kompilacja i stworzenie obrazu płyty jest nieco trudniejsza niż w przypadku NASMu, ale jak to mawiają ludzie ja tego nie zrobię?!. Z pewnością przyda się krótki plik Makefile, żeby za każdym razem nie trzeba było się zastanawiać jak się to budowało.

Potrzebne nam będą pliki pomocnicze: ten oraz ten. Pierwszy z nich to obraz dyskietki floppy, a drugi to Makefile. Nie zostaje nic jak wpisać szatańskie polecenie `make` i czekać na obraz płyty. Płytkę można oczywiście sobie wypalić, aby się przekonać na własnych chipach, że wszystko huczy. Zanim jednak do tego dojdzie proponuję skonfigurować jakąś maszynę wirtualną i na niej przeprowadzać testy. Osobiście przetestowałem temat na netbooku. Oto co zobaczyłem po wypaleniu obrazu na zwykłą pamięć USB i odpowiednim przestawieniu BIOSa w komputerze:

Image captured by a digital camera
Dziękuję za uwagę.