| 1 | |
| 2 | * Copyright (C) 1995 Linus Torvalds
|
| 3 | *
|
| 4 | * Pentium III FXSR, SSE support
|
| 5 | * Gareth Hughes <[email protected]>, May 2000
|
| 6 |
|
| 7 |
|
| 8 | |
| 9 | * This file handles the architecture-dependent parts of process handling..
|
| 10 |
|
| 11 |
|
| 12 | #include <linux/cpu.h>
|
| 13 | #include <linux/errno.h>
|
| 14 | #include <linux/sched.h>
|
| 15 | #include <linux/sched/task.h>
|
| 16 | #include <linux/sched/task_stack.h>
|
| 17 | #include <linux/fs.h>
|
| 18 | #include <linux/kernel.h>
|
| 19 | #include <linux/mm.h>
|
| 20 | #include <linux/elfcore.h>
|
| 21 | #include <linux/smp.h>
|
| 22 | #include <linux/stddef.h>
|
| 23 | #include <linux/slab.h>
|
| 24 | #include <linux/vmalloc.h>
|
| 25 | #include <linux/user.h>
|
| 26 | #include <linux/interrupt.h>
|
| 27 | #include <linux/delay.h>
|
| 28 | #include <linux/reboot.h>
|
| 29 | #include <linux/mc146818rtc.h>
|
| 30 | #include <linux/export.h>
|
| 31 | #include <linux/kallsyms.h>
|
| 32 | #include <linux/ptrace.h>
|
| 33 | #include <linux/personality.h>
|
| 34 | #include <linux/percpu.h>
|
| 35 | #include <linux/prctl.h>
|
| 36 | #include <linux/ftrace.h>
|
| 37 | #include <linux/uaccess.h>
|
| 38 | #include <linux/io.h>
|
| 39 | #include <linux/kdebug.h>
|
| 40 | #include <linux/syscalls.h>
|
| 41 |
|
| 42 | #include <asm/ldt.h>
|
| 43 | #include <asm/processor.h>
|
| 44 | #include <asm/fpu/sched.h>
|
| 45 | #include <asm/desc.h>
|
| 46 |
|
| 47 | #include <linux/err.h>
|
| 48 |
|
| 49 | #include <asm/tlbflush.h>
|
| 50 | #include <asm/cpu.h>
|
| 51 | #include <asm/debugreg.h>
|
| 52 | #include <asm/switch_to.h>
|
| 53 | #include <asm/vm86.h>
|
| 54 | #include <asm/resctrl.h>
|
| 55 | #include <asm/proto.h>
|
| 56 |
|
| 57 | #include "process.h"
|
| 58 |
|
| 59 | void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
|
| 60 | const char *log_lvl)
|
| 61 | {
|
| 62 | unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
|
| 63 | unsigned long d0, d1, d2, d3, d6, d7;
|
| 64 | unsigned int gs;
|
| 65 |
|
| 66 | savesegment(gs, gs);
|
| 67 |
|
| 68 | show_ip(regs, log_lvl);
|
| 69 |
|
| 70 | printk("%sEAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
|
| 71 | log_lvl, regs->ax, regs->bx, regs->cx, regs->dx);
|
| 72 | printk("%sESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n",
|
| 73 | log_lvl, regs->si, regs->di, regs->bp, regs->sp);
|
| 74 | printk("%sDS: %04x ES: %04x FS: %04x GS: %04x SS: %04x EFLAGS: %08lx\n",
|
| 75 | log_lvl, (u16)regs->ds, (u16)regs->es, (u16)regs->fs, gs, regs->ss, regs->flags);
|
| 76 |
|
| 77 | if (mode != SHOW_REGS_ALL)
|
| 78 | return;
|
| 79 |
|
| 80 | cr0 = read_cr0();
|
| 81 | cr2 = read_cr2();
|
| 82 | cr3 = __read_cr3();
|
| 83 | cr4 = __read_cr4();
|
| 84 | printk("%sCR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
|
| 85 | log_lvl, cr0, cr2, cr3, cr4);
|
| 86 |
|
| 87 | get_debugreg(d0, 0);
|
| 88 | get_debugreg(d1, 1);
|
| 89 | get_debugreg(d2, 2);
|
| 90 | get_debugreg(d3, 3);
|
| 91 | get_debugreg(d6, 6);
|
| 92 | get_debugreg(d7, 7);
|
| 93 |
|
| 94 |
|
| 95 | if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
|
| 96 | (d6 == DR6_RESERVED) && (d7 == DR7_FIXED_1))
|
| 97 | return;
|
| 98 |
|
| 99 | printk("%sDR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
|
| 100 | log_lvl, d0, d1, d2, d3);
|
| 101 | printk("%sDR6: %08lx DR7: %08lx\n",
|
| 102 | log_lvl, d6, d7);
|
| 103 | }
|
| 104 |
|
| 105 | void release_thread(struct task_struct *dead_task)
|
| 106 | {
|
| 107 | BUG_ON(dead_task->mm);
|
| 108 | release_vm86_irqs(dead_task);
|
| 109 | }
|
| 110 |
|
| 111 | void
|
| 112 | start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
|
| 113 | {
|
| 114 | loadsegment(gs, 0);
|
| 115 | regs->fs = 0;
|
| 116 | regs->ds = __USER_DS;
|
| 117 | regs->es = __USER_DS;
|
| 118 | regs->ss = __USER_DS;
|
| 119 | regs->cs = __USER_CS;
|
| 120 | regs->ip = new_ip;
|
| 121 | regs->sp = new_sp;
|
| 122 | regs->flags = X86_EFLAGS_IF;
|
| 123 | }
|
| 124 | EXPORT_SYMBOL_GPL(start_thread);
|
| 125 |
|
| 126 |
|
| 127 | |
| 128 | * switch_to(x,y) should switch tasks from x to y.
|
| 129 | *
|
| 130 | * We fsave/fwait so that an exception goes off at the right time
|
| 131 | * (as a call from the fsave or fwait in effect) rather than to
|
| 132 | * the wrong process. Lazy FP saving no longer makes any sense
|
| 133 | * with modern CPU's, and this simplifies a lot of things (SMP
|
| 134 | * and UP become the same).
|
| 135 | *
|
| 136 | * NOTE! We used to use the x86 hardware context switching. The
|
| 137 | * reason for not using it any more becomes apparent when you
|
| 138 | * try to recover gracefully from saved state that is no longer
|
| 139 | * valid (stale segment register values in particular). With the
|
| 140 | * hardware task-switch, there is no way to fix up bad state in
|
| 141 | * a reasonable manner.
|
| 142 | *
|
| 143 | * The fact that Intel documents the hardware task-switching to
|
| 144 | * be slow is a fairly red herring - this code is not noticeably
|
| 145 | * faster. However, there _is_ some room for improvement here,
|
| 146 | * so the performance issues may eventually be a valid point.
|
| 147 | * More important, however, is the fact that this allows us much
|
| 148 | * more flexibility.
|
| 149 | *
|
| 150 | * The return value (in %ax) will be the "prev" task after
|
| 151 | * the task-switch, and shows up in ret_from_fork in entry.S,
|
| 152 | * for example.
|
| 153 |
|
| 154 | __visible __notrace_funcgraph struct task_struct *
|
| 155 | __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
|
| 156 | {
|
| 157 | struct thread_struct *prev = &prev_p->thread,
|
| 158 | *next = &next_p->thread;
|
| 159 | int cpu = smp_processor_id();
|
| 160 |
|
| 161 |
|
| 162 |
|
| 163 | switch_fpu(prev_p, cpu);
|
| 164 |
|
| 165 | |
| 166 | * Save away %gs. No need to save %fs, as it was saved on the
|
| 167 | * stack on entry. No need to save %es and %ds, as those are
|
| 168 | * always kernel segments while inside the kernel. Doing this
|
| 169 | * before setting the new TLS descriptors avoids the situation
|
| 170 | * where we temporarily have non-reloadable segments in %fs
|
| 171 | * and %gs. This could be an issue if the NMI handler ever
|
| 172 | * used %fs or %gs (it does not today), or if the kernel is
|
| 173 | * running inside of a hypervisor layer.
|
| 174 |
|
| 175 | savesegment(gs, prev->gs);
|
| 176 |
|
| 177 | |
| 178 | * Load the per-thread Thread-Local Storage descriptor.
|
| 179 |
|
| 180 | load_TLS(next, cpu);
|
| 181 |
|
| 182 | switch_to_extra(prev_p, next_p);
|
| 183 |
|
| 184 | |
| 185 | * Leave lazy mode, flushing any hypercalls made here.
|
| 186 | * This must be done before restoring TLS segments so
|
| 187 | * the GDT and LDT are properly updated.
|
| 188 |
|
| 189 | arch_end_context_switch(next_p);
|
| 190 |
|
| 191 | |
| 192 | * Reload esp0 and cpu_current_top_of_stack. This changes
|
| 193 | * current_thread_info(). Refresh the SYSENTER configuration in
|
| 194 | * case prev or next is vm86.
|
| 195 |
|
| 196 | update_task_stack(next_p);
|
| 197 | refresh_sysenter_cs(next);
|
| 198 | this_cpu_write(cpu_current_top_of_stack,
|
| 199 | (unsigned long)task_stack_page(next_p) +
|
| 200 | THREAD_SIZE);
|
| 201 |
|
| 202 | |
| 203 | * Restore %gs if needed (which is common)
|
| 204 |
|
| 205 | if (prev->gs | next->gs)
|
| 206 | loadsegment(gs, next->gs);
|
| 207 |
|
| 208 | raw_cpu_write(current_task, next_p);
|
| 209 |
|
| 210 |
|
| 211 | resctrl_arch_sched_in(next_p);
|
| 212 |
|
| 213 | return prev_p;
|
| 214 | }
|