[SOS] changement de privileges + interrupt manager
stephane duverger
duvergers at chello.fr
Dim 6 Mar 18:55:59 CET 2005
Ok, merci david j'arriverais a dormir cette nuit :)
bonne fin de journée
On Sun, 2005-03-06 at 18:29 +0100, David Decotigny wrote:
> stephane duverger wrote:
> > J'ai cependant une derniere question. En regardant l'algo d'iret (intel
> > volume 2) je n'ai pas vu (bien que ce soit spécifié dans le volume 3 au
> > chapitre des interruptions) que l'instruction remettait les infos de la
> > pile user (ss et esp) dans les registres lors du depilement.
>
> Je viens de jeter un coup d'oeil, et effectivement on dirait qu'ils ont
> "oublié" ce detail. En tout cas c'est pas tres clair. Pour la recup de
> SS, c'est presque sous-entendu au debut du pseudo code de
> RETURN-TO-OUTER-PRIVILGE-LEVEL ("Read return segment selector ... "),
> ils oublient juste de mettre a jour ss apres toutes les verifications.
> Par contre, pour esp, la c'est carrement "oublié". Ceci dit, on devine
> qu'il y a un "esp" dans le coup parce que le debut du pseudo-code dit
> qu'on verifie que la pile doit posseder 8 octets supplementaires dans le
> segment de pile actuel (ie SP [étendu a 32 bits] + ESP). Autre chose, a
> aucun moment on ne fait Pop() de ss et esp. Bref, ce pseudo-code est faux.
>
> La doc de reference correcte est celle du 5.12.1 dans la doc intel vol 3
> (Exception- or Interrupt-Handler Procedures). En tous cas c'est le
> comportement observe dans bochs, qemu, AMD k7 800, Cyrix 133, Intel PIV
> 2.4 ;)
>
> BTW, le code de qemu peut servir de reference plus "sure" que la doc
> Intel : target-i386/{op,helper}.c
> Ou voit clairement la chose :
>
> if (rpl == cpl) {
> ....
> } else {
> /* return to different priviledge level */
> if (shift == 1) {
> /* 32 bits */
> POPL(ssp, sp, sp_mask, new_esp);
> POPL(ssp, sp, sp_mask, new_ss);
> new_ss &= 0xffff;
> } else {
> ...
> }
> ...
> }
>
> > J'ai vu dans ton code de la version "au debut sos devait fonctionner
> > comme ca" que tu preparais bien la pile avec ses infos en plus des
> > flags, cs et eip. Cela justifie bien que l'iret changera de pile au
> > retour. Je voulais juste avoir confirmation.
>
> Voui, voir code bochs/qemu + Intel 5.12.1 (figure 5-4) dans le vol 3
>
> > Tu places aussi un code d'erreur (push $0) et fait l'iret, hors n'est-il
> > pas a la charge du programmeur de supprimer ce fameux code d'erreur
> > avant un iret comme l'on fait durant le traitement d'une interruption
> > "normale" ?
>
> C'etait en effet completement faux (iret n'a jamais eu a dependre d'un
> code d'erreur empilé), c'etait pour voir si vous suiviez.
>
> Je me suis plante de version dans le cvs, il fallait lire le code suivant :
> --------------------------------------------------------------------
> .globl sos_cpu_context_switch_to_user_mode
> .type sos_cpu_context_switch_to_user_mode, @function
> sos_cpu_context_switch_to_user_mode:
> // arg2= user_initial_SP -- esp+8
> // arg1= user_initial_PC -- esp+4
> // caller ip -- esp
>
> /*
> * Store the kernel SP where the CPU will have to return to when
> * returning from user to kernel mode. That SP is the value of
> * the SP before the call to this function
> */
> movl %esp, %eax
> addl $12, %eax /* SP before function call is 12B above current SP */
> pushl %eax
> call sos_cpu_context_update_kernel_tss_switch_to_user
> addl $4, %esp
>
> /*
> * Setup the stack so as to suit the iret instruction for a "return"
> * with privilege change. See figure 6-5 of Intel x86 vol 1 (error
> * code is skipped). We could have used the "far ret" instruction,
> * the only difference would have been that the IF flag of the
> * EFLAGS register would not have been setup so that the IRQ inside
> * the user thread are allowed
> */
>
> /* Push SS register of the user context */
> pushl $SOS_BUILD_SEGMENT_REG_VALUE(3, 0, SOS_SEG_UDATA) // ==> esp += 4
>
> /* Push the initial user SP */
> pushl 12(%esp) // ==> esp += 4
>
> /* Push the initial user EFLAGS register */
> pushl $(1 << 9) // IF flag set ==> esp += 4
>
> /* Push the CS register of the user context */
> pushl $SOS_BUILD_SEGMENT_REG_VALUE(3, 0, SOS_SEG_UCODE) // ==> esp += 4
>
> /* Push the PC of the user context */
> pushl 20(%esp)
>
> /*
> * Reset the general purpose user segment registers
> */
> /* Build the contents of these registers */
> movw $SOS_BUILD_SEGMENT_REG_VALUE(3, 0, SOS_SEG_UDATA), %ax
> pushw %ax ; popw %ds
> pushw %ax ; popw %es
> pushw %ax ; popw %fs
> pushw %ax ; popw %gs
>
> /*
> * Reset the general purpose registers
> */
> movl $0, %eax
> movl $0, %ebx
> movl $0, %ecx
> movl $0, %edx
> movl $0, %ebp
> movl $0, %esi
> movl $0, %edi
>
> /* Now switch to user context ! */
> iret
> --------------------------------------------------------------------
> Ce code-la a ete testé et approuvé.
>
> Bonne journee,
> _______________________________________________
> Sos mailing list
> Sos at the-doors.enix.org
> http://the-doors.enix.org/cgi-bin/mailman/listinfo/sos
--
stephane duverger <duvergers at chello.fr>
Plus d'informations sur la liste de diffusion Sos