KEMBAR78
Chapter-2 - Operating Systems Organization | PDF | Kernel (Operating System) | Booting
0% found this document useful (0 votes)
8 views33 pages

Chapter-2 - Operating Systems Organization

.

Uploaded by

fawad.sidd17
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views33 pages

Chapter-2 - Operating Systems Organization

.

Uploaded by

fawad.sidd17
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

Operating System

Organization
Chapter 2
Introduction

Jobs of an OS
1. Time-sharing of hardware resources among processes
2. Isolation of processes
3. Interaction between processes (how, remember?)

Monolithic Kernel as in Unix and inspired OS’s.


Xv6 is written in LP64C->Long and pointers are 64 bits, integers is 32 bits
Introduction

64-bit RISC-V emulated in QEMU


UART
RAM Keyboard
Core 1 Core 2

ROM
Bootloader

DISK
2.2 User mode, supervisor mode, and system calls
RISC-V Hardware Modes
Machine Mode Privileged Registers
mtvec
Supervisor Mode
mcause
User Mode stvec mepc
sepc mret
scause mscratch
sscratch
sstatus
satp

System call: ecall


instruction
In RISC-V
2.2 User mode, supervisor mode, and system calls
2.3 Kernel
Organization
1. Monolithic Kernel
a. All system calls run in supervisor mode, an error in user
program may cause kernel to fail
b. Complex interfaces between parts
c. Difficult to expand
2. Micro Kernel
a. Simpler interfaces
b. Modular design so easy to expand
c. System calls may run in user mode so microkernels do not
easily fail
3. Xv6 is monolithic but still much smaller than microkernels of
commercial OS’s
2.5 Process Overview
● Xv6 is written in “LP64” C meaning
64-bit longs & pointers and 32 bit Process
integers
● RISC-V uses only 39 bits addressing
● Xv6 uses only 38 bits
● MAXVA=2^38
=0x40000_00000
256 Gibibytes
2.5 Process Overview- Data Structures
https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/proc.h

Where is file
descriptor table
here?
How to access fields of p?
2.5 Process Overview- Data Structures p->kstack
https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/proc.h p->pagetable
p->state

State info running on CPU


2.5 Process Overview- Data Structures
● In summary, a process bundles two design ideas: an address space to give a
process the illusion of its own memory, and, a thread, to give the process the
illusion of its own CPU.
● In xv6, a process consists of one address space and one thread. In real
operating systems a process may have more than one thread to take
advantage of multiple CPUs.
2.6 XV6 Start-up
Sequence
Step 1-Boot loading xv6 kernel into physical memory
(RAM)
(a) When the RISC-V computer powers on, it initializes itself and runs a boot
loader which is stored in read-only memory.

(b) The bootloader loads the xv6 kernel into memory at physical address
0x8000_0000. The address range 0x0:0x7FFF_FFFF is used for I/O devices
such as ROM, DISK, UART, PLIC.
Step 1-Memory mapped I/O Devices

Emulated I/O Devices in QEMU


● Boot ROM
● Core-Level Interrupt (CLINT)
such as software and timer
interrupts
● Platform Level Interrupt
(PLIC) such as signals from
I/O devices including other
HARTs (hardware threads)
● HART=CPU=Core
Step 1
Phase-Locked Loop Design
https://www.linkedin.com/
posts/salmanzaffar_pll-an
alogdesign-analog-activity
-7084766446332821504-
Z6HU?utm_source=share
&utm_medium=member_
desktop
Step 2-Stack Initialization

(a) In Machine Mode, the CPU


executes xv6 starting at _entry in
(kernel/entry.S:7). This is the start
of kernel code execution
(b) The RISC-V starts with paging
hardware disabled: virtual
addresses map directly to
physical addresses. This is why
KERNBASE=0x8000_0000
Step 2-Stack Initialization
Step 2-Stack Initialization

(a) The instructions at _entry setup a stack


so that xv6 can run C code.
(b) Xv6 declares space for an initial stack,
stack0, in the file start.c 0x20
(kernel/start.c:11) 0x10
__attribute__ ((aligned (16))) char stack0[4096 * NCPU]; 0x00
(c) The code at _entry loads the stack
pointer register sp with the address
stack0+4096, the top of the sub-stack
for first CPU, because the stack on
RISC-V grows down.
Step 3-Interrupt Handling
(a) Hardware interrupt configuration: Delegation from M-mode to S-mode
(b) M-mode to S-mode return sequence

https://tools.cloudbear.ru/docs/riscv-privileged-1.12-20211203.pdf
Step 3-Interrupt Handling
(a) Hardware interrupt configuration
(b) M-mode to S-mode return sequence
Step 3-From M-mode to S-Mode

When mret instruction is called, program


execution jumps to the address held in mepc

https://tools.cloudbear.ru/docs/riscv-privileged-1.12-20211203.pdf
Array of Functions in C
#include <stdio.h>
// Define some simple functions
void sayHello() { printf("Hello!\n"); }
void sayGoodbye() { printf("Goodbye!\n"); }
void askQuestion() { printf("How are you?\n"); }
int main() {
// 1. Create an array of function pointers
void (*functionArray[3])() = {sayHello, askQuestion, sayGoodbye};
// 2. Access and call a function by its index
functionArray[0](); // Output: "Hello!"
Hello!
// 3. Loop through and call every function
printf("Making introductions:\n"); Making introductions:
for(int i = 0; i < 3; i++) { Hello!
functionArray[i]();
} How are you?
return 0; Goodbye!
}

Note: We can pass arguments to functions


Step 4-Final steps before launch
(a) Powering up cores
(b) Main CPU leads

A variable changeable by an external hardware too

What does this do?


Leader CPU
Boot HART
NB HARTS
Silence :)!
1. The started flag is set earlier in some versions of xv6. In some implementations, the started = 1 line might be
placed before the call to userinit(). This would allow the non-boot harts to start printing their messages while the
boot hart is still working on creating the first user process, perfectly explaining your observation.
○ Boot hart sets started = 1
○ Non-boot harts break from the loop and print their messages.
○ Boot hart then finishes by calling userinit(), which prints the shell message.
2. Race Condition and Console Output Buffering: Even if started is set after userinit(), the console driver might have
buffers. The printf from the shell process might be sitting in a buffer while the printf from the kernel (hart 2)
immediately flushes to the hardware. The non-boot hart's message could "win" the race to the screen.
Step 4-Final steps before launch
(a) First process created in kernel uvmfirst(). Any guess? For which program?
(b) Overall execution moves to user space, only to come to kernel space through ecall
(c) initcode.S (in hex format) is placed in process to mimic running the first system call exec
Step 4-Final steps before launch
(a) Number 7 being stored in a7 which will be read to initiate the exec command
Step 4-Final steps before launch

Replaces first
process
userinit() with
init. exec returns
only if error
Step 4-Launch

If console is not yet created, create it and


then open it. File descriptors assigned.

childless process
child created

exec executes sh.c in child so shell occupies the


(: ‫ ﻻﻧﭻ ﮨو ﮔﯾﺎ ﮨﮯ۔‬xv6 ‫ﺗو‬ child address space now
Step 4-Launch
2.7 Security Model

Vulnerabilities on User Side Kernel Side


Dereference pointers outside its allowed
Written by careful programmers
address space

Execute those RISC-V instructions not


Bug-free and no malicious code
intended for user-space

RISC-V CPU, RAM and Disk are all


Read or write RISC-V CSRs
assumed to operate as advertised

Passing clever values to systems calls in


an attempt to trick kernel into crashing or
doing something stupid
2.7 Security Model
Of course in real life things are not so straightforward.

● It’s difficult to prevent clever user code from making a system unusable (or causing it to panic) by
consuming kernel-protected resources – disk space, CPU time, process table slots, etc.
● It’s usually impossible to write bug-free code or design bug-free hardware; if the writers of malicious
user code are aware of kernel or hardware bugs, they will exploit them. Even in mature, widely-used
kernels, such as Linux, people discover new vulnerabilities continuously [1].
● It’s worthwhile to design safeguards into the kernel against the possibility that it has bugs: assertions,
type checking, stack guard pages, etc.
● Finally, the distinction between user and kernel code is sometimes blurred: some privileged user-level
processes may provide essential services and effectively be part of the operating system, and in some
operating systems privileged user code can insert new code into the kernel (as with Linux’s loadable
kernel modules).
Assignments in C Language
#include <stdio.h>
#include <unistd.h>

// Function prototypes for system calls


void syscall1() { We define two functions, syscall1 and syscall2, which
printf("Executing System Call 1\n");
} simulate system calls by printing messages to the
void syscall2() { console.
printf("Executing System Call 2\n");
}
// Array of function pointers We create an array of function pointers named syscall,
void (*syscall[2])() = {syscall1, syscall2}; which holds the addresses of these two functions.

int main() {
In the main function, we invoke syscall[1](), which calls
// Invoking the second system call
syscall[1](); // This will call syscall2 syscall2, resulting in the output: "Executing System Call
return 0; 2".
}

You might also like