RFC: getting rid of the TSS + patch

Ingo Molnar (mingo@pc7537.hil.siemens.at)
Wed, 27 Aug 1997 13:57:06 +0200 (MET DST)


On 27 Aug 1997, H. Peter Anvin wrote:

> Under Linux/i386 it would be, at least, since Linux would need minor
> redesign to go beyond 4,000-odd processes and major redesign to go
> beyond 8,000-odd; this is because Linux uses i386 TSS, which means
> each process needs a slot in the GDT.[...]

i've already done this part a few weeks ago: full soft thread switching
without any TSS switching, with full iopl() and ioperm() interface
compatibility and other stuff like full LDT support and vm86() things. The
only limitation i'm aware of is that we need 1 TSS per CPU, so we need
another major redesign in this part of the kernel to support more than
8000 CPUs ;)

i'd be more than happy to hear comments about this patch. The major goal
was not to give more threads, but to add a feature Linus mentioned some
time ago: 'lazy MMU state switching', alias smarter TLB flushing
capabilities wrt kernel threads. Also, it makes future pure 64-bit Linux
on the IA64 a few orders easier wrt thread switches.

Theoretically, thread switching times should improve, though the code is
not optimal on the assembly level yet. I've only timed SMP, where it is
about on par with the TSS solution, mainly due to some unavoidable atomic
things SMP has to do to get the lazy TLB issue right.

the patch does some other things too, naturally it makes 'struct
task_struct' smaller by 25%, which speeds up fork()/clone(). Cleans up
some stuff: removes all references to tss, man did it look funny to see
references to current.tss in asm-sparc/*.h ;))) but it breaks other
platforms in the process.

and some other things i forgot, comments more than welcome. The patch is
against 2.1.48, but there was no earthshaking change in this area since
then, so it should apply more or less cleanly. Btw, it was never even
compiled on uniprocessors :)

-- mingo

diff -ru --new-file 2.1.48-pre2/include/asm-i386/switch.h linux/include/asm-i386/switch.h
--- 2.1.48-pre2/include/asm-i386/switch.h Wed Aug 6 18:08:14 1997
+++ linux/include/asm-i386/switch.h Sat Aug 9 06:31:30 1997
@@ -0,0 +1,220 @@
+
+/*
+ * This is the Linux x86 thread soft switching stuff.
+ *
+ * There are four kind of contexts which must be taken
+ * care of:
+ *
+ * 1) CPU execution context
+ *
+ * Fortunately we do not carry too much CPU state where
+ * we switch, because user-context is saved at system
+ * entry, and GCC needs at most %ebp,%esp and EIP at
+ * that point. The per-thread ring 0 stack address of
+ * the next thread has to be restored into the TSS as well.
+ *
+ * 2) FPU context
+ *
+ * here we do lazy context saving. The hardware helps us,
+ * if the TS bit in %cr0 is set and an FPU instruction is
+ * used, we get a trap. Thus we can avoid saving FPU state
+ * for threads which do not use the FPU. Also, we distinct
+ * between 'used' and 'empty' FPU registers. In the later
+ * case we only have to save the FPU 'environment', but
+ * not the (empty!) registers themselves. ['empty' stuff
+ * not implemented yet]
+ *
+ * [ SMP doesnt do lazy FPU, because it's (probably) not
+ * worth the IPI to carry lazy FPU state across CPUs.. ]
+ *
+ * 3) MMU context
+ *
+ * this thing is about the TLB cache. The address space of
+ * an x86 Linux thread has two distinct parts: user-space
+ * mappings and kernel-space mappings. Kernel space mappings
+ * are identical for all threads in Linux. For kernel-only
+ * threads, there are no user-space mappings. The above
+ * memory model creates the following three kinds of thread
+ * switches:
+ *
+ * - user-thread <=> user-thread, different user-space
+ * - user-thread <=> user-thread, same user-space
+ * - any thread <=> kernel-thread
+ *
+ * Thus we can 'carry' the TLB state of user-threads into
+ * kernel threads, and we can even carry it out, if we
+ * switch back to the same user-thread. This is especially
+ * important for short-term switches to the idle thread and
+ * back. Also, service threads (eg. NFS biod) generate fast
+ * forth -and back switches as well. [see the FIXME in this
+ * file why lazy MMU is switched off now]
+ *
+ * 4) misc: IO permissions context, debug registers, LDT
+ *
+ * most applications have no IO permission rights. For them
+ * we have a 'standard' IO permission bitmap.
+ * Threads with own IO permissions have their own bitmap,
+ * and it's copied into the per-CPU TSS when the bitmap
+ * address changes. Worst case is a 128 bytes copy.
+ * Debug registers have to be saved as well, only if they
+ * are used. LDT's have their own management as well, like
+ * IO permission bitmaps.
+ *
+ * [ anything missing? --mingo ]
+ *
+ * FIXME: lazy FPU for uniprocessor case missing.
+ * switch_threads() isnt asm optimized yet.
+ */
+
+#include <linux/config.h>
+#include <asm/smp_lock.h>
+
+#define ALL_REGS_CLOBBERED "ax","bx","cx","dx","si","di","bp","memory"
+#define ASM __asm__ __volatile__
+
+#ifdef CONFIG_i386
+# define SYNC_FPU ASM ("fwait")
+#else
+# define SYNC_FPU
+#endif
+
+/*
+ * The default IO permissions bitmap, management functions.
+ */
+extern struct IO_bitmap_struct std_zero_access_bitmap;
+extern void destroy_x86_IO_bitmap (struct task_struct * tsk);
+void init_x86_IO_bitmap (void);
+
+void init_threads (void);
+
+extern __inline__ struct task_struct * switch_threads
+ (struct task_struct * prev, struct task_struct * next)
+{
+ if (prev->flags&PF_USEDFPU)
+ {
+ ASM ("fnsave %0":"=m" (prev->thread.i387.hard));
+ SYNC_FPU;
+ prev->flags&=~PF_USEDFPU;
+ }
+
+/*
+ * WARNING: we dont do the lazy TLB trick yet, because it
+ * interacts with mem subsystems badly. (freelists dont
+ * get filled up properrly, leading to a lockup after some
+ * time). I think this is due to the delayed freeing of
+ * process pages.
+ *
+ * Also, we should merge this into mmu_context.h
+ */
+
+ if (!next->thread.cr3) {
+ atomic_inc((atomic_t *)&prev->mm->count);
+ next->mm=prev->mm;
+ }
+
+ ASM (
+ " movl %0,%%eax; "
+ " cmpl $0, %%eax; "
+ " jz 2f; "
+ " cmpl %%eax, %1; "
+ " je 2f; "
+ " movl %%eax, %%cr3; "
+ "2: "
+ :
+ : "m" (next->thread.cr3),
+ "m" (prev->thread.cr3)
+ : "ax" );
+
+ /* Now maybe reload the debug registers */
+ if ((prev)->debugreg[7]){
+ loaddebug((prev),0);
+ loaddebug((prev),1);
+ loaddebug((prev),2);
+ loaddebug((prev),3);
+ loaddebug((prev),6);
+ loaddebug((prev),7);
+ }
+
+ /*
+ * reload the LDT if necessary.
+ */
+ if (next->thread.ldt_sel != prev->thread.ldt_sel)
+ load_ldt(next->thread.ldt_sel);
+
+ /*
+ * reload the IO bitmap if necessary. 128 bytes if present,
+ * 0 bytes if not present.
+ */
+ if (next->thread.io_bitmap != prev->thread.io_bitmap)
+ memcpy(prev->thread.tss->io_bitmap,
+ next->thread.io_bitmap->map,
+ sizeof(struct IO_bitmap_struct));
+
+/*
+ * We all hate #ifdef's. But i'm unable to tell GCC that we fold
+ * the uniprocessor case into the SMP architecture via NR_CPUS==1.
+ * And every cycle counts.
+ */
+#ifdef __SMP__
+ prev->thread.esp0 = prev->thread.tss->esp0;
+ /*
+ * This really does something if we migrate a thread
+ * across CPUs:
+ */
+ next->thread.tss = prev->thread.tss;
+ next->thread.tss->esp0 = next->thread.esp0;
+#else
+ prev->thread.esp0 = init_TSS[0].esp0;
+ init_TSS[0].esp0 = next->thread.esp0;
+#endif
+
+ /*
+ * Finally, switch threads. We could even get rid of the jmp ...
+ * but i havent found any (easy) way to get the first schedule
+ * of a thread right, so we dont do it yet.
+ */
+ ASM (" pushl %%ebp; "
+ " movl %%esp, %0; "
+ " movl %1, %%esp; "
+ " movl $1f, %%eax; "
+ " movl %%eax, %2; "
+ " movl %3, %%eax; "
+ " jmp %%eax; "
+ "1: popl %%ebp; "
+
+ :"=m" (prev->thread.esp),
+ "=m" (next->thread.esp),
+ "=m" (prev->thread.eip),
+ "=m" (next->thread.eip),
+ "=c" (prev)
+ : "c" (prev)
+ : ALL_REGS_CLOBBERED );
+ return prev;
+}
+
+
+extern __inline__ void put_mmu_context (struct task_struct * from)
+{
+ if (!from->thread.cr3) {
+ struct mm_struct * mm = from->mm;
+
+ spin_unlock(&scheduler_lock);
+ /*
+ * from this point on we cannot use 'from'!
+ * this is why the unlock stuff is so ugly
+ */
+
+ if (atomic_dec_and_test((atomic_t *)&mm->count)) {
+ lock_kernel();
+ exit_mmap(mm);
+ free_page_tables(mm);
+ kmem_cache_free(mm_cachep, mm);
+ unlock_kernel();
+ }
+ } else
+ spin_unlock(&scheduler_lock);
+}
+
+#undef ALL_REGS_CLOBBERED
+#undef ASM
+
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- 2.1.48-pre2/arch/i386/kernel/init_task.c Wed May 14 07:41:01 1997
+++ linux/arch/i386/kernel/init_task.c Sat Aug 9 00:49:50 1997
@@ -9,6 +9,8 @@
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;

+struct TSS_struct init_TSS[NR_CPUS] = { INIT_TSS, };
+
/*
* Initial task structure.
*
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c
--- 2.1.48-pre2/arch/i386/kernel/ioport.c Tue Feb 4 15:44:24 1997
+++ linux/arch/i386/kernel/ioport.c Sat Aug 9 06:03:28 1997
@@ -2,7 +2,7 @@
* linux/arch/i386/kernel/ioport.c
*
* This contains the io-permission bitmap code - written by obz, with changes
- * by Linus.
+ * by Linus. Further tweaked by mingo.
*/

#include <linux/sched.h>
@@ -13,9 +13,62 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+/*
+ * SLAB cache for IO permission bitmaps. They are copied onto the
+ * standard TSS if necessary. The theory is that it's a 128 bytes
+ * copy only, and that ioperm() is seldom.
+ */
+static kmem_cache_t *io_bitmap_cachep;
+
+struct IO_bitmap_struct std_zero_access_bitmap;
+
+void init_x86_IO_bitmap (void)
+{
+ io_bitmap_cachep = kmem_cache_create
+ ("x86_IO_bitmap_cache",
+ sizeof(struct IO_bitmap_struct),
+ 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if(!io_bitmap_cachep)
+ panic("Cannot create x86 IO bitmap SLAB cache\n");
+
+ printk("x86 IO bitmap cache created.\n");
+ memset (&std_zero_access_bitmap, ~0,
+ sizeof(struct IO_bitmap_struct));
+}
+
+/*
+ * Creates a new bitmap for the current process, if not present yet.
+ */
+static inline int create_x86_IO_bitmap (void)
+{
+ if (!(
+ current->thread.io_bitmap =
+ kmem_cache_alloc (io_bitmap_cachep, SLAB_KERNEL)
+ ))
+ return -ENOMEM;
+
+ memset (current->thread.io_bitmap, ~0,
+ sizeof(struct IO_bitmap_struct));
+ return 0;
+}
+
+/*
+ * Destroys a bitmap for a process, if present.
+ */
+void destroy_x86_IO_bitmap (struct task_struct * tsk)
+{
+ if (tsk->thread.io_bitmap != &std_zero_access_bitmap) {
+ kmem_cache_free (io_bitmap_cachep, tsk->thread.io_bitmap);
+ tsk->thread.io_bitmap = &std_zero_access_bitmap;
+ }
+}

/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
+static void set_bitmap (unsigned long *bitmap, short base,
+ short extent, int new_value)
{
int mask;
unsigned long *bitmap_base = bitmap + (base >> 5);
@@ -57,12 +110,20 @@
return -EINVAL;
if (!suser())
return -EPERM;
-
- set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
+
+ if (current->thread.io_bitmap == &std_zero_access_bitmap)
+ if (create_x86_IO_bitmap())
+ return -ENOMEM;
+ /*
+ * Set in both in the current TSS, and the per-thread IO bitmap.
+ * this is not performance sensitive.
+ */
+ set_bitmap ((unsigned long *)current->thread.tss->io_bitmap,
+ from, num, !turn_on);
+ set_bitmap ((unsigned long *)current->thread.io_bitmap,
+ from, num, !turn_on);
return 0;
}
-
-unsigned int *stack;

/*
* sys_iopl has to be used when you want to access the IO ports
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- 2.1.48-pre2/arch/i386/kernel/ldt.c Sun Jan 26 11:07:04 1997
+++ linux/arch/i386/kernel/ldt.c Sat Aug 9 05:17:25 1997
@@ -18,7 +18,7 @@

static int read_ldt(void * ptr, unsigned long bytecount)
{
- void * address = current->ldt;
+ void * address = current->thread.ldt;
unsigned long size;

if (!ptr)
@@ -76,19 +76,20 @@
if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0))
return -EINVAL;

- if (!current->ldt) {
+ if (!current->thread.ldt) {
for (i=1 ; i<NR_TASKS ; i++) {
if (task[i] == current) {
- if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
+ if (!(current->thread.ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
return -ENOMEM;
- memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
- set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
+ memset(current->thread.ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->thread.ldt, LDT_ENTRIES);
+ current->thread.ldt_sel=i;
load_ldt(i);
}
}
}

- lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
+ lp = (unsigned long *) &current->thread.ldt[ldt_info.entry_number];
/* Allow LDTs to be cleared by the user. */
if (ldt_info.base_addr == 0 && ldt_info.limit == 0
&& (oldmode ||
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- 2.1.48-pre2/arch/i386/kernel/process.c Mon Jul 14 19:17:29 1997
+++ linux/arch/i386/kernel/process.c Sat Aug 9 05:11:28 1997
@@ -40,6 +40,8 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ldt.h>
+#include <asm/processor.h>
+#include <asm/switch.h>

#ifdef __SMP__
asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
@@ -412,7 +414,7 @@
}

/*
- * Free current thread data structures etc..
+ * Free current->thread data structures etc..
*/

void exit_thread(void)
@@ -421,13 +423,18 @@
if (last_task_used_math == current)
last_task_used_math = NULL;
/* forget local segments */
- __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
+ __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs"
: /* no outputs */
: "r" (0));
- current->tss.ldt = 0;
- if (current->ldt) {
- void * ldt = current->ldt;
- current->ldt = NULL;
+ /*
+ * LDT back to default. Can do no harm and makes the next
+ * schedule() faster.
+ */
+ current->thread.ldt_sel = 0;
+ load_ldt(0);
+ if (current->thread.ldt) {
+ void * ldt = current->thread.ldt;
+ current->thread.ldt = NULL;
vfree(ldt);
}
}
@@ -436,14 +443,15 @@
{
int i;

- if (current->ldt) {
- free_page((unsigned long) current->ldt);
- current->ldt = NULL;
+ if (current->thread.ldt) {
+ free_page((unsigned long) current->thread.ldt);
+ current->thread.ldt = NULL;
for (i=1 ; i<NR_TASKS ; i++) {
if (task[i] == current) {
set_ldt_desc(gdt+(i<<1)+
FIRST_LDT_ENTRY,&default_ldt, 1);
load_ldt(i);
+ current->thread.ldt_sel=0;
}
}
}
@@ -470,53 +478,53 @@

void release_thread(struct task_struct *dead_task)
{
+ destroy_x86_IO_bitmap(dead_task);
}

int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
struct task_struct * p, struct pt_regs * regs)
{
- int i;
struct pt_regs * childregs;

- p->tss.tr = _TSS(nr);
- p->tss.ldt = _LDT(nr);
- p->tss.es = KERNEL_DS;
- p->tss.cs = KERNEL_CS;
- p->tss.ss = KERNEL_DS;
- p->tss.ds = KERNEL_DS;
- p->tss.fs = USER_DS;
- p->tss.gs = USER_DS;
- p->tss.ss0 = KERNEL_DS;
- p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p;
- childregs = ((struct pt_regs *) (p->tss.esp0)) - 1;
- p->tss.esp = (unsigned long) childregs;
+ p->thread.esp0 = 2*PAGE_SIZE + (unsigned long) p;
+ childregs = ((struct pt_regs *) (p->thread.esp0)) - 1;
+ p->thread.esp = (unsigned long) childregs;
+ p->thread.io_bitmap = &std_zero_access_bitmap;
+/*
+ * cr3==NULL means a kernel thread, it shares TLB with any other
+ * thread. It has no user-space memory mappings.
+ *
+ * FIXME: see switch.h for details why this doesnt work.
+ */
+#if 0
+ if (clone_flags & CLONE_TLB)
+ p->thread.cr3 = 0;
+#endif
+
#ifdef __SMP__
- p->tss.eip = (unsigned long) ret_from_smpfork;
- p->tss.eflags = regs->eflags & 0xffffcdff; /* iopl always 0 for a new process */
+ p->thread.eip = (unsigned long) ret_from_smpfork;
#else
- p->tss.eip = (unsigned long) ret_from_sys_call;
- p->tss.eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */
+ p->thread.tss->eip = (unsigned long) ret_from_sys_call;
#endif
- p->tss.ebx = (unsigned long) p;
*childregs = *regs;
childregs->eax = 0;
childregs->esp = esp;
- p->tss.back_link = 0;
- if (p->ldt) {
- p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (p->ldt != NULL)
- memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
- }
- set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
- if (p->ldt)
- set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
- else
+
+ if (p->thread.ldt) {
+ p->thread.ldt = (struct desc_struct*)
+ vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+ if (p->thread.ldt != NULL)
+ memcpy(p->thread.ldt, current->thread.ldt,
+ LDT_ENTRIES*LDT_ENTRY_SIZE);
+ set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->thread.ldt, 512);
+ p->thread.ldt_sel = nr;
+ } else {
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
- p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
- for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
- p->tss.io_bitmap[i] = ~0;
+ p->thread.ldt_sel = 0;
+ }
+
if (last_task_used_math == current)
- __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+ __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->thread.i387));

return 0;
}
@@ -535,7 +543,7 @@
if (last_task_used_math == current)
__asm__("clts ; fnsave %0": :"m" (*fpu));
else
- memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
+ memcpy(fpu,&current->thread.i387.hard,sizeof(*fpu));
}
} else {
/* we should dump the emulator state here, but we need to
@@ -633,3 +641,35 @@
unlock_kernel();
return error;
}
+
+/*
+ * FIXME: merge the final version into process.h
+ */
+void init_threads (void)
+{
+ int nr = 0;
+ struct pt_regs * childregs;
+ struct task_struct * p = current;
+
+ p->thread.tss->tr = _TSS(nr);
+ p->thread.tss->ldt = _LDT(nr);
+ p->thread.ldt_sel = nr;
+ p->thread.tss->es = KERNEL_DS;
+ p->thread.tss->cs = KERNEL_CS;
+ p->thread.tss->ss = KERNEL_DS;
+ p->thread.tss->ds = KERNEL_DS;
+ p->thread.tss->fs = USER_DS;
+ p->thread.tss->gs = USER_DS;
+ p->thread.tss->ss0 = KERNEL_DS;
+ p->thread.tss->esp0 = 2*PAGE_SIZE + (unsigned long) p;
+ childregs = ((struct pt_regs *) (p->thread.tss->esp0)) - 1;
+ p->thread.tss->esp = (unsigned long) childregs;
+ p->thread.tss->ebx = (unsigned long) p;
+ p->thread.tss->back_link = 0;
+ set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&init_TSS[0]);
+ p->thread.io_bitmap = &std_zero_access_bitmap;
+ memset (&std_zero_access_bitmap, ~0,
+ sizeof(struct IO_bitmap_struct));
+ p->thread.tss->bitmap = offsetof(struct TSS_struct,io_bitmap);
+}
+
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- 2.1.48-pre2/arch/i386/kernel/ptrace.c Fri May 16 01:48:01 1997
+++ linux/arch/i386/kernel/ptrace.c Sat Aug 9 05:18:59 1997
@@ -44,7 +44,7 @@
{
unsigned char *stack;

- stack = (unsigned char *)task->tss.esp0;
+ stack = (unsigned char *)task->thread.esp0;
stack += offset;
return (*((int *)stack));
}
@@ -60,7 +60,7 @@
{
unsigned char * stack;

- stack = (unsigned char *) task->tss.esp0;
+ stack = (unsigned char *) task->thread.esp0;
stack += offset;
*(unsigned long *) stack = data;
return 0;
@@ -291,14 +291,19 @@
case ORIG_EAX:
return -EIO;
case FS:
+#warning hm, what about these. We have fs/gs in pt_regs.
+#if 0
if (value && (value & 3) != 3)
return -EIO;
child->tss.fs = value;
+#endif
return 0;
case GS:
+#if 0
if (value && (value & 3) != 3)
return -EIO;
child->tss.gs = value;
+#endif
return 0;
case DS:
case ES:
@@ -328,11 +333,16 @@
unsigned long retval = ~0UL;

switch (regno >> 2) {
+#warning hm, what about these. We have them in %fs/%gs already i think.
case FS:
+#if 0
retval = child->tss.fs;
+#endif
break;
case GS:
+#if 0
retval = child->tss.gs;
+#endif
break;
case DS:
case ES:
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- 2.1.48-pre2/arch/i386/kernel/signal.c Fri May 16 01:48:01 1997
+++ linux/arch/i386/kernel/signal.c Sat Aug 9 05:18:03 1997
@@ -64,7 +64,7 @@
#endif
current->used_math = 1;
current->flags &= ~PF_USEDFPU;
- copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
+ copy_from_user(&current->thread.i387.hard, buf, sizeof(*buf));
}

static void restore_i387(struct _fpstate *buf)
@@ -145,20 +145,20 @@
{
#ifdef __SMP__
if (current->flags & PF_USEDFPU) {
- __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
+ __asm__ __volatile__("fnsave %0":"=m" (current->thread.i387.hard));
stts();
current->flags &= ~PF_USEDFPU;
}
#else
if (current == last_task_used_math) {
- __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
+ __asm__ __volatile__("fnsave %0":"=m" (current->thread.i387.hard));
last_task_used_math = NULL;
__asm__ __volatile__("fwait"); /* not needed on 486+ */
stts();
}
#endif
- current->tss.i387.hard.status = current->tss.i387.hard.swd;
- copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf));
+ current->thread.i387.hard.status = current->thread.i387.hard.swd;
+ copy_to_user(buf, &current->thread.i387.hard, sizeof(*buf));
current->used_math = 0;
return buf;
}
@@ -226,8 +226,8 @@
__put_user(regs->edx, frame+11);
__put_user(regs->ecx, frame+12);
__put_user(regs->eax, frame+13);
- __put_user(current->tss.trap_no, frame+14);
- __put_user(current->tss..error_code, frame+15);
+ __put_user(current->thread.trap_no, frame+14);
+ __put_user(current->thread.error_code, frame+15);
__put_user(regs->eip, frame+16);
__put_user(regs->xcs, frame+17);
__put_user(regs->eflags, frame+18);
@@ -236,7 +236,7 @@
__put_user((unsigned long) save_i387((struct _fpstate *)(frame+32)),frame+21);
/* non-iBCS2 extensions.. */
__put_user(oldmask, frame+22);
- __put_user(current->tss.cr2, frame+23);
+ __put_user(current->thread.cr2, frame+23);
/* set up the return code... */
__put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
__put_user(0x80cd0000, CODE(4)); /* int $0x80 */
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- 2.1.48-pre2/arch/i386/kernel/smp.c Tue Jun 17 01:35:53 1997
+++ linux/arch/i386/kernel/smp.c Sat Aug 9 05:19:46 1997
@@ -659,20 +659,34 @@
}

/*
- * Everything has been set up for the secondary
- * CPU's - they just need to reload everything
- * from the task structure
+ * Everything has been set up for the secondary CPU's - they just
+ * need to set up their TSS and reload everything from the task
+ * structure.
*/
__initfunc(void initialize_secondary(void))
{
- struct thread_struct * p = &current->tss;
+ /*
+ * We run this function only from idle threads:
+ */
+ int nr = cpu_number_map[smp_processor_id()];
+ unsigned long __tr = _TSS(nr);
+ struct new_thread_struct * p = &current->thread;
+
+ init_TSS[nr] = init_TSS[0];
+ p->tss = &init_TSS[nr];
+ load_ldt(0);
+
+ /*
+ * copy_thread() no more sets the TSS descriptor, so we have
+ * to init it here, for the first and last time:
+ */
+ set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&init_TSS[nr]);
+ asm volatile("ltr %%ax": :"a" (__tr));

/*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
- asm volatile("lldt %%ax": :"a" (p->ldt));
- asm volatile("ltr %%ax": :"a" (p->tr));
asm volatile(
"movl %0,%%esp\n\t"
"jmp *%1"
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- 2.1.48-pre2/arch/i386/kernel/traps.c Tue Jun 17 01:35:53 1997
+++ linux/arch/i386/kernel/traps.c Sat Aug 9 05:27:03 1997
@@ -44,8 +44,8 @@
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
lock_kernel(); \
- tsk->tss.error_code = error_code; \
- tsk->tss.trap_no = trapnr; \
+ tsk->thread.error_code = error_code; \
+ tsk->thread.trap_no = trapnr; \
force_sig(signr, tsk); \
die_if_kernel(str,regs,error_code); \
unlock_kernel(); \
@@ -60,8 +60,8 @@
goto out; \
/* else fall through */ \
} \
- tsk->tss.error_code = error_code; \
- tsk->tss.trap_no = trapnr; \
+ tsk->thread.error_code = error_code; \
+ tsk->thread.trap_no = trapnr; \
force_sig(signr, tsk); \
die_if_kernel(str,regs,error_code); \
out: \
@@ -188,9 +188,11 @@
if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3)
return;
console_verbose();
+
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
+ for (;;) __sti();
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
@@ -219,8 +221,8 @@
return;
}
die_if_kernel("cache flush denied",regs,error_code);
- current->tss.error_code = error_code;
- current->tss.trap_no = 19;
+ current->thread.error_code = error_code;
+ current->thread.trap_no = 19;
force_sig(SIGSEGV, current);
}

@@ -232,8 +234,8 @@
goto out;
}
die_if_kernel("general protection",regs,error_code);
- current->tss.error_code = error_code;
- current->tss.trap_no = 13;
+ current->thread.error_code = error_code;
+ current->thread.trap_no = 13;
force_sig(SIGSEGV, current);
out:
unlock_kernel();
@@ -288,8 +290,8 @@
goto out;
}
force_sig(SIGTRAP, current);
- current->tss.trap_no = 1;
- current->tss.error_code = error_code;
+ current->thread.trap_no = 1;
+ current->thread.error_code = error_code;
if ((regs->xcs & 3) == 0) {
/* If this is a kernel mode trap, then reset db7 and allow us to continue */
__asm__("movl %0,%%db7"
@@ -326,13 +328,13 @@
/*
* Save the info for the exception handler
*/
- __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
+ __asm__ __volatile__("fnsave %0":"=m" (task->thread.i387.hard));
task->flags&=~PF_USEDFPU;
stts();

force_sig(SIGFPE, task);
- task->tss.trap_no = 16;
- task->tss.error_code = 0;
+ task->thread.trap_no = 16;
+ task->thread.error_code = 0;
#ifndef __SMP__
out:
#endif
@@ -374,14 +376,14 @@
if (last_task_used_math == current)
return;
if (last_task_used_math)
- __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
+ __asm__("fnsave %0":"=m" (last_task_used_math->thread.i387));
else
__asm__("fnclex");
last_task_used_math = current;
#endif

if(current->used_math)
- __asm__("frstor %0": :"m" (current->tss.i387));
+ __asm__("frstor %0": :"m" (current->thread.i387));
else
{
/*
@@ -438,7 +440,7 @@
set_system_gate(0x80,&system_call);
/* set up GDT task & ldt entries */
p = gdt+FIRST_TSS_ENTRY;
- set_tss_desc(p, &init_task.tss);
+ set_tss_desc(p, &init_TSS[0]);
p++;
set_ldt_desc(p, &default_ldt, 1);
p++;
diff -ru --new-file 2.1.48-pre2/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- 2.1.48-pre2/arch/i386/kernel/vm86.c Wed May 14 07:41:01 1997
+++ linux/arch/i386/kernel/vm86.c Sat Aug 9 03:16:42 1997
@@ -48,8 +48,8 @@
/*
* virtual flags (16 and 32-bit versions)
*/
-#define VFLAGS (*(unsigned short *)&(current->tss.v86flags))
-#define VEFLAGS (current->tss.v86flags)
+#define VFLAGS (*(unsigned short *)&(current->thread.v86flags))
+#define VEFLAGS (current->thread.v86flags)

#define set_flags(X,new,mask) \
((X) = ((X) & ~(mask)) | ((new) & (mask)))
@@ -66,23 +66,25 @@
{
struct pt_regs *ret;
unsigned long tmp;
+ struct new_thread_struct * t = &current->thread;

lock_kernel();
- if (!current->tss.vm86_info) {
+ if (!t->vm86_info) {
printk("no vm86_info: BAD\n");
do_exit(SIGSEGV);
}
- set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->tss.v86mask);
- tmp = copy_to_user(&current->tss.vm86_info->regs,regs, VM86_REGS_SIZE1);
- tmp += copy_to_user(&current->tss.vm86_info->regs.VM86_REGS_PART2,
+ set_flags(regs->eflags, VEFLAGS, VIF_MASK | t->v86mask);
+ tmp = copy_to_user(&t->vm86_info->regs,regs, VM86_REGS_SIZE1);
+ tmp += copy_to_user(&t->vm86_info->regs.VM86_REGS_PART2,
&regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
- tmp += put_user(current->tss.screen_bitmap,&current->tss.vm86_info->screen_bitmap);
+ tmp += put_user(t->screen_bitmap,&t->vm86_info->screen_bitmap);
if (tmp) {
printk("vm86: could not access userspace vm86_info\n");
do_exit(SIGSEGV);
}
- current->tss.esp0 = current->tss.saved_esp0;
- current->tss.saved_esp0 = 0;
+ t->tss->esp0 = current->thread.saved_esp0;
+ t->esp0 = current->thread.saved_esp0;
+ t->saved_esp0 = 0;
ret = KVM86->regs32;
unlock_kernel();
return ret;
@@ -137,7 +139,7 @@

lock_kernel();
tsk = current;
- if (tsk->tss.saved_esp0)
+ if (tsk->thread.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -147,7 +149,7 @@
goto out;
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
info.regs32 = (struct pt_regs *) &v86;
- tsk->tss.vm86_info = v86;
+ tsk->thread.vm86_info = v86;
do_sys_vm86(&info, tsk);
ret = 0; /* we never return here */
out:
@@ -187,7 +189,7 @@

/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
ret = -EPERM;
- if (tsk->tss.saved_esp0)
+ if (tsk->thread.saved_esp0)
goto out;
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -197,7 +199,7 @@
goto out;
info.regs32 = (struct pt_regs *) &subfunction;
info.vm86plus.is_vm86pus = 1;
- tsk->tss.vm86_info = (struct vm86_struct *)v86;
+ tsk->thread.vm86_info = (struct vm86_struct *)v86;
do_sys_vm86(&info, tsk);
ret = 0; /* we never return here */
out:
@@ -230,16 +232,16 @@

switch (info->cpu_type) {
case CPU_286:
- tsk->tss.v86mask = 0;
+ tsk->thread.v86mask = 0;
break;
case CPU_386:
- tsk->tss.v86mask = NT_MASK | IOPL_MASK;
+ tsk->thread.v86mask = NT_MASK | IOPL_MASK;
break;
case CPU_486:
- tsk->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+ tsk->thread.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
break;
default:
- tsk->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+ tsk->thread.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
break;
}

@@ -247,10 +249,11 @@
* Save old state, set default return value (%eax) to 0
*/
info->regs32->eax = 0;
- tsk->tss.saved_esp0 = tsk->tss.esp0;
- tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
+ tsk->thread.saved_esp0 = tsk->thread.esp0;
+ tsk->thread.tss->esp0 = (unsigned long) &info->VM86_TSS_ESP0;
+ tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;

- tsk->tss.screen_bitmap = info->screen_bitmap;
+ tsk->thread.screen_bitmap = info->screen_bitmap;
if (info->flags & VM86_SCREEN_BITMAP)
mark_screen_rdonly(tsk);
unlock_kernel();
@@ -294,7 +297,7 @@

static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs)
{
- set_flags(VEFLAGS, eflags, current->tss.v86mask);
+ set_flags(VEFLAGS, eflags, current->thread.v86mask);
set_flags(regs->eflags, eflags, SAFE_MASK);
if (eflags & IF_MASK)
set_IF(regs);
@@ -302,7 +305,7 @@

static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs)
{
- set_flags(VFLAGS, flags, current->tss.v86mask);
+ set_flags(VFLAGS, flags, current->thread.v86mask);
set_flags(regs->eflags, flags, SAFE_MASK);
if (flags & IF_MASK)
set_IF(regs);
@@ -314,7 +317,7 @@

if (VEFLAGS & VIF_MASK)
flags |= IF_MASK;
- return flags | (VEFLAGS & current->tss.v86mask);
+ return flags | (VEFLAGS & current->thread.v86mask);
}

static inline int is_revectored(int nr, struct revectored_struct * bitmap)
@@ -441,8 +444,8 @@
if (current->flags & PF_PTRACED)
current->blocked &= ~(1 << (SIGTRAP-1));
send_sig(SIGTRAP, current, 1);
- current->tss.trap_no = trapno;
- current->tss.error_code = error_code;
+ current->thread.trap_no = trapno;
+ current->thread.error_code = error_code;
return 0;
}

diff -ru --new-file 2.1.48-pre2/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- 2.1.48-pre2/arch/i386/mm/fault.c Mon Jul 14 19:40:13 1997
+++ linux/arch/i386/mm/fault.c Sat Aug 9 06:06:00 1997
@@ -150,7 +150,7 @@
if (regs->eflags & VM_MASK) {
unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
if (bit < 32)
- tsk->tss.screen_bitmap |= 1 << bit;
+ tsk->thread.screen_bitmap |= 1 << bit;
}
goto out;

@@ -163,9 +163,9 @@

/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
- tsk->tss.cr2 = address;
- tsk->tss.error_code = error_code;
- tsk->tss.trap_no = 14;
+ tsk->thread.cr2 = address;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 14;
force_sig(SIGSEGV, tsk);
goto out;
}
@@ -199,8 +199,8 @@
printk(KERN_ALERT "Unable to handle kernel paging request");
printk(" at virtual address %08lx\n",address);
__asm__("movl %%cr3,%0" : "=r" (page));
- printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
- tsk->tss.cr3, page);
+ printk(KERN_ALERT "current->thread.cr3 = %08lx, %%cr3 = %08lx\n",
+ tsk->thread.cr3, page);
page = ((unsigned long *) __va(page))[address >> 22];
printk(KERN_ALERT "*pde = %08lx\n", page);
if (page & 1) {
diff -ru --new-file 2.1.48-pre2/fs/proc/array.c linux/fs/proc/array.c
--- 2.1.48-pre2/fs/proc/array.c Mon Jul 14 06:20:10 1997
+++ linux/fs/proc/array.c Fri Aug 8 21:47:15 1997
@@ -424,6 +424,8 @@
stack_page = 4096 + (unsigned long)p;
if (!stack_page)
return 0;
+#warning FIXME
+#if 0
ebp = p->tss.ebp;
do {
if (ebp < stack_page || ebp >= 4092+stack_page)
@@ -434,6 +436,7 @@
return eip;
ebp = *(unsigned long *) ebp;
} while (count++ < 16);
+#endif
}
#elif defined(__alpha__)
/*
@@ -449,6 +452,7 @@
unsigned long schedule_frame;
unsigned long pc;

+#warning have i broken this? --mingo
pc = thread_saved_pc(&p->tss);
if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
schedule_frame = ((unsigned long *)p->tss.ksp)[6];
diff -ru --new-file 2.1.48-pre2/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- 2.1.48-pre2/include/asm-i386/pgtable.h Fri Aug 8 11:34:28 1997
+++ linux/include/asm-i386/pgtable.h Sat Aug 9 06:20:00 1997
@@ -283,7 +283,7 @@
#define SET_PAGE_DIR(tsk,pgdir) \
do { \
unsigned long __pgdir = __pa(pgdir); \
- (tsk)->tss.cr3 = __pgdir; \
+ (tsk)->thread.cr3 = __pgdir; \
if ((tsk) == current) \
__asm__ __volatile__("movl %0,%%cr3": :"r" (__pgdir)); \
} while (0)
diff -ru --new-file 2.1.48-pre2/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- 2.1.48-pre2/include/asm-i386/processor.h Wed May 14 07:41:17 1997
+++ linux/include/asm-i386/processor.h Sat Aug 9 00:09:42 1997
@@ -87,7 +87,7 @@
struct i387_soft_struct soft;
};

-struct thread_struct {
+struct TSS_struct {
unsigned short back_link,__blh;
unsigned long esp0;
unsigned short ss0,__ss0h;
@@ -113,9 +113,33 @@
unsigned short trace, bitmap;
unsigned long io_bitmap[IO_BITMAP_SIZE+1];
unsigned long tr;
- unsigned long cr2, trap_no, error_code, segment;
+};
+
+extern struct TSS_struct init_TSS [NR_CPUS];
+
+struct IO_bitmap_struct {
+ unsigned long map[IO_BITMAP_SIZE+1];
+};
+
+struct new_thread_struct {
+
+ unsigned long cr3;
+ unsigned long eip;
+ unsigned long esp, esp0;
+ unsigned short ldt_sel, __ldth_sel;
+
+ struct TSS_struct *tss;
+
+ long access_mode;
+ unsigned long cr2, trap_no, error_code;
+
/* floating point info */
union i387_union i387;
+
+/* IO permission bitmap. */
+ struct IO_bitmap_struct *io_bitmap;
+/* LDT table */
+ struct desc_struct *ldt;
/* virtual 86 mode info */
struct vm86_struct * vm86_info;
unsigned long screen_bitmap;
@@ -136,9 +160,15 @@
_LDT(0),0, \
0, 0x8000, \
{~0, }, /* ioperm */ \
- _TSS(0), 0, 0, 0, KERNEL_DS, \
+ _TSS(0) \
+}
+
+#define INIT_THREAD { \
+ 0, 0, 0, 0, 0, 0, &init_TSS[0], KERNEL_DS, /* CPU state */ \
+ 0, 0, 0, /* trap state */ \
{ { 0, }, }, /* 387 state */ \
- NULL, 0, 0, 0, 0, 0 /* vm86_info */, \
+ NULL, NULL, /* IO bitmap, LDT */ \
+ NULL, 0, 0, 0, 0, 0 /* vm86_info */ \
}

#define start_thread(regs, new_eip, new_esp) do {\
@@ -159,7 +189,7 @@
/*
* Return saved PC of a blocked thread.
*/
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+extern inline unsigned long thread_saved_pc(struct new_thread_struct *t)
{
return ((unsigned long *)t->esp)[3];
}
diff -ru --new-file 2.1.48-pre2/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- 2.1.48-pre2/include/asm-i386/uaccess..h Fri Aug 8 11:34:43 1997
+++ linux/include/asm-i386/uaccess.h Sat Aug 9 06:23:58 1997
@@ -18,8 +18,8 @@
* For historical reasons, these macros are grossly misnamed.
*/

-#define get_fs() (current->tss.segment)
-#define set_fs(x) (current->tss.segment = (x))
+#define get_fs() (current->thread.access_mode)
+#define set_fs(x) (current->thread.access_mode = (x))
#define get_ds() (KERNEL_DS)

/*
diff -ru --new-file 2.1.48-pre2/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- 2.1.48-pre2/include/asm-i386/unistd.h Thu Jun 26 21:33:39 1997
+++ linux/include/asm-i386/unistd.h Wed Aug 6 14:21:03 1997
@@ -314,7 +314,7 @@
:"=a" (retval)
:"0" (__NR_clone), "i" (__NR_exit),
"r" (arg), "r" (fn),
- "b" (flags | CLONE_VM)
+ "b" (flags | CLONE_VM | CLONE_TLB)
:"si");
return retval;
}
Binary files 2.1.48-pre2/include/asm-sparc/kgdb.h and linux/include/asm-sparc/kgdb.h differ
Binary files 2.1.48-pre2/include/asm-sparc/machines.h and linux/include/asm-sparc/machines.h differ
diff -ru --new-file 2.1.48-pre2/include/linux/sched.h linux/include/linux/sched.h
--- 2.1.48-pre2/include/linux/sched.h Fri Aug 8 11:34:28 1997
+++ linux/include/linux/sched.h Sat Aug 9 06:20:00 1997
@@ -29,6 +29,7 @@
#define CLONE_FILES 0x00000400 /* set if open files shared between processes */
#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */
#define CLONE_PID 0x00001000 /* set if pid shared */
+#define CLONE_TLB 0x00002000 /* set if TLB shared, kernel-only */

/*
* These are the constant used to fake the fixed-point load-average
@@ -244,10 +245,8 @@
/* ipc stuff */
struct sem_undo *semundo;
struct sem_queue *semsleeping;
-/* ldt for this task - used by Wine. If NULL, default_ldt is used */
- struct desc_struct *ldt;
-/* tss for this task */
- struct thread_struct tss;
+/* CPU-specific thread state */
+ struct new_thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
@@ -330,8 +329,7 @@
/* comm */ "swapper", \
/* fs info */ 0,NULL, \
/* ipc */ NULL, NULL, \
-/* ldt */ NULL, \
-/* tss */ INIT_TSS, \
+/* thread */ INIT_THREAD, \
/* fs */ &init_fs, \
/* files */ &init_files, \
/* mm */ &init_mm, \
diff -ru --new-file 2.1.48-pre2/init/main.c linux/init/main.c
--- 2.1.48-pre2/init/main.c Thu Jul 31 19:14:39 1997
+++ linux/init/main.c Sat Aug 9 05:22:38 1997
@@ -40,6 +40,7 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/bugs.h>
+#include <asm/switch.h>

#include <stdarg.h>

@@ -906,6 +907,11 @@
inode_init();
file_table_init();
sock_init();
+/*
+ * FIXME: this needs SLAB, so we cannot put it into setup_arch() ..
+ */
+ init_x86_IO_bitmap();
+
#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
ipc_init();
#endif
diff -ru --new-file 2.1.48-pre2/kernel/sched.c linux/kernel/sched.c
--- 2.1.48-pre2/kernel/sched.c Fri Aug 8 12:05:40 1997
+++ linux/kernel/sched.c Sat Aug 9 05:11:01 1997
@@ -33,6 +33,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/slab.h>

#include <asm/system.h>
#include <asm/io.h>
@@ -363,6 +364,8 @@

#endif

+#include <asm/switch.h>
+
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
@@ -376,7 +379,7 @@
asmlinkage void schedule(void)
{
int lock_depth;
- struct task_struct * prev, * next;
+ struct task_struct * prev, * next, * from;
unsigned long timeout;
int this_cpu;

@@ -476,15 +479,23 @@
timer.function = process_timeout;
add_timer(&timer);
}
+
get_mmu_context(next);
- switch_to(prev,next);
+ from = switch_threads(prev,next);

if (timeout)
del_timer(&timer);
- }
- spin_unlock(&scheduler_lock);
+
+ /*
+ * this function _has_ to release the scheduler lock!
+ */
+ put_mmu_context(from);
+
+ } else
+ spin_unlock(&scheduler_lock);

reacquire_kernel_lock(prev, smp_processor_id(), lock_depth);
+
return;

scheduling_in_interrupt:
@@ -1514,13 +1525,14 @@
if (p == current)
printk(" current ");
else
- printk(" %08lX ", thread_saved_pc(&p->tss));
+ printk(" %08lX ", thread_saved_pc(&p->thread));
#else
if (p == current)
printk(" current task ");
else
- printk(" %016lx ", thread_saved_pc(&p->tss));
+ printk(" %016lx ", thread_saved_pc(&p->thread));
#endif
+#warning hmm, whats this? --mingo
#if 0
for (free = 1; free < PAGE_SIZE/sizeof(long) ; free++) {
if (((unsigned long *)p->kernel_stack_page)[free])
@@ -1571,6 +1583,16 @@
int nr = NR_TASKS;

init_task.processor=cpu;
+ init_threads();
+
+ SET_PAGE_DIR(current,swapper_pg_dir);
+
+/*
+ * FIXME: see switch.h for details why this doesnt work.
+ */
+#if 0
+ init_task.thread.cr3=0; /* kernel thread, lazy TLB flush */
+#endif

/* Init task array free list and pidhash table. */
while(--nr > 0)