Low-Level Thread Dispatching on the x86

Slides:



Advertisements
Similar presentations
CS 4284 Systems Capstone Godmar Back Processes and Threads.
Advertisements

R4 Dynamically loading processes. Overview R4 is closely related to R3, much of what you have written for R3 applies to R4 In R3, we executed procedures.
Assembly Language for x86 Processors 6th Edition Chapter 5: Procedures (c) Pearson Education, All rights reserved. You may modify and copy this slide.
C Programming and Assembly Language Janakiraman V – NITK Surathkal 2 nd August 2014.
1 Operating Systems and Protection CS Goals of Today’s Lecture How multiple programs can run at once  Processes  Context switching  Process.
Context Switch Animation Another one by Anastasia.
Assembly Language for Intel-Based Computers Chapter 5: Procedures Kip R. Irvine.
Project 2 Roadmap. Background – Context Switching One processor and multiple threads running concurrently – How?!! Give each thread a small time quantum.
Context switch in Linux
PC hardware and x86 3/3/08 Frans Kaashoek MIT
1 Lecture 5: Procedures Assembly Language for Intel-Based Computers, 4th edition Kip R. Irvine.
Accessing parameters from the stack and calling functions.
Practical Session 3. The Stack The stack is an area in memory that its purpose is to provide a space for temporary storage of addresses and data items.
ICS312 Set 3 Pentium Registers. Intel 8086 Family of Microprocessors All of the Intel chips from the 8086 to the latest pentium, have similar architectures.
Web siteWeb site ExamplesExamples Irvine, Kip R. Assembly Language for Intel-Based Computers, Stack Operations Runtime Stack PUSH Operation POP.
CEG 320/520: Computer Organization and Assembly Language ProgrammingIntel Assembly 1 Intel IA-32 vs Motorola
6.828: PC hardware and x86 Frans Kaashoek
Computer Architecture and Operating Systems CS 3230 :Assembly Section Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.
Multitasking Mr. Mahendra B. Salunke Asst. Prof. Dept. of Computer Engg., STES SITS, Narhe, Pune-41 STES Sinhgad Institute of Tech. & Science Dept. of.
Today’s topics Parameter passing on the system stack Parameter passing on the system stack Register indirect and base-indexed addressing modes Register.
Assembly Language for Intel-Based Computers, 6 th Edition Chapter 8: Advanced Procedures (c) Pearson Education, All rights reserved. You may.
IA32 (Pentium) Processor Architecture. Processor modes: 1.Protected (mode we will study) – 32-bit mode – 32-bit (4GB) address space 2.Virtual 8086 modes.
CS216: Program and Data Representation University of Virginia Computer Science Spring 2006 David Evans Lecture 22: Unconventional.
Exception Compiler Baojian Hua
Microprocessor system architectures – IA32 tasks Jakub Yaghob.
Chapter 2 Parts of a Computer System. 2.1 PC Hardware: Memory.
Functions/Methods in Assembly
6. HAL and IDT ENGI 3655 Lab Sessions. Richard Khoury2 Textbook Readings  Interrupts ◦ Section  Hardware Abstraction Layer ◦ Section
1 The Stack and Procedures Chapter 5. 2 A Process in Virtual Memory  This is how a process is placed into its virtual addressable space  The code is.
Assembly 08 Interrupts. Introduction Interrupts are similar to procedures –They are used to alter a program’s control flow –The interrupt service is also.
What You Need to Know for Project Three Steve Muckle Wednesday, February 19 th Spring 2003.
Introduction to Intel IA-32 and IA-64 Instruction Set Architectures.
1 Assembly Language: Function Calls Jennifer Rexford.
CSC 221 Computer Organization and Assembly Language Lecture 16: Procedures.
Assembly Language Data Movement Instructions. MOV Instruction Move source operand to destination mov destination, source The source and destination are.
CSC 221 Computer Organization and Assembly Language Lecture 15: STACK Related Instructions.
Microprocessors CSE- 341 Dr. Jia Uddin Assistant Professor, CSE, BRAC University Dr. Jia Uddin, CSE, BRAC University.
Assembly Language Addressing Modes. Introduction CISC processors usually supports more addressing modes than RISC processors. –RISC processors use the.
Chapter Overview General Concepts IA-32 Processor Architecture
Practical Session 3.
Stack Operations Dr. Hadi AL Saadi.
Assembly function call convention
Computer Architecture and Assembly Language
Homework / Exam Return and Review Exam #1 Reading Machine Projects
Assembly language.
C function call conventions and the stack
Operating Systems Engineering
Anton Burtsev February, 2017
Exploiting & Defense Day 2 Recap
Aaron Miller David Cohen Spring 2011
Chapter 4 Data Movement Instructions
Basic Microprocessor Architecture
Assembly IA-32.
Computer Architecture and Assembly Language
Stack Frames and Advanced Procedures
Introduction to Intel IA-32 and IA-64 Instruction Set Architectures
Assembly Language Programming II: C Compiler Calling Sequences
CS 301 Fall 2002 Computer Organization
Discussions on HW2 Objectives
Practical Session 4.
EECE.3170 Microprocessor Systems Design I
EECE.3170 Microprocessor Systems Design I
Multi-modules programming
Week 2: Buffer Overflow Part 1.
Computer Architecture CST 250
Discussions on HW2 Objectives
X86 Assembly Review.
CHAPTER 6 INPUT/OUTPUT PROGRAMMING
CSC 497/583 Advanced Topics in Computer Security
Computer Architecture and System Programming Laboratory
Presentation transcript:

Low-Level Thread Dispatching on the x86 Dispatching and Exception Handling RECAP: Exception Handling in the x86 How to use Exception Handling mechanisms for Dispatching RECAP: The Thread Control Block (TCB) in class Thread Dispatching in 4 Steps: Start, Store, Locate, Load Creating a Thread The Execution Lifecycle of a Thread

Low-Level Thread Dispatching Low-level Dispatch Thread::dispatch_to(Thread * _thread); Store state of current thread execution and load state of target thread onto CPU. Dispatching in 3 steps: Save state of current thread Load state of new thread Continue execution of new thread

Low-Level Thread Dispatching Dispatching in 3 steps: Save state of current thread Load state of new thread Continue execution of new thread Problems: How do we save the state of the current thread? How do we load the state of the new thread? How do we continue execution of new thread?!

Low-Level Thread Dispatching Problems: How do we save the state of the current thread? How do we load the state of the new state? How do we continue execution of new thread?! Q: Where else do we have the same problem? A: When we handle exceptions. Solution: Handle Thread Dispatching (somewhat) in the same manner!

RECAP: Exception Handling ; 0: Divide By Zero Exception _isr0: push byte 0 ; push dummy push byte 0 ; push interrupt no jmp isr_common_stub extern _dispatch_exception ; The common ISR stub. isr_common_stub: pusha push ds push es push fs push gs mov eax, esp push eax mov eax, _dispatch_exc call eax pop eax pop gs pop fs pop es pop ds popa add esp, 8 ; pop code and int no iret global _isr0 global _isr1 global _isr2 ... global _isr8 … global _isr30 global _isr31 ; 8: Double Fault Exception (Error Code!) _isr8: ; don’t push dummy! push byte 8 ; push interrupt no jmp isr_common_stub /* This defines what the stack looks like when the exception/interrupt reaches the exception dispatcher. */ typedef struct regs { unsigned int gs, fs, es, ds, /* pushed in common stub */ unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by pusha */ unsigned int int_no, err_code; /* pushed in _isrXX */ unsigned int eip, cs, eflags; /* pushed by processor */ } REGS;

RECAP: Saving and Loading State ; 0: Divide By Zero Exception _isr0: push byte 0 ; push dummy push byte 0 ; push interrupt no jmp isr_common_stub extern _dispatch_exception ; The common ISR stub. isr_common_stub: pusha push ds push es push fs push gs mov eax, esp push eax mov eax, _dispatch_exc call eax ; call exc dispatcher pop eax pop gs pop fs pop es pop ds popa add esp, 8 ; pop code and int no iret global _isr0 global _isr1 global _isr2 ... global _isr8 … global _isr30 global _isr31 Here we save the state Here we load the state

Saving and Restoring the State thread exception dispatcher exception handler exception function call thread “suspended”, waiting for exception handler to return iret return from function call return from interrupt

Saving and Restoring the State thread iret

Saving and Restoring the State thread Load another thread’s state! iret return from function call

Dispatching, Example Thread A Thread B Thread B “suspended” call function Thread::dispatch_to(B) Thread B “suspended” iret returns from previous call to Thread::dispatch_to(...) Thread A “suspended” call function Thread::dispatch_to(A) returns from previous call to Thread::dispatch_to(B) iret

RECAP: Structure of a Thread class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ int thread_id; /* thread identifier. Assigned upon creation. */ char * stack; /* pointer to the stack of the thread.*/ unsigned int stack_size; /* size of the stack (in byte) */ int priority; /* Maybe the scheduler wants to use priorities. */ etc... Thread Control Block TCB: thread id stack stackptr priority bookkeeping etc… stack top of stack

Dispatching Step-by-Step: 0. Start void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr _thread

Dispatching Step-by-Step: 1. Fix Stack void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack push eax ; save eax mov eax, [esp+4] ; get return address mov [esp-4], eax ; move return addr ; down 8 bytes from orig loc add esp, 8 ; move stack ptr up pushfd ; put eflags where return address was mov eax, [esp-4] ; restore saved value of eax push dword KERNEL_CS ; push cs selector sub esp, 4 ; point stack ptr ; at return address ; STEP 2: ... ... return_addr KERNEL_CS return_addr eflags _thread _thread

Dispatching Step-by-Step: 2. Save State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 int_no err_no return_addr KERNEL_CS eflags _thread

Dispatching Step-by-Step: 2. Save State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread

Dispatching Step-by-Step: 2. Save State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad push ds push es push fs push gs ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread

Dispatching Step-by-Step: 2. Save State class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ int thread_id; /* thread identifier. Assigned upon creation. */ char * stack; /* pointer to the stack of the thread.*/ unsigned int stack_size; /* size of the stack (in byte) */ int priority; /* Maybe the scheduler wants to use priorities. */ etc... gs void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad push ds push es push fs push gs ; Save stack pointer in the thread control block ; (at offset 0). mov eax, [_current_thread] mov [eax+0], esp ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread

Dispatching Step-by-Step: 3. Locate State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread mov eax, dword [esp+INTERRUPT_STATE_SIZE] ds edi esi ebp esp INTERRUPT_STATE_SIZE (68 Bytes) ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread

Dispatching Step-by-Step: 3. Locate State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs fs es es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread mov eax, dword [esp+INTERRUPT_STATE_SIZE] ; Make the new thread current, and switch to its stack. mov [_current_thread], eax mov esp, [eax+0] ds ds edi edi esi esi ebp ebp esp esp ebx ebx edx edx ecx ecx eax eax class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ etc... new thread int_no int_no err_no err_no return_addr return_addr KERNEL_CS KERNEL_CS eflags eflags _somethread _thread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _somethread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad int_no err_no return_addr KERNEL_CS eflags _somethread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad add esp, 8 ; skip int num and error code return_addr KERNEL_CS eflags _somethread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad add esp, 8 ; skip int num and error code ; We'll return to the place where the thread was ; executing last. iret void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr KERNEL_CS eflags _somethread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr KERNEL_CS eflags _somethread

Dispatching Step-by-Step: 4. Load State void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _somethread

Dispatching Step-by-Step: 4. Load State _somethread

Dispatching Step-by-Step: 4. Load State

Creating a Thread push tshutdown ret_addr void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); } inline void Thread::push(unsigned long _val) { stack_ptr -= 4; *((unsigned long *) stack_ptr) = _val; } push tshutdown ret_addr

Creating a Thread push _tfunction ret_addr push tshutdown ret_addr void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); } push _tfunction ret_addr push tshutdown ret_addr

Creating a Thread push thread_start eip push KERNEL_CS es push 0 void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); } push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr

Creating a Thread push 0 int_no push 0 err_code push thread_start eip void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); } push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr

Creating a Thread push 0 edi push 0 esi push 0 ebp push 0 esp push 0 void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); /* Initial values for general-purpose registers. */ push(0); ...; push(0); /* eax ... edi */ } push 0 edi push 0 esi push 0 ebp push 0 esp push 0 ebx push 0 edx push 0 ecx push 0 eax push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr

Creating a Thread push 0 gs push 0 fs push KERNEL_CS es push KERNEL_CS void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); /* Initial values for general-purpose registers. */ push(0); ...; push(0); /* eax ... edi */ /* Segment registers */ push(Machine::KERNEL_DS); /* ds */ push(Machine::KERNEL_DS); /* es */ push(0); push(0); /* fs; gs */ } push 0 gs push 0 fs push KERNEL_CS es push KERNEL_CS ds push 0 edi push 0 esi push 0 ebp push 0 esp push 0 ebx push 0 edx push 0 ecx push 0 eax push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr

Execution Lifecycle of a Thread gs fs es ds edi esi ebp esp ebx edx ecx eax int_no err_code push 0 push KERNEL_CS void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } push thread_start eip push KERNEL_CS es push 0 eflags push t_fun_1 ret_addr push tshutdown ret_addr

Execution Lifecycle of a Thread void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } push thread_start eip push KERNEL_CS es push 0 eflags push t_fun_1 ret_addr push tshutdown ret_addr

Execution Lifecycle of a Thread static void thread_start() { /* This function is used to release the thread for execution in the ready queue. */ /* We need to add code, but it is probably nothing more than enabling interrupts. */ } push t_fun_1 ret_addr push tshutdown ret_addr

Execution Lifecycle of a Thread void t_fun_1() { /* do_something_in_this_thread */ } push tshutdown ret_addr

Execution Lifecycle of a Thread static void tshutdown() { /* terminates thread after thread func returns*/ }

Execution Lifecycle of a Thread

Low-Level Dispatching on the x86 : Summary We learned: Dispatching can be implemented similarly to exception handlers. (Side Note: This approach is very general and portable.) Implementation of the Thread Control Block in C++ class Thread Dispatching in 4 Steps: Start, Store, Locate, Load Thread Creation The Execution Lifecycle of a Thread