{"id":108824,"date":"2023-09-26T07:00:00","date_gmt":"2023-09-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108824"},"modified":"2023-09-26T09:15:24","modified_gmt":"2023-09-26T16:15:24","slug":"20230926-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230926-00\/?p=108824","title":{"rendered":"Why is kernel32.dll running in user mode and not kernel mode, like its name implies?"},"content":{"rendered":"<p>So there&#8217;s this DLL in Windows called <code>kernel32.dll<\/code>. From its name, you might expect it to be the code that controls 32-bit kernel mode. But in reality, it runs in user mode. Why is the &#8220;kernel&#8221; running in user mode?<\/p>\n<p>Set the time machine to 1985.<\/p>\n<p>Windows 1.0 consisted of three primary components:<\/p>\n<ul>\n<li>KERNEL: Provides low-level services like memory management, task scheduling, file I\/O.<\/li>\n<li>GDI: Provides graphics services.<\/li>\n<li>USER: Provides user interface \/ window manager services.<\/li>\n<\/ul>\n<p>The 8086 processor did not have privilege levels, so there was no privilege separation between programs and the operating system. Any separation between them was accomplished by convention and mutual respect.<\/p>\n<p>When protected mode was introduced in the 80286 processor, it became possible to separate privileged from unprivileged code. The processor has four privilege levels, called <i>rings<\/i>, numbered from zero (most privileged) to three (least privileged). It also has a memory management unit that can be used to present separate address spaces to each application. However, for backward compatibility, 16-bit Windows didn&#8217;t use the address space separation feature because existing programs had gotten into the habit of accessing each other&#8217;s memory by just passing pointers directly back and forth.<\/p>\n<p>Windows also held back on using privilege separation between applications and the Windows kernel, and this ended up coming in handy, because the first 80386 version of Windows used ring 0 for the 32-bit virtual machine manager. The 32-bit virtual machine manager allowed the creation of multiple MS-DOS sessions, each running in a separate virtual machine, and all running alongside a virtual machine in which all of your Windows programs ran.<\/p>\n<p>But even though all of the Windows programs ran at the same privilege level as the Windows kernel, there was a virtual machine manager kernel that the Windows kernel in turn relied upon.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Ring 3<\/td>\n<td style=\"border: solid 1px currentcolor;\">16-bit Windows<\/p>\n<div style=\"padding: 1ex; margin: 1ex; border: solid 1px currentcolor;\">app1<\/div>\n<div style=\"padding: 1ex; margin: 1ex; border: solid 1px currentcolor;\">app2<\/div>\n<div style=\"padding: 1ex; margin: 1ex; border: solid 1px currentcolor;\">KERNEL<\/div>\n<\/td>\n<td style=\"border: solid 1px currentcolor;\">MS-DOS session<\/td>\n<td style=\"border: solid 1px currentcolor;\">MS-DOS session<\/td>\n<\/tr>\n<tr>\n<td>Ring 0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"3\">Virtual machine manager<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>It is the virtual machine manager that runs in ring zero. Initially, the virtual machine manager handled pre-emptive multi-tasking and virtual memory, but it left the file system in 16-bit code. In Windows 3.11 and Windows 95, even the file system itself moved into ring zero.<\/p>\n<p>The job of what you think of as a modern operating system kernel has moved into ring zero, but applications still called functions in <code>KERNEL<\/code> for memory allocation and file I\/O. Those functions in turned relied on ring zero services, but the interface to them is in ring three.<\/p>\n<p>You can think of the names <code>KERNEL<\/code>, <code>GDI<\/code> and <code>USER<\/code> as shorthand for <code>KERNELSERVICES<\/code>, <code>GRAPHICSSERVICES<\/code>, and <code>USERINTERFACESERVICES<\/code>, abbreviated to fit inside the 8-character filename limitation of MS-DOS: The <code>KERNEL<\/code> module is not the ring zero kernel. Rather, it is the thing that gives you access to services which are associated with a modern operating system kernel.<\/p>\n<p>The names <code>KERNEL<\/code>, <code>GDI<\/code>, and <code>USER<\/code>, carried forward to 32-bit Windows, leading to the somewhat confusing situation that <code>KERNEL32<\/code> runs in user mode. It isn&#8217;t the part of the system that runs in kernel mode. Instead, it&#8217;s the part of the operating system that provides kernel-ish services such as allocating memory, accessing files, and interacting with the scheduler.<\/p>\n<p><b>Bonus chatter<\/b>: The 80386 processor does not use the terms &#8220;kernel mode&#8221; and &#8220;user mode&#8221;. It calls the different privilege levels &#8220;rings&#8221;, and it so happens that Windows uses only rings zero and three.\u00b9<\/p>\n<p>Windows NT consolidated the four rings into just two privilege levels because most non-Intel processors supported only two privilege levels anyway. Since Windows NT positioned itself as a portable operating system, it could not be architecturally dependent on a feature that was not present in most potential target processors.<\/p>\n<p>\u00b9 The OS\/2 operating system used three of the four available rings. The privileged operating system code ran at ring zero, and most applications ran in ring three. However, an application could mark certain code segments to be run in ring two, which granted them access to I\/O ports.<\/p>\n<p>Ring one was intended to be used for device drivers, so they can be given access to more system services than regular applications, but without giving them full access to the entire system. I don&#8217;t know whether any operating system ever used ring one for that purpose.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s just a name, and it comes from the days before user-mode\/kernel-mode separation.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-108824","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>It&#8217;s just a name, and it comes from the days before user-mode\/kernel-mode separation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108824","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108824"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108824\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108824"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108824"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108824"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}