TDF_NEEDRESCHED when extending pcb on x86

Denis Ustimenko denus at ngs.ru
Mon Feb 28 22:55:37 GMT 2005


Hi, there!

I've tried s3switch utility from ports on 5.2.1 and found that 
i386_set_ioperm syscall doesn't work properly. The next code illustrates 
the problem. It will get SIGBUS with very high probability.

#include <sys/types.h>
#include <machine/sysarch.h>
#include <machine/cpufunc.h>

int main()
{
         if ( i386_set_ioperm( 0x80, 1, 1)) {
                 perror("XXX");
                 return 1;
         }
         inb( 0x80);
         return 0;
}

Now I have no 5.3 or CURRENT system but brief looking on code shows that 
it should give the same result on them.
The problem occurs when we extend pcb and set TDF_NEEDRESCHED bit hoping 
that thread will be rescheduled and new TSS will be loaded. But 
sched_switch function skips cpu_switch when thread was not changed and 
ltr is not executed.
So I've patched sys_machdep.c the patch is below. But two thoughts in 
this situation are not clear to me:
1. May be patching of scheduler code to call cpu_switch in case of 
TDF_NEEDRESCHED is more appropriate decision
2. Is it necessary to protect all new lines of i386_extend_pcb function 
by sched_lock? It looks like we could move at least ltr out of 
syncronized code.

*** /usr/src/sys/i386/include/segments.h.orig   Mon Feb 28 23:34:30 2005
--- /usr/src/sys/i386/include/segments.h        Mon Feb 28 23:34:53 2005
***************
*** 243,248 ****
--- 243,249 ----
   extern struct gate_descriptor *idt;
   extern union descriptor ldt[NLDT];
   extern struct region_descriptor r_gdt, r_idt;
+ extern int private_tss;

   void  lgdt(struct region_descriptor *rdp);
   void  sdtossd(struct segment_descriptor *sdp,
*** /usr/src/sys/i386/i386/sys_machdep.c.orig   Mon Feb 28 23:29:31 2005
--- /usr/src/sys/i386/i386/sys_machdep.c        Mon Feb 28 23:33:31 2005
***************
*** 172,179 ****
         mtx_lock_spin(&sched_lock);
         td->td_pcb->pcb_ext = ext;

!       /* switch to the new TSS after syscall completes */
!       td->td_flags |= TDF_NEEDRESCHED;
         mtx_unlock_spin(&sched_lock);

         return 0;
--- 172,180 ----
         mtx_lock_spin(&sched_lock);
         td->td_pcb->pcb_ext = ext;

!       private_tss |= 1 << PCPU_GET(cpuid);
!       *PCPU_GET(tss_gdt) = td->td_pcb->pcb_ext->ext_tssd;
!       ltr(GSEL(GPROC0_SEL, SEL_KPL));
         mtx_unlock_spin(&sched_lock);

         return 0;


-- 
Best regards
Denis


More information about the freebsd-hackers mailing list