Date: Tue, 01 Mar 2005 01:57:21 +0300 From: Denis Ustimenko <denus@ngs.ru> To: freebsd-hackers@freebsd.org Subject: TDF_NEEDRESCHED when extending pcb on x86 Message-ID: <4223A1D1.6000104@ngs.ru>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4223A1D1.6000104>
