Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[asm/C] 2x bootloader, jak uruchomić program, który...

Ostatnio zmodyfikowano 2012-11-01 18:08
Autor Wiadomość
crash
Temat założony przez niniejszego użytkownika
[asm/C] 2x bootloader, jak uruchomić program, który...
» 2012-11-01 07:59:08
Pytałem się koleżkę o zgodę na umieszczenie jego kodu tutaj, odpowiedzi nie dostałem, mimo że jest 24h na dobę... online ;] Trzeba się dzielić, może się komuś przydać.
Jeszcze do niedawna miał konto na Sourceforge (był tam ten kod), to raczej nie powinien mieć pretensji o zamieszczenie tutaj ;p

plik: bootloader.asm

;*************************************************************************
;the ultimate boot-strap loader
;to load a file from a DOS FAT12 floppy as the OS
;*************************************************************************
BITS 16
CPU 8086
ORG 0

     jmp short START
     nop

     OEM_ID                db "JON OS  "
     BytesPerSector        dw 0x0200
     SectorsPerCluster     db 0x01
     ReservedSectors       dw 0x0001
     TotalFATs             db 0x02
     MaxRootEntries        dw 0x00E0
     TotalSectorsSmall     dw 0x0B40
     MediaDescriptor       db 0xF0
     SectorsPerFAT         dw 0x0009
     SectorsPerTrack       dw 0x0012
     NumHeads              dw 0x0002
     HiddenSectors         dd 0x00000000
     TotalSectorsLarge     dd 0x00000000
     DriveNumber           db 0x00
     Flags                 db 0x00
     Signature             db 0x29
     VolumeID              dd 0xFFFFFFFF
     VolumeLabel           db "JON OS     "
     SystemID              db "FAT12   "
    
     START:
     ; code located at 0000:7C00, adjust segment registers
          cli
          mov     ax, 7C0h
          mov     ds, ax
          mov     es, ax
     ; create stack
          xor   ax, ax
          mov     ss, ax
          mov     sp, 0FFFFh
          sti
     LOAD_ROOT:
     ; compute size of root directory and store in ‘cx’
          xor     cx, cx
          xor     dx, dx
          mov     ax, 20h                             ; 32 byte directory entry
          mul     WORD [MaxRootEntries]               ; total size of directory
          div     WORD [BytesPerSector]               ; sectors used by directory
          xchg    ax, cx
     ; compute location of root directory and store in ‘ax’
          mov     al, BYTE [TotalFATs]                ; number of FATs
          mul     WORD [SectorsPerFAT]                ; sectors used by FATs
          add     ax, WORD [ReservedSectors]          ; adjust for bootsector
          mov     WORD [datasector], ax               ; base of root directory
          add     WORD [datasector], cx
     ; read root directory into memory (7C00:0200)
          mov     bx, 200h                            ; copy root dir above bootcode
          call    ReadSectors
     ; browse root directory for binary image
          mov     cx, WORD [MaxRootEntries]           ; load loop counter
          mov     di, 200h                            ; locate first root entry
     .LOOP:
          push    cx
          mov     cx, 0Bh                             ; eleven character name
          mov     si, ImageName                       ; image name to find
          push    di
          rep     cmpsb                               ; test for entry match
          pop     di
          je      LOAD_FAT
          pop     cx
          add     di, 20h                             ; queue next directory entry
          loop    .LOOP
          jmp     FAILURE
     LOAD_FAT:
     ; save starting cluster of boot image
          mov     dx, WORD [di + 0x001A]
          mov     WORD [cluster], dx                  ; file’s first cluster
     ; compute size of FAT and store in ‘cx’
          xor     ax, ax
          mov     al, BYTE [TotalFATs]                ; number of FATs
          mul     WORD [SectorsPerFAT]                ; sectors used by FATs
          mov     cx, ax
     ; compute location of FAT and store in ‘ax’
          mov     ax, WORD [ReservedSectors]          ; adjust for bootsector
     ; read FAT into memory (7C00:0200)
          mov     bx, 200h                            ; copy FAT above bootcode
          call    ReadSectors
     ; read image file into memory (0000:0600)
          xor   ax, ax                              ; destination of image CS
  mov     es, ax
          mov     bx, 0x0600                          ; destination for image IP
  push    bx
     LOAD_IMAGE:
          mov     ax, WORD [cluster]                  ; cluster to read
          pop     bx                                  ; buffer to read into
          call    ClusterLBA                          ; convert cluster to LBA
          xor     cx, cx
          mov     cl, BYTE [SectorsPerCluster]        ; sectors to read
          call    ReadSectors
          push    bx
     ; compute next cluster
          mov     ax, WORD [cluster]                  ; identify current cluster
          mov     cx, ax                              ; copy current cluster
          mov     dx, ax                              ; copy current cluster
          shr     dx, 1
     ;divide by two
          add     cx, dx                              ; sum for (3/2)
          mov     bx, 200h                            ; location of FAT in memory
          add     bx, cx                              ; index into FAT
          mov     dx, WORD [bx]                       ; read two bytes from FAT
          test    ax, 1
          jnz     .ODD_CLUSTER
     .EVEN_CLUSTER:
          and     dx, 0FFFh               ; take low twelve bits
          jmp     .DONE
     .ODD_CLUSTER:
       TIMES 4 shr dx, 1                          ; take high twelve bits
             ; times for 8086 compablility
      ; as it can't SHR by imm8
     .DONE:
          mov     WORD [cluster], dx                  ; store new cluster
          cmp     dx, 0x0FF0                          ; test for end of file
          jb      LOAD_IMAGE
     DONE:
       ;mov     si,msgExecute
  ;call    DisplayMessage
  jmp     0000h:0600h
FAILURE:
          mov     si, msgFailure
          call    DisplayMessage
          xor     ah,ah
  int     16h                                ; await keypress
  int     19h                                ; warm boot computer
    
     ;*************************************************************************
     ; PROCEDURE DisplayMessage
     ; display ASCIIZ string at ds:si via BIOS
     ;*************************************************************************
     DisplayMessage:
          push ax
          push bx
     disp_msg:
         lodsb                                       ; load next character
          test      al, al                           ; test for NUL character
          jz      .DONE
          mov     ah, 0Eh                            ; BIOS teletype
  xor   bx,bx                              ; attributes
  int     10h                                ; invoke BIOS
          jmp     disp_msg
     .DONE:
          pop bx
          pop ax
          ret
    
     ;*************************************************************************
     ; PROCEDURE ReadSectors
     ; reads ‘cx’ sectors from disk starting at ‘ax’ into
     ;memory location ‘es:bx’
     ;*************************************************************************
     ReadSectors:
     rs_MAIN:
          mov     di, 10                       ; five retries for error
     rs_SECTORLOOP:
          push    ax
          push    bx
          push    cx
          call    LBACHS
          mov     ah, 2                               ; BIOS read sector
          mov     al, 1                               ; read one sector
          mov     ch, BYTE [absoluteTrack]            ; track
          mov     cl, BYTE [absoluteSector]           ; sector
          mov     dh, BYTE [absoluteHead]             ; head
          mov     dl, BYTE [DriveNumber]              ; drive
          int     13h                                 ; invoke BIOS
          jnc   rs_SUCCESS                          ; test for read error
          xor     ax, ax                              ; BIOS reset disk
          int     13h                                 ; invoke BIOS
          dec     di                                  ; decrement error counter
          pop     cx
          pop     bx
          pop     ax
          jnz     rs_SECTORLOOP                       ; attempt to read again
  int     18h
     rs_SUCCESS:
          pop     cx
          pop     bx
          pop     ax
  mov     si,msgProgress
  call    DisplayMessage
          add     bx, WORD [BytesPerSector]           ; queue next buffer
          inc     ax                                  ; queue next sector
          loop    rs_MAIN                             ; read next sector
          ret
    
     ;*************************************************************************
     ; PROCEDURE ClusterLBA
     ; convert FAT cluster into LBA addressing scheme
     ; LBA = (cluster - 2) * sectors per cluster
     ;*************************************************************************
     ClusterLBA:
          sub     ax, 2                               ; zero base cluster number
          xor     cx, cx
          mov     cl, BYTE [SectorsPerCluster]        ; convert byte to word
          mul     cx
          add     ax, WORD [datasector]               ; base data sector
          ret
    
     ;*************************************************************************
     ; PROCEDURE LBACHS
     ; convert ‘ax’ LBA addressing scheme to CHS addressing scheme
     ; absolute sector = (logical sector / sectors per track) + 1
     ; absolute head   = (logical sector / sectors per track) MOD number of heads
     ; absolute track  = logical sector / (sectors per track * number of heads)
     ;*************************************************************************
     LBACHS:
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [SectorsPerTrack]              ; calculate
          inc     dl                                  ; adjust for sector 0
          mov     BYTE [absoluteSector], dl

          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [NumHeads]                     ; calculate
          mov     BYTE [absoluteHead], dl
          mov     BYTE [absoluteTrack], al
          ret

     absoluteSector db 0x00
     absoluteHead   db 0x00
     absoluteTrack  db 0x00
     datasector  dw 0x0000
     cluster     dw 0x0000
     ImageName   db "KERNEL  BIN"
     msgCRLF     db 0Dh, 0Ah, 0
     msgFailure  db 0Dh, 0Ah, "Disk boot faliture. Press any key to reboot", 0
     msgProgress db 177,0
     msgExecute db 0Dh,0Ah, "Booting JonOS!",0
          TIMES 510-($-$$) DB 0
          DW 0xAA55
     ;*************************************************************************


Ten bootloader ma uruchomić kernel.bin, nie mam do niego kodu źŸródłowego a tylko skompilowany plik .bin.

Drugi bootloader + skompilowany program w czystym C za pomocą GCC.

Tutaj mam pytanie X, które zadam na koniec. Całość odbywa się pod Ubuntu, u mnie 12.10. Odpaliłem na win7 pod Virtual-Box. Jeśli ktoś tak jak ja nie instalował wcześniej na swoim Ubulawu programu qemu, niech go zainstaluje, jest w repo (Qemulauncher, Qemulator).

Instrukcja krok po kroku, jak skompilować i uruchomić mini kernel. Całość bezczelnie zerżnięta z http://www.youtube.com/watch?v=Qit1civWf7Y

Tworzymy katalog, ja mam na pulpicie. W nim po kolei tworzymy wszystkie poniższe pliki.


plik: loader.asm  (loader, nie bootloader)

global loader
extern dmain
MODULEALIGN equ 1<<0
MEMINFO     equ 1<<1
FLAGS       equ MODULEALIGN | MEMINFO
MAGIC       equ 0x2BADB002
CHECKSUM    equ -(MAGIC + FLAGS)

section .text
align 4
MultiBootHeader:
dd MAGIC
dd FLAGS
dd CHECKSUM

STACKSIZE equ 0x4000

loader:
mov esp, stack+STACKSIZE
push eax
push ebx

call dmain

cli

hang:
hlt
jmp hang

section .bss
align 4
stack:
resb STACKSIZE

plik kernel.c
C/C++
void print( char *, int ); //co, kolor

void dmain( void * mbd, unsigned int magic ) //entry point
{
    /*ponizszego if'a mozna wykorzystac np. do sprawdzenia czy skompilowany kernel.c
      zostal uruchomiony z wlasciwiym parametrem, ktory jest ustawiany w loader.asm,
      oczywiscie skompilowanym do pliku .o
    */
   
    if( magic != 0x2BADB002 )
    {
        print( "Invaild execution", 0x07 );
    }
    else
    {
        print( "Booting...", 0x07 );
        //dalsze instrukcje
    }
}

void print( char * message, int color ) //prosty print
{
    char * mem =( char * )( 0xb8000 ); //dzialamy na ekranie
   
    while( * message != 0 ) //dla kazdego znaku message
    {
        //na ktorej komorce ekranu bedziem dzialac, tam trafia bajt txt
        * mem = * message;
       
        mem++; //przesuwamy o jeden komorke ekranu
        message++; //przesuwamy wiadomosc
        * mem =( char * ) color; //ustawiamy kolor
       
        /*znow przesuwamy ekran o jeden, kazdy bajt wyswietlany sklada sie z bajtu do wyswietlenia
          oraz bajtu odpowiedzialnego za kolor
        */
        mem++;
       
    }
}


Oba pliki trzeba będzie zlinkować. Ale to zaraz, najpierw plik linkera.


plik: linker.ld  http://speedy.sh/f8hvt/linker.ld

ENTRY (loader)
SECTIONS {

. =0x00100000;

.text : {
*(.text)
}
.rodata ALIGN (0x1000) : {
*(.data)
}
.bss : {
sbss = .;
*(COMMON)
*(.bss)
ebss = .;
}
}
>> Uwaga na formatowanie! Z tego co zauważyłem, linker jest czuły na spacje, należy używać tabulatora. W razie błędów po ctrl+c -> ctrl-v należy obczaić filma tak od 3/4..

Tworzymy teraz plik-skrypt. Będzie on wykonywał:
* kompilację kernel.c do postaci pliku obiektowego,
* kompilację loader.asm do pliku obiektowego,
* linkowanie plików obiektowych z użyciem pliku linkera linker.ld (wynik: kernel.bin)
* odpalenie zlinkowanego kernel.bin poprzez qemu

plik: compile.so

#!/bin/bash

gcc -o kernel.o -c kernel.c -Wall -Wextra -nostartfiles -nodefaultlibs

nasm -f elf -o loader.o loader.asm

ld -m elf_i386 -T linker.ld -o kernel.bin loader.o kernel.o

qemu-system-i386 -kernel kernel.bin

Moje Ubulawu nie miało qemu, a że nie wiedziałem które zainstalować z repo, zainstalowałem: Qemu Launcher oraz Qemulator ;p

Kiedy już zainstalowane, nadajemy w terminalu prawa wykonywalności skryptowi: chmod +x /sciezka/compile.so

Odpalamy skrypt.


#!/bin/bash

gcc -o kernel.o -c kernel.c -Wall -Wextra -nostartfiles -nodefaultlibs

nasm -f elf -o loader.o loader.asm

ld -m elf_i386 -T linker.ld -o kernel.bin loader.o kernel.o


Jeśli wszystko poszło dobrze, powinien uruchomić się nasz system operacyjny, powinien pojawić się komunikat: Booting...

Pytania.

Jak z poziomu kernel.c odpalić powiedzmy dosowy program napisany w BorlandC++3.1 16-bit? W skrypcie do kompilacji gcc wywoływany jest dla pliku kernel.c z parametrami uniemożliwiającymi używania biblioteki standardowej. Przyznam szczerze, że przychodzi mi do głowy w takim wypadku Borland-C++, ale tutaj znów nie idzie go zmusić do generowania pliku .o, jeśli już to tylko .exe.

Jak przejśc w tryb procesora 32-bit (protected)? Nie żebym chciał linuxdowsa pisać, pytam z ciekawości. Wszelkie sugestie mile widziane :)

Co ciekawe, ostatnio wszystko co do średnika szło dobrze, zrypało mi się qemu coś i to jak na złość, dzisiaj ;] Pojawia się komunikat w terminalu po wyłączeniu qemu:


Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.

Pomocy :)
P-68099
bingo009
» 2012-11-01 18:08:35
Pytanie 1:
Musiałbyś napisać system zgodny z DOS'em. Przykładowo, w DOS jest przerwanie 21h, podczas gdy nie występuje ono nigdzie indziej. Jest ono charakterystyczne tylko dla DOS/Windows. Aby uruchomić aplikację DOS, twój system musi działać w taki sam sposób, tak samo zarządzać pamięcią, mieć te same przerwania, komendy i inne mechanizmy, w skrócie musisz napisać drugiego DOS'a. Zamiast bawić się w odczytywanie plików DOS'a, napisz w systemie odczytywanie plików twojego własnego formatu, napisz bibliotekę do jakiegoś języka(np. C), która zawiera funkcje, które rozpoznaje twój system. Tak będzie dużo prościej i lepiej. Możesz popatrzeć jak to jest zrobione w MikeOS, który może uruchamiać programy i ma własną bibliotekę do pisania programów w C pod niego.

Pytanie 2:
Teoretycznie wygląda to tak:
Ładujesz Global Description Table, oraz Local Description Table(nie wiem, czy jest ona konieczna), wypadało by też odblokować linię A20(żeby mieć dostęp do więcej niż 1MB pamięci, procesor 32bitowy może maksymalnie zaadresować 4GB), zapalasz bit rejestru cr0 i robisz długi skok. Praktycznie, odsyłam znowu do źródeł MikeOS, albo do jakiegoś kursu, w którym jest to wyjaśnione. Po wpisaniu w Google jest tego trochę.

Pytanie 3:
Błąd mówi, że nie znaleziono modułu KVM, przeinstaluj go, albo całe qemu.
P-68126
« 1 »
  Strona 1 z 1