> For the complete documentation index, see [llms.txt](https://dev.tesa.or.th/tesa-developer/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dev.tesa.or.th/tesa-developer/tesa-technical-contents/linux-os/zero-to-linux-hero/anatomy-of-linux-kernel/linux-os-architecture.md).

# Linux OS Architecture

ตั้งแต่ที่ Andrew Tanenbaum ได้สร้าง Microkernel *<mark style="color:blue;">(อ่านรายละเอียดของ Linux Kernel เพิ่มเติม)</mark>* version of UNIX® ที่เรียกขานกันว่า "MINIX" (for minimal UNIX) สำหรับให้สามารถใช้งานได้บนเครื่องคอมพิวเตอร์ส่วนบุคคลขนาดเล็ก ทำให้ Linus Torvalds เริ่มปล่อย kernel source codes ตั้งแต่นั้นมา (early 1990s)

โครงสร้างพื้นฐานภายในระบบปฏิบัติการลีนุกซ์ซึ่งมีเคอร์เนลเป็นตัวเชื่อมโยงกลางระหว่างโปรแกรมระบบ และระบบฮาร์ดแวร์ ซึ่งเคอร์เนลนั้นจะถูกห่อหุ้มโดยเชลล์ (Shell) ที่มีด้วยกัน 2 ส่วนคือ CLI (Command Line Interface) และ GUI (Graphic User Interface) ส่วนชั้นนอกสุดจะเป็นส่วนโปรแกรมสำหรับผู้ใช้ดังแสดงในรูปข้างล่าง

### รายละเอียดของแต่ละชั้นภายในสถาปัตยกรรมของระบบปฏิบัติการลีนุกซ์

จากรูปโครงสร้างสถาปัตยกรรมของระบบปฏิบัติการลีนุกซ์ข้างล่าง ส่วนของชั้นบนสุดจะเป็นส่วนของโปรแกรมประยุกต์ต่างๆสำหรับให้ผู้ใช้ได้เรียกใช้งานได้ ซึ่งสามารถเรียกไปยังเคอร์เนลได้ 2 ทางคือผ่าน GNU C Library และเรียกตรงไปยัง System Call Interface (SCI) โดยที่โปรแกรมสำหรับผู้ใช้ และ GNU C Library นั้นจะอยู่ในพื้นที่ส่วนของผู้้ใช้ที่เรียกว่า User Space

ในส่วนของพื้นที่ที่สำคัญมากอีกส่วนคือ Kernel Space ซึ่งประกอบไปด้วย SCI, เคอร์เนล และส่วนเคอร์เนลที่ขึ้นอยู่กับชนิดของสถาปัตยกรรมนั้นๆ เรียกกันว่า Board Support Package (BSP) โดยตัว SCI จะมีบทบาทสำคัญที่เป็นตัวกลางให้กับโปรแกรมประยุกต์ต่างๆ รวมทั้ง C Library ทั้งหมดเพื่อรองรับการเรียกใช้เคอร์เนลของระบบในการขอเข้าถึงระบบฮาร์ดแวร์ต่างๆ

ตัวอย่างการทำงานเช่นเมื่อผู้ใช้ต้องการจะเปิดอ่านไฟล์ที่ถูกเก็บอยู่ใน USB Storage ผู้ใช้ก็จะทำการเรียกใช้โปรแกรมประยุกต์ตัวหนึ่งขึ้นมา โดยภายในโปรแกรมประยุกต์นั้นจะต้องเรียกใช้ฟังก์ชัน read/write ไฟล์ที่เป็นฟังก์ชันภายใน GNU C Library ซึ่งจะเรียกตรงไปยังฟังก์ชันภายใน System Call อีกต่อนึง เมื่อต้องการเปิดไฟล์ที่ถูกเก็บอยู่ใน USB Storage ตัวเคอร์เนลก็ต้องรู้วิธีการเข้าถึงระบบไฟล์ (File System) ที่ USB Storage นั้นใช้อยู่ เช่น FAT32 ดังนั้นตัวคอร์เนลจะต้องใช้ฟังก์ชันไดรเวอร์ภายในเคอร์เนลเพื่อเข้าถึงไฟล์ตามรูปแบบมาตราฐานโปรโตคอลของในระบบไฟล์ชนิด FAT32

จากโครงสร้างข้างต้น แต่ละชั้นมีรายละเอียดดังนี้

* <mark style="color:blue;">Hardware Layer</mark> - อุปกรณ์ฮาร์ดแวร์ภายในบอร์ด ตัวอย่างเช่น หน่วยประมวลผลขนาด 32 บิตขึ้นไป หน่วยจัดการหน่วยความจำ (MMU - Memory Management Unit) หน่วยความจำขนาดเล็ก (RAM) หน่วยความจำแบบอ่านได้อย่างเดียว (ROM) ตัวบันทึกข้อมูลประเภทแฟลต เช่น MMC/SD Card เป็นต้น
* <mark style="color:blue;">Linux Kernel Layer</mark> *(Kernel-space)* - ทำหน้าที่ควบคุมจัดการอุปกรณ์ฮาร์ดแวร์ทั้งหมด จัดการการจัดคิวของโปรเซสต่างๆ จัดเตรียมฟังก์ชันสำคัญ (System Calls) ให้กับโปรแกรมประยุกต์ เป็นต้น ซึ่งจะมีองค์ประกอบภายในที่มีหน้าที่สำคัญๆ ได้แก่
  * *<mark style="color:orange;">Low-level interfaces</mark>*
    * จัดเตรียมชุด APIs (Application Programming Interface) สำหรับการติดต่อกับฮาร์ดแวร์ แบบที่ไม่ขึ้นอยู่กับรุ่นของฮาร์ดแวร์
    * เป็นส่วนดูแลและจัดการฮาร์ดแวร์ต่างๆเช่น การทำงานของหน่วยประมวลผลกลาง การทำงานของหน่วยความจำ ติดต่อกับพอร์ตสื่อสาร และ I/O Devices เป็นต้น
  * *<mark style="color:orange;">High-level abstractions</mark>*
    * จะจัดเตรียมฟังก์ชันให้โปรแกรมประยุกต์สามารถสื่อสารระหว่างกันได้ และทำงานแบบ multi-tasking ได้ เช่น IPC, Threading, Socket, Signalling เป็นต้น
    * โค้ดโปรแกรมส่วนใหญ่สามารถนำไปใช้ต่อได้เกือบทุกสถาปัตยกรรม
  * *<mark style="color:orange;">Filesystems</mark>*
    * สามารถรองรับระบบ filesystems ต่างๆที่มีอยู่ในปัจจุบันได้ไม่น้อยกว่า 40 ชนิด
    * จะมี Virtual Filesystem layer ที่ทำให้การเรียกใช้ filesystems ที่แตกต่างเหล่านั้นง่ายและสะดวกขึ้นโดยที่ไม่ต้องเขียนโค้ดใหม่
  * *<mark style="color:orange;">Networking protocols</mark>*
    * รองรับโปรโตคอลมาตราฐานต่างๆที่ใช้กันอยู่ในปัจจุบันได้ไม่น้อยกว่า 50 ชนิด
    * มีฟังก์ชัน Socket APIs ที่ใช้ในการจัดการและกำหนดการเชื่อมต่อในแต่ละแบบของระบบเครือข่ายนั้นๆ

3. <mark style="color:blue;">Libraries</mark> *(User-space)* - ไลบรารีที่อยู่ในระดับของ user space ที่มีความหลากหลายมากกว่าที่มีอยู่ในเคอร์เนล ไม่ว่าจะเป็นไลบรารีทางด้านการคำนวณ การแสดงผลกราฟฟิก การประมวลผลข้อมูลดิจิตอล การสื่อสารข้อมูลผ่านระบบเครือข่าย การเข้ารหัส/ถอดรหัส และ การติดต่อกับอุปกรณ์ฮาร์ดแวร์ที่มาเชื่อมต่อกับบอร์ด เป็นต้น ดังนั้นถ้าโปรแกรมประยุกต์ต้องการจะติดต่อกับเคอร์เนลจะเรียกผ่านไลบรารีชื่อว่า glibc (ซึ่งประกอบไปด้วยตัวย่อยคือ uClibc และ eglibc)

### A history of shells <a href="#a-history-of-shells" id="a-history-of-shells"></a>

Shells หรือตัวแปลคำสั่ง มีประวัติอันยาวนาน แต่ในเนื้อหานี้เราจะเริ่มต้นด้วย shell แรกของ UNIX® ที่ Ken Thompson (จาก Bell Labs) พัฒนาขึ้นเรียกว่า `V6 shell` ในปี 1971 ซึ่งเหมือนกับลำดับก่อนหน้าใน Multics shell นี้ (`/bin/sh`) เป็นโปรแกรมผู้ใช้ที่เป็นอิสระที่ดำเนินการอยู่นอกเคอร์เนล แนวคิดเช่น Globbing เป็นเทคนิคที่ใช้ในการระบุหนึ่งหรือหลายไฟล์ด้วยแพทเทิร์น ส่วนใหญ่ใช้ในกรณีที่ผู้ใช้ไม่ต้องการหรือไม่สามารถระบุแต่ละไฟล์ได้โดยตรง สัญลักษณ์ที่ใช้ในการ globbing สามารถแตกต่างกันไปตามระบบปฏิบัติการ แต่ในระบบปฏิบัติการที่ใช้ Unix เช่น Linux หรือ macOS ประกอบด้วย:

1. `*` (ดาว): ตรงกับศูนย์หรือมากกว่ารายการที่มีอยู่
2. `?` (เครื่องหมายคำถาม): ตรงกับตัวอักษรเดียว
3. `[]` (สแควร์บราเก็ต): ตรงกับตัวอักษรใดตัวอักษรหนึ่งที่อยู่ในสแควร์บราเก็ต

ตัวอย่างการใช้ globbing:

* `*.txt`: สั่งให้ระบบทำงานกับไฟล์ทั้งหมดที่มีนามสกุล .txt
* `data?`: สั่งให้ระบบทำงานกับไฟล์ที่ชื่อขึ้นต้นด้วย "data" และตามด้วยตัวอักษรอื่นๆ ตัวเดียว
* `data[0-9]`: สั่งให้ระบบทำงานกับไฟล์ที่ชื่อขึ้นต้นด้วย "data" และตามด้วยตัวเลข 0-9 อันใดอันหนึ่ง

การใช้ globbing ทำให้การจัดการไฟล์ต่างๆ ที่มีลักษณะที่คล้ายคลึงกันเป็นเรื่องง่ายขึ้นโดยสามารถระบุเป็นกลุ่ม ทำให้ไม่จำเป็นต้องระบุชื่อไฟล์ที่แน่นอนทุกครั้ง ทำให้การทำงานมีความรวดเร็วและมีประสิทธิภาพมากขึ้น โดยแนคิดนี้จึงถูก implement ในโปรแกรม utility ที่เรียกว่า `glob` เช่นเดียวกับคำสั่ง `if` สำหรับการประเมินนิพจน์เงื่อนไข การแยกส่วนนี้ทำให้ shell มีขนาดเล็ก ที่เขียนด้วยภาษา C ต่ำกว่า 900 บรรทัด

> Shell นำเสนอไวยากรณ์ที่สั้นกระชับสำหรับการเปลี่ยนทาง (< > และ >>) และการท่อ (| หรือ ^) ที่ยังคงมีอยู่ใน shell สมัยใหม่ คุณยังพบการสนับสนุนการเรียกใช้คำสั่งที่ต่อเนื่อง (ด้วย ;) และคำสั่งที่ไม่ประสานกัน (ด้วย &)

> สิ่งที่ขาดหายไปใน shell ของ Thompson คือความสามารถในการเขียนสคริปต์ จุดประสงค์เดียวของมันคือเป็น shell แบบโต้ตอบ (ตัวแปลคำสั่ง) เพื่อเรียกใช้คำสั่งและดูผลลัพธ์

ตั้งแต่ที่ Thompson Shell เกิดขึ้น แต่คนก็พยายามหา shell ยุคสมัยใหม่อย่าง Bourne shell ที่เกิดขึ้นใน คศ. 1977 ซึ่งถูกสร้างโดย Stephen Bourne ที่ AT\&T Bell Labs สำหรับ V7 UNIX และยังเป็น shell ที่มีประโยชน์ในปัจจุบัน (บางกลุ่มเรียกว่า root shell) ไวยากรณ์ (syntax) ของ Bourne shell จะมีความคล้ายคลึงกับ Algorithmic Language (ALGOL) มากกว่า shell อื่น ๆ

Bourne shell มีสองเป้าหมายหลักคือทำหน้าที่เป็นตัวแปลคำสั่งเพื่อใช้ในการเรียกใช้คำสั่งของระบบปฏิบัติการแบบโต้ตอบและสำหรับสคริปต์ (เขียนสคริปต์ที่สามารถใช้ซ้ำและเรียกใช้ผ่าน shell) นอกจากการแทนที่ shell ของ Thompson แล้ว Bourne shell ยังมีหลายข้อดีเหนือตัวอื่น ๆ โดยได้นำเสนอ control flows, loops, และ variables ลงในสคริปต์ ให้ภาษามีประสิทธิภาพมากขึ้นในการโต้ตอบกับระบบปฏิบัติการได้

#### Basic Shell Architecture

สถาปัตยกรรมพื้นฐานของ hypothetical shell นั้นเรียบง่าย *(ตามที่แสดงให้เห็นโดย shell ของ Bourne ในรูปข้างล่าง)* โดยสถาปัตยกรรมพื้นฐานดูคล้ายกับ pipeline ที่ทำการวิเคราะห์และแยกส่วนข้อมูลที่ป้อนเข้ามา, สัญลักษณ์ (symbols) จะนำมาถูกขยายความ (เช่น การขยายและการแทนที่ brace, tilde, variable และ parameter, และการสร้างชื่อไฟล์) และในที่สุดคำสั่งจะถูกดำเนินการ (โดยใช้คำสั่งที่ต่อติดใน shell, หรือคำสั่งภายนอก)
