Eigenes OS?
-
Ich wollte an dieser Stelle darauf hinweisen, dass die deutsche Übersetzung der dritten Auflage von Tanenbaum's Meisterwerk verfügbar ist und kann dieses Grundlagen- und Nachschlagewerk nur empfehlen: Andrew S. Tanenbaum et.al., Moderne Betriebssysteme, 3. Auflage, Pearson Studium, April 2009 (Übersetzung von "Modern Operating Systems", Prentice Hall, Dec 2007). Der wesentliche Makel der deutschen Ausgabe ist, dass das IMHO gelungene Titelbild des Originals nicht enthalten ist.
deutsch: http://www.pearson-studium.de/media_local/shop_u1bigs_3d/9783827373427.jpg (April 2009)
amerikanisch: http://vig-fp.prenhall.com/bigcovers/0136006639.jpg (Dec 2007)
Für mich neben den Intel Manuals und einem Assemblerbuch eine wesentliche Fundgrube für Fakten und Ideen.
Allerdings staune ich immer wieder, dass selbst so ein Standardwerk noch Fehler, didaktische Luecken und Ungereimtheiten enthaelt.Gibt es eigentlich schon so etwas wie "OS Development for Dummies" in engl. oder deutsch? Ist mir bisher nicht unter gekommen.
-
Kurzer Zwischenstand: z.Z. kämpfe ich mit dem "echten" User Mode (Ring 3).
Da gibt es noch GPF.EDIT: http://www.henkessoft.de/OS_Dev/Downloads/20090522_43_user_mode.zip
PrettyOS arbeitet zum ersten Mal im "echten" User Mode (Ring 3). Wichtig ist, dass man im ring3 ss und esp vor die eflags "pusht" (Intel Manual 3A, Kap. 5.12).task_t* create_task(void* entry, UCHAR privilege) { cli(); page_directory_t* directory = clone_directory(current_directory); task_t* new_task = (task_t*)k_malloc(sizeof(task_t),0,0); new_task->id = next_pid++; new_task->page_directory = directory; new_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE; new_task->next = 0; task_t* tmp_task = (task_t*)ready_queue; while (tmp_task->next) tmp_task = tmp_task->next; tmp_task->next = new_task; // ... and extend it ULONG* kernel_stack = (ULONG*) new_task->kernel_stack; ULONG code_segment=0x08, data_segment=0x10; if(privilege == 3) { //Intel 3A Chapter 5.12 *(--kernel_stack) = new_task->ss = 0x23; // ss *(--kernel_stack) = new_task->kernel_stack; // esp = esp0 code_segment = 0x1B; // 0x18|0x3=0x1B } *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0 *(--kernel_stack) = code_segment; // cs *(--kernel_stack) = (ULONG)entry; // eip *(--kernel_stack) = 0; // error code *(--kernel_stack) = 0; // interrupt nummer // general purpose registers w/o esp *(--kernel_stack) = 0; *(--kernel_stack) = 0; *(--kernel_stack) = 0; *(--kernel_stack) = 0; *(--kernel_stack) = 0; *(--kernel_stack) = 0; *(--kernel_stack) = 0; if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23 *(--kernel_stack) = data_segment; *(--kernel_stack) = data_segment; *(--kernel_stack) = data_segment; *(--kernel_stack) = data_segment; //setup TSS tss_entry.ss0 = 0x10; tss_entry.esp0 = new_task->kernel_stack; tss_entry.ss = data_segment; //setup task_t new_task->ebp = 0xd00fc0de; // test value new_task->esp = (ULONG)kernel_stack; new_task->eip = (ULONG)irq_tail; new_task->ss = data_segment; sti(); return new_task; }
void test5() { while(TRUE) { syscall_puts("5"); //puts("5"); } } //... task_t* task5 = create_task (test5,3);
Ohne syscall ( Aufruf Kernel-Fkt. aus Ring 3 ) ==>
44444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444
Page Fault ( read-only - write operation user-mode) at 000B8C06h - EIP: 00008986hFür echte User-"Programme" benötigt man ja auch noch Stack und Heap im User-Privileg. Da denke ich gerade nach, wie man das einfach möglichst einfach in Ring3 mappen/allokieren kann.
Bei obigem Programm gibt es noch Probleme, wenn man das while in test5 streicht. Da überlege ich gerade eine Umhüllung oder ein exit. Wenn da jemand eine Idee hätte?
-
Ich hab noch eine kleine Anmerkung zum Stack.
Zwar weiß ich nicht, was Du da jetzt alles drüber abwickeln willst, (sagst ja, lokale Speicheranforderung extra etc.), und ich weiß deshalb nicht, ob hier ein Problem entstehen kann. Solltest aber einen klitzekleinen Moment drüber verwenden, ob hier memory fragmentation reinspielen kann oder nicht. Wenn ja, unterschätze den Effekt nicht. Ich habe damals an die DJGPP-newsgroup ein sample geschickt (okay, das ist jetzt lokale Speicheranforderung), was den gcc abschiessen konnte, obwohl alles korrekt war. Hatte einfach zufällige Mengen von Speicheranforderungen und -freigaben in rauher Menge laufen lassen.
Auf die Bemerkung, das wäre ja nun sehr willkürlich, habe ich einfach gekontert, dass bei einer OOP-Sprache wie C++ doch kaum noch absehbar ist, was in den vielen kleinen Blackboxes alles passiert. Das haben sie dann doch ernst genommen, und das ganze Kapitel so überarbeitet, dass sich mein Sample auf den Kopf stellen konnte - es blieb stabil! Vielleicht kann man durch debuggen/disassemblen des new-Befehls mal schauen, was für ein Grundprinzip dahinter steckt.
Kann schlecht abschätzen, ob Du so etwas an der bewußten Stelle auch brauchst.
Reine fifo-Dinge werden es wohl auch nicht mehr sein.
-
@Bitsy: Danke für den Hinweis. Momentan kämpfe ich dermaßen mit Prozessen (Multitasking/Privilegien/Syscall/Interrupts), dass ich gar keine Zeit für das Speichermanagement habe.
Du meinst, wenn ständig irgendein Prozess 4 KB Stack anfordert und anschließend wieder frei gibt? Wir betreiben das Spiel mit den Stacks auf dem Heap. Ich muss mal schauen, wie man diese geordenete Liste aller "freien Löcher" bzw. "belegten Blocks" (Heap Code von James Molloy, Kernel Tutorial, Kap. 7, übernommen) visualisieren kann. Dann könnten wir den Algo testweise stressen.
Vielleicht hat jemand Zeit/Lust für so eine Sonderaufgabe?
-
Zum Thema Multitasking/UserMode/Syscalls:
Wenn man früher aus einer Task ausbrechen will, als die Timeslice dauert, lässt sich das leicht über einen Software-Interrupt realisieren:
void exit_task() //exit to next task { asm volatile("int $0x21"); // <== welchen INT würdet ihr verwenden? } void f2() { while(TRUE) { settextcolor(getpid(),0); putch(getpid()+'@'); exit_task(); } } void f3() //user mode at ring 3 requires syscall_... { while(TRUE) { syscall_settextcolor(syscall_getpid(),0); syscall_putch(syscall_getpid()+'@'); syscall_exit_task(); } } int main() { //... // create two additional tasks task_t* task2 = create_task (f2,0); // kernel mode (ring 0) task_t* task3 = create_task (f3,3); // user mode (ring 3) pODA->ts_flag = 1; // enable task_switching while(TRUE) { settextcolor(getpid(),0); putch(getpid()+'@'); exit_task(); } return 0; }
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB
CABCABCABABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB
CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCACABCABCABCAB
CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA
BCABCACABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCBCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABSyscalls (Überbrückung Ring3 ==> Ring0):
#define DECL_SYSCALL0(fn) int syscall_##fn(); //etc. #define DEFN_SYSCALL0(fn, num) \ int syscall_##fn() \ { \ int a; \ asm volatile("int $0x7F" : "=a" (a) : "0" (num)); \ return a; \ } //etc. DECL_SYSCALL1(puts, UCHAR*) DECL_SYSCALL1(putch, UCHAR) DECL_SYSCALL2(settextcolor, UCHAR, UCHAR) DECL_SYSCALL0(getpid) DECL_SYSCALL0(f3) DECL_SYSCALL0(nop) DECL_SYSCALL0(exit_task) DEFN_SYSCALL1( puts, 0, UCHAR* ) DEFN_SYSCALL1( putch, 1, UCHAR ) DEFN_SYSCALL2( settextcolor, 2, UCHAR, UCHAR ) DEFN_SYSCALL0( getpid, 3 ) DEFN_SYSCALL0( f3, 4 ) DEFN_SYSCALL0( nop, 5 ) DEFN_SYSCALL0( exit_task, 6 ) #define NUM_SYSCALLS 7 static void* syscalls[NUM_SYSCALLS] = { &puts, &putch, &settextcolor, &getpid, &f3, &nop, &exit_task };
-
Das ist wohl eher ein task_yield(), da der Prozess wieder auftaucht und nicht aus der Liste der lauffaehigen Prozesse ausgetragen wird. Prozesse geben normalerweise nicht freiwillig auf, und wenn, dann mit exit endgueltig.
-
zosxc63Tr schrieb:
Das ist wohl eher ein task_yield(), da der Prozess wieder auftaucht und nicht aus der Liste der lauffaehigen Prozesse ausgetragen wird. Prozesse geben normalerweise nicht freiwillig auf, und wenn, dann mit exit endgueltig.
Ja, alles richtig, werde dies auf ein exit() umbauen. Obiger Mechanismus koennte evtl. fuer ein thread_yield verwendet werden.
-
Wie geht es weiter mit dem OS Skript? Wann wird nach GRUB und Linux Tools umgestellt wie sonst ueblich?
-
was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?
-
Ich denke mal, es soll dazu dienen, zu verstehen, wie ein OS funktioniert. Deswegen wird es von Grund auf programmiert. Und da so etas nicht einfach ist, muss man etwas geduld mitbringen.
-
upperleft schrieb:
was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?
Genau! Und warum progammieren Anfänger immer diese Hello World Programme? Die gibts doch schon! Ich verstehe wirklich nicht, was das bringen soll...
-
so ist das nun. bildungsresitenz breitet sich hierzulande immer mehr aus
-
sothis_ schrieb:
bildungsresitenz
Vorsicht! Bildungsresistenz falsch zu schreiben, ist ähnlich gefährlich wie bei Intelligenz...
-
I _matze
upperleft schrieb:
was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?
Wie matze schon meinte, es dient zur Übung und ein OS ist eine gute Herausforderung. Hätte ich das Wissen und die Zeit dazu, würde ich mich auch dran versuchen. Wer kann schon von sich sagen, er habe alleine sein eigenes OS gebaut?
-
_matze schrieb:
sothis_ schrieb:
bildungsresitenz
Vorsicht! Bildungsresistenz falsch zu schreiben, ist ähnlich gefährlich wie bei Intelligenz...
ich habe nicht behauptet, dass ich mich davon selbst ausschließe
-
nein, ihr habt mein posting nicht verstanden. es gibt schon minix, wsa genau für diesen zweck geschrieben wurde und in einem umfangreichen buch schritt für schritt, sowohl in der theorie als auch in der praxis (anhand des quellcodes) erläutert wie ein OS funktioniert. also wozu genau das gleiche hier nochmal?
-
upperleft schrieb:
also wozu genau das gleiche hier nochmal?
weil es menschen gibt, die besser lernen wenn sie es selbst von grund auf durcharbeiten. wenn sie andere an der arbeit teilhaben lassen kommt dies dem eigenen lernprozess und dem der anderen zu gute. deswegen existieren unzählige halbfertige betriebssystem-kernel, und das ist auch gut so.
-
sothis_ schrieb:
deswegen existieren unzählige halbfertige betriebssystem-kernel, und das ist auch gut so.
Ab wann ist denn ein Stück Software fertig... Heisst es nicht, ist Software fertig, dann wohl veraltet
-
und all dies für dieses frickelicke baumhaus mit zig anbauten namens x86. naja wers sich gern unnötig schwermacht
wenn ich mal zeit habe schreibe ich auch mal ein buch über ein kleines betriebssystem, aber das läuft dann auf einem schönen MIPS oder ARM oder so, damit der leser sich aufs wesentliche konzentrieren kann und ned auf x86 frickelei.
-
^^das statement hätte von mir sein können (bis auf das bücher schreiben). aber naja, es war nunmal erhards entscheidung.