---
# System prepended metadata

title: OS-Chap12 - I/O systems_
tags: [作業系統 Operating System note, 110-1, '2021']

---

# OS-Chap12 - I/O systems_
###### tags: `作業系統 Operating System note`,  `110-1`, `2021`
# Contents
[TOC]
<style>
.blue {
  color: red;
}
</style>

---
# Overview
- 電腦主要工作有兩類
    - I/O
    - 運算(Computation)
> < I/O佔絕大部分的時間。>
1. I/O device(device 太多，所以分種類)
    - 儲存型(storage) device：disk（硬碟）、tapes（磁碟機）
    - 傳輸型(transmission) device：網卡
    - 人機介面(human-interface) device：鍵盤、滑鼠、螢幕
    - 其餘特殊(specialized) device：遊戲手把（搖桿）、觸控面板
- 分類的意義在於，不同類型的 device，要做的功能也不同
    - storage ➜ Read/ Write
        - flash ➜ 特殊協定(protocal)
        - SD 卡 ➜ 想要 R/W 還需下 command，並等 SD 卡回覆
    - transmission ➜ ts/ rs (transfer傳送/receive接收)
- 所以只要統計好上方這幾個種類，可能最終會使用到多少的功能，也可以說其資料結構會需要哪幾種函數指標(function)，在依據各種不同 categories，繼承該 device 所需要的資料結構即可。
    - ex. Keyboard 需要 buffer，但 network card 不用，所以 buffer 的資料結構就可以只加在 human-interface device 上。


2. I/O Subsystem :star:
    - 為 **OS的子系統 (Subsystem)**
    - ==**管理、控制與電腦連接的各項裝置**==。
3. Device drivers :star:
    - 要有一個**統一的存取方式(uniform device-access interface)** 給 I/O subsystem。

4. I/O Hardware(硬體設備)
    - Port: 
        - 每個 device 都會有自己的編號(port)
        ![](https://i.imgur.com/ggPosfE.jpg)
    - Bus: 
        ![](https://i.imgur.com/rblJyUr.jpg)
        - 除了 CPU 外，
        :star: why CPU 不需要 memory address？
        :star2: why device 需要 memory address？
            - :star2: 因為 device 需要 memory address 來控制每個 device 的開關(register)。
            - :star: 且因為 CPU 是 master！他是主動 enable/ disable CPU 裏頭的 RAM、ROM、timer、interrupt、GPIO，前面這些被包含在 CPU 的晶片哩，也有各自的 controller 去控制裏頭的 I/O，故亦可以控制 CPU 裡面的資料何時被送出。
                - 結論： **CPU 裏頭的 register 不用用位置存取！(r0~r15, $sp)** 
    - Controller: 用來操作 device 的控制器
        - 每個 device 都會有自己的 controller。
    - 整體觀念:
        ![](https://i.imgur.com/nL3u3V9.jpg)
    - example: (個人電腦_PC)
        ![](https://i.imgur.com/F0kP51Z.jpg)
        - CPU 有 4 個核心，表示有 4 個 controller
            (每個核心裡面都各自有 clock，所以可以各自執行自己的工作)
        - 北橋晶片相對於南橋晶片接近 CPU，故北橋的 clock 較南橋來的快。
        - CPU frequent : 北橋 frequent : 南橋 frequent = 1:4:8
            - 此頻率是透過 counter 實作(counter 是用 JK正反器實作)
         >   // 設備的快慢取決於 clock
         >   // 正反器就是開關。
        - 從上圖中可以得知，clock(I/O)速度 : CPU > 北橋 > 南僑(只是連接 device，所以不用那麼快)
            - 因 main memory 連接在北橋上，而 CPU 每次要存取 memory 時，都得經過北橋晶片才能存取 memory，耗費時間極多(讓 CPU stall 很多 cycle)。
            - 所以才會加了一堆 MMU、cache、TLB，為了加速記憶體存取的時間。

> 上課黑板老師畫的開關圖
> ![](https://i.imgur.com/HVXsHFk.png)
> 左邊 12V 在開關接上後(開)，中間的磁圈會產生磁場，造成右方 220V 的電流流通。
> :star:因為兩個電路在不同迴路，所以開關時電路不會燒壞 12V 電路的原因。
> 繼電器（Relay）：中間那個磁圈的東西
> :+1:但是當多次迅速得開關時，右方 220V 的線圈，會因伏特數越高、凸波越高，而產生火花，突破臨界時就將線圈的鐵融化掉了(就黏住了！！！)。



- 系統複雜度高，因為 I/O 硬體裝置間差異度高，例如各裝置速度、功能都不同，故**獨立於 Kernel 外另設 Subsystem**。



ex. 每個設備都要初始化，所以 OS 在設備出現後，就會給他一個資料結構(OS想管理就是用一個資料結構)。
若現在電腦有 100 個設備，就有 100 個資料結構，OS 想管理這些資料結構，就是用 linked-list(or tree) 把這些資料結構存起來。
    當 application 要求網卡時，就從 linked-list(or tree) 中找出想要的 device。
    假設想要使用該網卡的傳送資料，就會從該資料結構裡面找出一個「函數指標」，並呼叫 transfer＜ts＞ 的那個函數，**而這個傳送「函數指標」的行為，就是 driver ！**
// ts 代表傳送，rs 代表接收
 :star: **這就是為甚麼 device 都得先註冊，把該 device 的 driver 掛上去 OS 的 API，讓上面 app 可以呼叫他！** :star: 
:+1: 也就是說！ :star: 
- I/O subsystem 會提供一些 API 給 OS 使用；而 OS 要將這些 API 給上層 app 使用時，則讓 app 透過 system call 呼叫 OS ，就可以使用這些 device 掛上去 API 的 driver。
 
 
# 和 device(設備, I/O) 溝通的「管道」有兩種
- ### 存取 device 的方法
## Port-mapped I/O
1. By Port
2. 每個 port 都有各自獨特的 port address(ID)，用來讓 CPU 存取每個 device。
==**＜非 memory address space＞**==
        ![](https://i.imgur.com/ggPosfE.jpg)
3. 每個 I/O port 由 **四個暫存器(four registers)** 組合而成。
    - **Data in** reg. :
    - **Data out** reg. : 
    - **Status** reg. : 
    - **Control** reg. : 
>    暫存器的位置就是 I/O port 的位置。
4. 若想透過 I/O port 存取各個 I/O，==需要透過些『特殊指令(special I/O instructions)』== 存取 device。
    - ex. x86 的 IN, OUT 指令
>    special I/O instructions 的意思是「不同於 memory access 」的存取指令。(memory access 用 memory address 的方式存取 I/O)


## Memory-mapped I/O 
- #### :star: 現今都用 memory-mapped 的方式 :star:
1. By Bus(匯流排):
2. 每個 I/O 都給記憶體位置 memory address，用來讓 CPU 存取每個 device。
    >    把 device 看成一般的 memory。
    - 因為會保留 RAM 中用不到的 memory address，把這些 addr. 當成 I/O device 存取的門牌號碼(地址)！
        eg. RAM 的位置在 memory 的上半部，device(周邊 device) 的位置在 memory 的下半部(高位元的部分)。
        - 優: 對於存取大一點的 memory I/O 是有益的(ex. 顯卡__graphic card)
            > - memory-mapped 可以直接透過 DMA 的方式存取想要的 I/O，就不用透過特殊指令的 move 傳入 CPU 再拿出。
            > - 因為想要的 I/O 本身是 controller，本身就有 clock，不用靠別人搬動。
        - 缺: 如果 RAM 和 I/O 的範圍沒有限制好，可能會造成「想存取/改動(modification) RAM 的值，卻改動到 I/O」➜ accidental modification ➜ error。
### 小小整理結論
1. I/O mapped I/O(port-mapped I/O或Direct I/O)
- I/O與memory均擁有自己的記憶體空間
- 需要特別的指令來處理I/O
- 好處是完全不用考慮記憶體空間被I/O佔用，缺點需要額外的指令專門處理I/O存取。
![](https://i.imgur.com/PrrGLLt.png)

2. Memory Mapped I/O
- I/O與memory共用記憶體空間
- 不需要特別指令來處理I/O
- 其實Memory mapped I/O只是將I/O的port或memory 映射(mapping)到記憶體位址(memory address)上，
- 好處就是**可以把I/O存取直接當成存取記憶體來用**，缺點是**有映射到的區域原則上就不能放真正的記憶體**。
![](https://i.imgur.com/qIf7487.png)


# 和 device(設備) 溝通的「方式」有兩種
- #### 想知道設備有沒有我要的資料
## Busy-Waiting = Poll
- 用迴圈不斷的找想要的資料
- processor 定期的向 device 詢問其儲存狀態的暫存器(state reg.)
- ex. 手機怎麼知道何時有人打電話進來？
    - 一直不斷地偵測/ 詢問(poll) 有沒有接收到訊號。

## Interrupt
- device 做完該做的工作後，若有需要 CPU 執行，再向其發出訊號。
- ex. timer(時間)
    - 每隔一段時間(10 ns)後向 CPU 發出訊號。(中斷他)


# 「傳送資料」(transfer) 的方式有兩種
## Programmed I/O
- 就是寫程式 read/write、in/out，並由 CPU 控制其傳輸。 
- conclusion to Property of Programmed I/O
    - 在 CPU 內
    - 透過程式碼決定傳送甚麼資料到哪裡

## DMA :star: :star: :star: :star2: :star2: (好像很重要)
###### Direct memory access - 直接記憶體存取
- #### 適用於==欲傳送的資料比較大的時候。(large data transfer)==
- 用範例來解釋！
    - ex. net card(網卡)
    - ex. camera(攝影機/攝像頭)➜把 camera 的資料傳到 RAM 裡 
    > - 若傳輸大資料使用 CPU，會占用 CPU 太多時間，使得 CPU 無法做其他事 
    > - 因 CPU 在執行五個 stage 時，只有兩個 stage 會使用到 bus，其餘用不到的時間 DMA 就可以趁機使用 bus 來傳遞資料了！（而且 bus 很大，可以很快地就傳完資料。）
- DMA Controller : 用來實作 DMA 的控制器＜hardware＞
    1. 控制何時讓資料從 device 透過 bus 流出。
    2. 當 DMA 傳輸完成後，發送一個通知(Interrupt)給 OS
- conclusion to Property of DMA
    - 為了一次性 or 快速**傳遞大量資料**而發展出的方法
    - 有 **DMA controller**
    - 因為用 bus 傳，所以屬於 **memory-mapped** 的方法
    - controller 做完該做的事情，要告知 OS ➜ **Interrupt**
- :star2: :star2: :star2: :star2: :star2: ![](https://i.imgur.com/t5DUebG.png)

## Blocking 
- blocking 發生 interrupt 時，會讓 process 整個處於停滯的狀態，等到 I/O 完成後回傳，OS才會繼續做
- User Program 要資料時 system call 呼叫 kernel，kernel 沒完成找到且 copy 資料前，Process 不能做任何事情。
- //Process 去 sleep 了，直到 kernel 叫她起床
## Non-Blocking
- Non blocking-> 即使某個 process 發起 interrput時，IO 也會繼續處理下一條 Process(pineline的概念)
- 很多 User Program 同時用 Polling 去查看資料到底找到沒，不斷呼叫kernel，若沒找到直接回傳 no_data。找到後就 copy 資料成功後回傳給 User Program
- //Process不會sleep，有一個資料kernel找到後，回傳給user


### [ref.](https://www.itread01.com/content/1549696876.html)
### [ref.](https://kaka-lin.github.io/2020/07/io_models/)

## Asynchronous(非同步)
- Asynchronous(user program & kernel不是同步的)->user program要讀資料時，System call 呼叫 kenel，叫 kernel 去處理這些事，kernel處理完之後才呼叫 user program
- //kernel變工具人，像是user網購下訂單填入地址付完錢(user)，然後剩下讓網站(kernel)去找貨、上貨、物流，到貨的時候才通知user，user負責收貨

![](https://i.imgur.com/KvnZtTe.png)
![](https://i.imgur.com/QoWA0TA.png)


---

# H.W.

## 13.2
- Q: What are the ==advantages and disadvantages== of supporting **memory-mapped I/O** to device control registers?
- A:
    - The **advantage** of supporting memory-mapped I/O to device control registers is that it **eliminates the need for *special I/O instructions* from the instruction set** and therefore also does not require the enforcement of protection rules that prevent user programs from executing these I/O instructions. 
    - The **disadvantage** is that the resulting **flexibility** needs to be handled with **care**; the **memory translation units** need to ensure that **the memory addresses associated with the device control registers** are **==not== accessible ==by user programs==** in order to ensure protection.

>－－－－－－－－－－－－－－－－－－－－－－－－－
>- Advantages include:
>    1. Memory mapped I/O gives you **a single address space** and **a common set of instructions** for both **data** and **I/O operations**.
>    2. You can define memory ordering rules and memory barriers that apply both to device accesses and normal memory.
>    3. You do**n’t need a whole separate set of opcodes for I/O instructions**. You can **reuse your ==ordinary memory access instructions==**.
>    4. You can use pointers in languages such as C and C++ to access devices, rather than platform-specific intrinsics or inline assembly. Caveats:
>        - You still need to tag those pointers volatile.
>        - You may still need intrinsics or inline assembly to implement memory barriers.
>    5. You can **reuse the same memory mapping mechanisms** you use for other memory to control access to devices (e.g. page table entries).
>    6. You may benefit from much of the low-latency buses and request routing infrastructure put in place to optimize normal data accesses.

>- Disadvantages include:
>    1. It potentially **complicates your cache controller**, as **device accesses behave differently from normal memory accesses**.
>    2. It potentially complicates instruction scheduling (especially speculation) as the processor doesn’t know immediately that a given load or store goes to device memory; rather, the MMU or some other structure in or near the memory system informs it once it receives and decodes the address.
>    3. It adds corner conditions and restrictions, such as requiring certain specific access widths (e.g. 32-bit writes only; no 8-bit, 16-bit, or 64-bit writes), which may catch some compilers by surprise.
>    4. You still end up with high access latency and lower throughput when your request steps off the fast, low-latency path meant for data into an I/O subsystem with slower, simpler buses.
>    5. You can get some nasty surprises when you use types such as std::atomic to perform MMIO, and discover the compiler uses an instruction that isn’t compatible with your peripheral.
>- [ref.](https://www.quora.com/What-are-the-advantages-and-disadvantages-of-memory-mapped-I-O)


## 13.5
- Q: What are the various kinds of performance overhead associated with **servicing an interrupt**?
- A:[![](https://i.imgur.com/ccvnIKQ.png)](https://nanopdf.com/download/exe-c07-io_pdf)

回顧：什麼是overhead(可以點圖片)
[![](https://i.imgur.com/SiHBxyC.png)](https://hackmd.io/@cindyrumi/cindyOSchp3#Context-Switch)


      
簡而言之：
利用Interrupt來跟I/O設備傳輸資料時，需要中斷CPU內的程序，流程如下：
1. 儲存原本執行中的Process狀態
2. 因爲Process被中斷：清空Pipeline上的指令
3. ..傳輸傳輸傳輸..
4. 恢復之前的Process狀態
5. 把之前的指令放回Pipeline

所以overhead會取決於：
* 儲存和回復Process的速度
* 清空和回復Pipeline的速度


- [ref. of answer](https://nanopdf.com/download/exe-c07-io_pdf)


## 13.6
- Q: $^{(1)}$Describe three circumstance under which blocking I/O should be used.
    $^{(2)}$Describe three circumstances under which nonblocking I/O should be used.
    $^{(3)}$Why not just implement nonblocking I/O and have processes busy-wait until their devices are ready?
[![](https://i.imgur.com/t1X4vYz.png)](https://nanopdf.com/download/exe-c07-io_pdf)

blocking vs non-blocking：
* Blocking的I/O傳輸在等待資料傳輸時，CPU會直接卡在I/O操作上，無法做其他事情，而Non-blocking類似於busy-waiting，會直接回傳資料的傳輸狀態，但是process需要一直詢問kernel資料傳好了沒。
* ![](https://i.imgur.com/uKukRsR.png)


什麼情況要用non-Blocking：
* 如果I/O設備很多（例如sockets），可以使用non-blocking來達到多工的效果（I/O multiplexing），每個設備輪流詢問CPU I/O的資料狀況，使得單一thread同時監控多個設備的作用，而不需要使用多個thread/process造成系統資源的浪費。
* 斷斷續續的資料傳輸（例如UDP協定的傳輸或串流），可以使用non-blocking來解決I/O設備不連續傳送的狀況，如果用 blocking，就會需要等到收到一份完整的資料（例如UDP封包）後，才會回傳狀態，這時CPU就會浪費很多時間在等待I/O設備發送資料。
* 用於實現資料同步，如果使用blocking來實現同步就會需要等待一個資料傳完，再傳下一個，此時可能其餘的I/O設備都是空閒的，所以可以使用non-blocking來實現多個來源的資料同步處理。

- [ref. of answer](https://nanopdf.com/download/exe-c07-io_pdf)
- [ref. of infor. 菜鳥成長史](https://wirelessr.gitbooks.io/working-life/content/io_model.html)
- blocking vs non-blocking
    - :star: [Java的I/O模型](https://medium.com/@clu1022/%E6%B7%BA%E8%AB%87i-o-model-32da09c619e6) :star: 
    - [我所理解的 I/O](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/81519/)
    - [Stack overflow : Blocking IO vs non-blocking IO](https://stackoverflow.com/questions/1241429/blocking-io-vs-non-blocking-io-looking-for-good-articles)
    - [Stack overflow :  What is "non-blocking" concurrency](https://stackoverflow.com/questions/2824225/what-is-non-blocking-concurrency-and-how-is-it-different-than-normal-concurren)
    - [計算機網路-TCP和UDP總結（區別、優缺點、應用場景）](https://www.796t.com/article.php?id=161917)

--
- 概括來說，一個IO操作可以分爲兩個部分：發出請求、結果完成。
- 若從發出請求到結果返回，一直Block，那就是Blocking IO；如果發出請求就可以返回（結果完成不考慮），就是non-blocking IO；如果發出請求就返回，結果返回是Block在select或者poll上的，則其只能稱爲IO multiplexing；如果發出請求就返回，結果返回通過Call Back的方式被處理，就是AIO。
- $^{(1)}$
- $^{(2)}$
    - Non-blocking I/O is useful when I/O may come from more than one source and the order of the I/O arrival is not predetermined. Examples include network daemons listening to more than one network socket, window managers that accept mouse movement as well as keyboard input, and I/O-management programs, such as a copy command that copies data between I/O devices. In the last case, the program could optimize its performance by buffering the input and output and using non-blocking I/O to keep both devices fully occupied.

 
- $^{(3)}$Non-blocking I/O is more complicated for programmers, because of the asynchonous rendezvous that is needed when an I/O occurs. Also, busy waiting is less efﬁcient than interrupt-driven I/O so the overall system performance would decrease.
[ref.](http://fcs351.pbworks.com/w/page/6493664/Tutorial9)


## 13.8
- Q: Some **DMA controllers** support **direct virtual memory access**, where the targets of I/O operations are specified as virtual addresses and **a translation from virtual to physical address** is performed **during the DMA**. ==How does this designed complicate the design of the DMA controller?== What are the **advantages** of providing such functionality?

讓 DMA controller 支援虛擬記憶體的直接訪問，意味着需要把第二記憶體（如硬碟）的部分資料復制到記憶體中。而虛擬記憶體的實現是利用查 page表，來對應虛擬記憶體位置與實際的位置，DMA controller就會需要**同時處理實體位置和虛擬位置**，而這個特性就會讓虛擬記憶體的轉換（查表）變得更復雜。

優點是使其餘硬體也能和CPU一起享有虛擬記憶體的好處，例如：
* 連續的記憶體區塊
* 額外的記憶體空間

- [What do you think a DMA controller can get direct access to the virtual memory or not?](https://www.quora.com/What-do-you-think-a-DMA-controller-can-get-direct-access-to-the-virtual-memory-or-not)

![](https://i.imgur.com/M314vc9.png)
- Answer:
- **Direct virtual memory access** allows a device to **perform a transfer from two memory-mapped devices *without the intervention of the CPU* or *the use of main memory as a staging ground(暫存地)***;
- **直接虛擬內存訪問**允許設備**執行來自兩個內存映射設備的傳輸*無需 CPU 干預*或*使用主內存作為暫存地***
- 
- the device simply issues(發出) memory operations to the memory-mapped addresses of a target device and the ensuing virtual address translation guarantees that the data is transferred to the appropriate device. 
- 設備簡單地向目標設備的內存映射地址發出內存操作，隨後的虛擬地址轉換保證數據傳輸到適當的設備。
- 
- This functionality, however, comes at the **cost** of having to support virtual address translation on addresses accessed by a DMA controller and ==requires the addition of an address-translation unit **(MMU)** to the DMA controller.== 
- 然而，此功能的代價是必須支持對 DMA 控制器訪問的地址進行虛擬地址轉換，並且需要向 DMA 控制器添加地址轉換單元。
- 
- The address translation results in **both hardware and software costs** and might also result in ==coherence problems(一致性問題)== between **the data structures <span class="blue">maintained</span> by the CPU for address translation** and **corresponding structures used by the DMA controller**. 
- 地址轉換會導致硬件和軟件成本，並且還可能導致 CPU <span class="blue">維護</span>的用於**地址轉換的數據結構**與 **DMA 控制器使用的相應結構**之間的==一致性問題==。
- 
- These coherence issues would also need to be dealt with and result in a further increase in system complexity.
- 這些連貫性問題也需要處理，並導致系統複雜性進一步增加。
- 
![](https://i.imgur.com/JlOtYwi.png)





# 我的作業解答

## 13.2
- ![](https://i.imgur.com/OVRZTr7.png)
## 13.5
- ![](https://i.imgur.com/ixZLxgh.png)

## 13.6
- ![](https://i.imgur.com/cXOeDDX.png)
    
## 13.8
- ![](https://i.imgur.com/4lVYgQS.png)


