Operating Systems 2022F Lecture 3: Difference between revisions
Created page with "==Textbook Readings== * [https://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf 5. Process API]" |
No edit summary |
||
Line 1: | Line 1: | ||
==Video== | |||
Video from the lecture given on September 15, 2022 is now available: | |||
* [https://homeostasis.scs.carleton.ca/~soma/os-2022f/lectures/comp3000-2022f-lec03-20220915.m4v video] | |||
Sorry for the lack of subtitles and bad video quality, there were technical issues. | |||
==Textbook Readings== | ==Textbook Readings== | ||
* [https://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf 5. Process API] | * [https://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf 5. Process API] | ||
==Notes== | |||
<pre> | |||
Lecture 3 | |||
--------- | |||
Sorry about the Zoom technical glitches, we'll see how Teams works! | |||
The key material in this course is all in the tutorials | |||
- assignments are intended to see if you've learned what you should from | |||
the tutorials | |||
Remember for the tutorials you have until the corresponding assignment is due | |||
- you should try to finish them in a week | |||
- you get marks by showing your work to a TA | |||
- it doesn't have to be written, you just need to convince | |||
your TA that you made a serious effort at the tutorial | |||
In general, I'd try to get checked off at the end of the tutorial time | |||
- you may not have finished, but you can generally get checked off if | |||
you spend most of the time in tutorial working on the material | |||
- you'll likely want to spend more time afterwards making sure you understand everything | |||
- getting checked off just means you are on the way to understanding | |||
the material, not that you've finished | |||
Part of this class is realizing you have lots to learn, you'll always | |||
have lots to learn, and developing the skills to only learn *what you | |||
need to* to accomplish the tasks in front of you. | |||
- assembly language/machine code | |||
- libraries & library code | |||
- system calls | |||
Machine code: the code the CPU actually runs | |||
- bunch of numbers! | |||
- we don't want to program this way | |||
You can program in machine code directly, but that is VERY painful | |||
But there is a human-readable version: assembly code | |||
You can actually translate machine code into assembly, it is called "disassembly" of code | |||
Typically when we look at raw binary data, like machine code, we see it in hexadecimal notation. Why? | |||
- why not do decimals? | |||
- because each hex number corresponds to 4 bits | |||
- decimal numbers don't align on bit boundaries | |||
- octal is also used for a similar reason | |||
- each digit is 3 bits | |||
Now there are many kinds of machine code | |||
- that's what we are talking about when we say things like x86-64, ARMv7, etc | |||
When we create a program in a compiled language such as C, most tool chains do the following: | |||
Source -> assembly -> object files -> complete binary (runnable program) | |||
When looking at assembly | |||
- symbols starting with a . are assembler directives, they don't directly translate to machine code. | |||
- symbols ending with a : are memory locations that are referenced elsewhere | |||
- symbols starting with % refer to registers | |||
- fixed storage in the CPU that can actually be operated on | |||
- (data in memory can't be directly manipulated, it must be loaded into a register) | |||
- symbols starting with $ are constants (i.e., numbers) | |||
- in assembly language, functions get their arguments by looking into registers | |||
- which ones? that is purely by convention, and it varies | |||
- if there are too many arguments, they go on the stack | |||
We mostly don't work in assembly because it is | |||
- painful/overly verbose | |||
- minimal error checking (you can do whatever you want) | |||
- and is architecture specific | |||
- not so portable | |||
But sometimes we HAVE to work in assembly | |||
- because that is how you can access low-level CPU and hardware functionality | |||
Specifically, you HAVE to make system calls in assembly language, you can't make them directly in C or any other language | |||
So, what is a system call? | |||
2254 Emacs | | | |||
1122 Firefox | The Linux Kernel | The hardware | |||
1111 ls | | | |||
So, to a first approximation, the kernel is the part of the system that controls/manages the hardware, allows regular programs to run | |||
Turns out that regular processe do run directly on the CPU | |||
- they are in machine code, compiled from another language | |||
- BUT, the CPU is running in a limited capability mode | |||
The CPU runs in multiple modes | |||
- supervisor mode (ring 0 on Intel/AMD chips, x86) | |||
- CPU can access all resources | |||
- user mode (ring 3 on Intel/AMD chips, x86) | |||
- CPU can only access limited sets of resources | |||
Firefox, Emacs run in user mode | |||
the kernel runs in supervisor mode | |||
A system call is a request from user mode to supervisor mode | |||
- looks like a function call in code, often | |||
- BUT, causes the CPU to switch modes, and thus in a system | |||
call it can do things that can't be done otherwise | |||
If something is running in Ring 0/supervisor mode, it can access EVERYTHING | |||
- i.e., it can modify the kernel | |||
- so everything is at risk | |||
- and errors will crash your system | |||
A "kernel panic" is equivalent to a segfault in userpsace (but in kernel space) | |||
- but is much more serious obviously because the kernel is potentially corrupted | |||
What's different between user mode and supervisor mode? | |||
- RAM | |||
- user mode: limited | |||
- supervisor mode: all | |||
- network | |||
- user mode: sockets/defined routes | |||
- supervisor mode: can change network protocols, change how IP and TCP work | |||
- disk | |||
- user mode: files, directories, must obey file permissions | |||
- supervisor mode: disk blocks, filesystems (how files/directories are implemented), can ignore and in fact implements file permissions | |||
Kernel allocates resources and implements abstractions on those resources | |||
Because the CPU must change modes to run kernel code, you can't get make a system call through a simple function call (which just starts executing code at a different memory location) | |||
If a process wants to get more RAM, make a thread, access files, the network, the screen, keyboard - it MUST deal with the kernel, and thus must make system calls | |||
The set of all processes and regular programs on a system is called "userspace" to distinguish it from "kernel space", i.e., the stuff in the kernel | |||
"breaking userspace" means the API provided by the kernel has changed in a way that makes programs break | |||
- normally kernels are developed so they don't change their API in ways that break existing programs. If they want to do new things they add new interfaces (system calls, etc) | |||
Different kernels can have very different number of system calls | |||
- microkernels have very few system calls | |||
- the Windows NT kernel and the Linux kernel have lots of system calls | |||
- and the number keeps growing | |||
Windows has a system call interface, but it is private | |||
- programs make calls to the Win32/64 library, and it translates those into system calls in ways that may change between Windows releases | |||
An OS kernel is the basic technology that allows us to run multiple programs on a system at the same time and not have them mess with each other too much. | |||
"call" in assembly is a function call, it is NEVER a system call | |||
- BUT, it can be a call to a wrapper around a system call | |||
For example, the read system call is invoked using the C library read() function. | |||
In the C library, if you call a function defined in <unistd.h>, it is generally a thin wrapper around the corresponding system call | |||
NOTE THAT there exist system calls that have no standard wrapper | |||
- regular programs shouldn't be calling it, apparently | |||
- There is a C function "syscall" that allows you to make such system calls. | |||
So back to the tool chain | |||
Source -> assembly -> object files -> complete binary (runnable program) | |||
The object file is just a translation of the assembly into machine code | |||
To get a complete binary, ADDITIONAL CODE must be included | |||
- and by default, it is quite a bit of code | |||
- this code comes from the C library, implements all the things a C | |||
program expects to be there | |||
- standard functions | |||
- sets up the environment (code that runs before and after main()) | |||
Note that the default binary was much smaller but generated a lot more system calls, and the "-static" one was larger but generated fewer system calls | |||
Basic idea | |||
- default is "dynamic", it loads most of the code at runtime from | |||
separate files | |||
- "static" binaries have all the code included, no need to load in | |||
other files (libraries) at runtime, they were added in at compile time | |||
(linked in) | |||
SYSTEM CALLS DO NOT MAKE SYSTEM CALLS | |||
- we will discuss why next time | |||
</pre> |
Revision as of 17:19, 15 September 2022
Video
Video from the lecture given on September 15, 2022 is now available:
Sorry for the lack of subtitles and bad video quality, there were technical issues.
Textbook Readings
Notes
Lecture 3 --------- Sorry about the Zoom technical glitches, we'll see how Teams works! The key material in this course is all in the tutorials - assignments are intended to see if you've learned what you should from the tutorials Remember for the tutorials you have until the corresponding assignment is due - you should try to finish them in a week - you get marks by showing your work to a TA - it doesn't have to be written, you just need to convince your TA that you made a serious effort at the tutorial In general, I'd try to get checked off at the end of the tutorial time - you may not have finished, but you can generally get checked off if you spend most of the time in tutorial working on the material - you'll likely want to spend more time afterwards making sure you understand everything - getting checked off just means you are on the way to understanding the material, not that you've finished Part of this class is realizing you have lots to learn, you'll always have lots to learn, and developing the skills to only learn *what you need to* to accomplish the tasks in front of you. - assembly language/machine code - libraries & library code - system calls Machine code: the code the CPU actually runs - bunch of numbers! - we don't want to program this way You can program in machine code directly, but that is VERY painful But there is a human-readable version: assembly code You can actually translate machine code into assembly, it is called "disassembly" of code Typically when we look at raw binary data, like machine code, we see it in hexadecimal notation. Why? - why not do decimals? - because each hex number corresponds to 4 bits - decimal numbers don't align on bit boundaries - octal is also used for a similar reason - each digit is 3 bits Now there are many kinds of machine code - that's what we are talking about when we say things like x86-64, ARMv7, etc When we create a program in a compiled language such as C, most tool chains do the following: Source -> assembly -> object files -> complete binary (runnable program) When looking at assembly - symbols starting with a . are assembler directives, they don't directly translate to machine code. - symbols ending with a : are memory locations that are referenced elsewhere - symbols starting with % refer to registers - fixed storage in the CPU that can actually be operated on - (data in memory can't be directly manipulated, it must be loaded into a register) - symbols starting with $ are constants (i.e., numbers) - in assembly language, functions get their arguments by looking into registers - which ones? that is purely by convention, and it varies - if there are too many arguments, they go on the stack We mostly don't work in assembly because it is - painful/overly verbose - minimal error checking (you can do whatever you want) - and is architecture specific - not so portable But sometimes we HAVE to work in assembly - because that is how you can access low-level CPU and hardware functionality Specifically, you HAVE to make system calls in assembly language, you can't make them directly in C or any other language So, what is a system call? 2254 Emacs | | 1122 Firefox | The Linux Kernel | The hardware 1111 ls | | So, to a first approximation, the kernel is the part of the system that controls/manages the hardware, allows regular programs to run Turns out that regular processe do run directly on the CPU - they are in machine code, compiled from another language - BUT, the CPU is running in a limited capability mode The CPU runs in multiple modes - supervisor mode (ring 0 on Intel/AMD chips, x86) - CPU can access all resources - user mode (ring 3 on Intel/AMD chips, x86) - CPU can only access limited sets of resources Firefox, Emacs run in user mode the kernel runs in supervisor mode A system call is a request from user mode to supervisor mode - looks like a function call in code, often - BUT, causes the CPU to switch modes, and thus in a system call it can do things that can't be done otherwise If something is running in Ring 0/supervisor mode, it can access EVERYTHING - i.e., it can modify the kernel - so everything is at risk - and errors will crash your system A "kernel panic" is equivalent to a segfault in userpsace (but in kernel space) - but is much more serious obviously because the kernel is potentially corrupted What's different between user mode and supervisor mode? - RAM - user mode: limited - supervisor mode: all - network - user mode: sockets/defined routes - supervisor mode: can change network protocols, change how IP and TCP work - disk - user mode: files, directories, must obey file permissions - supervisor mode: disk blocks, filesystems (how files/directories are implemented), can ignore and in fact implements file permissions Kernel allocates resources and implements abstractions on those resources Because the CPU must change modes to run kernel code, you can't get make a system call through a simple function call (which just starts executing code at a different memory location) If a process wants to get more RAM, make a thread, access files, the network, the screen, keyboard - it MUST deal with the kernel, and thus must make system calls The set of all processes and regular programs on a system is called "userspace" to distinguish it from "kernel space", i.e., the stuff in the kernel "breaking userspace" means the API provided by the kernel has changed in a way that makes programs break - normally kernels are developed so they don't change their API in ways that break existing programs. If they want to do new things they add new interfaces (system calls, etc) Different kernels can have very different number of system calls - microkernels have very few system calls - the Windows NT kernel and the Linux kernel have lots of system calls - and the number keeps growing Windows has a system call interface, but it is private - programs make calls to the Win32/64 library, and it translates those into system calls in ways that may change between Windows releases An OS kernel is the basic technology that allows us to run multiple programs on a system at the same time and not have them mess with each other too much. "call" in assembly is a function call, it is NEVER a system call - BUT, it can be a call to a wrapper around a system call For example, the read system call is invoked using the C library read() function. In the C library, if you call a function defined in <unistd.h>, it is generally a thin wrapper around the corresponding system call NOTE THAT there exist system calls that have no standard wrapper - regular programs shouldn't be calling it, apparently - There is a C function "syscall" that allows you to make such system calls. So back to the tool chain Source -> assembly -> object files -> complete binary (runnable program) The object file is just a translation of the assembly into machine code To get a complete binary, ADDITIONAL CODE must be included - and by default, it is quite a bit of code - this code comes from the C library, implements all the things a C program expects to be there - standard functions - sets up the environment (code that runs before and after main()) Note that the default binary was much smaller but generated a lot more system calls, and the "-static" one was larger but generated fewer system calls Basic idea - default is "dynamic", it loads most of the code at runtime from separate files - "static" binaries have all the code included, no need to load in other files (libraries) at runtime, they were added in at compile time (linked in) SYSTEM CALLS DO NOT MAKE SYSTEM CALLS - we will discuss why next time