The manual I use (http://www.cs.nyu.edu/~mwalfish/classes/14fa/ … i386/s06_03.htm ) only mentions a few (examples) of the type checking performed during loading segments(e.g. using a MOV instruction) and during execution of memory accesses(using the loaded segment descriptor to resolve or fault memory accesses). Anyone has the complete list of what's done at what point? What's checked(of the type descriptor field) during load-time(MOV Segreg,XX) and what's used during normal execution(instruction fetches and normal memory accesses(e.g. MOV AX,[0000h]))? The manuals I've found isn't entirely clear on that, for some reason, even though that'll have a big impact on running software(e.g. fauling on a segment register load itself vs faulting on an instruction using a segment register that's loaded).
Something I've found out: both manuals have the same error in bit 3 of the type field(left of the E or C bits): the bits are set to 0 in both images. It should have 0 for data and 1 for code? So 0EW for data and 1CR for executable segments?
Pages 109-110 give some examples on when the type field is checked against memory or loading access, but don't say any more about other cases (it just gives examples, not the complete truth)?
This is what I currently do on every memory access by the CPU(using the already loaded descriptors in the caches):
1byte CPU_MMU_checkrights_cause = 0; //What cause? 2//Used by the CPU(VERR/VERW)&MMU I/O! forreading=0: Write, 1=Read normal, 3=Read opcode 3byte CPU_MMU_checkrights(int segment, word segmentval, uint_32 offset, int forreading, SEGMENT_DESCRIPTOR *descriptor, byte addrtest) 4{ 5 //byte isconforming; 6 7 if (getcpumode() == CPU_MODE_PROTECTED) //Not real mode? Check rights for zero descriptors! 8 { 9 if ((segment != CPU_SEGMENT_CS) && (segment != CPU_SEGMENT_SS) && (!getDescriptorIndex(segmentval)) && ((segmentval&4)==0)) //Accessing memory with DS,ES,FS or GS, when they contain a NULL selector? 10 { 11 CPU_MMU_checkrights_cause = 1; //What cause? 12 return 1; //Error! 13 } 14 } 15 16 //First: type checking! 17 18 if (GENERALSEGMENTPTR_P(descriptor)==0) //Not present(invalid in the cache)? 19 { 20 CPU_MMU_checkrights_cause = 2; //What cause? 21 if (segment==CPU_SEGMENT_SS) //Stack fault? 22 { 23 return 3; //Stack fault! 24 } 25 else 26 { 27 return 2; //#NP! 28 } 29 } 30 31 if (getcpumode()==CPU_MODE_PROTECTED) //Not real mode? Check rights! 32 { 33 switch (((descriptor->AccessRights>>1)&0x7)) //What type of descriptor? 34 { 35 case 0: //Data, read-only 36 case 2: //Data(expand down), read-only 37 case 5: //Code, execute/read 38 case 7: //Code, execute/read, conforming 39 if (forreading==0) //Writing? 40 { 41 CPU_MMU_checkrights_cause = 3; //What cause? 42 return 1; //Error! 43 } 44 break; //Allow! 45 case 1: //Data, read/write 46 case 3: //Data(expand down), read/write 47 break; //Allow! 48 case 4: //Code, execute-only 49 case 6: //Code, execute-only, conforming 50 if (forreading!=3) //Writing or reading normally? 51 { 52 CPU_MMU_checkrights_cause = 3; //What cause? 53 return 1; //Error! 54 } 55 break; //Allow! 56 } 57 } 58 59 //Next: limit checking! 60
…Show last 61 lines
61 uint_32 limit; //The limit! 62 byte isvalid; 63 64 limit = ((SEGDESCPTR_NONCALLGATE_LIMIT_HIGH(descriptor) << 16) | descriptor->limit_low); //Base limit! 65 66 if ((SEGDESCPTR_NONCALLGATE_G(descriptor)&CPU[activeCPU].G_Mask) && (EMULATED_CPU>=CPU_80386)) //Granularity? 67 { 68 limit = ((limit << 12) | 0xFFF); //4KB for a limit of 4GB, fill lower 12 bits with 1! 69 } 70 71 if (addrtest) //Execute address test? 72 { 73 isvalid = (offset<=limit); //Valid address range! 74 if ((GENERALSEGMENTPTR_S(descriptor) == 1) && (EXECSEGMENTPTR_ISEXEC(descriptor) == 0)) //Data segment? 75 { 76 if (DATASEGMENTPTR_E(descriptor)) //Expand-down data segment? 77 { 78 isvalid = !isvalid; //Reversed valid! 79 if (SEGDESCPTR_NONCALLGATE_G(descriptor) == 0) //Small granularity? 80 { 81 isvalid = (isvalid && (offset <= 0x10000)); //Limit to 64K! 82 } 83 } 84 } 85 if (!isvalid) //Not valid? 86 { 87 CPU_MMU_checkrights_cause = 6; //What cause? 88 if (segment==CPU_SEGMENT_SS) //Stack fault? 89 { 90 return 3; //Error! 91 } 92 else //Normal #GP? 93 { 94 return 1; //Error! 95 } 96 } 97 } 98 99 //Third: privilege levels & Restrict access to data! 100 101 /* 102 switch (descriptor->AccessRights) //What type? 103 { 104 case AVL_CODE_EXECUTEONLY_CONFORMING: 105 case AVL_CODE_EXECUTEONLY_CONFORMING_ACCESSED: 106 case AVL_CODE_EXECUTE_READONLY_CONFORMING: 107 case AVL_CODE_EXECUTE_READONLY_CONFORMING_ACCESSED: //Conforming? 108 isconforming = 1; 109 break; 110 default: //Not conforming? 111 isconforming = 0; 112 break; 113 } 114 */ 115 116 //Don't perform rights checks: This is done when loading the segment register only! 117 118 //Fifth: Accessing data in Code segments? 119 120 return 0; //OK! 121}
And this is what's done (type checking) on loading the segment registers themselves with new values(loading the caches):
1 //Handle invalid types now! 2 if ((segment==CPU_SEGMENT_CS) && 3 (getLoadedTYPE(&LOADEDDESCRIPTOR)!=1) //Data or System in CS (non-exec)? 4 ) 5 { 6 THROWDESCGP(segmentval,0,(segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error! 7 return NULL; //Not present: invalid descriptor type loaded! 8 } 9 else if ((getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && (segment!=CPU_SEGMENT_CS) && (EXECSEGMENT_R(LOADEDDESCRIPTOR.desc)==0)) //Executable non-readable in non-executable segment? 10 { 11 THROWDESCGP(segmentval,0,(segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error! 12 return NULL; //Not present: invalid descriptor type loaded! 13 } 14 else if (getLoadedTYPE(&LOADEDDESCRIPTOR)==0) //Data descriptor loaded? 15 { 16 if ((segment!=CPU_SEGMENT_DS) && (segment!=CPU_SEGMENT_ES) && (segment!=CPU_SEGMENT_FS) && (segment!=CPU_SEGMENT_GS) && (segment!=CPU_SEGMENT_SS)) //Data descriptor in invalid type? 17 { 18 THROWDESCGP(segmentval,0,(segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error! 19 return NULL; //Not present: invalid descriptor type loaded! 20 } 21 if ((DATASEGMENT_W(LOADEDDESCRIPTOR.desc)==0) && (segment==CPU_SEGMENT_SS)) //Non-writable SS segment? 22 { 23 THROWDESCGP(segmentval,0,(segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error! 24 return NULL; //Not present: invalid descriptor type loaded! 25 } 26 } 27 else if (getLoadedTYPE(&LOADEDDESCRIPTOR)==2) //System descriptor loaded? 28 { 29 if ((segment==CPU_SEGMENT_DS) || (segment==CPU_SEGMENT_ES) || (segment==CPU_SEGMENT_FS) || (segment==CPU_SEGMENT_GS) || (segment==CPU_SEGMENT_SS)) //System descriptor in invalid register? 30 { 31 THROWDESCGP(segmentval,0,(segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error! 32 return NULL; //Not present: invalid descriptor type loaded! 33 } 34 }
After that it updates the cache with the new data and performs any post-loading actions(copying stack, loading other registers required for a privilege switch etc.).
Checking for data segments loaded into a code segment can't be done in real (or virtual 8086 mode), due to problems with compatibility. Since CS is loaded with access rights byte 0x93, it would cause all code fetches to be invalid when checked at runtime(since it's actually a data descriptor instead of a code descriptor, but it's set up that way by the CPU itself when loading CS with any segment (selector)).
Checking CS for executable type gives problems when entering protected mode (directly after MOV CR0,XX, it would crash because CS holds selector 0x93, which is a data segment. This would result in a triple fault in most cases, due to unavailable or not completely initialized tables in memory, as well as the CS still needing to be loaded(containing a real-mode selector still, instead of it's protected mode version).
It is 0 for data and 1 for code. Figure 6-1 in the link you gave has the correct bits for both data and executable segments. Do you mean a different image?
The cs.nyu.edu link tells me as I've implemented it. The pdf file linked to by vladstamate instead tells 10CRA instead of the (probably correct) 11CRA fields? They're both supposed to be the same manual. Perhaps the html version is a newer revision?