DM14 1. Obligatoriske opgave Systemkald Antal sider: 7 inkl. 2 bilag Afleveret: d. 18/3-2004 Afleveret af: Jacob Christiansen, 130282-2111 Side 1 af 5
Intro: Formålet med opgaven at et lave en system kald til en Linux kerne, i vores tilfælde en User-Mode- Linux kerne. Der skal implementeres en system kald, som ved hjælp af region based memory, gør det muligt at dele data mellem processer. Region based memory er en inter process communication (IPC) metode, som blandt andet bruges I distributed shared memory systems. Det vil sige det er en metode som gør det muligt for processer, at dele en klump hukommelse. Dette område kan tilgås ved hjælp specielle operationer, her et systemkald. Implementation: System kaldet er implementeret efter den opgivne guid på kursets hjemmeside. Det vil sige at følgende filer er ændret, for at tilføje systemkaldet: Unistd.h Sys_call_table.c Desuden er Makefile blevet opdateret, så systemkaldet bliver compilet, når UML kompiles. Herefter er header-filen implementeret. Dette gøres for at andre c-programmer i UML, kan kalde systemkaldet. Header-filen moffe42_mem.h er vedlagt som bilag. I filen er selve systemkaldet defineret, samt nogle globale variabler, som bruges når selve kaldet sker i et c-program (ie. MOFFE42_MEM_READ 1) Selve systemkaldet er implementeret I moffe42_mem.c. moffe42_mem.c er også vedlagt som bilag. I filen er der først inkluderet nogle header-filer, som gør det muligt at lave et nyt systemkald. Derefter defineres størrelsen på det hukommelses område, som systemkaldet skal kunne tilgå. Til sidst defineres selve systemkalds funktionen. Systemkaldet kaldes med 4 argumenter: int flag: Et integer argumet, som angiver om der skal skrives til hukommelses området eller læses. Char *buf: En pointer til et char array. Kilde eller destinations array, alt efter om der er tale om skrivning eller læsning. Int offset: Et integer argument, som angiver et offset fra starten af hukommelses område, der tilgås. Int length: Et integer argument, som angiver hvor lang char arrayet er eller hvor meget af den der skal skrives i hukommelses området. Det første der sker i funktionen er en erklæring af et char array, som bruges til at tilgå hukommelses området. Derefter tjekkes der om alle argumenter er korrekte. Er de ikke det, returnere funktionen en fejlværdig til hoved-programmet, ellers fortsættes der. Herefter kontrolleres der hvad flag er sat til og derefter læses eller skrives der til hukommelses området. Skulle funktionen, mod forventning ikke skrive eller læse hele char arrayet, vil funktionen returnere en fejl besked. Side 2 af 5
Til sidst er testprogrammet implementeret, for at se om systemkaldet virker som det skal. Programmet virker som et hvilket andet, hvor man kalder systemkaldet. Først kaldes systemkaldet med READ og derefter WRITE. Efter hvert kald tjekkes der om systemkaldet har returneret en fejl og dermed ikke fuldført rigtigt. Her skal man huske at resette errno, da det ellers ikke er muligt at kalde perror igen. Rent implementationsmæssigt er det gjort som man kunne forvente, dog er der ting som kunne være gjort anderledes og nogle ting som ikke er implementeres. For eksempel kunne man have valgt ikke at lave length som et argument, men i stedet, når funktionen kaldes, kontrollere hvor lang char arrayet er og bruge det. Dog ville dette ikke give noget fordel, snare tvært imod. Samme princip, kunne man bruge til at tjekke om char arrayet virkelig er et char array og om det indeholder en end værdi. En end værdi vil være at foretrække, så frem man vil printe char arrayet efter det er læst. Desuden kunne erklæringen med MOFFE42_MEM_READ og MOFFE42_MEM_WRITE godt glemmes, da funktionen bare skal have et 1 eller 2. Det bruges dog, for letheden skyld, så kaldet af systemkaldet gøres mere gennemskueligt. Samtidige kald: En af de ting man altid er nød til at tage i betragtning, når man har en funktion, der kan kaldes samtidig fra flere processer samtidig, er selvfølgelig, hvad vil der ske i det tilfælde hvor 2 processer kalder funktionen samtidig. Umiddelbart er det ikke lige til at sige, så frem der ikke er en separat scheduler til at håndtere systemkald. Det mest oplagte er hvis systemkaldet, kan udføres i en timeslice. Så vil første kald køre efter planen. Det samme vil det andet, dog har man ingen anelse om hvad det er for data der vil ligge i hukommelses området. Et andet tilfælde vil være at systemkaldet ikke ville kunne blive færdig på en timeslice. Et lille eksempel: 1. Proces 1 bruger det sidste af sin timeslice, til lige at nå at læse de to første char i hukommelsen. 2. Proces 2 begynder lige ved systemkaldet når timeslicen starter. Proces 2 når at skrive 5 char til hukommelsen. 3. Process 1 læser videre i sin nye timeslice, men data passer ikke sammen, med det forventede. 4. Osv. En sidste mulighed er at der er en eller anden form for memory-manegement, som holder styr på hvilke processer der har adgang til hvilke dele af hukommelsen. I et sådant tilfælde, vil andet kald til samme område, returnere en fejl, da den ikke kan tilgå hukommelsen. Side 3 af 5
Test: For at vise at vores systemkald virker, er det nødvendigt at kalde det med rigtige argumenter, samt med forkerte. Følgende test er udført: 1. moffe42_mem(moffe42_mem_write, Hello region, 1024, 13) 2. moffe42_mem(moffe42_mem_write, Hello region, 1024, 13) moffe42_mem(moffe42_mem_read, out, 1024, 6) 3. moffe42_mem(moffe42_mem_write, Hello region, 1024, 6) 4. moffe42_mem(moffe42_mem_write, Hello region, 1024, -13) 5. moffe42_mem(moffe42_mem_write, Hello region, 1048576, 13) 6. moffe42_mem(4, Hello region, 1024, 13) Testene gav følgende output: 1. Output: Hello region 2. Output: Hello @HÞ@À 3. Output: Hello region 4. Write: Invalid argument 5. Write: Cannot allocate memory 6. Write: Invalid argument Alle test gav det forventede output på nær 2. Test 2 skriver mere end forventet. Dette skal dog ikke ses som en fejl i systemkaldet, men en fejl i funktionen printf. Funktionen printer ind til den møder et end tegn. Da systemkaldet ikke har skrevet et end tegn i char arrayet, vil den fortsætte med at printe ind til den møder et tilfældigt. Desuden giver test 3 også anledning til nærmere undersøgelse. Systemkaldet skulle kun skrive Hello, men alligevel kommer der Hello region ud. Dette skyldes at der i forvejen ligger resten, ligger der fra en forgående kørsel. Havde man i stedet skrevet det et andet sted i hukommelsen, havde vi fået samme besked som i test 2. Havde vi i stedet kaldt WRITE kun med Hello og ikke Hello region, ville det rigtige resultat komme ud, da printf, da printf ville finde et end tegn efter Hello. Side 4 af 5
Aflevering: Opgaven løb på at lave et systemkald, som gjorde det muligt at skrive til et hukommelses område. Dette er nu gjort, samt der er taget højde for at systemkaldet kun tager de rigtige argumenter. Desuden er der taget hånd om fejlhåndtering, så systemkaldet ikke terminer uhensigtsmæssigt.. Side 5 af 5
// // Main-prog til moffe42_mem syscall // //Include header-files #include "arch/um/include/moffe42_mem.h" #include <stdio.h> #include <errno.h> #include "asm/arch/unistd.h" //Definition of syscall _syscall4(void, moffe42_mem, int, flag, char *, buf, int, offset, int, length) //Main int main() { //Initialization char *in = "Hello region"; char out[13]; //Reset errno errno = 0; //Write to kernel mem moffe42_mem(moffe42_mem_write, in, 1024, 13); //Error handling if(errno) { perror("write"); return 0; } //Reset errno errno = 0; //Read from kernel ; //Error handling if(errno) { perror("read"); return 0; } //Print output printf("output: %s\n", out); return 0; }
Output: Hello region