//---------------------------------------------------------------- // newapp86.cpp // // This utility creates 'boilerplate' source-text for a new // application program in 'as86' assembly language which is // designed to be loaded (from floppy diskette track #0) by // our 'trackldr.s' boot-loader. // // usage: $ newapp86 // // programmer: ALLAN CRUSE // written on: 19 FEB 2004 // revised on: 26 APR 2004 -- added additional boilerplate // revised on: 27 MAY 2005 -- added stack-display in isrGPF //---------------------------------------------------------------- #include // for fprintf(), fopen(), etc #include // for strncpy(), strncat() #include // for time(), localtime() char authorname[] = "ALLAN CRUSE"; // substitute YOUR name char monthlist[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; int main( int argc, char *argv[] ) { // check for module-name as command-line argument if ( argc == 1 ) { fprintf( stderr, "Must specify module-name\n" ); return -1; } // prepare program name char appname[33] = ""; strncpy( appname, argv[1], 28 ); // prepare code-file name char srcname[33] = ""; strncpy( srcname, argv[1], 28 ); strncat( srcname, ".s", 22 ); // announce this program's purpose printf( "\nCreating skeleton for program " ); printf( "named \'%s\' \n", srcname ); // insure source-file doesn't already exist FILE *fp = fopen( srcname, "rb" ); if ( fp != NULL ) { fclose( fp ); fprintf( stderr, "File \'%s\' already exists\n", srcname ); return -1; } // create the new source-file fp = fopen( srcname, "wb" ); if ( fp == NULL ) { fprintf( stderr, "Cannot create source-file\n" ); return -1; } // obtain today's date (in DD MMM YYYY format) time_t now = time( (time_t *)NULL ); struct tm *t = localtime( &now ); char month[4] = ""; strncpy( month, monthlist+3*t->tm_mon, 3 ); month[3] = '\0'; char when[16] = ""; sprintf( when, "%02d %3s %04d", t->tm_mday, month, 1900+t->tm_year ); char border[68] = ""; memset( border, '-', 65 ); fprintf( fp, ";//%s\n", border+2 ); fprintf( fp, ";//\t%s\n", srcname ); fprintf( fp, ";//\n" ); fprintf( fp, ";//\n" ); fprintf( fp, ";//\n" ); fprintf( fp, ";//\t assemble with: " ); fprintf( fp, "$ as86 %s -b %s.b \n", srcname, appname ); fprintf( fp, ";//\t install using: " ); fprintf( fp, "$ dd if=%s.b of=/dev/fd0 seek=1 \n", appname ); fprintf( fp, ";//\n" ); fprintf( fp, ";//\tNOTE: This code begins executing " ); fprintf( fp, "with CS:IP = 1000:0002. \n" ); fprintf( fp, ";//\n" ); fprintf( fp, ";//\tprogrammer: %s\n", authorname ); fprintf( fp, ";//\tdate begun: %s\n", when ); fprintf( fp, ";//%s\n", border+2 ); fprintf( fp, "\n" ); fprintf( fp, "\n\t.SECT\t.TEXT\n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "\t.WORD\t0xABCD\t\t\t; programming signature \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "main:" ); fprintf( fp, "\tmov\tax, cs\t\t\t" ); fprintf( fp, "; address this segment \n" ); fprintf( fp, "\tmov\tds, ax\t\t\t" ); fprintf( fp, "; with DS register \n" ); fprintf( fp, "\tpop\tdword return_address\t" ); fprintf( fp, "; store return-address \n" ); fprintf( fp, "\tmov\tss, ax\t\t\t" ); fprintf( fp, "; adjust SS register \n" ); fprintf( fp, "\tlea\tesp, tos0\t\t" ); fprintf( fp, "; and set new stacktop \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tcall\tinitialize_os_tables \n" ); fprintf( fp, "\tcall\tenter_protected_mode \n" ); fprintf( fp, "\tcall\texecute_program_demo \n" ); fprintf( fp, "\tcall\tleave_protected_mode \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tpush\tdword return_address\t" ); fprintf( fp, "; recover our exit-address \n" ); fprintf( fp, "\tretf\t\t\t\t; exit to program launcher \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "return_address:\t.LONG\t0\t\t" ); fprintf( fp, "; to store exit-address \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "; EQUATES \n" ); fprintf( fp, "realCS\tEQU\t0x1000\t\t\t; segment-address of code \n" ); fprintf( fp, "limGDT\tEQU\t0x003F\t\t\t; allocates 8 descriptors \n" ); fprintf( fp, "sel_es\tEQU\t0x0008\t\t\t; vram-segment selector \n" ); fprintf( fp, "sel_cs\tEQU\t0x0010\t\t\t; code-segment selector \n" ); fprintf( fp, "sel_ss\tEQU\t0x0018\t\t\t; data-segment selector \n" ); fprintf( fp, "sel_fs\tEQU\t0x0020\t\t\t; flat-segment selector \n" ); fprintf( fp, "sel_CS\tEQU\t0x0028\t\t\t; code-segment selector \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "\t.ALIGN\t8 \n" ); fprintf( fp, "theGDT:" ); fprintf( fp, "\t.WORD\t0x0000, 0x0000, 0x0000, 0x0000" ); fprintf( fp, "\t; null descriptor \n" ); fprintf( fp, "\t.WORD\t0x7FFF, 0x8000, 0x920B, 0x0000" ); fprintf( fp, "\t; vram descriptor \n" ); fprintf( fp, "\t.WORD\t0xFFFF, 0x0000, 0x9A01, 0x0000" ); fprintf( fp, "\t; code descriptor \n" ); fprintf( fp, "\t.WORD\t0xFFFF, 0x0000, 0x9201, 0x0000" ); fprintf( fp, "\t; data descriptor \n" ); fprintf( fp, "\t.WORD\t0xFFFF, 0x0000, 0x9200, 0x008F" ); fprintf( fp, "\t; flat descriptor \n" ); fprintf( fp, "\t.WORD\t0xFFFF, 0x0000, 0x9A01, 0x0040" ); fprintf( fp, "\t; code descriptor \n" ); fprintf( fp, "\t.WORD\t0x0000, 0x0000, 0x0000, 0x0000" ); fprintf( fp, "\t; null descriptor \n" ); fprintf( fp, "\t.WORD\t0x0000, 0x0000, 0x0000, 0x0000" ); fprintf( fp, "\t; null descriptor \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "theIDT:\t.SPACE\t2048\t" ); fprintf( fp, "\t; enough for 256 gate-descriptors \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, ";%s\n", border ); fprintf( fp, "enter_protected_mode: \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tcli\t\t\t" ); fprintf( fp, "\t; no device interrupts \n" ); fprintf( fp, "\tmov\teax, cr0\t" ); fprintf( fp, "\t; get machine status \n" ); fprintf( fp, "\tbts\teax, #0\t\t" ); fprintf( fp, "\t; set PE-bit to 1 \n" ); fprintf( fp, "\tmov\tcr0, eax\t" ); fprintf( fp, "\t; enable protection \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tpush\t#0x0001\t\t" ); fprintf( fp, "\t; push base-address hiword \n" ); fprintf( fp, "\tpush\t#theGDT\t\t" ); fprintf( fp, "\t; push base-address loword \n" ); fprintf( fp, "\tpush\t#limGDT\t\t" ); fprintf( fp, "\t; push GDT's segment-limit \n" ); fprintf( fp, "\tlgdt\t[esp]\t\t" ); fprintf( fp, "\t; load GDTR register-image \n" ); fprintf( fp, "\tadd\tsp, #6\t\t" ); fprintf( fp, "\t; discard three stackwords \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tpush\t#0x0001\t\t" ); fprintf( fp, "\t; push base-address hiword \n" ); fprintf( fp, "\tpush\t#theIDT\t\t" ); fprintf( fp, "\t; push base-address loword \n" ); fprintf( fp, "\tpush\t#0x07FF\t\t" ); fprintf( fp, "\t; push IDT's segment-limit \n" ); fprintf( fp, "\tlidt\t[esp]\t\t" ); fprintf( fp, "\t; load IDTR register-image \n" ); fprintf( fp, "\tadd\tsp, #6\t\t" ); fprintf( fp, "\t; discard three stackwords \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tjmpf\t#pm, #sel_cs\t" ); fprintf( fp, "\t; reload register CS \n" ); fprintf( fp, "pm:" ); fprintf( fp, "\tmov\tax, #sel_ss\t\t" ); fprintf( fp, "\n" ); fprintf( fp, "\tmov\tss, ax\t\t" ); fprintf( fp, "\t; reload register SS \n" ); fprintf( fp, "\tmov\tds, ax\t\t" ); fprintf( fp, "\t; reload register DS \n" ); fprintf( fp, "\n" ); fprintf( fp, "\txor\tax, ax\t\t" ); fprintf( fp, "\t; use \"null\" selector \n" ); fprintf( fp, "\tmov\tes, ax\t\t" ); fprintf( fp, "\t; to purge invalid ES \n" ); fprintf( fp, "\tmov\tfs, ax\t\t" ); fprintf( fp, "\t; to purge invalid FS \n" ); fprintf( fp, "\tmov\tgs, ax\t\t" ); fprintf( fp, "\t; to purge invalid GS \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tret\t\t\t" ); fprintf( fp, "\t; back to main routine \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "leave_protected_mode: \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tmov\tax, ss\t\t" ); fprintf( fp, "\t; address 64KB r/w segment \n" ); fprintf( fp, "\tmov\tds, ax\t\t" ); fprintf( fp, "\t; using DS register \n" ); fprintf( fp, "\tmov\tes, ax\t\t" ); fprintf( fp, "\t; and ES register \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tmov\teax, cr0\t" ); fprintf( fp, "\t; get machine status \n" ); fprintf( fp, "\tbtr\teax, #0\t\t" ); fprintf( fp, "\t; reset PE-bit to 0 \n" ); fprintf( fp, "\tmov\tcr0, eax\t" ); fprintf( fp, "\t; disable protection \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tpush\t#0x0000\t\t" ); fprintf( fp, "\t; push base-address hiword \n" ); fprintf( fp, "\tpush\t#0x0000\t\t" ); fprintf( fp, "\t; push base-address loword \n" ); fprintf( fp, "\tpush\t#0x03FF\t\t" ); fprintf( fp, "\t; push IDT's segment-limit \n" ); fprintf( fp, "\tlidt\t[esp]\t\t" ); fprintf( fp, "\t; load IDTR register-image \n" ); fprintf( fp, "\tadd\tsp, #6\t\t" ); fprintf( fp, "\t; discard three stackwords \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tjmpf\t#rm, #realCS\t" ); fprintf( fp, "\t; reload register CS \n" ); fprintf( fp, "rm:" ); fprintf( fp, "\tmov\tax, cs\t" ); fprintf( fp, "\n" ); fprintf( fp, "\tmov\tss, ax\t\t" ); fprintf( fp, "\t; reload register SS \n" ); fprintf( fp, "\tmov\tds, ax\t\t" ); fprintf( fp, "\t; reload register DS \n" ); fprintf( fp, "\tsti\t\t\t" ); fprintf( fp, "\t; interrupts allowed \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tret\t\t\t" ); fprintf( fp, "\t; back to main routine \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, ";%s\n", border ); fprintf( fp, "initialize_os_tables: \n" ); fprintf( fp, "\n" ); fprintf( fp, "\t; initialize IDT descriptor for gate 0x0D \n" ); fprintf( fp, "\tmov\tedi, #0x0D\t" ); fprintf( fp, "\t; ID-number for the gate \n" ); fprintf( fp, "\tlea\tdi, theIDT[edi*8]" ); fprintf( fp, "\t; gate's offset-address \n" ); fprintf( fp, "\tmov\t0[di], #isrGPF\t" ); fprintf( fp, "\t; entry-point's loword \n" ); fprintf( fp, "\tmov\t2[di], #sel_CS\t" ); fprintf( fp, "\t; code-segment selector \n" ); fprintf( fp, "\tmov\t4[di], #0x8E00\t" ); fprintf( fp, "\t; 386 interrupt-gate \n" ); fprintf( fp, "\tmov\t6[di], #0x0000\t" ); fprintf( fp, "\t; entry-point's hiword \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tret\t\t\t" ); fprintf( fp, "\t; back to main routine \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "tossave: .WORD\t0, 0, 0 \t" ); fprintf( fp, "\t; stores 48-bit pointer \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "execute_program_demo: \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tmov\ttossave+0, esp \t" ); fprintf( fp, "\t; preserve 32-bit offset \n" ); fprintf( fp, "\tmov\ttossave+4, ss \t" ); fprintf( fp, "\t; plus 16-bit selector \n" ); fprintf( fp, "\n" ); fprintf( fp, "\t; your application-specific demo-routines " ); fprintf( fp, "would go here \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tint\t0xFF \t" ); fprintf( fp, ";<-- this instruction is only for testing \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "finish_up_main_thread: \n" ); fprintf( fp, "\tCSEG \t\t\t" ); fprintf( fp, "\t; address this segment \n" ); fprintf( fp, "\tlss\tesp, tossave \t" ); fprintf( fp, "\t; to reload SS and ESP \n" ); fprintf( fp, "\tret\t\t\t" ); fprintf( fp, "\t; back to main routine \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "\tUSE32" ); fprintf( fp, "\t; assemble instructions for a 32-bit code-segment \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "eax2hex: ; " ); fprintf( fp, "converts EAX to hexadecimal digit-string at ES:EDI \n" ); fprintf( fp, "\tpushad \n" ); fprintf( fp, "\tmov\tedx, eax \t" ); fprintf( fp, "\t; transfer datum to EDX \n" ); fprintf( fp, "\tmov\tecx, #8 \t" ); fprintf( fp, "\t; setup count of nybbles \n" ); fprintf( fp, "nxnyb:\trol\tedx, #4 \t" ); fprintf( fp, "\t; next nybble into DL \n" ); fprintf( fp, "\tmov\tal, dl \t\t" ); fprintf( fp, "\t; copy nybble into AL \n" ); fprintf( fp, "\tand\tal, #0x0F \t" ); fprintf( fp, "\t; isolate nybble's bits \n" ); fprintf( fp, "\tcmp\tal, #10 \t" ); fprintf( fp, "\t; -- Lopez algorithm -- \n" ); fprintf( fp, "\tsbb\tal, #0x69 \t" ); fprintf( fp, "\t; -- converts binary -- \n" ); fprintf( fp, "\tdas \t\t\t" ); fprintf( fp, "\t; -- to hex numeral -- \n" ); fprintf( fp, "\tmov\t[edi], al \t" ); fprintf( fp, "\t; store numeral in buffer\n" ); fprintf( fp, "\tinc\tedi \t\t" ); fprintf( fp, "\t; advance buffer pointer \n" ); fprintf( fp, "\tloop\tnxnyb \t\t" ); fprintf( fp, "\t; process other nybbles \n" ); fprintf( fp, "\tpopad \n" ); fprintf( fp, "\tret \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "place:\t.LONG\t3800 \n" ); fprintf( fp, "names:\t.ASCII\t\" ES DS\" \n" ); fprintf( fp, "\t.ASCII\t\" EDI ESI EBP ESP EBX EDX ECX EAX\" \n" ); fprintf( fp, "\t.ASCII\t\" err EIP CS EFL\" \n" ); fprintf( fp, "nitem:\t.LONG\t(* - names)/4 \n" ); fprintf( fp, "color:\t.BYTE\t0x70 \n" ); fprintf( fp, "buffer:\t.ASCII\t\"nnnn=xxxxxxxx \" \n" ); fprintf( fp, "buflen:\t.LONG\t* - buffer \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, ";%s\n", border ); fprintf( fp, "isrGPF:" ); fprintf( fp, "\t; fault-handler for General Protection Exceptions \n" ); fprintf( fp, "\tpushad \t\t\t" ); fprintf( fp, "\t; save registers on stack \n" ); fprintf( fp, "\tmov\tebp, esp \t" ); fprintf( fp, "\t; setup pointer for stack \n" ); fprintf( fp, "\t \n" ); fprintf( fp, "\tpush\tdword #0 \t" ); fprintf( fp, "\t; make space on stack \n" ); fprintf( fp, "\tmov\t[esp], ds \t" ); fprintf( fp, "\t; for saving DS value \n" ); fprintf( fp, "\tpush\tdword #0 \t" ); fprintf( fp, "\t; make space on stack \n" ); fprintf( fp, "\tmov\t[esp], es \t" ); fprintf( fp, "\t; for saving ES value \n" ); fprintf( fp, "\t \n" ); fprintf( fp, "\tmov\tax, #sel_ss \t" ); fprintf( fp, "\t; address program data \n" ); fprintf( fp, "\tmov\tds, ax \t\t" ); fprintf( fp, "\t; with DS register \n" ); fprintf( fp, "\tmov\tax, #sel_es \t" ); fprintf( fp, "\t; address video memory \n" ); fprintf( fp, "\tmov\tes, ax \t\t" ); fprintf( fp, "\t; with ES register \n" ); fprintf( fp, "\t \n" ); fprintf( fp, "\t; display items on the kernel stack \n" ); fprintf( fp, "\txor\tebx, ebx \t" ); fprintf( fp, "\t; initial item-number\n" ); fprintf( fp, "nxitm:\t; setup next item-label in buffer \n" ); fprintf( fp, "\tmov\teax, names[ebx*4] " ); fprintf( fp, "\t; fetch item's label \n" ); fprintf( fp, "\tmov\t[buffer], eax \t" ); fprintf( fp, "\t; store item's label \n" ); fprintf( fp, "\t; setup next item-value in buffer \n" ); fprintf( fp, "\tlea\tedi, [buffer+5] " ); fprintf( fp, "\t; setup field pointer \n" ); fprintf( fp, "\tmov\teax, [ebp + ebx*4 - 8] " ); fprintf( fp, "\t; fetch item's value \n" ); fprintf( fp, "\tcall\teax2hex \t" ); fprintf( fp, "\t; convert value to hex \n" ); fprintf( fp, "\t; transfer buffer-contents to the screen \n" ); fprintf( fp, "\tmov\tedi, [place] \t" ); fprintf( fp, "\t; point ES:EDI to screen \n" ); fprintf( fp, "\timul\teax, ebx, #160 \t" ); fprintf( fp, "\t; compute width of rows \n" ); fprintf( fp, "\tsub\tedi, eax \t" ); fprintf( fp, "\t; and adjust pointer \n" ); fprintf( fp, "\tlea\tesi, [buffer] \t" ); fprintf( fp, "\t; point DS:ESI to string \n" ); fprintf( fp, "\tcld \t\t\t" ); fprintf( fp, "\t; do forward processing \n" ); fprintf( fp, "\tmov\tah, [color] \t" ); fprintf( fp, "\t; setup attribute byte \n" ); fprintf( fp, "\tmov\tecx, [buflen] \t" ); fprintf( fp, "\t; setup string's length \n" ); fprintf( fp, "nxchr:\tlodsb \t\t\t" ); fprintf( fp, "\t; fetch next character \n" ); fprintf( fp, "\tstosw \t\t\t" ); fprintf( fp, "\t; store char and color \n" ); fprintf( fp, "\tloop\tnxchr \t\t" ); fprintf( fp, "\t; again if other chars\n" ); fprintf( fp, "\t \n" ); fprintf( fp, "\tinc\tebx \t\t" ); fprintf( fp, "\t; increment item-number \n" ); fprintf( fp, "\tcmp\tebx, [nitem] \t" ); fprintf( fp, "\t; final item displayed? \n" ); fprintf( fp, "\tjb\tnxitm \t\t" ); fprintf( fp, "\t; no, show another item \n" ); fprintf( fp, "\n" ); fprintf( fp, "\tjmpf\t#finish_up_main_thread, #sel_cs" ); fprintf( fp, "\t; to 16-bit code \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "\t.ALIGN\t16\t\t\t; alignment at paragraph \n" ); fprintf( fp, "\t.SPACE\t512\t\t\t; reserved for stack use \n" ); fprintf( fp, "tos0:\t\t\t\t\t; label fop top-of-stack \n" ); fprintf( fp, ";%s\n", border ); fprintf( fp, "\tEND\n" ); printf( "\n" ); }