μΌ | μ | ν | μ | λͺ© | κΈ | ν |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- materialapp
- flutter
- create
- file
- algorithm
- scaffold
- icon button
- stack growth
- System call
- pintos
- Cow
- widget
- Flutter
- BFS
- Copy-on-write
- vm
- Today
- Total
JunHyeok
[PintOS - VM] Introduction λ³Έλ¬Έ
π¬ Introduction
By now you should have some familiarity with the inner workings of Pintos. Your OS can properly handle multiple threads of execution with proper synchronization, and can load multiple user programs at once. However, the number and size of programs that can run is limited by the machine's main memory size. In this assignment, you will remove that limitation by buiding an illusion of infinite memory.
Thread λ¨μμμ μ°λ¦¬λ μ¬λ¬ μ°λ λλ₯Ό λ€λ£¨λ©° λκΈ°ν νλ λ²μ νμμ£ ?
μ΄λ²μλ μ¬λ¬κ°μuserprog
μ λ‘λν¨μ λ¬Όλ‘ ,Main Memory
μ¬μ΄μ¦μ μ μ½μ λ²μ΄λ κ°κ°μ νλ‘μΈμ€κ°Main Memory
μ 체λ₯Ό νμ©νλ€λ νμμ μ¬μ΄μ€ κ² μ λλ€!
ποΈ Background
Source Files
You will work in the vm directory for this project. The Makefile is updated to turn on the setting -DVM. We provide an enormous amount of template code. You MUST follow the given template. That is, if you submit the code, that is not based on the given template, you get 0pts. Also, you should never change the template where it is marked "DO NOT CHANGE". Here, we provide some details about each template file that you will be modifying.
λ°λμ μ£Όμ΄μ§ ν νλ¦Ώμ λ°λ₯΄μΈμ!! μ£Όμ΄μ§ ν νλ¦Ώμ κΈ°λ°νμ§ μκ³ μ½λλ₯Ό μ μΆνλ€λ©΄ 0μ μ λ°μ΅λλ€! λν, βDO NOT CHANGEβλΌκ³ μ νμλ λΆλΆμ μ½λλ μ λ μμ νμ§ λ§μΈμ. μλμ κ° ν νλ¦Ώ νμΌμμ λΉμ μ΄ μμ νκ² λ λΆλΆμ λν μμΈν μ€λͺ μ νκ² μ΅λλ€.
νμ§ λ§λΌλ©΄ νμ§ λ§μ!
include/vm/vm.h, vm/vm.c
enum vm_type {
/* page not initialized */
VM_UNINIT = 0,
/* page not related to the file, aka anonymous page */
VM_ANON = 1,
/* page that realated to the file */
VM_FILE = 2,
/* page that hold the page cache, for project 4 */
VM_PAGE_CACHE = 3,
/* Bit flags to store state */
/* Auxillary bit flag marker for store information. You can add more
* markers, until the value is fit in the int. */
VM_MARKER_0 = (1 << 3),
VM_MARKER_1 = (1 << 4),
/* DO NOT EXCEED THIS VALUE. */
VM_MARKER_END = (1 << 31),
};
VM_UNINIT.c
Provides operations for uninitialized pages (vm_type = VM_UNINIT). Under the current design, all pages are initially set up as uninitialized pages, then it transforms to anonymous pages or file-backed pages.
μ΄κΈ°νλμ§ μμ νμ΄μ§μ λν μ°μ°μ μ 곡ν¨. λͺ¨λ νμ΄μ§λ
VM_UNINIT
λ‘ μ€μ λ λ€μVM_ANON
νΉμfile-backed pages
λ‘ λ³νλ¨.
vm/anon.c
Provides operations for anonymous pages (vm_type = VM_ANON).
vm/file.c
Provides operations for file-backed pages (vm_type = VM_FILE).
vm/inspect.c
gradingμ μν λ©λͺ¨λ¦¬ κΈ°λ₯ κ²μ¬. μμ κΈμ§! π«
Memory Terminology
Pages
- μΆμ² : [1]
63 48 47 39 38 30 29 21 20 12 11 0
+-------------+----------------+----------------+----------------+-------------+------------+
| Sign Extend | Page-Map | Page-Directory | Page-directory | Page-Table | Page |
| | Level-4 Offset | Pointer | Offset | Offset | Offset |
+-------------+----------------+----------------+----------------+-------------+------------+
| | | | | |
+------- 9 ------+------- 9 ------+------- 9 ------+----- 9 -----+---- 12 ----+
Virtual Address
A page, sometimes called a virtual page, is a continuous region of virtual memory of size 4,096 bytes (the page size) in length. A page must be page-aligned, that is, start on a virtual address evenly divisible by the page size. Thus, the last 12 bits of a 64-bit virtual address is the page offset (or just offset). The upper bits are used to indicate the index in the page table, which will be introduced soon. With 64-bit system, we use 4-level page table, which makes a virtual address to look like this:
κ°μ νμ΄μ§λ ν¬κΈ°κ° 4,096 bytes μΈ κ°μ λ©λͺ¨λ¦¬μ μ°μμ μΈ μμμ λλ€. νμ΄μ§λ νμ΄μ§ μ λ ¬μ΄ λμ΄ μμ΄μΌ ν©λλ€, μ¦ νμ΄μ§ ν¬κΈ°λ‘ κ· λ±νκ² λλ μ μλ κ°μ μ£Όμμμ μμν΄μΌ ν©λλ€. λ°λΌμ 64λΉνΈ κ°μ μ£Όμμ λ§μ§λ§ 12λΉνΈκ° νμ΄μ§ μ€νμ (λλ κ·Έλ₯ μ€νμ )μ λλ€. μμͺ½ λΉνΈλ νμ΄μ§ ν μ΄λΈμ μΈλ±μ€λ₯Ό λνλ΄λ λ° μ¬μ©λλ©°, μ΄λ κ³§ μκ°ν νμ΄μ§ ν μ΄λΈμ νμλ©λλ€. 64λΉνΈ μμ€ν μμλ κ°μ μ£Όμλ₯Ό λ€μκ³Ό κ°μ΄ 보μ΄λλ‘ νλ 4λ¨κ³ νμ΄μ§ ν μ΄λΈμ μ¬μ©ν©λλ€:
4KBλ 4096 λ°μ΄νΈμ λλ€.
4096μ 212
λ°λΌμ, 4KB νμ΄μ§μ μ£Όμλ₯Ό λνλ΄λ €λ©΄ 12λΉνΈκ° νμν©λλ€.
Each process has an independent set of user (virtual) pages, which are those pages below the virtual address KERN_BASE (0x8004000000). The set of kernel (virtual) pages, on the other hand, is global, and thus remain in the same position regardless of what thread or process is running. The kernel may access both user and kernel pages, but a user process may access only its own user pages. See Virtual Memory Layout, for more information.
κ° νλ‘μΈμ€λ KERN_BASE(0x8004000000) 'μλ' μ λ 립μ μΈ κ³΅κ°μ κ°λ
user (virtual) pages
λ₯Ό κ°κ³ μμ΅λλ€. λ°λ©΄μ,kernel (virtual) pages
λ μ μμ μΌλ‘ μ°μ΄λ©°, νμ κ°μ μμΉμ μ‘΄μ¬ν©λλ€.
컀λμ μ μ νμ΄μ§μ 컀λ νμ΄μ§ λͺ¨λμ μ κ·Όν μ μμ§λ§, μ μ νλ‘μΈμ€λ λ³ΈμΈμ μ μ νμ΄μ§μλ§ μ κ·Όν μ μμ΅λλ€
KERN_BASE (0x8004000000) π€?
μ΄ κ°μ μ£Όμλ 컀λ 곡κ°μ΄ μμλλ μ§μ μ λνλ λλ€. μ¦, μ΄ μ£Όμ μ΄μμ μμμ 컀λ μ μ©μ΄κ³ , μ΄ μ£Όμ λ―Έλ§μ μμμ μ¬μ©μ μ μ©μ λλ€.
Pintos provides several useful functions for working with virtual addresses. See Section Virtual Addresses, for details.
https://casys-kaist.github.io/pintos-kaist/appendix/virtual_address.html
Frames
A frame, sometimes called a physical frame or a page frame, is a continuous region of physical memory. Like pages, frames must be page-size and page-aligned. Thus, a 64-bit physical address can be divided into a frame number and a frame offset (or just offset), like this:
Frame
μ 물리μ νλ μ λλpage frame
μΌλ‘ λΆλ¦¬κΈ°λ νλ©°, 물리μ λ©λͺ¨λ¦¬μ μ°μμ μΈ μμμ λλ€. νμ΄μ§μ λ§μ°¬κ°μ§λ‘ νλ μμpage-size
μpage-aligned
μ΄ λμ΄ μμ΄μΌ ν©λλ€. λ°λΌμ 64λΉνΈ 물리μ μ£Όμλ λ€μκ³Ό κ°μ΄ νλ μ λ²νΈμ νλ μ μ€νμ (λλ κ·Έλ₯ μ€νμ )μΌλ‘ λλ μ μμ΅λλ€:
12 11 0
+-----------------------+-----------+
| Frame Number | Offset |
+-----------------------+-----------+
Physical Address
νμ΄μ§ μ λ ¬ (page-aligned)μ λ©λͺ¨λ¦¬ μ£Όμκ° νμ΄μ§ ν¬κΈ°μ λ°°μμΈ κ²½μ°λ₯Ό μλ―Έν©λλ€. μ¦, νμ΄μ§μ μμ μ£Όμκ° νμ΄μ§ ν¬κΈ°μ λ°°μμ¬μΌ ν©λλ€.
4KB νμ΄μ§μ κ²½μ°, νμ΄μ§ μ λ ¬ μ£Όμλ 0x0000, 0x1000, 0x2000 λ±κ³Ό κ°μ΄ 4096(0x1000)μ λ°°μμ
λλ€.
x86-64 doesn't provide any way to directly access memory at a physical address. Pintos works around this by mapping kernel virtual memory directly to physical memory - the first page of kernel virtual memory is mapped to the first frame of physical memory, the second page to the second frame, and so on. Thus, frames can be accessed through kernel virtual memory.
x86-64λ 물리μ μ£Όμμμ λ©λͺ¨λ¦¬μ μ§μ μ‘μΈμ€νλ λ°©λ²μ μ 곡νμ§ μμ΅λλ€. νν μ€λ 컀λ κ°μ λ©λͺ¨λ¦¬λ₯Ό 물리μ λ©λͺ¨λ¦¬μ μ§μ λ§€ννμ¬ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν©λλ€. 컀λ κ°μ λ©λͺ¨λ¦¬μ 첫 λ²μ§Έ νμ΄μ§λ 물리μ λ©λͺ¨λ¦¬μ 첫 λ²μ§Έ νλ μμ λ§€νλκ³ , λ λ²μ§Έ νμ΄μ§λ λ λ²μ§Έ νλ μμ λ§€νλ©λλ€. λ°λΌμ νλ μμ 컀λ κ°μ λ©λͺ¨λ¦¬λ₯Ό ν΅ν΄ μ‘μΈμ€ν μ μμ΅λλ€.
Page Tables
A page table is a data structure that the CPU uses to translate a virtual address to a physical address, that is, from a page to a frame. The page table format is dictated by the x86-64 architecture. Pintos provides page table management code in threads/mmu.c.
νμ΄μ§ ν μ΄λΈμ CPUκ° κ°μ μ£Όμλ₯Ό 물리 μ£Όμ, μ¦
page
μμframe
μΌλ‘ λ³ννλ λ° μ¬μ©νλ μλ£κ΅¬μ‘° μ λλ€. νμ΄μ§ ν μ΄λΈ νμμ x86-64 μν€ν μ²μ μν΄ κ²°μ λ©λλ€. νν μ€λ νμ΄μ§ ν μ΄λΈ κ΄λ¦¬ μ½λλ₯Ό μ€λ λ/mmu.cλ‘ μ 곡ν©λλ€.
The diagram below illustrates the relationship between pages and frames. The virtual address, on the left, consists of a page number and an offset. The page table translates the page number into a frame number, which is combined with the unmodified offset to obtain the physical address, on the right.
μλ λ€μ΄μ΄κ·Έλ¨μ
page
μframe
μ κ΄κ³λ₯Ό 보μ¬μ€λλ€. μΌμͺ½μ κ°μ μ£Όμλ νμ΄μ§ λ²νΈμ μ€νμ μΌλ‘ ꡬμ±λμ΄ μμ΅λλ€. νμ΄μ§ ν μ΄λΈμ νμ΄μ§ λ²νΈλ₯Ό νλ μ λ²νΈλ‘ λ³ννκ³ μ€λ₯Έμͺ½μ μμ λμ§ μμ μ€νμ κ³Ό κ²°ν©νμ¬ λ¬Όλ¦¬μ μ£Όμλ₯Ό μ»μ΅λλ€.
Swap Slots
A swap slot is a page-size region of disk space in the swap partition. Although hardware limitations dictating the placement of slots are more flexible than for frames, swap slots should be page-aligned because there is no downside in doing so.
μ€μ μ¬λ‘―μ μ€μ νν°μ μμ λμ€ν¬ 곡κ°μ νμ΄μ§ ν¬κΈ° μμμ λλ€. μ¬λ‘―μ λ°°μΉλ₯Ό μ§μνλ νλμ¨μ΄ μ νμ΄ νλ μλ³΄λ€ λ μ μ°νμ§λ§, μ€μ μ¬λ‘―μ
page-aligned
λ₯Ό νλ μνλ ν° μ°¨μ΄κ° μκΈ°μ (λ¨μ μ μκΈ°μ) μ λ ¬ν΄μ€λλ€.
πΉοΈ Resource Management Overview
You will need to design/implement the following data structures:
Supplemental page table
Enables page fault handling by supplementing the page table. See Managing the Supplemental Page Table below.
page table
μ 보쑰νμ¬page fault handling
μ²λ¦¬λ₯Ό νμ±νν©λλ€. μλ 보좩 νμ΄μ§ ν μ΄λΈ κ΄λ¦¬λ₯Ό μ°Έμ‘°νμμμ€.
Frame table
Allows efficient implementation of eviction policy of physical frames. See Managing the Frame Table below.
물리μ νλ μμ ν΄κ±° μ μ± μ ν¨μ¨μ μΌλ‘ ꡬνν μ μμ΅λλ€. μλμ νλ μ ν μ΄λΈ κ΄λ¦¬λ₯Ό μ°Έμ‘°νμμμ€.
Swap table
Tracks usage of swap slots. See Managing the Swap Table below.
μ€μ μ¬λ‘―μ΄ μ¬μ©λλ κ²μ μΆμ ν©λλ€. μλμ μ€μ ν μ΄λΈ κ΄λ¦¬ λΆλΆμ μ°Έκ³ νμΈμ.
You do not necessarily need to implement three completely distinct data structures: it may be convenient to wholly or partially merge related resources into a unified data structure.
For each data structure, you need to determine what information each element should contain. You also need to decide on the data structure's scope, either local (per-process) or global (applying to the whole system), and how many instances are required within its scope.
To simplify your design, you may store these data structures in non-pageable memory (e.g., memory allocated by calloc
or malloc
). That means that you can be sure that pointers among them will remain valid.
κ° μλ£κ΅¬μ‘°λ₯Ό μμ ν λ³κ°λ‘ ꡬνν νμλ μμ΅λλ€. μλ‘ κ΄λ ¨λ μμμ ν΅ν©λ μλ£κ΅¬μ‘°λ‘ ν©μΉλ κ²μ΄ νΈλ¦¬ν μ μμ΅λλ€. κ° μλ£κ΅¬μ‘°μμ κ° μμκ° μ΄λ€ μ 보λ₯Ό λ΄λμ§ κ²°μ ν΄μΌ νκ³ , μλ£κ΅¬μ‘°λ₯Ό μ§μ(νλ‘μΈμ€λ³) λλ μ μ(μ 체 μμ€ν μ μ μ©)μΌλ‘ μ μ©ν μ§ κ²°μ ν΄μΌ ν©λλ€. λν νμν μΈμ€ν΄μ€μ μλ₯Ό κ²°μ ν΄μΌ ν©λλ€.
μ€κ³λ₯Ό λ¨μννκΈ° μν΄, non-pageable λ©λͺ¨λ¦¬μ μ΄λ¬ν μλ£κ΅¬μ‘°λ₯Ό μ μ₯ν μ μμ΅λλ€. μ΄λ callocμ΄λ mallocμΌλ‘ ν λΉλ λ©λͺ¨λ¦¬λ₯Ό μλ―Έν©λλ€. μ¦, μλ£κ΅¬μ‘°λ€ μ¬μ΄μ ν¬μΈν°κ° νμ μ ν¨ν μνλ‘ μ μ§λ κ²μ 보μ₯ν μ μμ΅λλ€.
Choices of implementation (Performance perspective)
Possible choices for implementation include arrays, lists, bitmaps, and hash tables. An array is often the simplest approach, but a sparsely populated array wastes memory. Lists are also simple, but traversing a long list to find a particular position wastes time. Both arrays and lists can be resized, but lists more efficiently support insertion and deletion in the middle.
ꡬνμ μν΄ μ νν μ μλ λ°©λ²μΌλ‘λ λ°°μ΄, λͺ©λ‘, λΉνΈλ§΅, ν΄μ ν μ΄λΈ λ±μ΄ μμ΅λλ€. λ°°μ΄μ΄ κ°μ₯ κ°λ¨ν λ°©λ²μΈ κ²½μ°κ° λ§μ§λ§, λ°λκ° ν¬λ°ν λ°°μ΄μ λ©λͺ¨λ¦¬λ₯Ό λλΉν©λλ€. listsλ κ°λ¨νμ§λ§ νΉμ μμΉλ₯Ό μ°ΎκΈ° μν΄ κΈ΄ λͺ©λ‘μ μ΄λνλ κ²μ μκ°μ λλΉν©λλ€. λ°°μ΄κ³Ό listsμ λͺ¨λ ν¬κΈ°λ₯Ό μ‘°μ ν μ μμ§λ§ listsμ μ€κ°μ μ½μ κ³Ό μμ λ₯Ό λ ν¨μ¨μ μΌλ‘ μ§μν©λλ€.
Pintos includes a bitmap data structure in lib/kernel/bitmap.c and include/lib/kernel/bitmap.h. A bitmap is an array of bits, each of which can be true or false. Bitmaps are typically used to track usage in a set of (identical) resources: if resource n is in use, then bit n of the bitmap is true. Pintos bitmaps are fixed in size, although you could extend their implementation to support resizing.
pintOS
λ λΉνΈλ§΅ λ°μ΄ν° ꡬ쑰λ₯Ό ν¬ν¨ν©λλ€. λΉνΈλ§΅μ λΉνΈλ€μ λ°°μ΄λ‘, κ°κ° μ°Έμ΄κ±°λ κ±°μ§μΌ μ μμ΅λλ€. λΉνΈλ§΅λ€μ μΌλ°μ μΌλ‘ μμλ€μ μ§ν©μμ μ¬μ©μ μΆμ νλ λ° μ¬μ©λλλ°, μμ nμ΄ μ¬μ© μ€μ΄λ©΄ λΉνΈλ§΅μ λΉνΈ nμ μ°Έμ λλ€. νν μ€ λΉνΈλ§΅λ€μ ν¬κΈ°κ° κ³ μ λμ΄ μμ§λ§, re-sizingμ μ§μνλλ‘ κ΅¬νμ νμ₯ν μ μμ΅λλ€.
Pintos also includes a hash table data structure (See Hash Table). Pintos hash tables efficiently support insertions and deletions over a wide range of table sizes.
νν μ€λ ν΄μ ν μ΄λΈ μ¬λ£ ꡬ쑰λ ν¬ν¨νκ³ μμ΅λλ€(ν΄μ ν μ΄λΈ μ°Έμ‘°). νν μ€ ν΄μ ν μ΄λΈμ λ€μν ν μ΄λΈ ν¬κΈ°μμ μ½μ κ³Ό μμ λ₯Ό ν¨μ¨μ μΌλ‘ μ§μν©λλ€.
π Managing the Supplemental Page Table
The supplemental page table supplements the page table with additional data about each page. It is needed because of the limitations imposed by the page table's format. Such a data structure is often called a "page table" also; we add the word "supplemental" to reduce confusion.
보쑰 νμ΄μ§ ν μ΄λΈ
μ κ° νμ΄μ§μ λν μΆκ° λ°μ΄ν°λ‘ νμ΄μ§ ν μ΄λΈμ 보μν©λλ€. νμ΄μ§ ν μ΄λΈμ νμμ λ°λ₯Έ μ ν λλ¬Έμ νμν©λλ€. μ΄λ¬ν λ°μ΄ν° ꡬ쑰λ μ’ μ’ "page table
"μ΄λΌκ³ λ λΆλ¦¬λλ°, μ°λ¦¬λ νΌλμ μ€μ΄κΈ° μν΄ "보쑰"μ΄λΌλ λ¨μ΄λ₯Ό μΆκ°ν©λλ€.
Supplemental Page Tableμ νλ‘μΈμ€λ§λ€ μ‘΄μ¬νλ μλ£κ΅¬μ‘°μ λλ€.
β κ°κ°μ νμ΄μ§μ λν΄μ λ°μ΄ν°κ° μ‘΄μ¬νλ κ³³(frame, disk, swap μ€ μ΄λμ μ‘΄μ¬νλμ§), μ΄μ μμνλ 컀λ κ°μμ£Όμλ₯Ό κ°λ¦¬ν€λ ν¬μΈν° μ 보, activeμΈμ§ inactive μΈμ§ λ±
The supplemental page table is used for at least two purposes. Most importantly, on a page fault, the kernel looks up the virtual page that faulted in the supplemental page table to find out what data should be there. Second, the kernel consults the supplemental page table when a process terminates, to decide what resources to free.
보쑰 νμ΄μ§ ν μ΄λΈμ μ μ΄λ λ κ°μ§ λͺ©μ μ μν΄ μ¬μ©λ©λλ€. κ°μ₯ μ€μν κ²μ
page fault
μ λν΄ μ»€λμ΄ λ³΄μ‘° νμ΄μ§ ν μ΄λΈμμfault
κ° λ°μν κ°μ νμ΄μ§λ₯Ό κ²μνμ¬ μ΄λ€ λ°μ΄ν°κ° μμ΄μΌ νλμ§ νμΈνλ κ²μ λλ€. λμ§Έ, 컀λμ νλ‘μΈμ€κ° μ’ λ£λ λ 보쑰 νμ΄μ§ ν μ΄λΈμ μ‘°μ¬νμ¬ μ΄λ€ 리μμ€λ₯Όfree
ν κ²μΈμ§ κ²°μ ν©λλ€.
π§Ή Organization of Supplemental Page Table
You may organize the supplemental page table as you wish. There are at least two basic approaches to its organization: in terms of segments or in terms of pages. A segment here refers to a consecutive group of pages, i.e., memory region containing an executable or a memory-mapped file.
μ°λ¦¬κ° μνλ λλ‘ λ³΄μ‘° νμ΄μ§ ν μ΄λΈμ ꡬμ±ν μ μμ΅λλ€. 보쑰 νμ΄μ§ ν μ΄λΈ ꡬμ±μ λν μ΅μν λ κ°μ§ κΈ°λ³Έμ μΈ μ κ·Όλ²μ΄ μμ΅λλ€:
μΈκ·Έλ¨ΌνΈ μΈ‘λ©΄
λλνμ΄μ§ μΈ‘λ©΄
.
μ¬κΈ°μ μΈκ·Έλ¨ΌνΈλ μ°μμ μΈ νμ΄μ§ κ·Έλ£Ή, μ¦ μ€ν νμΌ λλ λ©λͺ¨λ¦¬ λ§€νλ νμΌμ ν¬ν¨νλ λ©λͺ¨λ¦¬ μμμ λνλ λλ€.
Optionally, you may use the page table itself to track the members of the supplemental page table. You will have to modify the Pintos page table implementation in threads/mmu.c to do so. We recommend this approach for advanced students only.
"advanced students only"
β Handling page fault
The most important user of the supplemental page table is the page fault handler. In project 2, a page fault always indicated a bug in the kernel or a user program. In project 3, this is no longer true. Now, a page fault might only indicate that the page must be brought in from a file or swap slot. You will have to implement a more sophisticated page fault handler to handle these cases. The page fault handler, which is page_fault() in userprog/exception.c, calls your page fault handler, vm_try_handle_fault() in vm/vm.c.
보쑰 νμ΄μ§ ν μ΄λΈμμ κ°μ₯ μ€μν κ²μ
page fault handler
μ λλ€. project 2μμpage fault
λ νμ 컀λμ΄λ μ¬μ©μ νλ‘κ·Έλ¨μ λ²κ·Έλ₯Ό λνλ λλ€. νμ§λ§ Project 3μμλ μλλλ€. νμ¬ νλ‘μ νΈμμλpage fault
κ° ν΄λΉ νμ΄μ§λ₯Ό νμΌμ΄λ μ€μ μ¬λ‘―μμ κ°μ ΈμμΌ νλ€λ κ²λ§ λνλΌ μ μμ΅λλ€. μ΄λ¬ν κ²½μ°λ₯Ό μ²λ¦¬νλ €λ©΄ λ³΄λ€ μ κ΅νpage fault handler
λ₯Ό ꡬνν΄μΌ ν©λλ€. userprog/exception.cμμ page_fault()μΈpage fault handler
λ vm/vm.cμμ μ°λ¦¬μ μ½λμpage fault handler
μΈ vm_try_handle_fault()λ₯Ό νΈμΆν©λλ€.
νμ΄μ§ ν΄νΈ νΈλ€λ¬λ λλ΅ λ€μ μμ μ μνν΄μΌ ν©λλ€:
Supplemental Page Tableμμ μ€λ₯κ° λ°μν νμ΄μ§λ₯Ό μ°Ύμ΅λλ€: λ©λͺ¨λ¦¬ μ°Έμ‘°κ° μ ν¨ν κ²½μ°, Supplemental Page Table νλͺ©μ μ¬μ©νμ¬ ν΄λΉ νμ΄μ§μ λ€μ΄κ°λ λ°μ΄ν°λ₯Ό μ°Ύμ΅λλ€. λ°μ΄ν°λ νμΌ μμ€ν μ΄λ μ€μ μ¬λ‘―μ μμ μ μμΌλ©°, λ¨μν all-zero page μΌ μλ μμ΅λλ€. Copy-on-Writeλ₯Ό ꡬννλ κ²½μ°, νμ΄μ§μ λ°μ΄ν°λ μ΄λ―Έ νμ΄μ§ νλ μμ μμ μ μμ§λ§ νμ΄μ§ ν μ΄λΈμλ μμ μλ μμ΅λλ€. Supplemental Page Tableμμ μ¬μ©μ νλ‘μΈμ€κ° μ κ·Όνλ €λ μ£Όμμ λ°μ΄ν°κ° μμ κ²μΌλ‘ κΈ°λν΄μλ μ λ©λλ€. νμ΄μ§κ° 컀λ κ°μ λ©λͺ¨λ¦¬ λ΄μ μκ±°λ, μ½κΈ° μ μ© νμ΄μ§μ μ°κΈ°λ₯Ό μλνλ κ²½μ°, μ κ·Όμ΄ μ ν¨νμ§ μμ΅λλ€. μλͺ»λ μ κ·Όμ νλ‘μΈμ€λ₯Ό μ’ λ£νμ¬ λͺ¨λ 리μμ€λ₯Ό ν΄μ ν©λλ€.
νμ΄μ§λ₯Ό μ μ₯ν νλ μμ μ»μ΅λλ€: Copy-on-Writeλ₯Ό ꡬνν κ²½μ° νμν λ°μ΄ν°κ° μ΄λ―Έ νλ μμ μμ μ μμΌλ©°, μ΄ κ²½μ° ν΄λΉ νλ μμ μ°ΎμμΌ ν©λλ€.
λ°μ΄ν°λ₯Ό νλ μμΌλ‘ κ°μ Έμ΅λλ€: νμΌ μμ€ν μμ μ½μ΄μ€κ±°λ μ€μ, zeroing λ±μ ν΅ν΄ λ°μ΄ν°λ₯Ό νλ μμΌλ‘ κ°μ Έμ΅λλ€. Copy-on-Writeλ₯Ό ꡬνν κ²½μ° νμν νμ΄μ§κ° μ΄λ―Έ νλ μμ μμ μ μμΌλ©°, μ΄ κ²½μ° μ΄ λ¨κ³μμ μΆκ° μ‘°μΉκ° νμνμ§ μμ΅λλ€.
νμ΄μ§ ν μ΄λΈ νλͺ©μ μ λ°μ΄νΈν©λλ€: ν΄νΈκ° λ°μν κ°μ μ£Όμμ νμ΄μ§ ν μ΄λΈ νλͺ©μ 물리 νμ΄μ§λ‘ λ§€νν©λλ€. μ΄λ₯Ό μν΄
threads/mmu.c
μ κΈ°λ₯μ μ¬μ©ν μ μμ΅λλ€.
πΌοΈ Managing the Frame Table
The frame table contains one entry for each frame. Each entry in the frame table contains a pointer to the page, if any, that currently occupies it, and other data of your choice. The frame table allows Pintos to efficiently implement an eviction policy, by choosing a page to evict when no frames are free.
Frame Table
μλ κ°Frame
μ λν΄ νλμ νλͺ©μ΄ ν¬ν¨λ©λλ€.Frame Table
μ κ° νλͺ©μλ νμ¬ ν΄λΉFrame
μ μ μ νκ³ μλPage
μ λν ν¬μΈν°μ κΈ°ν λ°μ΄ν°κ° ν¬ν¨λμ΄ μμ΅λλ€.Frame Table
μ ν΅ν΄ PintosλFrame
μ΄ λΆμ‘±ν λ ν΄μΆνPage
λ₯Ό μ ννμ¬ ν¨μ¨μ μΈ ν΄μΆ μ μ± μ ꡬνν μ μμ΅λλ€.
The frames used for user pages should be obtained from the "user pool," by calling palloc_get_page(PAL_USER). You must use PAL_USER to avoid allocating from the "kernel pool," which could cause some test cases to fail unexpectedly. If you modify palloc.c as part of your frame table implementation, be sure to retain the distinction between the two pools.
μ¬μ©μ νμ΄μ§μ μ¬μ©λλ
Frame
μuser pool
μμ μ»μ΄μΌ νλ©°, μ΄λ₯Ό μν΄palloc_get_page(PAL_USER)
λ₯Ό νΈμΆν΄μΌ ν©λλ€.PAL_USER
λ₯Ό μ¬μ©νμ¬kernel pool
μμ ν λΉνλ κ²μ νΌν΄μΌ ν©λλ€. κ·Έλ μ§ μμΌλ©΄ μΌλΆ ν μ€νΈ μΌμ΄μ€κ° μκΈ°μΉ μκ² μ€ν¨ν μ μμ΅λλ€.Frame Table
ꡬνμ μΌνμΌλ‘palloc.c
λ₯Ό μμ νλ κ²½μ°, λ ν κ°μ ꡬλΆμ λ°λμ μ μ§ν΄μΌ ν©λλ€.
The most important operation on the frame table is obtaining an unused frame. This is easy when a frame is free. When none is free, a frame must be made free by evicting some page from its frame.
Frame Table
μμ κ°μ₯ μ€μν μμ μ μ¬μ©λμ§ μμFrame
μ μ»λ κ²μ λλ€.Frame
μ΄ λΉμ΄ μμ λλ μ΄ μμ μ΄ μ½μ΅λλ€. κ·Έλ¬λ λΉμ΄ μλFrame
μ΄ μμ κ²½μ°, μ΄λ€Page
λ₯Ό ν΄μΆνμ¬Frame
μ λΉμμΌ ν©λλ€.
If no frame can be evicted without allocating a swap slot, but swap is full, panic the kernel. Real OS apply a wide range of policies to recover from or prevent such situations, but these policies are beyond the scope of this project.
μ΄λ€
Frame
λ μ€μ μ¬λ‘―μ ν λΉνμ§ μκ³ ν΄μΆν μ μκ³ , μ€μμ΄ κ°λ μ°¬ κ²½μ°, 컀λμ ν¨λ μνλ‘ λ§λμμμ€. μ€μ μ΄μ체μ λ μ΄λ¬ν μν©μμ 볡ꡬνκ±°λ λ°©μ§νκΈ° μν΄ λ€μν μ μ± μ μ μ©νμ§λ§, μ΄λ¬ν μ μ± μ μ΄ νλ‘μ νΈμ λ²μλ₯Ό λ²μ΄λ©λλ€.
ν΄μΆ κ³Όμ μ λλ΅ λ€μ λ¨κ³λ‘ ꡬμ±λ©λλ€
- νμ΄μ§ κ΅μ²΄ μκ³ λ¦¬μ¦μ μ¬μ©νμ¬ ν΄μΆν
Frame
μ μ νν©λλ€. μλμ μ€λͺ λ λλ‘, νμ΄μ§ ν μ΄λΈμ "accessed" λΉνΈμ "dirty" λΉνΈκ° μ μ©ν κ²μ λλ€. - ν΄λΉ
Frame
μ μ°Έμ‘°νλ λͺ¨λ νμ΄μ§ ν μ΄λΈμμ μ°Έμ‘°λ₯Ό μ κ±°ν©λλ€. 곡μ λ₯Ό ꡬννμ§ μμ κ²½μ°, μ΄λ μμ μμλ νλμPage
λ§μ΄Frame
μ μ°Έμ‘°ν΄μΌ ν©λλ€. - νμν κ²½μ°, νμ΄μ§λ₯Ό νμΌ μμ€ν
μ΄λ μ€μμ κΈ°λ‘ν©λλ€. ν΄μΆλ
Frame
μ λ€λ₯ΈPage
λ₯Ό μ μ₯νλ λ° μ¬μ©λ μ μμ΅λλ€.
ποΈ Accessed and Dirty Bits
x86-64 hardware provides some assistance for implementing page replacement algorithms, through a pair of bits in the page table entry (PTE) for each page. On any read or write to a page, the CPU sets the accessed bit to 1 in the page's PTE, and on any write, the CPU sets the dirty bit to 1. The CPU never resets these bits to 0, but the OS may do so.
x86-64 νλμ¨μ΄λ κ° νμ΄μ§ ν μ΄λΈ νλͺ©(
PTE
)μ μλ λ κ°μ λΉνΈλ₯Ό ν΅ν΄ νμ΄μ§ κ΅μ²΄ μκ³ λ¦¬μ¦μ ꡬννλ λ° λμμ μ€λλ€. νμ΄μ§μ λν μ½κΈ° λλ μ°κΈ°κ° λ°μν λλ§λ€ CPUλ νμ΄μ§μ PTEμμaccessed
λΉνΈλ₯Ό 1λ‘ μ€μ νκ³ , μ°κΈ°κ° λ°μν λλ§λ€ CPUλdirty bit
λ₯Ό 1λ‘ μ€μ ν©λλ€. CPUλ μ΄λ¬ν λΉνΈλ₯Ό 0μΌλ‘ μ¬μ€μ νμ§ μμ§λ§, μ΄μ체μ κ° μ΄λ₯Ό ν μ μμ΅λλ€.
You need to be aware of aliases, that is, two (or more) pages that refer to the same frame. When an aliased frame is accessed, the accessed and dirty bits are updated in only one page table entry (the one for the page used for access). The accessed and dirty bits for the other aliases are not updated.
Aliases
λΌκ³ νλ κ²μ μ£Όμν΄μΌ ν©λλ€. μ΄κ²μ λ κ° μ΄μμ νμ΄μ§κ° λμΌν νλ μμ μ°Έμ‘°νλ κ²½μ°λ₯Ό λ§ν©λλ€. Aliased νλ μμ μ‘μΈμ€ν λ, μ‘μΈμ€λ νμ΄μ§μ λν΄μλ§ νμ΄μ§ ν μ΄λΈ νλͺ©(PTE)μμaccessed
λ°dirty
λΉνΈκ° μ λ°μ΄νΈλ©λλ€. λ€λ₯Έ λ³μΉμ λνaccessed
λ°dirty
λΉνΈλ μ λ°μ΄νΈλμ§ μμ΅λλ€.
In Pintos, every user virtual page is aliased to its kernel virtual page. You must manage these aliases somehow. For example, your code could check and update the accessed and dirty bits for both addresses. Alternatively, the kernel could avoid the problem by only accessing user data through the user virtual address.
Pintos
μμλ λͺ¨λ μ¬μ©μ κ°μ νμ΄μ§κ° ν΄λΉνλ 컀λ κ°μ νμ΄μ§μ λ³μΉμΌλ‘ μ§μ λ©λλ€. μ΄ λ³μΉμ μ΄λ»κ² κ΄λ¦¬ν μ§ κ²°μ ν΄μΌ ν©λλ€. μλ₯Ό λ€μ΄, μ½λμμλ κ° μ£Όμμaccess
λ°dirty
λΉνΈλ₯Ό νμΈνκ³ μ λ°μ΄νΈν μ μμ΅λλ€. λλ 컀λμ μ¬μ©μ λ°μ΄ν°μ λν΄μλ§ μ¬μ©μ κ°μ μ£Όμλ₯Ό ν΅ν΄ μ‘μΈμ€νμ¬ μ΄ λ¬Έμ λ₯Ό ννΌν μλ μμ΅λλ€.
Other aliases should only arise if you implement sharing or if there is a bug in your code.
See Section Page Table Accessed and Dirty Bits for details of the functions to work with accessed and dirty bits.
π₯ Managing the Swap Table
The swap table tracks in-use and free swap slots. It should allow picking an unused swap slot for evicting a page from its frame to the swap partition. It should allow freeing a swap slot when its page is read back or the process whose page was swapped is terminated.
μ€μ ν μ΄λΈμ μ¬μ© μ€μΈ μ€μ μ¬λ‘―κ³Ό λΉ μ€μ μ¬λ‘―μ μΆμ ν©λλ€. μ΄λ νμ΄μ§λ₯Ό ν΄λΉ νλ μμμ μ€μ νν°μ μΌλ‘ ν΄μΆνκΈ° μν΄ μ¬μ©λμ§ μμ μ€μ μ¬λ‘―μ μ νν μ μμ΄μΌ ν¨μ μλ―Έν©λλ€. νμ΄μ§κ° λ€μ μ½νκ±°λ νμ΄μ§λ₯Ό μ€μν νλ‘μΈμ€κ° μ’ λ£λ λ μ€μ μ¬λ‘―μ
free
ν μ μμ΄μΌ ν©λλ€.
From the vm/build directory, use the command pintos-mkdisk swap.dsk --swap-size=n to create a disk named swap.dsk that contains a n-MB swap partition. Afterward, swap.dsk will automatically be attached as an extra disk when you run pintos. Alternatively, you can tell pintos to use a temporary n-MB swap disk for a single run with --swap-size=n.
vm/build
λλ ν 리μμpintos-mkdisk swap.dsk --swap-size=n
λͺ λ Ήμ μ¬μ©νμ¬ n-MB μ€μ νν°μ μ ν¬ν¨νλswap.dsk
λΌλ λμ€ν¬λ₯Ό μμ±ν©λλ€. μ΄νμswap.dsk
λ pintosλ₯Ό μ€νν λ μλμΌλ‘ μΆκ° λμ€ν¬λ‘ μ°κ²°λ©λλ€. λλ--swap-size=n
μ μ¬μ©νμ¬ λ¨μΌ μ€νμ λν μμ n-MB μ€μ λμ€ν¬λ₯Ό μ¬μ©νλλ‘ pintosμ μ§μν μ μμ΅λλ€.
Swap slots should be allocated lazily, that is, only when they are actually required by eviction. Reading data pages from the executable and writing them to swap immediately at process startup is not lazy. Swap slots should not be reserved to store particular pages.
Free a swap slot when its contents are read back into a frame.
μ€μ μ¬λ‘―μ
lazy
νκ² ν λΉλμ΄μΌ ν©λλ€. μ΄ λ§μ, evictionμ μ€μ λ‘ νμν λλ§ ν λΉλμ΄μΌ νλ€λ λ§μ λλ€. νλ‘μΈμ€κ° μμλ λ μ€ννμΌμμ λ°μ΄ν° νμ΄μ§λ€μ μ½κ³ μ€μμ κ³§λ°λ‘ μ°λ νμλlazy
νμ§ λͺ»ν νμμ λλ€. νΉμ νμ΄μ§λ₯Ό μ μ₯νκΈ° μν΄ μ€μ μ¬λ‘―μ΄ μμ½λμ΄μλ μ λ©λλ€.
μ€μ μ¬λ‘―μ λ΄μ©λ¬Όμ΄ νλ μμΌλ‘ μ½ν λμμ€λ©΄ κ·Έ λ μ€μ μ¬λ‘―μ free ν΄μ£Όλ©΄ λ©λλ€.
π Managing Memory Mapped Files
The file system is most commonly accessed with read
and write
system calls. A secondary interface is to "map" the file into virtual pages, using the mmap
system call. The program can then use memory instructions directly on the file data. Suppose file foo
is 0x1000 bytes (4 kB, or one page) long. If foo
is mapped into memory starting at address 0x5000, then any memory accesses to locations 0x5000...0x5fff will access the corresponding bytes of foo
.
νμΌ μμ€ν μ μ£Όλ‘
read
μwrite
μμ€ν νΈμΆμ μ¬μ©νμ¬ μ‘μΈμ€λ©λλ€. 보쑰 μΈν°νμ΄μ€λ‘λ νμΌμ κ°μ νμ΄μ§λ‘ "λ§€ν"νλ κ² μ λλ€. μ΄λmmap
μμ€ν νΈμΆμ μ¬μ©ν©λλ€. νλ‘κ·Έλ¨μ κ·Έλ° λ€μ νμΌ λ°μ΄ν°μ λν΄ μ§μ λ©λͺ¨λ¦¬ λͺ λ Ήμ μ¬μ©ν μ μμ΅λλ€. μλ₯Ό λ€μ΄, νμΌfoo
κ° 0x1000 λ°μ΄νΈ(4KB λλ ν νμ΄μ§) κΈΈμ΄μΈ κ²½μ°μ λλ€. νμΌfoo
κ° μ£Όμ 0x5000μμ λ©λͺ¨λ¦¬μ λ§€νλμ΄ μλ€κ³ κ°μ ν΄λ³΄μΈμ. κ·ΈλΌ μ£Όμ 0x5000λΆν° 0x5fffκΉμ§μ λͺ¨λ λ©λͺ¨λ¦¬ μ‘μΈμ€λfoo
μ ν΄λΉ λ°μ΄νΈμ μ‘μΈμ€νκ² λ©λλ€.
#include <stdio.h>
#include <syscall.h>
int main (int argc UNUSED, char *argv[])
{
void *data = (void *) 0x10000000; /* Address at which to map. */
int fd = open (argv[1]); /* Open file. */
void *map = mmap (data, filesize (fd), 0, fd, 0); /* Map file. */
write (1, data, filesize (fd)); /* Write file to console. */
munmap (map); /* Unmap file (optional). */
return 0;
}
π Sitation π
- κΆμμ§(2022). "Virtual Memory.pptx"
- μλ¬Έ μΆμ²: https://casys-kaist.github.io/pintos-kaist/appendix/virtual_address.html
'PintOS' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[PintOS - VM] Anonymous Page (2) | 2024.06.07 |
---|---|
[PintOS - VM] Memory Management (1) | 2024.06.07 |
[PintOS - Userprog] Exec (0) | 2024.05.30 |
[PintOS - Userprog] Wait (0) | 2024.05.29 |
[PintOS - Userprog] Fork, Exec, Wait μ λ€μ΄κ°κΈ° μμ... (0) | 2024.05.29 |