ウォンツテック

そでやまのーと

OS作成 - シェル編

Privilege Levelの異なる場合での割り込みを検知しようと思いIntel manualの以下のようなCPUの擬似コードを熟読していたけど、どうやらeflagsなどでの検知はできないみたい。期待としてはRETURN-TO-OUTER-PRIVILGE-LEVELのところでCPUがeflagsのなんらかのビットを立ててくれると嬉しかった。仕方ないんで検知は何らかのグローバル変数を使用することで検知するかstackのss,csの想定位置を検査してssが存在すればuserモード→kernelモードと検知して、switch_to時にespの値を偽装して無理やりiretする方式にしようかな。※気をつけないとespがswitchのたびに増加or減少するという危険があるけど。
※それにしてもIntel CPU使えネー(と言ってみるが実は検知出来る方法あるかもしれない(汁

PROTECTED-MODE-RETURN: (* PE=1, VM=0 in flags image *)
  IF return code segment selector is null THEN GP(0); FI;
  IF return code segment selector addrsses descriptor beyond descriptor table limit
    THEN GP(selector; FI;
  Read segment descriptor pointed to by the return code segment selector
  IF return code segment descriptor is not a code segment THEN #GP(selector); FI;
  IF return code segment selector RPL < CPL THEN #GP(selector); FI;
  IF return code segment descriptor is conforming
    AND return code segment DPL > return code segment selector RPL
    THEN #GP(selector); FI;
  IF return code segment descriptor is not present THEN #NP(selector); FI:
  IF return code segment selector RPL > CPL
    THEN GOTO RETURN-OUTER-PRIVILEGE-LEVEL;
    ELSE GOTO RETURN-TO-SAME-PRIVILEGE-LEVEL
  FI;
END;

RETURN-TO-SAME-PRIVILEGE-LEVEL: (* PE=1, VM=0 in flags image, RPL=CPL *)
  IF EIP is not within code segment limits THEN #GP(0); FI;
  EIP ← tempEIP;
  CS ← tempCS; (* segment descriptor information also loaded *)
  EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT) ← tempEFLAGS;
  IF OperandSize=32
    THEN
      EFLAGS(RF, AC, ID) ← tempEFLAGS;
  FI;
  IF CPL ≤ IOPL
    THEN
      EFLAGS(IF) ← tempEFLAGS;
  FI;
  IF CPL = 0
    THEN
      EFLAGS(IOPL) ← tempEFLAGS;
      IF OperandSize=32
        THEN EFLAGS(VM, VIF, VIP) ← tempEFLAGS;
      FI;
  FI;
END;

RETURN-TO-OUTER-PRIVILGE-LEVEL:
  IF OperandSize=32
    THEN
      IF top 8 bytes on stack are not within limits THEN #SS(0); FI;
      ELSE (* OperandSize=16 *)
        IF top 4 bytes on stack are not within limits THEN #SS(0); FI;
  FI;
Read return segment selector;
IF stack segment selector is null THEN #GP(0); FI;
IF return stack segment selector index is not within its descriptor table limits
  THEN #GP(SSselector); FI;
Read segment descriptor pointed to by return segment selector;
IF stack segment selector RPL ≠ RPL of the return code segment selector
  IF stack segment selector RPL ≠ RPL of the return code segment selector
  OR the stack segment descriptor does not indicate a a writable data segment;
  OR stack segment DPL ≠ RPL of the return code segment selector
    THEN #GP(SS selector);
  FI;
  IF stack segment is not present THEN #SS(SS selector); FI;
IF tempEIP is not within code segment limit THEN #GP(0); FI;
EIP ← tempEIP;
CS ← tempCS;
EFLAGS (CF, PF, AF, ZF, SF, TF, DF, OF, NT) ← tempEFLAGS;
IF OperandSize=32
  THEN
    EFLAGS(RF, AC, ID) ← tempEFLAGS;
FI;
IF CPL ≤ IOPL
  THEN
    EFLAGS(IF) ← tempEFLAGS;
FI;
IF CPL = 0
  THEN
    EFLAGS(IOPL) ← tempEFLAGS;
    IF OperandSize=32
      THEN EFLAGS(VM, VIF, VIP) ← tempEFLAGS;
    FI;
FI;
CPL ← RPL of the return code segment selector;
FOR each of segment register (ES, FS, GS, and DS)
  DO;
    IF segment register points to data or non-conforming code segment
    AND CPL > segment descriptor DPL (* stored in hidden part of segment
    register *)
      THEN (* segment register invalid *)
        SegmentSelector ← 0; (* null segment selector *)
    FI;
  OD;
END: