|
- Programming4Fun http://www.programming4fun.pun.pl/index.php - Poradniki http://www.programming4fun.pun.pl/viewforum.php?id=19 - Pisanie systemów operacyjnych cz. II - tryb chroniony http://www.programming4fun.pun.pl/viewtopic.php?id=7 |
| arnon - 2014-07-10 11:43:06 |
Jak napisać własny, PRAWDZIWY SYSTEM OPERACYJNY - TAKI CO MA JĄDRO I MOŻNA NORMALNIE ZAINSTALOWAĆ NA KOMPUTERZE!!!!!! Kod:; tak jak poprzednio BIOS nasz bootsektor zaladowal pod 0x7C00 [ORG 0x7C00] ; w tybie rzeczywistym uzywamy 16 bitowego kodu [BITS 16] start: ; ustawiamy stos dla trybu rzeczywistego mov ax, 0x1000 mov ss, ax xor esp, esp ; inicjujemy tryb wideo 80x25 (tekstowy) xor ah, ah mov al, 3 int 0x10 ; ladujemy jadro pod adres 0x1000 xor ah, ah int 0x10 mov ah, 2 mov al, 10 xor ch, ch mov cl, 2 mov dh, 0 mov bx, 0x1000 mov es, bx mov bx, 0 int 0x13 Po wykonaniu tego kodu następne 5kb z dyskietki znajdzie się w pamięci pod adresem 0x10000, bedziemy mieli stos z wierzchołkiem 0x1000 i tryb wideo 80x25 (0x03). Kod:[ 16B | młodsze słowo limitu ]
[ 16B | młodsze słowo bazy ]
[ 8B | młodszy bajt starszego słowa bazy ]
[ 8B | _ ]
|
|- [ 1B | P ]
|- [ 2B | DPL ]
|- [ 1B | DT ]
'- [ 4B | typ ]
[ 8B | _ ]
|
|- [ 1B | G ]
|- [ 1B | D ]
|- [ 1B | L ]
|- [ 1B | AVL ]
'- [ 4B | bity limitu ]
[ 8B | najstarszy bajt bazy ]Tera troche wyjaśnień, bazą nazywamy miejsce w pamięci gdzie zaczyna się dany segment, natomiast limit jest jego długością. Kod:gdt: ; NULL Descriptor dd 0 dd 0 ; kod, baza: 0, limit: 4GB, DPL: 0 dw 0xFFFF ; mlodsze slowo limitu dw 0 ; mlodsze slowo bazy db 0 ; wlodszy bajt starszego slowa bazy db 10011010b ; kod / exec-read db 11001111b ; flagi i 4 bity limitu db 0 ; najstarszy bajt bazy ; dane (odczyt/zapis), baza: 0, limit: 4GB, DPL: 0 dw 0xFFFF dw 0 db 0 db 10010010b db 11001111b db 0 gdt_end: ; naglowek gdt_descr: dw gdt_end - gdt - 1 ; rozmiar gdt dd gdt ; adres pierwszego deskryptora Zerowy deskryptor jednym z zabezpieczen trybu chronionego i po prostu musimy go uwzględnić, nie warto się w to zagłębiać, więc po dodatkowe info odsyłłam do manuali. Kod:lgdt [gdt_descr] mov eax, cr0 or eax, 1 mov cr0, eax Teraz należy ustawić rejestry segmentowe z naszej nowej tablicy. Tym razem nie dzielimy adresu liniowego przez 16 i zapisujemy w rejestrach, tylko mnożymy pozycję deksryptora (zaczynając od zera) przez 8. Ustawiamy tylko rejestry danych ponieważ CS sam wybierze prawidłową wartość po wykonaniu skoku. Kod:mov ax, 0x10 ; deksryptor danych (8 * 2 = 16 = 0x10) mov ss, ax mov ds, ax mov es, ax mov fs, ax mov gs, ax Warto zauważyć, że jeśli przed przejściem do trybu chronionego ustawimy jakiś rejestr segmentowy, bedzię on prawidłowy w trybie chronionym i będziemy mogli go używać, natomiast już w pmode musimy ładować rejestry segmentowe wartościami z GDT. Kod:jmp 0x08:start32 ; uzywamy segmentu kodu z GDT [BITS 32] start32: Po tym zabiegu możemy skoczyć do jądra. Kod:jmp 0x08:0x10000 0x07. Szkielet jądra w języku C. Kod:void print(unsigned char *str, unsigned char color)
{
unsigned char *vga = (unsigned char *)0xb8000; //wskaznik do pamieci ekranu
while(*str != 0) //dopoki nie napotkamy na koniec - #0
{
*vga = *str; //zapisz znak
*(vga + 1) = color; //zapisz kolor
str++; //nastepny znak
vga += 2; //jak wyzej (znaki w pamieci ekranu maja 2 bajty)
}
}Teraz z grubsza co ona robi. Jak można sie domyśleć wyświetla tekst na ekranie, lecz z haczykiem - jeśli wywołamy ją dwa razy tekst zostanie nadpisany, dlatego należałoby utworzyć jakąś zmienna z aktualną pozycją, ale to pozostawiam Wam. Kod:void k_main()
{
print("Krzeslo PMODE operating system :)", 3);
}Aby było wiadomo, że ta funkcja ma się wykonać jako pierwsza będziemy musieli napisać kod startowy w assemblerze. Kod:[BITS 32] [EXTERN _k_main] ; wyjasnienie nizej call _k_main ; uruchamiamy kernela hlt ; po wyjsciu z kernela zatrzymujemy komputer Wyjaśnienie będzie dotyczyło dwóch rzeczy, słowa kluczowego extern i znaku _ (podkreślenie) przed nazwą funkcji. Dzięki extern nasza funkcja jest widoczna dla linkera, którym otrzymamy plik binarny z skompilowanego kodu C i ASM. Znak podkreślenia dodawany jest do zewnętrznych funkcji przez kompilator GCC pod systemami Windows (nie wiem dlaczego tak się dzieje, jakby ktoś to wiedział i potrafił temu zapobiec prosze o kontakt), pod innymi systemami nie ma takich niespodzianek. Kod:OUTPUT_FORMAT("binary")
ENTRY("_k_main")
SECTIONS {
.text 0x10000 : {
code = . ; _code = . ;
*(.text)
}
.data : {
*(.data)
}
.bss : {
bss = . ; _bss = . ;
*(.bss)
*(.COMMON)
}
end = . ; _end = . ;
}Natomiast w pliku make.bat umieścimy: Kod:nasm -f coff entry.asm -o entry.o gcc -c kernel.c -O2 -o kernel.o ld -Map kernel.map entry.o kernel.o -Tlink.ld -o kernel.bin merge.exe boot.bin kernel.bin image.img 0x09. Użycie Bochsa. Kod:romimage: file=bios/BIOS-bochs-latest, address=0xf0000
megs: 128
vgaromimage: bios/VGABIOS-elpin-2.40
floppya: 1_44={ TUTAJ SCIEZKA DO TWOJEGO OBRAZU Z OSEM }, status=inserted
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x368, irq=9
ata0-slave: type=cdrom, path=E:, status=inserted
boot: floppy
floppy_bootsig_check: disabled=0
log: bochsout.txt
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
debugger_log: bochs_debug.txt
parport1: enabled=1, file="parport.out"
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
floppy_command_delay: 500
ips: 1000000
mouse: enabled=0
private_colormap: enabled=0
fullscreen: enabled=0
screenmode: name="sample"
keyboard_mapping: enabled=0, map=
i440fxsupport: enabled=0Warto zapoznać się z domyślnym plikiem bochsrc.txt w którym wszystko jest ładnie skomentowane i opisane. Tak więc gdy mamy już skonfigurowanego bochsa wystarczy go uruchomić, możemy np dodać do naszego pliku make.bat Kod:cd { SCIEZKA Z BOCHSEM }
bochs.exe -qDzięki parametrowi q nasz "komputer" odrazu się właczy bez wyświetlania menu. |
| Hoguzzos - 2014-07-10 12:02:31 |
Jak dodasz do tego małe kotki to chyba sie skusze :P |