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>