Main Page | Modules | File List | File Members

rZero.c

00001 /* ndk - [ rZero.c ]
00002  * (c)2002 neuraldk
00003  *    dcipher
00004  *    carbonBased
00005  *
00006  * rZero modules are ndk's method of externalizing functions of the
00007  * kernel which users might want to customize (such as the
00008  * scheduling method used, the start-up splash screen, memory
00009  * management, etc).
00010  *
00011  * In essence, the kernel will automatically load these modules and
00012  * run-time link them into the kernel (allowing the modules access
00013  * to a select few kernel functions, and publishing the required
00014  * symbols from the module, to the kernel).
00015  *
00016  * With such a system, it should also be able to change these modules
00017  * from withen the operating system.
00018  *
00019  * For more information, see doc/rZeroModules.kwd
00020  */
00021 
00022 #include "rZero.h"
00023 #include "rdoff.h"
00024 
00025 #define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))
00026 
00027 /* Listed here will be the _only_ symbols exported to
00028  * rZero modules.  As a security precaution, so they
00029  * can't take the whole system down (seeing as
00030  * though, by definition, rZero modules run at the
00031  * highest privelege level).
00032  */
00033 rZeroSymbolInfo rZeroExports[] = {
00034   { "consoleClear"   , (long)consoleClear   , 0 },
00035   { "consoleOut"     , (long)printf         , 0 },
00036   { "inportb"        , (long)inportb        , 0 },
00037   { "memcpy"         , (long)memcpy         , 0 },
00038   { "memoryAllocPage", (long)memoryAllocPage, 0 },
00039   { "memoryFreePage" , (long)memoryFreePage , 0 },
00040   { "memset"         , (long)memset         , 0 },
00041   { "outportb"       , (long)outportb       , 0 },
00042   { "outportw"       , (long)outportw       , 0 },
00043 //{ "multibootInfo"  , (long)multibootInfo  , 0 },
00044   { "strcmp"         , (long)strcmp         , 0 },
00045   { "strncmp"        , (long)strncmp        , 0 },
00046   { "timerGetTicks"  , (long)timerGetTicks  , 0 },
00047   { (char *)NULL     , NULL                 , 0 }
00048 };
00049 
00050 /* And here are all the symbols we wanted imported from
00051  * the rZero modules.  Again, it's impossible for a rouge
00052  * module to replace any system code, as these symbols
00053  * will be the only ones changed.  An attempt to overwrite
00054  * an already defined symbol will also flag an error.
00055  */
00056 rZeroSymbolInfo rZeroImports[] = {
00057   {"_main"          , NULL, 0 },
00058   { "main"          , NULL, 0 },
00059   { "splashPrint"   , NULL, 0 },
00060   { "splashProgress", NULL, 0 },
00061   { "splashScreen"  , NULL, 0 },
00062   { "taskNew"       , NULL, 0 },
00063   { "taskSwitch"    , NULL, 0 },
00064   { (char *)NULL    , NULL, 0 }
00065 };
00066 
00067 void rZeroInit(void) {
00068   module_t *mod;        // multiboot module structure
00069   rZeroObj obj;         // rZero module structure
00070   int i;
00071 
00072   /* Do we have ring zero modules? */
00073   if( !CHECK_FLAG(multibootInfo->flags, 3)) {
00074     consoleOut("No rZero Modules Found!!!\n");
00075     consoleOut("The following modules:\n");
00076     consoleOut("  scheduler.r0\n");
00077     consoleOut("  progress.r0\n");
00078     consoleOut("are required by ndk!\n");
00079     //exit(1);
00080   }
00081 
00082   consoleOut("Total rZero Modules: %d, Starting at: 0x%8x\n",
00083         (int)multibootInfo->mods_count,
00084         (int)multibootInfo->mods_addr);
00085 
00086   /* loop through all the modules, and parse/link them
00087    * into the kernel
00088    */
00089   mod = (module_t *) multibootInfo->mods_addr;
00090   for(i = 0; i < multibootInfo->mods_count; i++) {
00091     obj.mem = (char *)mod[i].mod_start;
00092     obj.end = (char *)mod[i].mod_end;
00093     obj.name = (char *)mod[i].string;
00094     rZeroClearSegments();
00095     rZeroParse(&obj);
00096     //rZeroRelocate(&obj);
00097   }
00098   return;
00099 }
00100 
00101 /* Clear any linking references the previous module
00102  * may have left (ie, allow for more than one
00103  * module to use consoleOut, for example)
00104  */
00105 void rZeroClearSegments(void) {
00106   int i = 0;
00107   while(rZeroExports[i].symbolName != NULL) {
00108     rZeroExports[i++].segmentNum = 0;
00109   }
00110 }
00111 
00112 /* Loop through the given symbol table, returning
00113  * an index to the provided symbol.  Usually used with rZeroImports
00114  */
00115 int rZeroFindSymbol(char *symbol, rZeroSymbolInfo *symInfo) {
00116   int i = 0;
00117 
00118   // NOTE: could also use a bsearch, if symbol names are alphabetical...
00119   while(strcmp(symbol, symInfo[i].symbolName) != 0) {
00120     if(symInfo[i].symbolName == 0) {
00121       consoleOut("Could not find symbol: %s\n", symbol);
00122       return -1;
00123     }
00124     i++;
00125   }
00126   return i;
00127 }
00128 
00129 /* Loop through the given symbol table, returning
00130  * an index to the provided symbol.  Usually used with rZeroExports
00131  */
00132 int rZeroFindSegment(short segment, rZeroSymbolInfo *symInfo) {
00133   int i = 0;
00134   while(symInfo[i].segmentNum != segment) i++;
00135 
00136   return i;
00137 }
00138 
00139 /* Parse an rZero module.  This function will validate
00140  * that the module is, infact, in the rdoff format, record
00141  * information on all segments included in the file and
00142  * then call rZeroParseHeader (to parse the header information
00143  * and link it into the kernel)
00144  */
00145 void rZeroParse(rZeroObj *obj) {
00146   // Does the module have the rdoff signature?
00147   if(strncmp(obj->mem, "RDOFF", 5)) {
00148     consoleOut("rZero module (%s) not in RDOFF format\n", obj->name);
00149     return;
00150   } else {
00151     obj->version = obj->mem[5] - '0';
00152     consoleOut("RDOFF Version %d.0\n", obj->version);
00153   }
00154   // skip past the signature
00155   obj->pos = 6;
00156 
00157   // this length read doesn't work properly!
00158   // However, everything else does!?
00159   if(obj->version > 1) {
00160     obj->length = readLong(obj);
00161     consoleOut("Object content size: %d bytes\n", (int)obj->length);
00162   }
00163 
00164   // find the length of the header and record it
00165   obj->headerLength = readLong(obj);
00166   obj->headerOffset = obj->pos;
00167 
00168   // skip over the header for now...
00169   obj->pos += obj->headerLength;
00170 
00171   // because I need segment info first!
00172   rZeroParseSegments(obj);
00173 
00174   // skip back to the header
00175   obj->pos = obj->headerOffset;
00176 
00177   // and parse it!
00178   consoleOut("Header (%d bytes):\n", obj->headerLength);
00179   rZeroParseHeader(obj);
00180 
00181   return;
00182 }
00183 
00184 /* This function will parse through an rZero/rdoff header
00185  * and link it.  It currently works in one step because, it
00186  * seems, Nasm will always include segment definitions before
00187  * actually using them.  This doesn't have to be the case with
00188  * rdoff, however, and so if Nasm does sometimes include segment
00189  * uses before definitions, this code will break!  I can't see
00190  * it happening though... but something to keep in mind :)
00191  */
00192 void rZeroParseHeader(rZeroObj *obj) {
00193   char buf[129], type, segment, length, flags;
00194   unsigned char recordLength;
00195   long offset, labelLength;
00196   short refSegment;
00197   long headerLength;
00198 
00199   char isRelative;
00200   long symbolIndex;
00201   long relocation;
00202   char *segReloc;
00203 
00204   // loop through the length of the header
00205   headerLength = obj->headerLength;
00206   while (headerLength > 0) {
00207     // read the segment type
00208     type = readByte(obj);
00209 
00210     // if this is rdoff2, also read the record length
00211     if (obj->version >= 2) {
00212       recordLength = readByte(obj);
00213     }
00214 
00215     // which type have we got?
00216     switch(type) {
00217 
00218     case 1:             /* relocation record */
00219     case 6:             /* segment relocation */
00220       consoleOut("relocation (%d) :", type);
00221       segment    = readByte(obj);
00222       offset     = readLong(obj);
00223       length     = readByte(obj);
00224       refSegment = readShort(obj);
00225       consoleOut("seg: %x, offs %x, len %x, refSeg %x\n", segment, offset, length, refSegment);
00226 
00227       // if the referenced segment is less than three, we're
00228       // working with either the text, code or bss segment
00229       if(refSegment < 3) {
00230         relocation = (long)obj->mem + obj->segment[refSegment].offset;
00231       }
00232       // otherwise, it's a segment/symbol which must be imported
00233       else {
00234         // find the segment (as mentioned above, if this is defined in the
00235         // rdoff _after_ it's used (here), this code will break.  _Shouldn't_
00236         // ever happen, though...
00237         symbolIndex = rZeroFindSegment(refSegment, rZeroExports);
00238         //consoleOut("rs: %d, symbolIndex: %d\n", rs, symbolIndex);
00239         // record the location of this segment
00240         relocation = rZeroExports[symbolIndex].symbolLocation;
00241         //consoleOut("symbol location %x, actual %x\n", rel, consoleOut);
00242       }
00243 
00244       isRelative = ((segment & 64) == 64);
00245       segment &= 63;
00246 
00247       // if this relocation is defined as relative, make sure our
00248       // relocation is defined as relative to the start of the
00249       // proper segment
00250       if( isRelative )
00251         relocation -= (long)obj->mem + obj->segment[ segment ].offset;
00252 
00253 
00254       // calculate the address of the segment we're going to patch
00255       if(segment == 0) segReloc = (char *)obj->mem + obj->segment[0].offset;
00256       else if(segment == 1) segReloc = (char *)obj->mem + obj->segment[1].offset;
00257       else {
00258         // ??? BSS relocation ever needed?
00259         consoleOut("relocation not needed here!\n");
00260         continue;
00261       }
00262 
00263       // debugging info...
00264       consoleOut("obj->mem: %x, obj->mem + seg[0].off %x\n",
00265              obj->mem,
00266              obj->mem + obj->segment[ segment  ].offset);
00267       consoleOut("patching area: %x + %x with %x\n", (long)segReloc,
00268                                                  (long)offset,
00269                                                  (long)relocation);
00270 
00271       // and, finally, perform the patch, based on the relocation size
00272       switch(length) {
00273         case 1:
00274           segReloc[offset] += (char)relocation;
00275           break;
00276         case 2:
00277           *(short *)(segReloc + offset) += (short)relocation;
00278           break;
00279         case 4:
00280             //consoleOut("current mem: %x\n", *(long *)(seg + o));
00281             *(long *)(segReloc + offset) += (long)relocation;
00282           break;
00283         default:
00284           consoleOut("unknown relocation size!\n");
00285           break;
00286       }
00287 
00288       //consoleOut("  %s: location (%04x:%08x), length %d, "
00289       //     "referred seg %04x\n", t == 1 ? "relocation" : "seg relocation",
00290       //     (int)s, o,(int)l, rs);
00291       // perform some error checks...
00292       if(obj->version >= 2 && recordLength != 8)
00293         consoleOut("warning: reclen != 8\n");
00294       if(obj->version == 1)
00295         headerLength -= 9;
00296       if(obj->version == 1 && type == 6)
00297         consoleOut("warning: seg relocation not supported in RDOFF1\n");
00298       break;
00299 
00300     case 2:             /* import record */
00301     case 7:             /* import far symbol */
00302       consoleOut("import: ");
00303       // get the referenced segment
00304       refSegment  = readShort(obj);
00305       labelLength = 0;
00306 
00307       // read in the symbol name (different method, depending on
00308       // rdoff version!
00309       if (obj->version == 1) {  // zero delimited
00310         do {
00311           buf[labelLength] = readByte(obj);
00312         } while (buf[labelLength++]);
00313       } else {                  // record length delimited (65536 - 4, max?)
00314         for (;labelLength < recordLength - 2; labelLength++)
00315           buf[labelLength] = readByte(obj);
00316       }
00317       consoleOut("%s\n", buf);
00318 
00319       //consoleOut("  %simport: segment %04x = %s\n",t == 7 ? "far " : "",
00320       //     rs,buf);
00321       // update our length (ie, skip over this record)
00322       if (obj->version == 1) headerLength -= labelLength + 3;
00323 
00324       // error checking...
00325       if (obj->version == 1 && type == 7)
00326         consoleOut ("    warning: far import not supported in RDOFF1\n");
00327 
00328 
00329       // find the exported symbol, and assign it the segment number
00330       symbolIndex = rZeroFindSymbol(buf, rZeroExports);
00331       if(symbolIndex == -1) consoleOut("Cannot find!\n");
00332       rZeroExports[symbolIndex].segmentNum = refSegment;
00333       break;
00334 
00335     case 3:             /* export record */
00336       consoleOut("export: ");
00337       flags       = readByte(obj);
00338       segment     = readByte(obj);
00339       offset      = readLong(obj);
00340       labelLength = 0;
00341 
00342       // read in the symbol name (different method depending on rdoff version)
00343       if (obj->version == 1) {
00344         do {
00345           buf[labelLength] = readByte(obj);
00346         } while (buf[labelLength++]);
00347       } else {
00348         for (; labelLength < recordLength - 6; labelLength++)
00349           buf[labelLength] = readByte(obj);
00350       }
00351       consoleOut("%s\n", buf);
00352 
00353       /* what type of export?
00354       if (flags & SYM_GLOBAL)
00355         consoleOut("  export");
00356       else
00357         consoleOut("  global");
00358       if (flags & SYM_FUNCTION) consoleOut(" proc");
00359       if (flags & SYM_DATA) consoleOut(" data");
00360       consoleOut(": (%04x:%08x) = %s\n",(int)s,o,buf);
00361       */
00362       // adjust the length for rdoff1 objects
00363       if (obj->version == 1) headerLength -= labelLength + 6;
00364 
00365       // import this symbol into the kernel
00366       symbolIndex = rZeroFindSymbol(buf, rZeroImports);
00367       if(symbolIndex != -1)
00368         rZeroImports[symbolIndex].symbolLocation =
00369           (long)obj->mem + obj->segment[segment].offset + offset;
00370       else consoleOut("couldn't export\n");
00371 
00372       break;
00373 
00374     case 4:             /* DLL and Module records */
00375     case 8:
00376       labelLength = 0;
00377 
00378       // read the module/dll name
00379       if(obj->version == 1) {
00380         do {
00381           buf[labelLength] = readByte(obj);
00382         } while (buf[labelLength++]);
00383       } else {
00384         for (; labelLength < recordLength; labelLength++)
00385           buf[labelLength] = readByte(obj);
00386       }
00387 
00388       // simply print which module/dll is required (this should never
00389       // happen with an rZero module)
00390       if (type == 4) consoleOut("  requires dll: %s\n", buf);
00391       else consoleOut("  requires module: %s\n", buf);
00392 
00393       // adjust the length for rdoff1
00394       if (obj->version == 1) headerLength -= labelLength + 1;
00395       break;
00396     case 5:             /* BSS reservation */
00397       labelLength = readLong(obj);
00398 
00399       // do nothing for bss yet, just print it...
00400       consoleOut("  bss reservation: %8x bytes\n", labelLength);
00401 
00402       // adjust length for rdoff1 and check for errors
00403       if (obj->version == 1)  headerLength -= 5;
00404       if (obj->version > 1 && recordLength != 4)
00405         consoleOut("    warning: reclen != 4\n");
00406       break;
00407 
00408     case 9:             /* MultiBoot header record */
00409       consoleOut("  MultiBoot header included!\n");
00410       consoleOut("  Currently unsupported in rZero modules.\nSkipping over\n");
00411       // no need to adjust rdoff1 length, MB Headers only exist in rdoff2
00412       break;
00413     default:
00414       // print out the details of an unknown type...
00415       consoleOut("  unrecognised record (type %d", (int)type);
00416       if (obj->version > 1) {
00417         consoleOut(", length %d)\n",(int)recordLength);
00418         obj->pos += recordLength;
00419       }
00420 
00421       // adjust rdoff1 length
00422       if (obj->version == 1) headerLength --;
00423     }
00424     // adjust rdoff2+ length
00425     if (obj->version != 1) headerLength -= 2 + recordLength;
00426   }
00427 }
00428 
00429 /* Record all information from the segment info section of
00430  * the rdoff object
00431  */
00432 void rZeroParseSegments(rZeroObj *obj) {
00433   short segType;
00434   int i;
00435 
00436   // load in all the segment info
00437   obj->numSegments = 0;
00438   segType = readShort(obj);
00439   while(segType != 0 /*&& obj->numSegments < 6*/) {
00440     obj->segment[obj->numSegments].type = segType;
00441     obj->segment[obj->numSegments].number = readShort(obj);
00442     obj->segment[obj->numSegments].reserved = readShort(obj);
00443     obj->segment[obj->numSegments].length = readLong(obj);
00444     obj->segment[obj->numSegments].offset = obj->pos;
00445 
00446     // seek past this segment
00447     obj->pos += obj->segment[obj->numSegments].length;
00448     obj->numSegments++;
00449 
00450     segType = readShort(obj);
00451   }
00452 
00453   // and print out a summary...
00454   consoleOut("%d segments:\n", obj->numSegments);
00455   for(i = 0; i < obj->numSegments; i++) {
00456     consoleOut("Type %d, Number %d, Reserved %d, Length %d, Offset %d\n",
00457       obj->segment[i].type,
00458       obj->segment[i].number,
00459       obj->segment[i].reserved,
00460       obj->segment[i].length,
00461       obj->segment[i].offset);
00462   }
00463   return;
00464 }
00465 
00466 /* The following read a long, short or byte from memory, converting it
00467  * from little-endian format to the processor's native format (unnecessary
00468  * for intel processors, but... it's portable, so I left it in :)
00469  */
00470 long volatile readLong(rZeroObj *obj) {
00471   char *start = &obj->mem[obj->pos];
00472   long r = 0;
00473 
00474   /*
00475   r = start[3];
00476   r = (r << 8) + start[2];
00477   r = (r << 8) + start[1];
00478   r = (r << 8) + start[0];
00479   */
00480 
00481   r = *(long *)start;
00482 
00483   obj->pos += 4;
00484   return r;
00485 }
00486 
00487 short volatile readShort(rZeroObj *obj) {
00488   char *start = &obj->mem[obj->pos];
00489   short r = 0;
00490 
00491   //r = (start[1] << 8) + *start;
00492   r = *(short *)start;
00493 
00494   obj->pos += 2;
00495   return r;
00496 }
00497 
00498 char volatile readByte(rZeroObj *obj) {
00499   return obj->mem[obj->pos++];
00500 }

Generated on Sun Nov 21 18:26:11 2004 for ndk by doxygen 1.3.2