blog/public/2023/11/kernel-syscalls/index.html

388 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" dir="auto">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="robots" content="index, follow">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Kernel, syscalls | Morgan&#39;s Blog</title>
<meta name="keywords" content="">
<meta name="description" content="Deep dive Linux Kernel #1">
<meta name="author" content="Me">
<link rel="canonical" href="http://blog.morgan.kr/2023/11/kernel-syscalls/">
<script type="text/javascript">
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
</script>
<link crossorigin="anonymous" href="/assets/css/stylesheet.dde9171333af37b8e856933e0deb815c09f761bbd3ee0e6826d3a1309b808533.css" integrity="sha256-3ekXEzOvN7joVpM&#43;DeuBXAn3YbvT7g5oJtOhMJuAhTM=" rel="preload stylesheet" as="style">
<script defer crossorigin="anonymous" src="/assets/js/highlight.f413e19d0714851f6474e7ee9632408e58ac146fbdbe62747134bea2fa3415e0.js" integrity="sha256-9BPhnQcUhR9kdOfuljJAjlisFG&#43;9vmJ0cTS&#43;ovo0FeA="
onload="hljs.initHighlightingOnLoad();"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" onload="renderMathInElement(document.body);"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "$", right: "$", display: false}
]
});
});
</script>
<link rel="icon" href="https://blog.morgan.kr/favicon.ico">
<meta name="theme-color" content="#2e2e33">
<meta name="msapplication-TileColor" content="#2e2e33">
<noscript>
<style>
#theme-toggle,
.top-link {
display: none;
}
</style>
</noscript><meta property="og:title" content="Kernel, syscalls" />
<meta property="og:description" content="Deep dive Linux Kernel #1" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://blog.morgan.kr/2023/11/kernel-syscalls/" /><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2023-11-11T01:22:30+00:00" />
<meta property="article:modified_time" content="2023-11-11T01:22:30+00:00" /><meta property="og:site_name" content="Morgan&#39;s Blog" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Kernel, syscalls"/>
<meta name="twitter:description" content="Deep dive Linux Kernel #1"/>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [,
{
"@type": "ListItem",
"position": 2 ,
"name": "Posts",
"item": "http://blog.morgan.kr/posts/"
},
{
"@type": "ListItem",
"position": 3 ,
"name": "Kernel, syscalls",
"item": "http://blog.morgan.kr/2023/11/kernel-syscalls/"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Kernel, syscalls",
"name": "Kernel, syscalls",
"description": "Deep dive Linux Kernel #1",
"keywords": [
],
"articleBody": "sys_fork() .align 2 _sys_fork: call _find_empty_process testl %eax,%eax js 1f push %gs pushl %esi pushl %edi pushl %ebp pushl %eax call _copy_process addl $20,%esp 1: ret FUNCTION find_empty_process() A: IF ++last_pid \u003c 0 last_pid = 1 FOR i : 0 -\u003e NR_TASKS IF task[i] \u0026\u0026 task[i].pid == last_pid GOTO A FOR i : 1 -\u003e NR_TASKS IF NOT task[i] RETURN i RETURN -1 Set last_pid to 1 or more.\nFrom taskid from 0 to max_tasks, if task exists and pid is last_pid then increases pid and again.\nFrom taskid from 1 to max_tasks, if tasks not exists, return.\n-\u003e It just iterates through tasks and find last taskid linearly.\nFUNCTION copy_process \u003c- nr, EBP, EDI, ESI, GS, EBX~EDX, CS~FS, EIP, EFLAGS, ESP, SS -\u003e INT TASK_STRUCT P INT I FILE F P = (TASK_STRUCT)(GET_FREE_PAGE()) IF NOT P RET ERR SET P START_TIME = RUNNING PID = LAST_PID FATHER = CURRENT_PID COUNTER = PRIORITY START_TIME = jiffies SIGNAL, ALARM, LEADER, UTIME, STIME, CUTIME, CSDTIME, BACK_LINK = 0 SET TSS BACK_LINK = 0 ESP0 = PAGE_SIZE + ADDR(P) SS0 = 0x10 EAX = 0 ES ~ GS = 0xFFFF LDT = _LDT(nr) EIP, EFLAGS = ARGUMENT ECX ~ EDI = ARGUMENT TRACR_BITMAP = 0x80000000 COPY_MEM (nr, p) IF \u003c- FREE_PAGE ADDR(P) RET ERR FOR i : 0 ~ NR_OPEN IF f = P.filp[i] THEN INCR f.f_count 1 IF CURRENT.PWD THEN INCR CURRENT.PWD.i_count 1 IF CURRENT.ROOT THEN INCR CURRENT.ROOT.i_count 1 SET_TSS_DESC \u003c- (GDT + nr/2 + FIRST_TSS_ENTRY) , P.TSS SET_LDT_DESC \u003c- (GDT + nr/2 + FIRST_LDT_ENTRY) , P.LDT task(nr) \u003c- p RET last_pid “nr” passed is the index of the new task in the task array, where each element corresponds to a process slot. fork() copies the parents kernel context, as well as general registers and segment selectors required for a new process to run in user space. It creates a new task structure from a new free page and sets up default values and certain parameters inherited from the parent, such as process ID, priority, and execution times. Then it copies memory regions from the parent to the new process, referred to by “nr,” which is the index of the new process in the task array. Changes the parent processs working directory (PWD) and root directory reference counters, incrementing them by 1 to reflect the new child process now also using these resources. Sets the Task State Segment (TSS) and Local Descriptor Table (LDT) entries, which are x86-specific structures used for task switching and memory segmentation, respectively. TSS holds information about the tasks stack for privilege level changes and also the hardware context when a task switch occurs. LDT is a segment descriptor table that stores descriptors for local segments, giving a task its own set of segment registers. Finally, it assigns the newly created task structure, p, to the task array at index “nr.” This effectively makes the new task available for scheduling. _sys_fork() “sys_fork” finds an empty process ID using the search loop in _find_empty_process, then it invokes _copy_process to clone the parents kernel context to the new process. This sets up a complete environment for the new process to run independently from the parent, but initially as a nearly identical copy.\n",
"wordCount" : "532",
"inLanguage": "en",
"datePublished": "2023-11-11T01:22:30Z",
"dateModified": "2023-11-11T01:22:30Z",
"author":{
"@type": "Person",
"name": "Me"
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "http://blog.morgan.kr/2023/11/kernel-syscalls/"
},
"publisher": {
"@type": "Organization",
"name": "Morgan's Blog",
"logo": {
"@type": "ImageObject",
"url": "https://blog.morgan.kr/favicon.ico"
}
}
}
</script>
</head>
<body class=" dark" id="top"><header class="header">
</header>
<script>
if (localStorage.getItem("pref-theme") === "light") {
document.body.classList.remove('dark')
document.getElementById('main-logo').src = "\/favicon-inv.png";
}
</script>
<main class="main">
<article class="post-single">
<header class="post-header">
<h1 class="post-title">
Kernel, syscalls
</h1>
<div class="post-description">
Deep dive Linux Kernel #1
</div>
<div class="post-meta"><span title='2023-11-11 01:22:30 &#43;0000 UTC'>
Nov 11, 2023
</span>
</div>
</header>
<div class="post-divider"></div>
<div class="post-content"><h3 id="sys_fork">sys_fork()<a hidden class="anchor" aria-hidden="true" href="#sys_fork">#</a></h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="na">.align</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="nl">_sys_fork:</span>
</span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="no">_find_empty_process</span>
</span></span><span class="line"><span class="cl"> <span class="nf">testl</span> <span class="nv">%eax</span><span class="p">,</span><span class="nv">%eax</span>
</span></span><span class="line"><span class="cl"> <span class="nf">js</span> <span class="mi">1</span><span class="no">f</span>
</span></span><span class="line"><span class="cl"> <span class="nf">push</span> <span class="nv">%gs</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pushl</span> <span class="nv">%esi</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pushl</span> <span class="nv">%edi</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pushl</span> <span class="nv">%ebp</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pushl</span> <span class="nv">%eax</span>
</span></span><span class="line"><span class="cl"> <span class="nf">call</span> <span class="no">_copy_process</span>
</span></span><span class="line"><span class="cl"> <span class="nf">addl</span> <span class="no">$20</span><span class="p">,</span><span class="nv">%esp</span>
</span></span><span class="line"><span class="cl"><span class="err">1:</span> <span class="nf">ret</span>
</span></span></code></pre></div><h4 id="function-find_empty_process"><code>FUNCTION find_empty_process()</code><a hidden class="anchor" aria-hidden="true" href="#function-find_empty_process">#</a></h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">A:
</span></span><span class="line"><span class="cl"> IF ++last_pid &lt; 0
</span></span><span class="line"><span class="cl"> last_pid = 1
</span></span><span class="line"><span class="cl"> FOR i : 0 -&gt; NR_TASKS
</span></span><span class="line"><span class="cl"> IF task[i] &amp;&amp; task[i].pid == last_pid
</span></span><span class="line"><span class="cl"> GOTO A
</span></span><span class="line"><span class="cl"> FOR i : 1 -&gt; NR_TASKS
</span></span><span class="line"><span class="cl"> IF NOT task[i]
</span></span><span class="line"><span class="cl"> RETURN i
</span></span><span class="line"><span class="cl"> RETURN -1
</span></span></code></pre></div><ol>
<li>
<p>Set last_pid to 1 or more.</p>
</li>
<li>
<p>From taskid from 0 to max_tasks, if task exists and pid is last_pid then increases pid and again.</p>
</li>
<li>
<p>From taskid from 1 to max_tasks, if tasks not exists, return.</p>
</li>
</ol>
<p>-&gt; It just iterates through tasks and find last taskid linearly.</p>
<h4 id="function-copy_process"><code>FUNCTION copy_process</code><a hidden class="anchor" aria-hidden="true" href="#function-copy_process">#</a></h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&lt;- nr, EBP, EDI, ESI, GS, EBX~EDX, CS~FS, EIP, EFLAGS, ESP, SS
</span></span><span class="line"><span class="cl">-&gt; INT
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">TASK_STRUCT P
</span></span><span class="line"><span class="cl">INT I
</span></span><span class="line"><span class="cl">FILE F
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">P = (TASK_STRUCT)(GET_FREE_PAGE())
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IF NOT P
</span></span><span class="line"><span class="cl"> RET ERR
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">SET P
</span></span><span class="line"><span class="cl"> START_TIME = RUNNING
</span></span><span class="line"><span class="cl"> PID = LAST_PID
</span></span><span class="line"><span class="cl"> FATHER = CURRENT_PID
</span></span><span class="line"><span class="cl"> COUNTER = PRIORITY
</span></span><span class="line"><span class="cl"> START_TIME = jiffies
</span></span><span class="line"><span class="cl"> SIGNAL, ALARM, LEADER, UTIME, STIME, CUTIME, CSDTIME, BACK_LINK = 0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> SET TSS
</span></span><span class="line"><span class="cl"> BACK_LINK = 0
</span></span><span class="line"><span class="cl"> ESP0 = PAGE_SIZE + ADDR(P)
</span></span><span class="line"><span class="cl"> SS0 = 0x10
</span></span><span class="line"><span class="cl"> EAX = 0
</span></span><span class="line"><span class="cl"> ES ~ GS = 0xFFFF
</span></span><span class="line"><span class="cl"> LDT = _LDT(nr)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> EIP, EFLAGS = ARGUMENT
</span></span><span class="line"><span class="cl"> ECX ~ EDI = ARGUMENT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> TRACR_BITMAP = 0x80000000
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">COPY_MEM (nr, p)
</span></span><span class="line"><span class="cl">IF &lt;-
</span></span><span class="line"><span class="cl"> FREE_PAGE ADDR(P)
</span></span><span class="line"><span class="cl"> RET ERR
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">FOR i : 0 ~ NR_OPEN
</span></span><span class="line"><span class="cl"> IF
</span></span><span class="line"><span class="cl"> f = P.filp[i]
</span></span><span class="line"><span class="cl"> THEN
</span></span><span class="line"><span class="cl"> INCR f.f_count 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IF
</span></span><span class="line"><span class="cl"> CURRENT.PWD
</span></span><span class="line"><span class="cl">THEN
</span></span><span class="line"><span class="cl"> INCR CURRENT.PWD.i_count 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IF
</span></span><span class="line"><span class="cl"> CURRENT.ROOT
</span></span><span class="line"><span class="cl">THEN
</span></span><span class="line"><span class="cl"> INCR CURRENT.ROOT.i_count 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">SET_TSS_DESC &lt;- (GDT + nr/2 + FIRST_TSS_ENTRY) , P.TSS
</span></span><span class="line"><span class="cl">SET_LDT_DESC &lt;- (GDT + nr/2 + FIRST_LDT_ENTRY) , P.LDT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">task(nr) &lt;- p
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">RET last_pid
</span></span></code></pre></div><ul>
<li>&ldquo;nr&rdquo; passed is the index of the new task in the task array, where each element corresponds to a process slot.</li>
<li>fork() copies the parent&rsquo;s kernel context, as well as general registers and segment selectors required for a new process to run in user space.</li>
<li>It creates a new task structure from a new free page and sets up default values and certain parameters inherited from the parent, such as process ID, priority, and execution times.</li>
<li>Then it copies memory regions from the parent to the new process, referred to by &ldquo;nr,&rdquo; which is the index of the new process in the task array.</li>
<li>Changes the parent process&rsquo;s working directory (PWD) and root directory reference counters, incrementing them by 1 to reflect the new child process now also using these resources.</li>
<li>Sets the Task State Segment (TSS) and Local Descriptor Table (LDT) entries, which are x86-specific structures used for task switching and memory segmentation, respectively.</li>
<li>TSS holds information about the task&rsquo;s stack for privilege level changes and also the hardware context when a task switch occurs.</li>
<li>LDT is a segment descriptor table that stores descriptors for local segments, giving a task its own set of segment registers.</li>
<li>Finally, it assigns the newly created task structure, p, to the task array at index &ldquo;nr.&rdquo; This effectively makes the new task available for scheduling.</li>
</ul>
<h3 id="_sys_fork"><code>_sys_fork()</code><a hidden class="anchor" aria-hidden="true" href="#_sys_fork">#</a></h3>
<p>&ldquo;sys_fork&rdquo; finds an empty process ID using the search loop in <code>_find_empty_process</code>, then it invokes <code>_copy_process</code> to clone the parent&rsquo;s kernel context to the new process. This sets up a complete environment for the new process to run independently from the parent, but initially as a nearly identical copy.</p>
</div>
<footer class="post-footer">
<ul class="post-tags">
</ul>
<nav class="pag-back">
<a href="#back" onclick="window.history.back()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" focusable="false" style="pointer-events: none; display: block; width: 100%; height: 100%;fill: var(--primary);stroke: var(--primary);" stroke-width="1"><polygon points="11.65,3.50 3.80,11.35 11.65,19.20 12.36,18.50 5.71,11.85 20.15,11.85 20.15,10.85 5.71,10.85 12.36,4.20"></polygon></svg>
</a>
</nav>
<br/>
</footer>
</article>
</main>
<footer class="footer">
<a href="/admin/" style="text-decoration: none;">&copy;</a> <span><a href="http://blog.morgan.kr">Morgan</a> · PaperMod</span>
<br/>
<span style="">Ver.11081623 </span>
<a href="#" id="theme-toggle">Toggle Dark Mode</a>
</footer>
<button id="top-link" class="top-link" onclick="window.scrollTo({top: 0, behavior: 'smooth'})">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" style="pointer-events: none; display: block; width: 100%; height: 100%;" fill="currentColor" stroke="white" stroke-width="1"><polygon points="19.35,11.5 11.5,3.65 3.65,11.5 4.35,12.21 11,5.56 11,20 12,20 12,5.56 18.65,12.21"></polygon></svg>
</button>
<script>
let menu = document.getElementById('menu')
if (menu) {
menu.scrollLeft = localStorage.getItem("menu-scroll-position");
menu.onscroll = function () {
localStorage.setItem("menu-scroll-position", menu.scrollLeft);
}
}
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
var id = this.getAttribute("href").substr(1);
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({
behavior: "smooth"
});
} else {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();
}
if (id === "top") {
history.replaceState(null, null, " ");
} else {
history.pushState(null, null, `#${id}`);
}
});
});
</script>
<script>
var mybutton = document.getElementById("top-link");
window.onscroll = function () {
if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {
mybutton.style.visibility = "visible";
mybutton.style.opacity = "1";
} else {
mybutton.style.visibility = "hidden";
mybutton.style.opacity = "0";
}
};
</script>
<script>
document.getElementById("theme-toggle").addEventListener("click", () => {
if (document.body.className.includes("dark")) {
document.body.classList.remove('dark');
localStorage.setItem("pref-theme", 'light');
document.getElementById('main-logo').src = "\/favicon-inv.png";
} else {
document.body.classList.add('dark');
localStorage.setItem("pref-theme", 'dark');
document.getElementById('main-logo').src = "\/favicon.png";
}
})
</script>
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement('button');
copybutton.classList.add('copy-code');
copybutton.innerHTML = 'copy';
function copyingDone() {
copybutton.innerHTML = 'copied!';
setTimeout(() => {
copybutton.innerHTML = 'copy';
}, 2000);
}
copybutton.addEventListener('click', (cb) => {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(codeblock.textContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
copyingDone();
} catch (e) { };
selection.removeRange(range);
});
if (container.classList.contains("highlight")) {
container.appendChild(copybutton);
} else if (container.parentNode.firstChild == container) {
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
} else {
codeblock.parentNode.appendChild(copybutton);
}
});
</script>
</body>
</html>