2012-02-21 6 views

답변

2

짧은 대답은 : 인터럽트가 높은 privelege 수준에

경우, SS와 ESP는 각각 4 바이트를 소모 스택에 푸시됩니다. 같은 단계에서이 단계는 건너 뜁니다.

그런 다음 EFLAGS, CS 및 EIP가 각각 4 바이트를 사용하여 스택으로 푸시됩니다. 따라서 스택에 20 바이트가있을 가능성이 큽니다.

작업 게이트, 결함, 문맥 x86/x64 Instruction Set Reference에서, 의사 코드에 너무 오래 답을 등 전환을위한 많은 complicted execptions과 규칙이 있습니다

(* The following operational description applies not only to the INT n and INTO instructions, but also to external interrupts, nonmaskable interrupts (NMIs), and exceptions. Some of these events push onto the stack an error code. *) 
(* The operational description specifies numerous checks whose failure may result in delivery of a nested exception. In these cases, the original event is not delivered. *) 
(* The operational description specifies the error code delivered by any nested exception. In some cases, the error code is specified with a pseudofunction error_code(num, idt, ext), where idt and ext are bit values. The pseudofunction produces an error code as follows: *) 
(* (1) if idt is 0, the error code is (num & FCH) | ext; *) 
(* (2) if idt is 1, the error code is (num << 3) | 2 | ext. *) 
(* In many cases, the pseudofunction error_code is invoked with a pseudovariable EXT. The value of EXT depends on the nature of the event whose delivery encountered a nested exception: if that event is a software interrupt, EXT is 0;otherwise, EXT is 1. *) 
IF PE = 0 
    GOTO REAL-ADDRESS-MODE; 
ELSE 
    IF PE = 1 
     IF (VM = 1 and IOPL < 3 AND INT n) 
      #GP(0); (* Bit 0 of error code is 0 because INT n *) 
     ELSE 
      (* Protected mode, IA-32e mode, or virtual-8086 mode interrupt *) 
      IF (IA32_EFER.LMA = 0) 
       (* Protected mode, or virtual-8086 mode interrupt *) 
       GOTO PROTECTED-MODE; 
      ELSE 
       (* IA-32e mode interrupt *) 
       GOTO IA-32e-MODE; 
      FI; 
     FI; 
    FI; 
FI; 
REAL-ADDRESS-MODE: 
    IF ((vector_number << 2) + 3) is not within IDT limit 
     #GP; 
    FI; 
    IF stack not large enough for a 6-byte return information 
     #SS; 
    FI; 
    Push (EFLAGS[15:0]); 
    IF = 0; (* Clear interrupt flag *) 
    TF = 0; (* Clear trap flag *) 
    AC = 0; (* Clear AC flag *) 
    Push(CS); 
    Push(IP); 
    (* No error codes are pushed in real-address mode *) 
    CS = IDT(Descriptor (vector_number << 2), selector)); 
    EIP = IDT(Descriptor (vector_number << 2), offset)); (* 16 bit offset AND 0000FFFFH *) 
END; 
PROTECTED-MODE: 
    IF ((vector_number << 3) + 7) is not within IDT limits or selected IDT descriptor is not an interrupt-, trap-, or task-gate type 
     #GP(error_code(vector_number, 1, EXT)); 
    FI; 
    (* idt operand to error_code set because vector is used *) 
    IF software interrupt (* Generated by INT n, INT3, or INTO *) 
     IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *) 
      #GP(error_code(vector_number, 1, 0)); 
     FI; 
     (* idt operand to error_code set because vector is used *) 
     (* ext operand to error_code is 0 because INT n, INT3, or INTO *) 
    FI; 
    IF gate not present 
     #NP(error_code(vector_number, 1, EXT)); 
    FI; 
    (* idt operand to error_code set because vector is used *) 
    IF task gate (* Specified in the selected interrupt table descriptor *) 
     GOTO TASK-GATE; 
    ELSE 
     GOTO TRAP-OR-INTERRUPT-GATE; (* PE = 1, trap/interrupt gate *) 
    FI; 
END; 
IA-32e-MODE: 
    IF INTO and CS.L = 1 (64-bit mode) 
     #UD; 
    FI; 
    IF ((vector_number << 4) + 15) is not in IDT limits or selected IDT descriptor is not an interrupt-, or trap-gate type 
     #GP(error_code(vector_number, 1, EXT)); 
     (* idt operand to error_code set because vector is used *) 
    FI; 
    IF software interrupt (* Generated by INT n, INT 3, or INTO *) 
     IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *) 
      #GP(error_code(vector_number, 1, 0)); (* idt operand to error_code set because vector is used *) 
      (* ext operand to error_code is 0 because INT n, INT3, or INTO *) 
     FI; 
    FI; 
    IF gate not present 
     #NP(error_code(vector_number, 1, EXT)); 
     (* idt operand to error_code set because vector is used *) 
    FI; 
    GOTO TRAP-OR-INTERRUPT-GATE; (* Trap/interrupt gate *) 
END; 
TASK-GATE: (* PE = 1, task gate *) 
    Read TSS selector in task gate (IDT descriptor); 
    IF local/global bit is set to local or index not within GDT limits 
     #GP(error_code(TSS selector, 0, EXT)); 
    FI; (* idt operand to error_code is 0 because selector is used *) 
    Access TSS descriptor in GDT; 
    IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001) 
     #GP(TSS selector, 0, EXT)); 
    FI; (* idt operand to error_code is 0 because selector is used *) 
    IF TSS not present 
     #NP(TSS selector, 0, EXT)); 
    FI; (* idt operand to error_code is 0 because selector is used *) 
    SWITCH-TASKS (with nesting) to TSS; 
    IF interrupt caused by fault with error code 
     IF stack limit does not allow push of error code 
      #SS(EXT); 
     FI; 
     Push(error code); 
    FI; 
    IF EIP not within code segment limit 
     #GP(EXT); 
    FI; 
END; 
TRAP-OR-INTERRUPT-GATE: 
    Read new code-segment selector for trap or interrupt gate (IDT descriptor); 
    IF new code-segment selector is NULL 
     #GP(EXT); 
    FI; (* Error code contains NULL selector *) 
    IF new code-segment selector is not within its descriptor table limits 
     #GP(error_code(new code-segment selector, 0, EXT)); 
    FI; 
    (* idt operand to error_code is 0 because selector is used *) 
    Read descriptor referenced by new code-segment selector; 
    IF descriptor does not indicate a code segment or new code-segment DPL > CPL 
     #GP(error_code(new code-segment selector, 0, EXT)); 
    FI; 
    (* idt operand to error_code is 0 because selector is used *) 
    IF new code-segment descriptor is not present, 
     #NP(error_code(new code-segment selector, 0, EXT)); 
    FI; 
    (* idt operand to error_code is 0 because selector is used *) 
    IF new code segment is non-conforming with DPL < CPL 
     IF VM = 0 
      GOTO INTER-PRIVILEGE-LEVEL-INTERRUPT; (* PE = 1, VM = 0, interrupt or trap gate, nonconforming code segment, DPL < CPL *) 
     ELSE 
      (* VM = 1 *) 
      IF new code-segment DPL != 0 
       #GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *) 
       GOTO INTERRUPT-FROM-VIRTUAL-8086-MODE; 
      FI; 
      (* PE = 1, interrupt or trap gate, DPL < CPL, VM = 1 *) 
     FI; 
    ELSE 
     (* PE = 1, interrupt or trap gate, DPL >= CPL *) 
     IF VM = 1 
      #GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *) 
     FI; 
     IF new code segment is conforming or new code-segment DPL = CPL 
      GOTO INTRA-PRIVILEGE-LEVEL-INTERRUPT; 
     ELSE 
      (* PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL *) 
      #GP(error_code(new code-segment selector, 0, EXT)); (* idt operand to error_code is 0 because selector is used *) 
     FI; 
    FI; 
END; 
INTER-PRIVILEGE-LEVEL-INTERRUPT: (* PE = 1, interrupt or trap gate, non-conforming code segment, DPL < CPL *) 
    IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) 
     (* Identify stack-segment selector for new privilege level in current TSS *) 
     IF current TSS is 32-bit 
      TSSstackAddress = (new code-segment DPL << 3) + 4; 
      IF (TSSstackAddress + 5) > current TSS limit 
       #TS(error_code(current TSS selector, 0, EXT)); 
      FI; 
      (* idt operand to error_code is 0 because selector is used *) 
      NewSS = 2 bytes loaded from (TSS base + TSSstackAddress + 4); 
      NewESP = 4 bytes loaded from (TSS base + TSSstackAddress); 
     ELSE 
      (* current TSS is 16-bit *) 
      TSSstackAddress = (new code-segment DPL << 2) + 2 
      IF (TSSstackAddress + 3) > current TSS limit 
       #TS(error_code(current TSS selector, 0, EXT)); 
      FI; 
      (* idt operand to error_code is 0 because selector is used *) 
      NewSS = 2 bytes loaded from (TSS base + TSSstackAddress + 2); 
      NewESP = 2 bytes loaded from (TSS base + TSSstackAddress); 
     FI; 
     IF NewSS is NULL 
      #TS(EXT); 
     FI; 
     IF NewSS index is not within its descriptor-table limits or NewSS RPL != new code-segment DPL 
      #TS(error_code(NewSS, 0, EXT)); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
     Read new stack-segment descriptor for NewSS in GDT or LDT; 
     IF new stack-segment DPL != new code-segment DPL or new stack-segment Type does not indicate writable data segment 
      #TS(error_code(NewSS, 0, EXT)); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
     IF NewSS is not present 
      #SS(error_code(NewSS, 0, EXT)); 
     FI; (* idt operand to error_code is 0 because selector is used *) 
    ELSE 
     (* IA-32e mode *) 
     IF IDT-gate IST = 0 
      TSSstackAddress = (new code-segment DPL << 3) + 4; 
     ELSE 
      TSSstackAddress = (IDT gate IST << 3) + 28; 
     FI; 
     IF (TSSstackAddress + 7) > current TSS limit 
      #TS(error_code(current TSS selector, 0, EXT); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
     NewRSP = 8 bytes loaded from (current TSS base + TSSstackAddress); 
     NewSS = new code-segment DPL; (* NULL selector with RPL = new CPL *) 
    FI; 
    IF IDT gate is 32-bit 
     IF new stack does not have room for 24 bytes (error code pushed) or 20 bytes (no error code pushed) 
      #SS(error_code(NewSS, 0, EXT)); 
      (* idt operand to error_code is 0 because selector is used *) 
     FI 
    ELSE 
     IF IDT gate is 16-bit 
      IF new stack does not have room for 12 bytes (error code pushed) or 10 bytes (no error code pushed); 
       #SS(error_code(NewSS, 0, EXT)); 
      FI; (* idt operand to error_code is 0 because selector is used *) 
     ELSE 
      (* 64-bit IDT gate *) 
      IF StackAddress is non-canonical 
       #SS(EXT); 
      FI; (* Error code contains NULL selector *) 
     FI; 
    FI; 
    IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) 
     IF instruction pointer from IDT gate is not within new code-segment limits 
      #GP(EXT); 
     FI; (* Error code contains NULL selector *) 
     ESP = NewESP; 
     SS = NewSS; (* Segment descriptor information also loaded *) 
    ELSE 
     (* IA-32e mode *) 
     IF instruction pointer from IDT gate contains a non-canonical address 
      #GP(EXT); 
     FI; (* Error code contains NULL selector *) 
     RSP = NewRSP & FFFFFFFFFFFFFFF0H; 
     SS = NewSS; 
    FI; 
    IF IDT gate is 32-bit 
     CS:EIP = Gate(CS:EIP); (* Segment descriptor information also loaded *) 
    ELSE 
     IF IDT gate 16-bit 
      CS:IP = Gate(CS:IP); (* Segment descriptor information also loaded *) 
     ELSE 
      (* 64-bit IDT gate *) 
      CS:RIP = Gate(CS:RIP); (* Segment descriptor information also loaded *) 
     FI; 
    FI; 
    IF IDT gate is 32-bit 
     Push(far pointer to old stack); (* Old SS and ESP, 3 words padded to 4 *) 
     Push(EFLAGS); 
     Push(far pointer to return instruction); (* Old CS and EIP, 3 words padded to 4 *) 
     Push(ErrorCode); (* If needed, 4 bytes *) 
    ELSE 
     IF IDT gate 16-bit 
      Push(far pointer to old stack); (* Old SS and SP, 2 words *) 
      Push(EFLAGS(15-0]); 
      Push(far pointer to return instruction); (* Old CS and IP, 2 words *) 
      Push(ErrorCode); (* If needed, 2 bytes *) 
     ELSE 
      (* 64-bit IDT gate *) 
      Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *) 
      Push(RFLAGS); (* 8-byte push *) 
      Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *) 
      Push(ErrorCode); (* If needed, 8-bytes *) 
     FI; 
    FI; 
    CPL = new code-segment DPL; 
    CS(RPL) = CPL; 
    IF IDT gate is interrupt gate 
     IF = 0 (* Interrupt flag set to 0, interrupts disabled *); 
    FI; 
    TF = 0; 
    VM = 0; 
    RF = 0; 
    NT = 0; 
END; 
INTERRUPT-FROM-VIRTUAL-8086-MODE: (* Identify stack-segment selector for privilege level 0 in current TSS *) 
    IF current TSS is 32-bit 
     IF TSS limit < 9 
      #TS(error_code(current TSS selector, 0, EXT)); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
     NewSS = 2 bytes loaded from (current TSS base + 8); 
     NewESP = 4 bytes loaded from (current TSS base + 4); 
    ELSE 
     (* current TSS is 16-bit *) 
     IF TSS limit < 5 
      #TS(error_code(current TSS selector, 0, EXT)); 
     FI; (* idt operand to error_code is 0 because selector is used *) 
     NewSS = 2 bytes loaded from (current TSS base + 4); 
     NewESP = 2 bytes loaded from (current TSS base + 2); 
    FI; 
    IF NewSS is NULL 
     #TS(EXT); 
    FI; (* Error code contains NULL selector *) 
    IF NewSS index is not within its descriptor table limits or NewSS RPL != 0 
     #TS(error_code(NewSS, 0, EXT)); 
    FI; 
    (* idt operand to error_code is 0 because selector is used *) 
    Read new stack-segment descriptor for NewSS in GDT or LDT; 
    IF new stack-segment DPL != 0 or stack segment does not indicate writable data segment 
     #TS(error_code(NewSS, 0, EXT)); 
    FI; 
    (* idt operand to error_code is 0 because selector is used *) 
    IF new stack segment not present 
     #SS(error_code(NewSS, 0, EXT)); 
    FI; (* idt operand to error_code is 0 because selector is used *) 
    IF IDT gate is 32-bit 
     IF new stack does not have room for 40 bytes (error code pushed) or 36 bytes (no error code pushed) 
      #SS(error_code(NewSS, 0, EXT)); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
    ELSE 
     (* IDT gate is 16-bit *) 
     IF new stack does not have room for 20 bytes (error code pushed) or 18 bytes (no error code pushed) 
      #SS(error_code(NewSS, 0, EXT)); 
     FI; 
     (* idt operand to error_code is 0 because selector is used *) 
    FI; 
    IF instruction pointer from IDT gate is not within new code-segment limits 
     #GP(EXT); 
    FI; (* Error code contains NULL selector *) 
    tempEFLAGS = EFLAGS; 
    VM = 0; 
    TF = 0; 
    RF = 0; 
    NT = 0; 
    IF service through interrupt gate 
     IF = 0; 
    FI; 
    TempSS = SS; 
    TempESP = ESP; 
    SS = NewSS; 
    ESP = NewESP; 
    (* Following pushes are 16 bits for 16-bit IDT gates and 32 bits for 32-bit IDT gates;Segment selector pushes in 32-bit mode are padded to two words *) 
    Push(GS); 
    Push(FS); 
    Push(DS); 
    Push(ES); 
    Push(TempSS); 
    Push(TempESP); 
    Push(TempEFlags); 
    Push(CS); 
    Push(EIP); 
    GS = 0; (* Segment registers made NULL, invalid for use in protected mode *) 
    FS = 0; 
    DS = 0; 
    ES = 0; 
    CS:IP = Gate(CS); (* Segment descriptor information also loaded *) 
    IF OperandSize = 32 
     EIP = Gate(instruction pointer); 
    ELSE 
     (* OperandSize is 16 *) 
     EIP = Gate(instruction pointer) AND 0000FFFFH; 
    FI; 
    (* Start execution of new routine in Protected Mode *) 
END; 
INTRA-PRIVILEGE-LEVEL-INTERRUPT: 
    (* PE = 1, DPL = CPL or conforming segment *) 
    IF IA32_EFER.LMA = 1 (* IA-32e mode *) 
     IF IDT-descriptor IST != 0 
      TSSstackAddress = (IDT-descriptor IST << 3) + 28; 
      IF (TSSstackAddress + 7) > TSS limit 
       #TS(error_code(current TSS selector, 0, EXT)); 
      FI; 
      (* idt operand to error_code is 0 because selector is used *) 
      NewRSP = 8 bytes loaded from (current TSS base + TSSstackAddress); 
     FI; 
     IF 32-bit gate (* implies IA32_EFER.LMA = 0 *) 
      IF current stack does not have room for 16 bytes (error code pushed) or 12 bytes (no error code pushed) 
       #SS(EXT); 
      FI; (* Error code contains NULL selector *) 
     ELSE 
      IF 16-bit gate (* implies IA32_EFER.LMA = 0 *) 
       IF current stack does not have room for 8 bytes (error code pushed) or 6 bytes (no error code pushed) 
        #SS(EXT); 
       FI; (* Error code contains NULL selector *) 
      ELSE 
       (* IA32_EFER.LMA = 1, 64-bit gate *) 
       IF NewRSP contains a non-canonical address 
        #SS(EXT); (* Error code contains NULL selector *) 
       FI; 
      FI; 
     FI; 
    FI; 
    IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) 
     IF instruction pointer from IDT gate is not within new code-segment limit 
      #GP(EXT); 
     FI; (* Error code contains NULL selector *) 
    ELSE 
     IF instruction pointer from IDT gate contains a non-canonical address 
      #GP(EXT); 
     FI; (* Error code contains NULL selector *) 
     RSP = NewRSP & FFFFFFFFFFFFFFF0H; 
    FI; 
    IF IDT gate is 32-bit (* implies IA32_EFER.LMA = 0 *) 
     Push (EFLAGS); 
     Push (far pointer to return instruction); (* 3 words padded to 4 *) 
     CS:EIP = Gate(CS:EIP); (* Segment descriptor information also loaded *) 
     Push (ErrorCode); (* If any *) 
    ELSE 
     IF IDT gate is 16-bit (* implies IA32_EFER.LMA = 0 *) 
      Push (FLAGS); 
      Push (far pointer to return location); (* 2 words *) 
      CS:IP = Gate(CS:IP); (* Segment descriptor information also loaded *) 
      Push (ErrorCode); (* If any *) 
     ELSE 
      (* IA32_EFER.LMA = 1, 64-bit gate *) 
      Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *) 
      Push(RFLAGS); (* 8-byte push *) 
      Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *) 
      Push(ErrorCode); (* If needed, 8 bytes *) 
      CS:RIP = GATE(CS:RIP); 
      (* Segment descriptor information also loaded *) 
     FI; 
    FI; 
    CS(RPL) = CPL; 
    IF IDT gate is interrupt gate 
     IF = 0; 
    FI; 
    (* Interrupt flag set to 0;interrupts disabled *) 
    TF = 0; 
    NT = 0; 
    VM = 0; 
    RF = 0; 
END; 
+0

왜 SS는 4 바이트를 소모한다는 것이다? 세그먼트 선택기가 2 바이트를 사용하는 것으로 알고 있습니다. 내가 뭘 놓치고 있니? – gztomas

+0

@gztomas 정렬. 2 개의 추가 바이트는 필러이므로 스택이 4의 배수로 정렬되도록 유지합니다. – hirschhornsalz

+0

스택 전환이 발생하면 스택에 'SS'/ 'ESP'가 저장됩니다. 이것은 (커널/링 0에 이미있는 동안 인터럽트 이벤트에 대한) 인터 특권 이벤트 (usermode/ring 3에있는 동안 인터럽트)와 기본 권한이 아닐 때 내부적 인 권한조차도 _force 할 수 있습니다. IDT에서 _task gate_. 이것은 일반적이지는 않습니다 (이중 장애에 대해서는 솔라리스 32 비트/x86입니다,'# DF'). "좋은 스택"을 보장하는 합리적인 방법이기 때문에, 값을 포함한 모든 레지스터 상태를 유지할 수 있습니다. "나쁜 스택 포인터"의). –