Autor: DjH | 5.8.2008 |
#ifndef _GLOBAL_INCLUDED_ #define _GLOBAL_INCLUDED_ /* * global.h * Zde jsou ulozene globalni promenne, * ktere se muzou pouzivat v celem tele kernelu. */ /* TEXT_COL, globalni promenna urcujici barvu textu */ char TEXT_COL = 0x07; #endifJak jste si všimli, ve hlavičkovém souboru se nachází #ifndef ... podmínka. To znamená, pokud byl již soubor inkludován, neměl by se inkludovat znovu. Toto tomu zabrání. Dále následuje krátký popis o souboru, může tam být i výčet a krátký popis funkcí a typů, které se v hlavičkovém souboru nacházejí. Zde budu psát jen důležité funkce, či jejich hlavní části. Nejaktuálnější zdrojové kódy jsou vždy v archivu.
#define _Cdecl void _Cdecl __int__ (int interruptnum); ...To nám pomůže lépe psát funkce:
/* * getch() * pocka na stisk klavesy, vrati jeji ASCII hodnotu */ char getch() { _AX = 0x00; __int__(0x16); return _AL; } /* * putch() * vytiskne ASCII znak */ void putch(char s) { if((s!='\r') && (s!='\n') && (s!='\t') && (s!='\b')) { /* barevne NEtisknout tyto znaky */ _AL = 0; _CX = 1; _BH = 0; _BL = TEXT_COL; _AH = 0x09; __int__(0x10); } _AL = s; _AH = 0x0e; _BL = 0x07; __int__(0x10); }video.h:
void textcolor(char col) { TEXT_COL = col; }string.h:
/* * putchar() * vytiskne ASCII znak, pokud je vstup 0x08 * (backspace), umaze jeden znak */ void putchar(char s) { if(s == '\b') { /* backspace */ putch('\b'); putch(' '); putch('\b'); } else { putch(s); } }> Tisknutý znak (backspace) přes interrupt obrazovky posune kurzor o jedno místo doleva (o konec se zastaví), ale znak nevymaže, pomůžeme tomu tak, že posuneme kurzor doleva, přepíšeme znak mezerou a vrátíme se zpět.
/* * puts() * vstup: ukazatel na string, ktery se bude tisknout na vystup * vystup: void */ void puts(const char *str) { int i; for(i = 0; str[i] != '\0' ; i++) { putchar(str[i]); } } ... char *strcpy(char * dest,const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0'); return tmp; } ... char *strcat(char * pDst, const char *pSrc) { char *r = pDst; while (*pDst != '\0') pDst++; while ((*pDst++ = *pSrc++) != '\0') continue; return r; }> funkci gets() jsem pořešil trochu jinak, a to tak, že jako parametr se nepřidá jen buffer, ale i maximální délka povoleného stringu k zadání. Tím zamezíme přetečení bufferu.
/* * gets() * sejme string z klavesnice o maximalni delce <size>, * kazdy znak vytiskne na monitor */ char *gets(char *cs, int size) { unsigned int counter = 0; unsigned char c = '\0'; char *s; s = cs; while (1) { if(counter >= size) break; c = getch(); if(c == '\r') break; if(c == '\n') break; if(c == '\0') break; if(c == '\t') c = ' '; if(!(counter == 0 && c == '\b')) { putchar(c); } if( c == '\b' ) { if (counter > 0) counter--; } else { *(s+(counter++)) = c; } } puts("\r\n"); *(s+(counter++)) = '\0'; return s; }init.h:
void init(void) { puts("............................ [ "); textcolor(LIGHTGREEN); puts("OK"); textcolor(LIGHTGRAY); puts(" ]\r\n\n"); puts("Startuji SHELL...\r\n\n"); return; }kernel.c: Nyní půjdemé psát samotné jednoduché jádro:
/* * KERNEL */ #include <asm.h> #include <global.h> #include <init.h> #include <string.h> #include <video.h> int main(void) { char cmd[80]; init(); while(1) { puts("[altair@os]/$ "); gets(cmd, 79); puts("Zadali jste: '"); puts(cmd); puts("'\r\n"); } return 0; }Jak jste si jistě všimli, inkludujeme všechny hlavičkové soubory. Mělo by být jedno v jakém pořadí. Nyní po startu vám OS vypíše
[altair@os]/$
a počká na váš string ukončený enterem, nebo 79 znakem. Po stisknutí enteru se váš zadaný řetězec vypíše na monitor.
[BITS 16] ; budeme pracovat v 16tibit. rezimu (RealMode) [EXTERN _main] ; fce main() z kernel.c, C pri kompilaci ; do OBJ pridava podtrzitko pred kazdy nazev fce [GLOBAL start] ; start bude mozno pouzit i jinde start: call _main ; zavolame main() z kernel.c jmp $ ; halt PC -> neco jako 'halt: jmp halt'Myslím že není co dodat a že je to jasné. Nyní to jen musíme nějak slinkovat. Na to nám pomůže jednoduchý jloc skriptík:
ALL: tmp\kernel_a.obj tmp\kernel.obj CBL: 0 0 0 *Třetí řádku trochu vysvětím, CBL je jen název „odkazu“, první nula je jaké mají mít segmentové registry číslo, což je nula, druhá nula je číslo, na jakém segmentu začíná aplikace. Kdyby to byla výše zmiňovaná *.com, tak tam bude 100, a třetí nula je začátek kódu, kde aplikace začíná. Hvězdička na konci značí konec sekce a může se linkovat.