- xv6 kernel uses the file descriptor as an index into a per-process table, so that every process has a private space of file descriptors starting at zero
- Two file descriptors share an offset if they were derived from the same original file descriptor by a sequence of fork and dup calls
- A newly allocated file descriptor is always the lowest-numbered unused descriptor of the current process
-
fork
fork copies the parent’s file descriptor table along with its memory
underlying file offset is shared between parent and child
if(fork() == 0) { write(1, "hello ", 6); exit(); } else { wait(); write(1, "world\n", 6); } // hello world
-
exec
replaces the calling process’s memory but preserves its file table
-
dup
both file descriptors share an offset
fd = dup(1); write(1, "hello ", 6); write(fd, "world\n", 6); // hello world
int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
} else {
close(p[0]);
write(p[1], "hello world\n", 12);
close(p[1]);
}
echo hello world | wc
echo hello world >/tmp/xyz; wc </tmp/xyz
-
user/kernel mode flag
kernel / user stack
hardware privilege level
-
address spaces
page table
kernel / user space arrangement?
MMU
-
time-slicing
context switch
- physical mem management
- virtual/phy mem mapping
- kernel/user mem privilege
-
what's segmentation?
-
what's paging and why is it needed?
-
privilege level implementation with segmentation and paging?
- The indirect jump is needed because the assembler would otherwise generate a PC-relative direct jump, which would execute the low-memory version of main?
- Modify xv6 so that the pages for the kernel are shared among processes, which reduces memory consumption
**IA-32 Volume 3(System Programming Guide): **chapter 3 protected-mode memory management
Intel 80386 Reference Programmer's Manual : Chapter 5-Memory Management & Chapter 6-Protection
segmentation is a way of dividing memory for programs:
- flat model
- protected flat model
- multi-segmented model
most os today uses flat model, which amounts to not using segmentation. Since it would require programs all loaded in memory, does not make economical sense.
- index: 15-3, support 8192 descriptors in GDT
- TI: 0=GDT, 1=LDT
- RPL: Requested Privilege Level (RPL), RPL & CPL & DPL
When a segment selector is loaded into the visible part of a segment register, the processor also loads the hidden part of the segment register with the base address, segment limit, and access control information from the segment descriptor pointed to by the segment selector
two kinds of instructions for loading segment registers:
- MOV, POP, LDS, LES, LSS, LGS, and LFS
- CALL, JMP, and RET, IRET, INTn, INTO and INT3, these instructions change the CS register
if the S bit 0 for system descriptor, 1 for segment descriptor
segment descriptor:GDTR Register
A segment descriptor is a data structure in a GDT or LDT that provides the processor with the size and location of a segment, as well as access control and status information. Segment descriptors are typically created by compilers, linkers, loaders, or the operating system or executive, but not application programs
two types of segment descriptor (stack is also data): code and data
All data segments are nonconforming, meaning that they cannot be accessed by less privileged programs or procedures
(code segment) A transfer of execution into a more-privileged conforming segment allows execution to continue at the current privilege level
Global and Local Descriptor Tables
system descriptor: IDTR register
- Local descriptor-table (LDT) segment descriptor
- Task-state segment (TSS) descriptor
- Call-gate descriptor
- Interrupt-gate descriptor
- Trap-gate descriptor
- Task-gate descriptor
To effiently share physical memory between multiple tasks, given them a 4Gb consistent view of address space.
- PG (paging) flag. Bit 31 of CR0
- PDBR: the physical address of the current page directory is stored in the CR3 register
- TLBs: the processor stores the most recently used page-directory and page-table entries in on-chip caches called translation lookaside buffers or TLBs. INVLPG instruction is provided to invalidate a specific page-table entry in the TLB
enable paging
# Load the physical address of entry_pgdir into cr3. entry_pgdir
# is defined in entrypgdir.c.
movl $(RELOC(entry_pgdir)), %eax
movl %eax, %cr3
# Turn on paging.
movl %cr0, %eax
orl $(CR0_PE|CR0_PG|CR0_WP), %eax
movl %eax, %cr0
initial paging directory
pde_t entry_pgdir[1024] = {
// Map VA's [0, 4MB) to PA's [0, 4MB)
[0] = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P,
// Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB)
[KERNBASE>>PDXSHIFT] = ((uintptr_t)entry_pgtable - KERNBASE) + PTE_P + PTE_W
};
// Entry 0 of the page table maps to physical page 0, entry 1 to
// physical page 1, etc.
pte_t entry_pgtable[1024] = {
0x000000 | PTE_P | PTE_W,
0x001000 | PTE_P | PTE_W,
...
0x3ff000 | PTE_P | PTE_W }
- Descriptor privilege level (DPL). The DPL is the privilege level of a segment or gate. It is stored in the DPL field of the segment or gate descriptor for the segment or gate
- Current privilege level (CPL): The CPL is the privilege level of the currently executing program or task. It is stored in bits 0 and 1 of the CS and SS segment registers. Normally, the CPL is equal to the privilege level of the code segment from which instructions are being fetched
- Requested privilege level (RPL). The RPL is an override privilege level that is assigned to segment selectors. It is stored in bits 0 and 1 of the segment selector.
- A segment selector is a 16 bit value held in a segment register
important facts
-
before the processor loads a segment selector into a segment register, it performs a privilege check
-
implicit use of segment registers, I.e. “ESP” == “SS:ESP”, “EIP” == “CS:EIP”
from above pics, only after the check passed can the segment descriptor content be put into correponding register designated by the segment selector, and with base, limits, access info put into hidden parts. That is to say segment selector is just a dynamic temp value, is under software control.
CPL == RPL == DPL
-
no privilege-level checks for near forms of the JMP, CALL, and RET instructions transfer program control within the current code segment
-
for far form accessing nonconforming code segments, CPL == DPL and RPL <= CPL
-
for far form accessing conforming code segments, CPL >= DPL, RPL won't be checked
When program control is transferred to a conforming code segment, the CPL does not change, even if the DPL of the destination code segment is less than the CPL. This situation is the only one where the CPL may be different from the DPL of the current code segment. Also, since the CPL does not change, no stack switch occurs.
Conforming segments are used for code modules such as math libraries and exception handlers, which support applications but do not require access to protected system facilities
-
accessing a Code Segment Through a Call Gate
-
stack switching
Whenever a call gate is used to transfer program control to a more privileged nonconforming code segment (that is, when the DPL of the nonconforming destination code segment is less than the CPL), the processor automatically switches to the stack for the destination code segment’s privilege level. This stack switching is carried out to prevent more privileged procedures from crashing due to insufficient stack space. It also prevents less privileged procedures from interfering (by accident or intent) with more privileged procedures through a shared stack
Pointers to the privilege level 0, 1, and 2 stacks are stored in the TSS for the currently running task (see Figure 6-2). Each of these pointers consists of a segment selector and a stack pointer (loaded into the ESP register)
-
returning from a Called Procedure
The RET instruction can be used to perform a near return, a far return at the same privilege level, and a far return to a different privilege level. This instruction is intended to execute returns from procedures that were called with a CALL instruction. It does not support returns from a JMP instruction, because the JMP instruction does not save a return instruction pointer on the stack
-
privileged instructions
They can be executed only when the CPL is 0:
- LGDT—Load GDT register.
- LLDT—Load LDT register.
- LTR—Load task register.
- LIDT—Load IDT register.
- MOV (control registers)—Load and store control registers.
- INVLPG—Invalidate TLB entry.
- HLT—Halt processor.
- ...
Page-level protection can be used alone or applied to segments. When page-level protection is used with the flat memory model, it allows supervisor code and data (the operating system or executive) to be protected from user code and data (application programs). It also allows pages containing code to be write protected
-
protection information for pages is contained in two flags in a page-directory or page-table entry: the read/write flag (bit 1) and the user/supervisor flag (bit 2)
-
supervisor mode vs user mode
If the processor is currently operating at a CPL of 0, 1, or 2, it is in supervisor mode, it can access all pages; if it is operating at a CPL of 3, it is in user mode, it can access only user-level pages
-
page type
- Read-only access (R/W flag is 0)
- Read/write access (R/W flag is 1)
-
two level page-directory and the page-table
-
overrides to Page Protection
access to segment descriptors in the GDT, LDT, or IDT
When paging is enabled, the processor evaluates segment protection first, then evaluates page protection. If the processor detects a protection violation at either the segment level or the page level, the memory access is not carried out and an exception is generated. If an exception is generated by segmentation, no paging exception is generated.
Page-level protections cannot be used to override segment-level protection
Page-level protection can be used to enhance segment-level protection
IA-32-3: 4.6 PRIVILEGE LEVEL CHECKING WHEN ACCESSING DATA SEGMENTS
physical & virtual page table views:
-
qemu
info mem info pg
-
xp paddr vs x vaddr
view content in virtual & physical address, should be the same
knowledge:
- BIOS
- ELF
- c calling convention: BUFFER OVERFLOW 6 The Function Stack
- i/o port development: Chapter 6: Parallel I/O ports
- makefile
- C: K & R