<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Blog do Rodrigo Branco]]></title><description><![CDATA[Blog do Rodrigo Branco]]></description><link>https://blog.rodrigobranco.net</link><image><url>https://substackcdn.com/image/fetch/$s_!4DXk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a96203-0b94-40e3-a18d-cfc4b328aadf_403x407.jpeg</url><title>Blog do Rodrigo Branco</title><link>https://blog.rodrigobranco.net</link></image><generator>Substack</generator><lastBuildDate>Wed, 22 Apr 2026 12:53:00 GMT</lastBuildDate><atom:link href="https://blog.rodrigobranco.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rodrigo Branco]]></copyright><language><![CDATA[pt]]></language><webMaster><![CDATA[rodrigobranco@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[rodrigobranco@substack.com]]></itunes:email><itunes:name><![CDATA[Rodrigo Gonçalves de Branco]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rodrigo Gonçalves de Branco]]></itunes:author><googleplay:owner><![CDATA[rodrigobranco@substack.com]]></googleplay:owner><googleplay:email><![CDATA[rodrigobranco@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rodrigo Gonçalves de Branco]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Interrupções de Hardware e Concurrency Hell]]></title><description><![CDATA[Trabalhando com PIC, PIT e as consequ&#234;ncias disso]]></description><link>https://blog.rodrigobranco.net/p/interrupcoes-de-hardware-e-concurrency</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/interrupcoes-de-hardware-e-concurrency</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Thu, 13 Feb 2025 00:37:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RMPy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RMPy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RMPy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RMPy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg" width="400" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RMPy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 424w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 848w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!RMPy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1cdcd0ef-9f0b-4ede-ab62-56ceb95362bf_400x480.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.meme-arsenal.com/en/create/meme/790224</figcaption></figure></div><p><a href="https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos">No post anterior</a> iniciamos o tratamento de interrup&#231;&#245;es, em especial na instala&#231;&#227;o do IDT e de exce&#231;&#245;es (interrup&#231;&#245;es de <em>software</em>). Fiz algumas corre&#231;&#245;es no c&#243;digo, os c&#243;digos hexadecimais no arquivo <code>isr.asm</code> estavam errados. Mas nada que voc&#234; n&#227;o consiga olhar o c&#243;digo e entender a mudan&#231;a.</p><p>Isso posto, vamos ao que interessa: interrup&#231;&#245;es de <em>hardware</em>! Voc&#234; vai entender o motivo de termos separado as interrup&#231;&#245;es. &#201; necess&#225;rio primeiro entender como as interrup&#231;&#245;es de <em>hardware </em>ocorrem.</p><p>O processador x86 possui uma linha dedicada para ser notificado das notifica&#231;&#245;es de <em>hardware</em>. Quando o nono bit do registrador EFLAGS (come&#231;ando de zero) est&#225; setado, significa que as interrup&#231;&#245;es est&#227;o ligadas. Qualquer indiv&#237;duo que envie sinais na linha de interrup&#231;&#227;o do processador far&#225; com que o processador pare o que est&#225; fazendo para tratar o dito cujo. E quem &#233; que est&#225; ligado nessa linha de interrup&#231;&#227;o no processador x86? Ele mesmo, o PIC (<em>Programmable Interrupt Controller</em>)!</p><p>O PIC &#233; um microcontrolador da fam&#237;lia 8259A, um <em>hardware </em>muito simples (quando comparamos com um processador), respons&#225;vel apenas por gerenciar as interrup&#231;&#245;es de <em>hardware</em>. Os perif&#233;ricos s&#227;o ligados nas linhas de pedido de interrup&#231;&#227;o, e o <em>hardware </em>&#233; t&#227;o simples que ele s&#243; tem 8 dessas linhas dispon&#237;veis. O pedido de interrup&#231;&#227;o &#233; popularmente conhecido como IRQ (Interrupt Request).</p><h2>Epa, s&#243; 8 IRQs? Meu computador tem muito mais hardware que isso!</h2><p>Voc&#234; &#233; perspicaz, pequeno jovem. De fato, 8 IRQs para todos os <em>hardwares</em> &#233; muito pouco. Inclusive antigamente, no tempo de guaran&#225; de rolha, voc&#234; tinha que individualmente nos <em>hardwares </em>indicar qual IRQ ele iria usar. Observe na imagem abaixo de uma placa <em>ISA Soundblaster</em> com seus jumpers de IRQ destacados.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DRIq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DRIq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DRIq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg" width="1456" height="773" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:773,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:357906,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DRIq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DRIq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d2737f8-a25b-48cf-bdba-a30bb31d8ce8_1600x849.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: http://nerdlypleasures.blogspot.com/2010/06/issues-with-sound-blasters.html</figcaption></figure></div><p>Era muito comum inclusive dois <em>hardwares</em> diferentes usarem a mesma IRQ, ai voc&#234; j&#225; viu onde isso vai dar. Hoje em dia &#233; pouqu&#237;ssimo comum algum tipo de configura&#231;&#227;o desse tipo, mas fica aqui o registro.</p><p>Mas voltando ao problema original, de ter a disposi&#231;&#227;o apenas 8 IRQs, uma caracter&#237;stica interessante do 8259A &#233; que ele pode ser usado em cascata. O que isso significa? Que voc&#234; usar umas das IRQs do 8259A para ligar outro 8259A! Assim, acabamos com 8 IRQs do primeiro PIC mais 8 IRQs do segundo. Menos um na verdade: umas das IRQs do primeiro &#233; usada para ligar o segundo). Assim, temos a nossa disposi&#231;&#227;o incr&#237;veis 15 IRQs para plugar todos os <em>hardwares</em>.</p><p>Note que nem todo <em>hardware </em>precisa ser ligado ao PIC, apenas os que interrompem o processador. Por exemplo, dispositivos de sa&#237;da, como monitores, n&#227;o necessariamente precisam usar interrup&#231;&#245;es (hoje em dia tudo &#233; programado, mas isso &#233; outra hist&#243;ria).</p><p>O diagrama de liga&#231;&#227;o do processador x86 e dos PICs &#233; apresentado a seguir.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YgQa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YgQa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 424w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 848w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 1272w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YgQa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png" width="792" height="534" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:534,&quot;width&quot;:792,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:210848,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YgQa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 424w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 848w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 1272w, https://substackcdn.com/image/fetch/$s_!YgQa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf82dee6-2bef-41f8-9b92-17d07b7c3777_792x534.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Obs: Se seu sistema est&#225; usando APIC (<em>Advanced Programmable Interrupt Controller</em>) ou IOAPIC (<em>Intel I/O Advanced Programmable Interrupt Controller</em>), provavelmente o funcionamento &#233; diferente. Nesse caso, sugiro que voc&#234; verifique como eles funcionam <a href="https://wiki.osdev.org/APIC">AQUI</a> e <a href="https://wiki.osdev.org/IOAPIC">AQUI</a>.</p><p>Continuando, ent&#227;o quando um <em>hardware </em>ligado a um dos PICs aciona um IRQ, ele identifica por qual linha de IRQ o pedido veio, e converte essa identifica&#231;&#227;o em um n&#250;mero bin&#225;rio e o armazena dentro do registrador do PIC. Por exemplo, o IRQ 0 se refere ao PIT (<em>Programmable Interval Timer</em>), e o veremos a seguir. Por hora, ele transforma esse n&#250;mero zero em zero bin&#225;rio (duh!) e o armazena nesse registrador. O PIC ent&#227;o aciona a INT Line para avisar o processador, e se ele estiver de bom humor (o nono bit do registrador EFLAGS estiver setado), o processador para o que estiver fazendo para tratar essa interrup&#231;&#227;o. O processador usa o valor do registrador do PIC para acessar a entrada correspondente no IDT e encontrar a rotina de tratamento. Para ver o post anterior sobre IDT, acesse <a href="https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos">AQUI</a>.</p><p>Como funciona para a cascata do segundo PIC? Suponha que chegou uma IRQ na quarta linha (come&#231;ando do zero) do segundo PIC. Essa interrup&#231;&#227;o veio do Mouse PS/2 (sabe o que &#233; isso jovem?). Esse PIC armazena quatro em bin&#225;rio no seu registrador, e ativa a sua linha de interrup&#231;&#227;o.</p><p>Essa linha de interrup&#231;&#227;o est&#225; ligada diretamente na IRQ 2 do PIC <em>master</em>. Quando vem interrup&#231;&#245;es dessa linha, o PIC sabe que ocorreu uma interrup&#231;&#227;o no PIC em cascata. Ele ent&#227;o consulta no registrador do primeiro PIC para descobri qual foi a interrup&#231;&#227;o que ocorreu. Ele ent&#227;o adiciona o offset de suas pr&#243;prias interrup&#231;&#245;es (ele possui 8 linhas de interrup&#231;&#227;o) e armazena em seu registrador o n&#250;mero resultante. Portanto, no PIC <em>master</em>, o que est&#225; registrado &#233; o valor 12. Esse, por sua vez, aciona a linha interrup&#231;&#227;o para indicar um evento de interrup&#231;&#227;o ao processador.</p><p>A tabela de IRQs &#233; bem conhecida e pode ser vista abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L00q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L00q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 424w, https://substackcdn.com/image/fetch/$s_!L00q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 848w, https://substackcdn.com/image/fetch/$s_!L00q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 1272w, https://substackcdn.com/image/fetch/$s_!L00q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L00q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png" width="414" height="551" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:551,&quot;width&quot;:414,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29031,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L00q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 424w, https://substackcdn.com/image/fetch/$s_!L00q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 848w, https://substackcdn.com/image/fetch/$s_!L00q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 1272w, https://substackcdn.com/image/fetch/$s_!L00q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F452af2b8-b2ab-45fe-b1a8-96e9efb2918e_414x551.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://wiki.osdev.org/Interrupts</figcaption></figure></div><p>No fim das contas, depois das corre&#231;&#245;es feitas se a interrup&#231;&#227;o se originou no PIC em cascata, o n&#250;mero de 0 a 15 indicar&#225; qual entrada no IDT ficar&#225; respons&#225;vel por tratar a respectiva interrup&#231;&#227;o de <em>hardware</em>. IRQ 0 &#233; o PIT, IRQ 1 &#233; o teclado e assim por diante.</p><h2>Algo n&#227;o me cheira bem&#8230;</h2><p>Os atentos perceber&#227;o que a entrada 0 do IDT j&#225; est&#225; preenchida, muito bem obrigado, pela exce&#231;&#227;o de software Erro de Divis&#227;o. Inclusive, simulamos isso no <a href="https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos">post anterior</a>. Sendo assim, como o processador sabe se o que ocorreu foi um erro de divis&#227;o ou o timer querendo aten&#231;&#227;o?</p><p>A resposta triste &#233; que ele n&#227;o sabe. Algu&#233;m na IBM n&#227;o se atentou a isso, foi um erro de design (ahhhhh quem nunca, n&#233;)?</p><p>No modo real, a BIOS remapeia as interrup&#231;&#245;es 0 a 7 para 8 a 0xf no IVT, conforme tabela abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OrJh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OrJh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 424w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 848w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 1272w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OrJh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png" width="514" height="115" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:115,&quot;width&quot;:514,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7092,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OrJh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 424w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 848w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 1272w, https://substackcdn.com/image/fetch/$s_!OrJh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3346658a-b9f4-48f2-a25b-b0ac7d539a7c_514x115.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://wiki.osdev.org/8259_PIC</figcaption></figure></div><p>Se voc&#234; notar na tabela de exce&#231;&#245;es, notar&#225; que a maioria das exce&#231;&#245;es n&#227;o acontece no modo real 16 bit. Por exemplo, n&#227;o faz sentido ter uma exce&#231;&#227;o <em>Page Fault</em> nesse modo. A BIOS &#233; esperta e sabe posicionar tanto as exce&#231;&#245;es de software quanto as interrup&#231;&#245;es de hardware fazendo o <em>offset </em>acima no IVT.</p><p>J&#225; no modo protegido 32 bit&#8230; Ai a gente tomou na rabiola. Agora n&#243;s temos 32 exce&#231;&#245;es, que conflitam com as IRQs.</p><p>Nossa sorte &#233; que, assim como a BIOS, n&#243;s tamb&#233;m conseguimos reprogramar os chips para que eles respondam com offsets diferentes e assim usarem outras entradas no IDT.</p><h2>Vamos programar esses dito cujos ent&#227;o!</h2><p>O que mais se encontra na internet s&#227;o c&#243;digos para reprogramar os PICs, se voc&#234; quer ir direto ao ponto, acesse esses c&#243;digos (ou o meu no <a href="https://github.com/rodrigogbranco/boring-os/blob/p3-v2/src/pic.cpp">github</a>) e use-o &#224; vontade. Mas eu gosto de saber o que estou fazendo, da raz&#227;o das coisas, do motivo que alguns valores s&#227;o usados e detesto mais ainda <em>Magic Numbers</em>, pelo menos at&#233; o limite do meu conhecimento. Isso porque h&#225; ocasi&#245;es onde eles s&#227;o inevit&#225;veis, programar microcontroladores em geral tem mais rela&#231;&#227;o com Engenharia El&#233;trica do que com Ci&#234;ncia da Computa&#231;&#227;o. Mas faremos o poss&#237;vel para esclarecer o que der.</p><p>Come&#231;amos definindo as fun&#231;&#245;es <code>outb </code>e <code>inb</code> (arquivo <code>common.h</code>). </p><pre><code>...
static inline void outb(uint16_t port, uint8_t value) {
  asm volatile("outb %0, %1" : : "a"(value), "Nd"(port));
}

static inline uint8_t inb(uint16_t port) {
  uint8_t value;
  asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
  return value;
}
...</code></pre><p>S&#227;o instru&#231;&#245;es para enviar ou receber dados (nesse caso, um byte) na/da porta de <em>hardware </em>definida como argumento. Os hardwares ficam atentos aos valores que passam nesse barramento, se algum dele casa com o endere&#231;o de hardware correspondente, o hardware reagir&#225; de acordo.</p><p>Definimos ainda no mesmo arquivo a fun&#231;&#227;o <code>io_wait</code>, que usa a fun&#231;&#227;o <code>outb </code>definida anteriormente para enviar um valor qualquer em uma porta n&#227;o usada por <em>hardware </em>nenhum. Isso garante que o comando emitido anteriormente tenha sido recebido e processado pelo hardware. Encare isso como uma instru&#231;&#227;o <code>nop </code>em um <em>pipeline</em>. A porta que estamos usando aqui, no caso &#233; a <code>0x80</code> (<code>#define UNUSED_PORT 0x80</code>).</p><pre><code>...
static inline void io_wait() { outb(UNUSED_PORT, 0); }
...</code></pre><p>E por onde come&#231;amos a programar os PICs? Voc&#234; come&#231;ar pelo <a href="https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html">datasheet do 8259</a>A, uma leitura (nada) agrad&#225;vel. Se voc&#234; n&#227;o &#233; engenheiro eletricista, prevejo problemas, voc&#234; encontrar&#225; coisas como os diagramas abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yeSZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yeSZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 424w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 848w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 1272w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yeSZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png" width="1087" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:1087,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66208,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yeSZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 424w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 848w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 1272w, https://substackcdn.com/image/fetch/$s_!yeSZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c49985c-09a8-4bbb-beab-70ca1c601166_1087x780.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html</figcaption></figure></div><p>L&#225; tem como voc&#234; deve encontrar o passo-a-passo de como programar o bixo, em uma l&#237;ngua que lembra vagamente ingl&#234;s.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G7rZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G7rZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 424w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 848w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 1272w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G7rZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png" width="519" height="388" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:388,&quot;width&quot;:519,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52483,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G7rZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 424w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 848w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 1272w, https://substackcdn.com/image/fetch/$s_!G7rZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f41d138-9a02-46cd-8e0f-38537443fdaf_519x388.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!boui!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!boui!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 424w, https://substackcdn.com/image/fetch/$s_!boui!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 848w, https://substackcdn.com/image/fetch/$s_!boui!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 1272w, https://substackcdn.com/image/fetch/$s_!boui!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!boui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png" width="520" height="636" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:636,&quot;width&quot;:520,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:94622,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!boui!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 424w, https://substackcdn.com/image/fetch/$s_!boui!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 848w, https://substackcdn.com/image/fetch/$s_!boui!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 1272w, https://substackcdn.com/image/fetch/$s_!boui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04497dab-6b77-4d40-ba09-5b59e850e3de_520x636.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html</figcaption></figure></div><p>Eu tamb&#233;m tenho dificuldades em ler esse tipo de documento, e perdi algum tempo relacionando o c&#243;digo de programa&#231;&#227;o do PIC dispon&#237;vel (por exemplo, no <a href="http://skelix.net/skelixos/tutorial04_en.html">Skelix</a> e no <a href="https://wiki.osdev.org/8259_PIC">OSDev</a>) com o que tem no <em>datasheet</em>. O resumo da &#243;pera &#233; que o 8259A &#233; um chip de interrup&#231;&#245;es de prop&#243;sito geral, ele tem v&#225;rios modos de opera&#231;&#227;o, com v&#225;rias combina&#231;&#245;es de op&#231;&#245;es poss&#237;veis. Mas existe um subconjunto dessas op&#231;&#245;es que se adequa &#224; arquitetura x86 e em como os PICs est&#227;o organizados em cascata nessa arquitetura. A sequ&#234;ncia de comandos que devemos enviar aos PICs &#233; a seguinte:</p><ol><li><p>Come&#231;amos enviando &#224; porta de dados dos PICs (<code>0x20</code> no <em>master</em>, <code>0xA0</code> no <em>slave</em>) o byte relativo &#224; inicializa&#231;&#227;o do PIC. Dependendo dos bits enviados, os PICs esperar&#227;o outros bytes na porta de dados deles (<code>0x21</code> no <em>master </em>e <code>0xA1</code> no <em>slave</em>). Esses bytes s&#227;o identificados pela sigla ICW (<em>Initialization Command Words</em>). Esse pr&#243;prio byte que est&#227;o enviado &#233; o primeiro deles: ICW1. Essa primeiro byte diz que estamos enviando um comando de inicializa&#231;&#227;o (<code>ICW1_INIT</code><em>), </em>que enviaremos posteriormente um byte ICW4 (obviamente depois dos bytes ICW2 e ICW3, se for o caso) (<code>ICW1_WITH_ICW4</code>), estamos trabalhando com PICs em cascata (<code>ICW1_CASCADE_MODE</code><em>), </em>estamos trabalhando no modo de endere&#231;amento das IRQ <em>default </em>(<code>ICW1_INTERVAL_8</code>), e em modo <em>level default </em>(<code>ICW1_LEVEL_MODE</code>). Esse &#250;ltimo tem rela&#231;&#227;o com a sensibilidade do onda quadrada que dispara a interrup&#231;&#227;o, e se voc&#234; quer mais detalhes, veja o quadro abaixo ou v&#225; direto no <em>datasheet</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NNxz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NNxz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 424w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 848w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 1272w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NNxz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png" width="1021" height="514" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:514,&quot;width&quot;:1021,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32543,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NNxz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 424w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 848w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 1272w, https://substackcdn.com/image/fetch/$s_!NNxz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673fcc72-67f1-4b51-b061-dd618a3c781c_1021x514.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html</figcaption></figure></div><pre><code>void install_pic(int new_offset_pic_master, int new_offset_pic_slave) {
  // ICW1 (Initialization Command Words number one - Init command)
  outb(PIC_MASTER_IO_COMMAND_PORT, ICW1_INIT | ICW1_WITH_ICW4 |
                                       ICW1_CASCADE_MODE | ICW1_INTERVAL_8 |
                                       ICW1_LEVEL_MODE);
  outb(PIC_SLAVE_IO_COMMAND_PORT, ICW1_INIT | ICW1_WITH_ICW4 |
                                      ICW1_CASCADE_MODE | ICW1_INTERVAL_8 |
                                      ICW1_LEVEL_MODE);
  io_wait();</code></pre></li><li><p>Com isso, os PICs sabem que est&#227;o em modo de inicializa&#231;&#227;o, e esperar&#227;o pelos pr&#243;ximos bytes ICW. O segundo deles (ICW2) indica qual &#233; o novo <em>offset </em>que os PICs devem responder. Como queremos &#237;ndices depois das 32 exce&#231;&#245;es de software (ou <code>0x1f</code>), queremos que o primeiro PIC responda no intervalo de <code>0x20</code> a <code>0x27</code>, enquanto o segundo responda do <code>0x28</code> a <code>0x2f</code>).</p><pre><code>  // ICW2 (Offset definition)
  outb(PIC_MASTER_IO_DATA_PORT, new_offset_pic_master);
  outb(PIC_SLAVE_IO_DATA_PORT, new_offset_pic_slave);
  io_wait();</code></pre></li><li><p>Como estamos trabalhando em modo cascata, os PICs esperar&#227;o o byte ICW3 para indicar como eles est&#227;o arranjados. Lembre-se, os chips 8259A s&#227;o chips de prop&#243;sito geral e podem ter v&#225;rias formas de arranjo. Nada impediria de voc&#234; cascatear mais alguns PICs no <em>master</em>, ou mesmo pendurar mais algum PIC no <em>slave</em>. Nossa miss&#227;o &#233; portanto indicar ao <em>master </em>em qual IRQs h&#225; PICs <em>slaves</em>, e indicar aos <em>slaves </em>a identifica&#231;&#227;o deles perante o <em>master</em>. No nosso caso, por exemplo, temos que indicar que o slave est&#225; na IRQ 2 (<code>0001b</code> = IRQ 0, <code>0010b</code> = IRQ 1, <code>0100b</code> = IRQ 2, <code>1000b</code> = IRQ 3 etc), e que o identificador do slave &#233; 2. Se houvesse PICs nas IRQs 5 e 7, por exemplo, indicar&#237;amos ao master o valor <code>10100000b</code>, ou <code>0xa0</code>. E para os respectivos PICs, indicar&#237;amos os valores 5 e 7. A figura abaixo ajuda a entender esse processo de identifica&#231;&#227;o das IRQs e do PIC.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VDRA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VDRA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 424w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 848w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 1272w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VDRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png" width="887" height="461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:461,&quot;width&quot;:887,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;ICW and OCW in 8259&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="ICW and OCW in 8259" title="ICW and OCW in 8259" srcset="https://substackcdn.com/image/fetch/$s_!VDRA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 424w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 848w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 1272w, https://substackcdn.com/image/fetch/$s_!VDRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31aa933e-662e-4965-a031-64659cfdc3d1_887x461.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://scienceeureka.com/icw-and-ocw-in-8259/</figcaption></figure></div><pre><code>  // ICW3 (Cascade mode)
  outb(PIC_MASTER_IO_DATA_PORT, ICW3_MASTER_IRQ2);
  outb(PIC_SLAVE_IO_DATA_PORT, ICW3_SLAVE_IRQ2_BINARY);
  io_wait();</code></pre></li><li><p>Por fim, como indicamos inicialmente que usar&#237;amos o ICW4, melhor apresentar o diagrama abaixo. No fim das contas, todos os bits est&#227;o zerados/default com exce&#231;&#227;o do bit zero, onde indicamos que usaremos o modo 8086/8088.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hK2c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hK2c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 424w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 848w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 1272w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hK2c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png" width="893" height="356" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:356,&quot;width&quot;:893,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;ICW and OCW in 8259&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="ICW and OCW in 8259" title="ICW and OCW in 8259" srcset="https://substackcdn.com/image/fetch/$s_!hK2c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 424w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 848w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 1272w, https://substackcdn.com/image/fetch/$s_!hK2c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d714bc8-0ff1-4f6a-ad61-bbf331219dd7_893x356.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://scienceeureka.com/icw-and-ocw-in-8259/</figcaption></figure></div><pre><code>  // ICW4 (Operation Model)
  outb(PIC_MASTER_IO_DATA_PORT, ICW4_8086 | ICW4_NORMAL_EOI |
                                    ICW4_NON_BUFFERED |
                                    ICW4_NOT_FULLY_NESTED_MODE);
  outb(PIC_SLAVE_IO_DATA_PORT, ICW4_8086 | ICW4_NORMAL_EOI | ICW4_NON_BUFFERED |
                                   ICW4_NOT_FULLY_NESTED_MODE);
  io_wait();</code></pre></li><li><p>Os procedimentos acima terminam a programa&#231;&#227;o dos PICs e eles j&#225; est&#227;o operacionais e podem receber OCWs (<em>Operation Control Words</em>).  Por fim, mascaramos todas as interrup&#231;&#245;es. Isso significa que os PICs sabe que as interrup&#231;&#245;es est&#227;o ocorrendo, eles s&#243; avisam ao processador. Fazemos isso a medida que vamos tratando as interrup&#231;&#245;es individualmente: vamos cuidar do PIT, ent&#227;o desmascaramos a IRQ 0. Depois, o teclado, e desmascaramos a IRQ 1 e assim por diante. Resumindo, bit 0 na IRQ, interrup&#231;&#227;o inibida. Caso contr&#225;rio, a IRQ pode notificar sobre interrup&#231;&#245;es. Isso do lado dos PICs. Do lado do processador, precisamos avisar que as interrup&#231;&#245;es est&#227;o ativas, setando o nono bit (come&#231;ando do zero) do registrador <code>EFLAGS</code>. Isso &#233; feito com a instru&#231;&#227;o <code>sti</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LD80!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LD80!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 424w, https://substackcdn.com/image/fetch/$s_!LD80!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 848w, https://substackcdn.com/image/fetch/$s_!LD80!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 1272w, https://substackcdn.com/image/fetch/$s_!LD80!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LD80!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png" width="510" height="164" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:164,&quot;width&quot;:510,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27216,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LD80!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 424w, https://substackcdn.com/image/fetch/$s_!LD80!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 848w, https://substackcdn.com/image/fetch/$s_!LD80!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 1272w, https://substackcdn.com/image/fetch/$s_!LD80!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d40e536-4ce8-46f8-bca8-49e7de012609_510x164.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66107/INTEL/8259A.html</figcaption></figure></div><pre><code>  outb(PIC_MASTER_IO_DATA_PORT, DISABLE_ALL_INTERRUPTS_MASK);
  outb(PIC_SLAVE_IO_DATA_PORT, DISABLE_ALL_INTERRUPTS_MASK);

  sti();
}</code></pre><p>Pergunta de prova: h&#225; alguma outra forma de setar o bit de interrup&#231;&#245;es do processador sem usar a instru&#231;&#227;o <code>sti</code>? Claro que sim, s&#243; que al&#233;m das instru&#231;&#245;es <code>cli</code> e <code>sti</code>, as &#250;nicas instru&#231;&#245;es que manipulam diretamente o registrador EFLAGS s&#227;o as instru&#231;&#245;es <code>pushf</code>/<code>popf</code>. Voc&#234; poderia fazer assim ent&#227;o:</p></li></ol><pre><code>  pushf
  or dword [esp], 0x200
  popf</code></pre><p>Ou seja, manda pra pilha, faz um <em>or bitwise</em> com o valor <code>0x200</code> (nono bit, come&#231;ando por zero) e pega o valor de volta. Mas divago, isso &#233; s&#243; uma curiosidade. </p><p>J&#225; podemos aproveitar e definir a opera&#231;&#227;o EOI (<em>End Of Interruption</em>). Ap&#243;s &#8220;servir&#8221; uma interrup&#231;&#227;o ao processador, o processador deve enviar um comando de <em>acknowledge</em>, informando ao PIC que ele j&#225; t&#225; sabendo da treta e que vai tomar as provid&#234;ncias necess&#225;rias. Se isso n&#227;o for feito, o PIC parar&#225; de enviar notifica&#231;&#245;es ao processador, at&#233; que ele envie o comando EOI. O &#250;nico problema &#233; que os PICs n&#227;o se conversam, eles s&#227;o brigados, esses putos. Ent&#227;o, se IRQ originou no segundo PIC (por exemplo, a IRQ 12 do mouse PS/2), devemos enviar o comando EOI aos dois. &#201; bem f&#225;cil de fazer isso: basta checar o n&#250;mero da interrup&#231;&#227;o, e se ela estiver na faixa do segundo PIC, enviamos o comando para ele tamb&#233;m.</p><p>Para enviar o EOI ao PIC, basta enviar o valor <code>0x20</code> para as portas de comando dos PICs (<code>0x20</code> para o <em>master</em> e <code>0xA0</code> para o <em>slave</em>).</p><pre><code>void pic_send_eoi(int isr_nr) {
  if (isr_nr &gt;= PIC_SLAVE_OFFSET) {
    outb(PIC_SLAVE_IO_COMMAND_PORT, PIC_EOI);
  }

  outb(PIC_MASTER_IO_COMMAND_PORT, PIC_EOI);
}</code></pre><p>Moleza, hein. Vamos agora cuidar da IRQ 0.</p><h2>PIT - Programmable Interval Timer</h2><p>Assim como o 8259A, o PIT &#233; um microcontrolador da fam&#237;lia 8254, e serve para como um gerador de interrup&#231;&#245;es a uma frequ&#234;ncia pr&#233;-determinada. O 8254 tamb&#233;m &#233; um microcontrolador de prop&#243;sito geral, e portanto, novamente h&#225; v&#225;rias op&#231;&#245;es, modos e frequ&#234;ncias que podem ser usadas. O datasheet desse dem&#244;nio pode ser encontrado <a href="https://www.alldatasheet.com/datasheet-pdf/pdf/66099/INTEL/8254.html">AQUI</a>.</p><p>O 8254 recebe comandos na porta <code>0x43</code>, e possui tr&#234;s canais que respondem nas portas <code>0x40</code>, <code>0x41</code> e <code>0x42</code>, respectivamente. Isso serve para compor v&#225;rias frequ&#234;ncias poss&#237;veis. No nosso caso, quero gerar 1000 interrup&#231;&#245;es por segundo (1000Hz), apenas o canal 0 (porta <code>0x40</code>) &#233; suficiente. O PIT opera em aproximadamente 1.193182 MHz, ent&#227;o iremos programar o PIT para executar a esse valor ai dividido pela frequ&#234;ncia desejada (vai ser 1000):</p><pre><code>void install_pit(int desired_hz) {
  unsigned int divisor = FREQUENCY_DIVISOR / desired_hz;</code></pre><p> S&#243; calculamos o divisor da frequ&#234;ncia, mas ainda n&#227;o o informamos ao PIT. Primeiro vamos programar o modo de opera&#231;&#227;o, que &#233; enviar o modo para a porta 0x43. Os modos poss&#237;veis s&#227;o:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gqEK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gqEK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 424w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 848w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 1272w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gqEK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png" width="539" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:539,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32513,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gqEK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 424w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 848w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 1272w, https://substackcdn.com/image/fetch/$s_!gqEK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4054315-b3dc-4bdc-ae87-e95aeb69cefd_539x386.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://wiki.osdev.org/Programmable_Interval_Timer</figcaption></figure></div><p>Queremos ent&#227;o o modo bin&#225;rio (bit 0=<code>0b</code>), no modo de opera&#231;&#227;o de gera&#231;&#227;o de taxa (bits 1 a 3=<code>110b</code>), modo de acesso <em>low byte/high byte</em> (bits 4 e 5=<code>11b</code>) no canal 0 (bits 6 e 7=<code>00b</code>). Vou tentar explicar o que sei desses valores.</p><p>O modo BCD de 4 d&#237;gitos (Binary-Coded Decimal) possui varia&#231;&#245;es, mas o mais tradicional a gente j&#225; conhece: &#233; a representa&#231;&#227;o bin&#225;ria de um n&#250;mero decimal, e para isso precisamos de 4 bits. O ponto &#233; que n&#227;o leremos informa&#231;&#227;o nenhuma do PIT, queremos que ele apenas gere as interrup&#231;&#245;es, o valor interno n&#227;o nos importa. Por isso o modo bin&#225;rio.</p><p>Quanto ao modo de opera&#231;&#227;o, o <a href="http://skelix.net/skelixos/tutorial05_en.html">Skelix</a> usa o modo de gerador de onda quadrada, enquanto o <a href="https://wiki.osdev.org/Programmable_Interval_Timer">OSDev</a> usa Gera&#231;&#227;o de Taxa. No <em>datasheet</em>, temos o seguinte:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_XUF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_XUF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 424w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 848w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 1272w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_XUF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png" width="619" height="147" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:147,&quot;width&quot;:619,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11697,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_XUF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 424w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 848w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 1272w, https://substackcdn.com/image/fetch/$s_!_XUF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F380d127c-0b9d-4407-9bd1-d6c0c197e55d_619x147.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66099/INTEL/8254.html</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DhPT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DhPT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 424w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 848w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 1272w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DhPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png" width="627" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab785665-3251-400a-b924-0be8ec65d1ad_627x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:627,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12032,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DhPT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 424w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 848w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 1272w, https://substackcdn.com/image/fetch/$s_!DhPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab785665-3251-400a-b924-0be8ec65d1ad_627x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://www.alldatasheet.com/datasheet-pdf/pdf/66099/INTEL/8254.html</figcaption></figure></div><p>Como queremos usar interrup&#231;&#245;es em tempo real, e n&#227;o parece ter taaaaanta diferen&#231;a assim em rela&#231;&#227;o ao que o <a href="http://skelix.net/skelixos/tutorial05_en.html">Skelix</a> usa, ficaremos com o modo 2 mesmo, <em>rate generator</em>. Na <a href="https://wiki.osdev.org/Programmable_Interval_Timer">p&#225;gina do OSDev</a> tem uma explica&#231;&#227;o legal para quem quiser se aprofundar.</p><p>Esse trecho do c&#243;digo fica ent&#227;o assim:</p><pre><code>  outb(MODE_COMMAND_PORT,
       BINARY_MODE | RATE_GENERATOR | LOW_BYTE_HIGH_BYTE | COUNTER_0);</code></pre><p>Hora de enviar o divisor ao canal do PIT. Como o modo de acesso foi definido para <em>low byte/high byte</em>, primeiro ent&#227;o enviamos os o bits menos significativos do divisor ao canal zero, seguido dois 8 bits mais significativos.</p><pre><code>  outb(CHANNEL_0_DATA_PORT, divisor &amp; 0xff);

  outb(CHANNEL_0_DATA_PORT, divisor &gt;&gt; 8);</code></pre><p>&#201; isso. Basta agora desmascarar a IRQ 0 para que o processador seja avisado das novas interrup&#231;&#245;es do timer. A gente preserva o valor anterior alterando s&#243; o bit da IRQ 0, ent&#227;o basta fazer um <em>and bitwise</em> com o valor <code>0xfe</code> (todos os bits setados, com exce&#231;&#227;o do &#250;ltimo. Isso vai preservar o valor original de todos os bits e zerar o &#250;ltimo bit, que &#233; o bit relacionado &#224; IRQ 0).</p><pre><code>  outb(PIC_MASTER_IO_DATA_PORT, inb(PIC_MASTER_IO_DATA_PORT) &amp; UNMASK_IRQ_0);</code></pre><p>Isso &#233; (quase) suficiente para terminar o PIC e PIT. S&#243; que apesar de termos apresentado a fun&#231;&#227;o <code>pic_send_eoi</code>, a gente ainda n&#227;o a usou. No primeiro tick do rel&#243;gio, se n&#227;o chamarmos essa fun&#231;&#227;o, o PIT parar&#225; de funcionar. Ent&#227;o, vamos tratar a IRQ 0 (arquivo <code>interrupt.cpp</code>):</p><pre><code>void irq0_system_timer(int isr_nr, __attribute__((unused)) int err_code) {
  pic_send_eoi(isr_nr);
  ...
};</code></pre><p>Os tr&#234;s pontinhos representam o trabalho atual do tratador da IRQ 0, que n&#227;o ser&#225; feito agora. Basicamente, aqui &#233; que chamaremos o escalonador para trocar as tarefas e de fato tornar este um kernel preemptivo. Mas isso n&#227;o ser&#225; feito agora.</p><p>Definida o handler <code>irq0_system_timer</code>, precisamos instal&#225;-lo no arquivo isr_handlers.cpp.</p><pre><code>void (*isr_handlers[])(int, int) = {
    // exceptions
    &amp;division_error, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;invalid_opcode, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;general_protection_fault, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,
    &amp;default_isr_handler, &amp;default_isr_handler,
    // IRQS
    &amp;irq0_system_timer, &amp;default_irq_handler, &amp;default_irq_handler,
    &amp;default_irq_handler, &amp;default_irq_handler, &amp;default_irq_handler,
    &amp;default_irq_handler, &amp;default_irq_handler, &amp;default_irq_handler,
    &amp;default_irq_handler, &amp;default_irq_handler, &amp;default_irq_handler,
    &amp;default_irq_handler, &amp;default_irq_handler, &amp;default_irq_handler,
    &amp;default_irq_handler};</code></pre><p>Se voc&#234; notar direitinho, apareceu um handler <code>general_protection_fault</code>. J&#225; j&#225; vai ficar claro o motivo disso&#8230;</p><p>Enfim, para fazer esse paranau&#234; todo funcionar, basta instalarmos o PIC e o PIT no arquivo <code>kernel.cpp</code>. A fun&#231;&#227;o completa <code>_start</code> por enquanto est&#225; assim:</p><pre><code>...

#define DESIRED_TIMER_HZ 1000

...

extern "C" void _start() {
  _init();
  clear_screen();

  install_gdt();
  install_idt();

  install_pic(PIC_MASTER_OFFSET, PIC_SLAVE_OFFSET);
  install_pit(DESIRED_TIMER_HZ);
  *user_entry_point = &amp;kernel_entry;

  sched-&gt;add_task(&amp;thread1, true);
  sched-&gt;add_task(&amp;thread2, true);
  sched-&gt;add_task(&amp;thread3, true);
  sched-&gt;add_task(&amp;thread4, true);
  sched-&gt;add_task(&amp;thread5, true);
  sched-&gt;add_task((void (*)())PROCESS1, false);
  sched-&gt;add_task((void (*)())PROCESS2, false);

  do_exit();

  while (true) {
    /* BUSY LOOP*/
  }

  /*If code has landed here, something very wrong happened...*/
  _fini();
}</code></pre><p>E para testar se a IRQ 0 est&#225; realmente funcionando, alterei a fun&#231;&#227;o <code>irq0_system_timer</code> para imprimir um contador na tela. Ela ficou assim:</p><pre><code>static int teste = 0;

void default_irq_handler(int isr_nr, __attribute__((unused)) int err_code) {
  pic_send_eoi(isr_nr);
  printk("IRQ ISR %x\n", isr_nr);
};

void irq0_system_timer(int isr_nr, __attribute__((unused)) int err_code) {
  pic_send_eoi(isr_nr);
  printk("IRQ0 %d\n", teste++);
  ...
};</code></pre><p>Ao compilar e executar, voc&#234; perceber&#225; que em algum momento o PIT parar&#225; de responder.</p><h2>Concurrency Hell</h2><p>&#201; agora que a m&#227;e chora e o beb&#234; n&#227;o v&#234;, meu amigo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tgx_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tgx_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tgx_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg" width="474" height="268" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:268,&quot;width&quot;:474,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;8 grandes ditados do Chapolin&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="8 grandes ditados do Chapolin" title="8 grandes ditados do Chapolin" srcset="https://substackcdn.com/image/fetch/$s_!tgx_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tgx_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73092db8-9253-436a-b1c0-d3ae28a1f5d5_474x268.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://hqscomcafe.com.br/2019/02/06/8-grandes-ditados-do-chapolin/</figcaption></figure></div><p>Voc&#234; est&#225; todo feliz ai, tratando de problema de concorr&#234;ncia em modo usu&#225;rio no Linux? Usando <code>pthreads</code>, protegendo regi&#245;es cr&#237;ticas, programando em CUDA, mexendo com <em>Streams </em>paralelas em Java&#8230; Est&#225; desesperado? Pfff meu amigo, me acompanha que agora fica tenso.</p><p>Meus skills de debugging melhoraram 1000% depois que eu consegui resolver esses problemas. Aqui, o gdb &#233; seu amigo, mas ele &#233; um amigo que n&#227;o conversa muito, sabe? S&#243; te responde o que voc&#234; pergunta&#8230; Dif&#237;cil lidar com esse cara.</p><p>Voltando ao problema, notei que em algum momento a IRQ 0 parava de responder. Obviamente que, se isso n&#227;o acontecia antes, deve ser algo que introduzimos agora no c&#243;digo, certo?</p><p>Comecei comentando todo o trecho do meu escalonador. No fim das contas, depois da fun&#231;&#227;o <code>install_pit</code>, s&#243; tinha o busy loop no fim da fun&#231;&#227;o <code>_start</code>. E quando eu deixava assim, o PIT voltava a funcionar. 1000 vezes por segundo.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;5fada9b2-2f85-4a32-8e15-b7fd2338934f&quot;,&quot;duration&quot;:null}"></div><p>O PIC e PIT est&#227;o ent&#227;o, de fato funcionando. O que estava havendo afinal?</p><p>Depois de muito executar, trocar as tarefas executadas, colocar threads de kernel, processos, etc, em algum momento eu dei a sorte de interromper a execu&#231;&#227;o e verificar o conte&#250;do dos registradores. Veja se voc&#234; tamb&#233;m nota algo esquisito:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7l6g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7l6g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 424w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 848w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 1272w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7l6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png" width="1456" height="530" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:530,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:137004,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7l6g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 424w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 848w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 1272w, https://substackcdn.com/image/fetch/$s_!7l6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8564c91a-4ba1-4ffa-9805-fd7beff9c2fa_1581x575.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Olhe ali logo acima do registrador EIP. Aquilo &#233; o conte&#250;do do registrador <code>EFLAGS</code>: <em>overflow, direct, interrupt, trap, sign, zero, auxiliary carry, parity</em> e <em>carry flags</em>, nessa ordem, da esquerda para a direita. Letra min&#250;scula, flag = 0, letra mai&#250;scula, flag = 1. Nesse exemplo da foto, as flags que est&#227;o ativas s&#227;o a <em>Zero flag</em> e <em>Parity flag</em>. Mas notou que a flag de interrup&#231;&#245;es est&#225; desabilitada? Em que momento desabilitamos as interrup&#231;&#245;es?</p><p>O problema todo, jovem, &#233; que o diabo mora nos detalhes. De fato, n&#227;o h&#225; nenhum momento que EXPLICITAMENTE desabilitamos as interrup&#231;&#245;es, n&#227;o intencionalmente.</p><p>Lembra das maneiras de se alterar o <code>EFLAGS</code>? <code>cli</code>/<code>sti</code> e <code>pushf</code>/<code>popf</code>&#8230; Isso &#233; feito assim que as tarefas s&#227;o colocadas para executar, na fun&#231;&#227;o <code>scheduler_entry</code>:</p><pre><code>scheduler_entry:
    push ebp
    mov ebp, esp
    call stop_kernel_timer

    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp
    mov esp, ebp
    call scheduler
    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]

    call start_timer
    pop ebp
    ret</code></pre><p>Logo ap&#243;s <code>call scheduler</code> vamos no PCB recuperar os registradores da tarefa, e os recuperamos com <code>popad</code> e <code>popfd</code>. Mas para uma tarefa rec&#233;m-criada, quais s&#227;o esses valores? Pois &#233;, n&#227;o definimos. E o compilador tratou de zerar os valores no construtor da classe <code>PCB</code>.</p><p>Assim, ao fazer o <code>popf</code>, o registrador EFLAGS estar&#225; todo zerado. Para a tarefa em si, isso n&#227;o tinha problema nenhum, mas para o sistema, zero significa interrup&#231;&#245;es desligadas.</p><p>Ent&#227;o, a primeira tentativa de corrigir isso foi definindo o registrador EFLAGS como 0x202 (o primeiro bit, come&#231;ando em zero, fica sempre ligado, <a href="https://en.wikipedia.org/wiki/FLAGS_register">conforme essa p&#225;gina dita</a>).</p><p>Bom, t&#225; f&#225;cil de resolver isso n&#233;? Basta ir no m&#233;todo <code>PCB::config</code> e setar esses registradores:</p><pre><code>  // set eflags to current value (to allow interrupts, if set)
  this-&gt;kregs[8] = EFLAGS_RESERVED | EFLAGS_INTERRUPT_ENABLED;
  this-&gt;uregs[8] = EFLAGS_RESERVED | EFLAGS_INTERRUPT_ENABLED;</code></pre><p>Piece of cake! E agora ao executar&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aWFj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aWFj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 424w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 848w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 1272w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aWFj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png" width="1092" height="115" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:115,&quot;width&quot;:1092,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21587,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aWFj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 424w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 848w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 1272w, https://substackcdn.com/image/fetch/$s_!aWFj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94214ae9-8b31-4a3b-b569-58c16a88f687_1092x115.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Agora o problema foi mais s&#233;rio, n&#227;o foi meu kernel que capotou (ele tamb&#233;m) mas o QEMU. Rapaz, para derrubar o emulador &#233; sinal que seu c&#243;digo est&#225; MUITO errado.</p><p>E nisso vai mais duas semanas debugando&#8230;</p><h2>A volta da regi&#227;o cr&#237;tica</h2><p>Depois de muito tempo perdido (ou aprendizado, se voc&#234; quiser ver o copo meio cheio), notei que em algum momento a retornar da interrup&#231;&#227;o (instru&#231;&#227;o <code>iret</code>) ele retornava para endere&#231;os de mem&#243;ria inv&#225;lidos.</p><p>Na realidade, o tratador dessa interrup&#231;&#227;o estava com o registrador <code>esp</code> apontando para endere&#231;os fora da faixa definida para isso <code>0x40000</code> - <code>0x52000</code>. O esp estava na verdade apontando para o PCB da tarefa atual. E foi ai que caiu a ficha.</p><p>Lembra da fun&#231;&#227;o <code>scheduler_entry</code>? Vamos analis&#225;-la novamente.</p><pre><code>scheduler_entry:
    push ebp
    mov ebp, esp
    call stop_kernel_timer

    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp
    mov esp, ebp
    call scheduler
    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]

    call start_timer
    pop ebp
    ret</code></pre><p>Lembre-se que as interrup&#231;&#245;es s&#227;o implac&#225;veis, elas podem acontecer a qualquer momento. O que acontece quando uma interrup&#231;&#227;o ocorre entre as op&#231;&#245;es <code>mov esp, [current_task]</code> e <code>lea esp, [esp + K_REGS_LIMIT]</code>? Nesse momento, estamos preparando para salvar os registradores no PCB, e o registrador <code>esp</code> N&#195;O aponta para uma pilha v&#225;lida, ele est&#225; apontando para um PCB. Se uma interrup&#231;&#227;o acontecer dai at&#233; o restauro da pilha na instru&#231;&#227;o <code>mov esp, [esp - ESP_OFFSET_FROM_LIMIT]</code> (e isso vai acontecer, acredite em mim!), seu sistema vai para a casa do chap&#233;u.</p><p>Isso &#233; uma regi&#227;o cr&#237;tica. Precisamos proteger o recurso (nesse caso, o registrador <code>esp</code>) para que outro concorrente n&#227;o possa bagun&#231;&#225;-lo. Nesse caso, n&#227;o tem jeito: em todo trecho que h&#225; altera&#231;&#227;o do esp para apontar para o PCB, precisamos desabilitar as interrup&#231;&#245;es:</p><pre><code>scheduler_entry:
    push ebp
    mov ebp, esp
    call stop_kernel_timer

    cli
    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp
    mov esp, ebp
    sti

    call scheduler

    cli
    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]
    sti

    call start_timer
    pop ebp
    ret</code></pre><p>O princ&#237;pio &#233; o mesmo para a troca de contextos de processo para kernel, na fun&#231;&#227;o <code>kernel_entry</code>, mas para evitar repeti&#231;&#245;es, vou omitir aqui. Consulte meu <a href="https://github.com/rodrigogbranco/boring-os/blob/p3-v2/src/entry.asm">github</a> para verificar os detalhes s&#243;rdidos. </p><p>Agora n&#227;o precisamos mais definir o <code>EFLAGS</code> no <code>PCB</code>. Ao sair das fun&#231;&#245;es <code>kernel_entry</code> e <code>scheduler_entry</code> o c&#243;digo se encarregar&#225; de ligar as interrup&#231;&#245;es com a instru&#231;&#227;o <code>sti</code>.</p><p>Agora vai?</p><h2>Bonus Round</h2><p>No fim das contas, eu ainda estava com problemas. De vez em quando ele gerava um <em>General Protection Fault</em> (o motivo de eu ter instalado um <em>handler </em>para ver o que estava acontecendo), &#224;s vezes disparava um <em>Invalid Opcode</em> e os <em>handlers default</em> sem eu ter solicitado&#8230; algo definitivamente ainda estava errado. Ele com certeza estava executando c&#243;digos que n&#227;o foi eu quem escrevi.</p><p>Como n&#227;o acreditamos em Poltergeist na computa&#231;&#227;o, em algum momento percebi que ele estava acessando a <em>Vtable</em> da classe <code>Scheduler</code>. Oxi, mas eu n&#227;o estava mais usando a classe derivada <code>FairScheduler</code>, por qual motivo o m&#233;todo virtual <code>sched</code> estava sendo invocado se meu objeto n&#227;o era do tipo <code>FairScheduler</code>?<strong> </strong>Vamos relembrar como essa classe est&#225;:</p><pre><code>class Scheduler {
...

public:
  ...
  virtual ~Scheduler() = default;
  void operator delete(void *, unsigned int) {};
  virtual void sched(QueueNode&lt;PCB&gt; *);
};

class FairScheduler : public Scheduler {
public:
  void sched(QueueNode&lt;PCB&gt; *);
};</code></pre><p>N&#227;o fazia sentido. Notei tamb&#233;m que isso acontecia quando eu tentava fazer um <code>unblock</code> no <code>lock</code>&#8230;</p><pre><code>extern Scheduler sched;

void Lock::lock_acquire() {
  if (this-&gt;mutex.exchange(true)) {
    sched.block(this);
  }
}

void Lock::lock_release() {
  if (this-&gt;blocked != nullptr) {
    sched.unblock(this);
  } else {
    // Util::printk("empty queue\n");
    this-&gt;mutex.store(false);
  }
}</code></pre><p>Mas calma l&#225;! No arquivo scheduler.cpp, para usar o <code>FairScheduler</code>, alteramos a vari&#225;vel <code>sched</code> para usar ponteiro!</p><pre><code>// FairScheduler fairSched;
// Scheduler *sched = &amp;fairSched;

Scheduler roundRobinSched;
Scheduler *sched = &amp;roundRobinSched;</code></pre><p>Considerando que estamos falando da mesma coisa (por isso o <code>extern</code> no arquivo <code>lock.cpp</code>), no arquivo <code>scheduler.cpp</code> a vari&#225;vel <code>sched</code> &#233; um ponteiro, mas no arquivo <code>lock.cpp</code> ele &#233; um objeto! Bom, se for s&#243; isso, &#233; f&#225;cil de alterar:</p><pre><code>extern Scheduler *sched;

void Lock::lock_acquire() {
  if (this-&gt;mutex.exchange(true)) {
    sched-&gt;block(this);
  }
}

void Lock::lock_release() {
  if (this-&gt;blocked != nullptr) {
    sched-&gt;unblock(this);
  } else {
    // Util::printk("empty queue\n");
    this-&gt;mutex.store(false);
  }
}</code></pre><p>Isso &#233; um bug que estava dormente h&#225; muito tempo e s&#243; se manifestou agora. Magicamente, agora tudo funcionou!</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;20c4d73e-6871-421f-91a8-b300f6728cf3&quot;,&quot;duration&quot;:null}"></div><p>O c&#243;digo, at&#233; o momento est&#225; no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p3-v2">github</a>. </p><p>Qual &#233; a moral da hist&#243;ria dessa linda f&#225;bula que acompanhamos at&#233; o momento? N&#227;o cometa erros, n&#227;o programe bugs. Espero ter ajudado! :D</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos"><span>Anterior</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Prontos para serem interrompidos?]]></title><description><![CDATA[Bom para voc&#234;! Eu n&#227;o estou.]]></description><link>https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Sat, 01 Feb 2025 21:14:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!T-MM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EqvH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EqvH!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 424w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 848w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 1272w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EqvH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif" width="320" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/392a6fef-4224-440e-b623-c0b568204938_220x220.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:220,&quot;resizeWidth&quot;:320,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Interruption Discord Emojis - Interruption Emojis For Discord&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Interruption Discord Emojis - Interruption Emojis For Discord" title="Interruption Discord Emojis - Interruption Emojis For Discord" srcset="https://substackcdn.com/image/fetch/$s_!EqvH!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 424w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 848w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 1272w, https://substackcdn.com/image/fetch/$s_!EqvH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F392a6fef-4224-440e-b623-c0b568204938_220x220.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://emoji.house/discord/interruption</figcaption></figure></div><p>No <a href="https://blog.rodrigobranco.net/p/apanhando-do-rdtsc">post anterior</a> n&#243;s finalmente finalizamos o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>, e come&#231;amos agora o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project3/p3.html">P3</a>, um Kernel Preemptivo, YAY! Mas o que isso significa?</p><p>Primeiro, at&#233; o momento, as tarefas precisam explicitamente ceder a CPU para as outras. Isso era feito via fun&#231;&#227;o <code>do_exit</code> para as <em>threads </em>do <em>kernel </em>e <em>syscall </em><code>yield</code> para os processos. Agora, haver&#225; um mecanismo externo que pode interromper a tarefa a qualquer momento.</p><h2>Que brisa &#233; essa?</h2><p>A arquitetura x86 &#233; uma arquitetura orientada a eventos. Significa que a CPU reage a est&#237;mulos externos e responde de acordo. Mas como isso funciona e qual seria a alternativa se esse mecanismo n&#227;o existisse?</p><p>Suponha que voc&#234; digitou uma tecla qualquer no seu teclado. Se o evento n&#227;o foi informado a CPU, ela deve periodicamente consultar o hardware do teclado para saber se alguma tecla foi pressionada, e em caso positivo, verificar o seu c&#243;digo. Esse mecanismo &#233; conhecido como <em>Polling</em> e &#233; bem conhecido em v&#225;rias aplica&#231;&#245;es.</p><p>Perceba que j&#225; usamos esse mecanismos de uma certa forma. As instru&#231;&#245;es <code>in</code> e <code>out</code>, que usamos para habilitar o <a href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode">A20 Gate nesse post aqui</a>, s&#227;o usadas para fazer <em>polling </em>no <em>hardware</em>.</p><p>Para isso funcionar, a tarefa deve voluntariamente ceder a CPU para que ela v&#225; buscar os dados no <em>hardware</em>. Se a tarefa n&#227;o colaborar, pouco pode ser feito. Al&#233;m disso, pode ser que voc&#234; v&#225; fazer o <em>polling </em>e o <em>hardware </em>n&#227;o tenha nada a informar (nenhuma tecla foi pressionada por exemplo). Nesse caso, estamos desperdi&#231;ando valiosos ciclos de CPU fazendo nada. Um desperd&#237;cio de recursos!</p><p>Por isso, a arquitetura x86 (e qualquer arquitetura moderna, como ARM) trabalha com o conceito de interrup&#231;&#245;es. Sempre que necess&#225;rio, o hardware envia um pedido de interrup&#231;&#227;o para a CPU. Esta para o que est&#225; fazendo, atende o hardware e volta para a tarefa como se nada tivesse acontecido. Na verdade, essa &#233; toda a magia da coisa: a tarefa n&#227;o faz ideia de que foi interrompida, e para ela esse mecanismo &#233; totalmente transparente.</p><p>Ok, e como fazemos para isso funcionar na pr&#225;tica? A resposta curta &#233; que basta instalar o IDT e as fun&#231;&#245;es tratadoras das interrup&#231;&#245;es. A resposta longa vem a seguir.</p><h2>Interrupt Descriptor Table</h2><p>Se voc&#234; acompanhou a saga da instala&#231;&#227;o do GDT <a href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode">nesse post aqui</a>, adianto que o IDT (<em>Interrupt Descriptor Table</em>) &#233; igual, mas &#233; diferente. Igual porque o IDT tamb&#233;m &#233; um registrador especial, de 48 bits, que armazena o endere&#231;o base e o tamanho da tabela, tal qual o GDT. Cada entrada na tabela do IDT tamb&#233;m tem 8 bytes, assim como as entradas do GDT.</p><p>Mas &#233; diferente porque cada entrada nessa tabela &#233; equivalente ao IVT (<em>Interrupt Vector Table</em>) da BIOS, que, sinto lhe dizer, n&#227;o existe mais.</p><h2>IVT?</h2><p>Para entendermos o IDT, acredito ser pedag&#243;gico se dominarmos o IVT. Quando o computador &#233; ligado, a CPU carrega o c&#243;digo da ROM BIOS, que faz v&#225;rias checagens e executa os c&#243;digos contidos nesse chip, notadamente o POST (<em>Power On Self Test</em>). Uma das coisas que a BIOS faz &#233; instalar o IVT na posi&#231;&#227;o 0x0 da mem&#243;ria. Lembre-se que nesse momento a CPU est&#225; operando em modo real, com segmenta&#231;&#227;o, em 16 bits.</p><p>Ent&#227;o, cada entrada no IVT cont&#233;m 4 bytes: 2 bytes para o <code>cs </code>e 2 bytes para o <em>offset</em>. <code>cs:offset</code> indica o endere&#231;o da fun&#231;&#227;o que trata as interrup&#231;&#245;es. Quando voc&#234; est&#225; nesse modo ent&#227;o, se voc&#234; pressionar uma tecla, o hardware do teclado disparar&#225; um pedido de interrup&#231;&#227;o (tamb&#233;m chamado de IRQ - <em>Interrupt Request</em>). As interrup&#231;&#245;es s&#227;o exclusivas de cada hardware, assim quando um pedido desse chega, a CPU sabe de qual hardware ele est&#225; vindo. O teclado, por exemplo, envia pedidos pela IRQ 1. Um mouse PS2 envia pedidos de IRQ 12. Para ver outros exemplos, <a href="https://wiki.osdev.org/Interrupts">veja aqui</a>.</p><p>Pois bem, esses n&#250;meros s&#227;o usados pela CPU como &#237;ndices para acessar as entradas do IVT e buscar a fun&#231;&#227;o que trata essa solicita&#231;&#227;o. Assim, no caso do teclado, a CPU carregar&#225; o <code>cs:offset</code> da entrada 1 e far&#225; um <code>call</code>/<code>jmp</code> para esse endere&#231;o. E o que essa fun&#231;&#227;o faz? Isso depende do <em>hardware</em>. No caso do teclado, a fun&#231;&#227;o usa instru&#231;&#245;es <code>in</code>/<code>out </code>para consultar os registradores do teclado e descobrir qual tecla foi pressionada.</p><p>Parece funcionar bem certo? Larga de ser burro e usa esse IVT para tratar as interrup&#231;&#245;es ent&#227;o, a tabela j&#225; foi constru&#237;da pela BIOS, para que refazer o servi&#231;o?</p><h2>Basta usar o IVT ent&#227;o!</h2><p>Tenho p&#233;ssimas not&#237;cias jovem. Uma vez que voc&#234; mudou a CPU para o modo Protegido/32bits, o IVT foi perdido. Uma, porque n&#227;o sabemos onde est&#227;o os endere&#231;os das fun&#231;&#245;es que foram instaladas no IVT. Outra, porque aquelas fun&#231;&#245;es usam manipula&#231;&#227;o de dados em modo real de 16 bits, que n&#227;o equivale aos registradores de segmento usados em modo 32 bits. Enfim, n&#227;o &#233; poss&#237;vel.</p><h2>Voltando ao IDT</h2><p>Obviamente h&#225; de se haver um jeito de instalar tratadores de interrup&#231;&#245;es para o modo protegido/32bits. E h&#225; mesmo, e nesse caso, voltamos ao IDT. Nossa miss&#227;o &#233; ent&#227;o, em cada entrada do IDT, o tratador correto da interrup&#231;&#227;o. Vamos ent&#227;o ver como &#233; uma t&#237;pica entrada do IDT.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bm3w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bm3w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 424w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 848w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 1272w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bm3w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png" width="917" height="209" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:209,&quot;width&quot;:917,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:40234,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bm3w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 424w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 848w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 1272w, https://substackcdn.com/image/fetch/$s_!Bm3w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60eaf9cb-a0e7-46ea-950e-0fcc4c2ef304_917x209.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>A entrada tem ent&#227;o 8 bytes, e &#233; ligeiramente mais simples do que uma entrada do GDT. Os campos <em>segment select</em> e <em>offset </em>tem um significado similar ao IVT: no fim das contas &#233; o endere&#231;o da fun&#231;&#227;o que vai tratar a interrup&#231;&#227;o. A diferen&#231;a &#233; que o seletor de segmento aponta para uma entrada v&#225;lida para um seletor de c&#243;digo do GDT. Em especial, pois no futuro o c&#243;digo de usu&#225;rio estar&#225; rodando em outro anel de prote&#231;&#227;o do kernel e por isso o registrador <code>cs </code>selecionar&#225; um segmento diferente do seletor de c&#243;digo do kernel, que executa no anel de prote&#231;&#227;o 0.</p><p>Adianto aos  aflitos que ainda n&#227;o vamos separar o c&#243;digo de usu&#225;rio para o <em>Ring </em>3. Isso vai acontecer apenas no <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project5/p5.html">P5 - mem&#243;ria virtual</a>. Adianto ent&#227;o que as tarefas estar&#227;o rodando no mesmo seletor de segmento do kernel, <em>Ring</em> 0, e todos eles apontam para a mesma entrada: <code>cs = 0x8</code> (para voc&#234; se situar, lembre-se que os seletores de segmento de dados <code>ds</code>, <code>es</code>, <code>fs</code>, <code>gs </code>e <code>ss </code>possuem valor <code>0x10</code>). Portanto, todas as entradas do IDT possuem esse <em>segment selector</em> igual a <code>0x8</code>, e o <code>offset </code>&#233; o endere&#231;o da fun&#231;&#227;o (32 bits partidos ao meio, 16 para cada). At&#233; aqui tudo bem?</p><p>Os bits 32 a 39 s&#227;o reservados. Basta inform&#225;-los como zero, assim como o bit 44.</p><p>O bit 47 &#233; o bit <em>Present</em>, indica que a entrada &#233; v&#225;lida e est&#225; ativa. Basta deixar com o valor 1.</p><p>Os bits 45 e 46 representam o DPL (<em>Descriptor Privilege Level</em>). Com dois bits, voc&#234; sabe que os valores poss&#237;veis s&#227;o 0, 1, 2 e 3, e voc&#234; j&#225; deve ter associado aos an&#233;is de prote&#231;&#227;o, corretamente. Mas o que esse valor significa neste contexto aqui?</p><p>Bom, esse valor s&#243; &#233; usado quando essa entrada do IDT est&#225; relacionado a uma interrup&#231;&#227;o de software invocada com a instru&#231;&#227;o <em>int</em>. Voc&#234; vai querer por exemplo que sua <em>syscall</em> seja dispon&#237;vel aos usu&#225;rios, portanto, no <em>Ring </em>3. Do restante, deixe sempre em <em>Ring </em>0. As interrup&#231;&#245;es de hardware ignoram esse valor.</p><p>Por fim, os bits 40 a 43 representam o <em>Gate Type</em>. Vale a pena explicar um pouco mais isso.</p><h2>Gate type</h2><p>Temos quatro bits para o <em>Gate Type</em>, mas apenas 5 valores v&#225;lidos.</p><h3>Task Gate</h3><p>O valor <code>0x5</code> indica que essa entrada &#233; um <em>Task Gate</em>, usada quando h&#225; troca de contexto via hardware, usando portanto entradas <code>TSS </code>no GDT. Nesse caso, o campo <em>offset </em>n&#227;o &#233; usado e deve estar zerado, pois n&#227;o h&#225; fun&#231;&#227;o de tratamento da interrup&#231;&#227;o. Em vez disso, o estado do processador &#233; salvo no TSS e o endere&#231;o da c&#243;digo interrompido &#233; armazenado no campo <em>Task Link</em> no TSS.</p><p>N&#227;o estamos fazendo troca de contexto via hardware, ent&#227;o n&#227;o usaremos esse valor.</p><h3>Interrupt Gate</h3><p>Os valores poss&#237;veis para esse tipo s&#227;o <code>0x6</code> para um <em>interrupt gate</em> de 16 bits e <code>0xe</code> para um <em>interrupt gate</em> de 32 bits. Obviamente o que nos interessa &#233; o valor <code>0xe</code> (<code>1110b</code>). Interrup&#231;&#245;es de <em>hardware </em>usam esse tipo de <em>gate</em>, bem como as instru&#231;&#245;es de software <code>int</code>. No caso de uma IRQ ou na instru&#231;&#227;o <code>int</code>, o valor &#8220;informado&#8221; &#233; o &#237;ndice para essa entrada no IDT, e o processador carrega o seletor de segmento e o <em>offset </em>para a fun&#231;&#227;o que trata essa interrup&#231;&#227;o. &#201; o tipo mais comum de interrup&#231;&#227;o. &#201; importante destacar que esse tipo de <em>gate</em> desabilita as interrup&#231;&#245;es automaticamente e as reabilita quando o tratamento &#233; encerrado, logo ap&#243;s a instru&#231;&#227;o <code>iret</code>.</p><h3>Trap Gate</h3><p>Esse tipo de <em>gate </em>possui valores v&#225;lidos de <code>0x7</code> para 16 bits e <code>0xf</code> para 32 bits. Novamente, nosso valor de interesse &#233; o de 32 bits, ent&#227;o <code>0xf</code>. Esse tipo &#233; pensado para ser usado no tratamento de exce&#231;&#245;es, por exemplo, uma divis&#227;o por zero.</p><p>Pois &#233;, n&#227;o sei se te ocorreu, mas h&#225; v&#225;rias situa&#231;&#245;es em que uma exce&#231;&#227;o pode ocorrer. Al&#233;m da divis&#227;o por zero, por exemplo, h&#225; outros exemplos, como <em>opcode </em>inv&#225;lido, ou um <em>page fault</em>, quando a mem&#243;ria virtual j&#225; est&#225; sendo usada, ou mesmo se voc&#234; tentar usar as instru&#231;&#245;es <code>in</code>, <code>out</code>, <code>lgdt </code>no <em>Ring </em>3, por exemplo.. Em qualquer desses casos, a CPU interrompe a tarefa atual e procura um tratador adequado.</p><p>Note que, do ponto de vista de procedimento, <em>Interrupt Gate</em> e <em>Trap Gate</em> s&#227;o virtualmente iguais. Inclusive, na sua entrada do IDT, voc&#234; pode usar <em>Trap Gate</em> para tratar IRQs ou <em>Interrupt Gate</em> para tratar exce&#231;&#245;es. A diferen&#231;a ainda n&#227;o foi dita: na verdade uma <em>Trap Gate</em> n&#227;o desabilita as interrup&#231;&#245;es e as reabilita ao final, com <code>iret</code>.</p><p>As consequ&#234;ncias s&#227;o grandes, pense por um momento. Se voc&#234; est&#225; tratando uma divis&#227;o por zero via <em>Trap Gate</em>, como as interrup&#231;&#245;es ainda est&#227;o habilitadas, pode chegar uma interrup&#231;&#227;o de teclado, por exemplo. Nesse caso, a fun&#231;&#227;o que est&#225; tratando a divis&#227;o por zero ser&#225; interrompida para atender a interrup&#231;&#227;o de teclado. Se isso &#233; desej&#225;vel ou mesmo se isso pode acontecer depende de cada caso.</p><p>Voc&#234; vai perceber que as primeiras 32 entradas do IDT s&#227;o exce&#231;&#245;es, e por isso, s&#227;o instaladas como <em>Trap Gate.</em> As demais ser&#227;o <em>Interrupt Gate</em>.</p><h3>Exce&#231;&#245;es</h3><p>Exce&#231;&#245;es ocorrem quando o processador entra em um estado indefinido, seja por erros ou falhas, como por exemplo, a falta de p&#225;gina na mem&#243;ria. Exce&#231;&#245;es podem ou n&#227;o informar um c&#243;digo de erro para o tratador saber o que aconteceu. As exce&#231;&#245;es podem ser divididas:</p><ul><li><p>Falhas: se tratado adequadamente, essa exce&#231;&#227;o retorna para a mesma instru&#231;&#227;o que causou a falha (uma divis&#227;o por zero, talvez?). Nesse caso, a instru&#231;&#227;o que causou o problema pode ser reexecutada se o problema for corrigido. Exemplos s&#227;o: Divis&#227;o por zero, TSS inv&#225;lido, Falta de p&#225;gina, etc.</p></li><li><p><em>Traps</em>: S&#227;o causadas intencionalmente, e o retorno do tratamento dessa interrup&#231;&#227;o acontece na pr&#243;xima instru&#231;&#227;o que originou o evento. Exemplos de <em>traps </em>s&#227;o: Debug, Breakpoint e Overflow (mas um tipo bem espec&#237;fico que s&#243; acontece quando o Overflow Flag no registrador EFLAGS est&#225; setado, e a instru&#231;&#227;o <code>into </code>&#233; executada). Obs: N&#227;o confundir o <em>Trap Gate</em> com uma exce&#231;&#227;o do tipo <em>Trap</em>. S&#227;o coisas diferentes, apesar de relacionadas.</p></li><li><p>Abortar: Esse tipo de exce&#231;&#227;o, em geral, &#233; irrecuper&#225;vel, e o processo que causou isso &#233; morto sem grandes cerim&#244;nias. Um tipo de exce&#231;&#227;o que tem esse comportamento &#233; a Dupla Falta. Imagine por exemplo que um determinado processo teve uma falha de p&#225;gina. Mas a fun&#231;&#227;o que trata falhas de p&#225;gina tamb&#233;m n&#227;o est&#225; na mem&#243;ria, causando uma nova falha de p&#225;ginas novamente. Nesse caso, n&#227;o h&#225; o que se fazer, j&#225; que nenhuma das falhas de p&#225;ginas que ocorreram podem ser tratadas, e o processo &#233; portanto encerrado.</p></li></ul><p>A arquitetura x86 tem uma lista bem definida de exce&#231;&#245;es, e o n&#250;mero no vetor equivale a entrada no IDT conforme imagem abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!T-MM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!T-MM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 424w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 848w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 1272w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!T-MM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png" width="615" height="961" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:961,&quot;width&quot;:615,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80243,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!T-MM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 424w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 848w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 1272w, https://substackcdn.com/image/fetch/$s_!T-MM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f5d62fe-b0a7-4a02-9d35-cf5d57c3b801_615x961.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://wiki.osdev.org/Exceptions</figcaption></figure></div><h2>Voc&#234; ainda est&#225; falando de Gate Type no IDT? Show me the code!</h2><p>Voc&#234; &#233; muito apressado, calma calabreso! Vamos come&#231;ar definindo as defini&#231;&#245;es (pleonasmo intencional).</p><p>No novo arquivo <code>idt.h</code>, vamos criar a classe <code>IDT</code>.</p><pre><code>...  #define PRESENT_BIT (1 &lt;&lt; 7) #define DPL_RING_0 0x0  ...  class IDT {   uint16_t offset_bytes_0_1;   uint16_t segment_selector_bytes_2_3{TYPE_CODE_SEG};   uint8_t reserved_byte_4{0};   uint8_t type_dpl_present_byte_5{PRESENT_BIT | ((DPL_RING_0 &amp; 0x3) &lt;&lt; 5)};   uint16_t offset_bytes_6_7; ... } __attribute__((__packed__));  ...</code></pre><p>Essa classe representa aquela estrutura de 8 bytes j&#225; mostrada anteriormente. Perceba que j&#225; defino alguns valores de antem&#227;o: o seletor do segmento &#233; igual a <code>TYPE_CODE_SEG</code> (definido com o valor <code>0x8</code> no arquivo <code>gdt.h</code>)  e o byte de tipo de <em>gate </em>n&#243;s j&#225; setamos o bit <em>Present</em>, e tamb&#233;m colocamos os bytes equivalentes ao <em>Ring 0</em> na posi&#231;&#227;o certa. O que mais falta ent&#227;o? O que vai mudar de entrada para entrada &#233; o endere&#231;o da fun&#231;&#227;o tratadora (offset) e o tipo de <em>gate</em>. Isso &#233; feito no m&#233;dodo <code>install_idt_entry </code>da classe <code>IDT</code>.</p><pre><code>...  enum GATE_TYPE {   INVALID_0,   INVALID_1,   INVALID_2,   INVALID_3,   INVALID_4,   TASK_GATE,   INT_GATE_16BIT,   TRAP_GATE_16BIT,   INVALID_8,   INVALID_9,   INVALID_A,   INVALID_B,   INVALID_C,   INVALID_D,   INT_GATE_32BIT,   TRAP_GATE_32BIT };  class IDT { ... public:   void install_idt_entry(void (*isr_entrypoint)(void), GATE_TYPE type) {     this-&gt;offset_bytes_0_1 = (uint32_t)*isr_entrypoint &amp; 0x0000ffff;     this-&gt;offset_bytes_6_7 = (uint32_t)*isr_entrypoint &gt;&gt; 16;     this-&gt;type_dpl_present_byte_5 |= type;     ...   }; } __attribute__((__packed__));  ...</code></pre><p>Basicamente, quebramos o endere&#231;o da fun&#231;&#227;o <code>isr_entrypoint</code> em duas partes, e as colocamos no lugar certo na entrada do <code>IDT</code>. E fazemos o mesmo para o tipo de gate. Lembra que temos 4 bits para isso, mas nem todos os valores poss&#237;veis est&#227;o dispon&#237;veis? Por isso usamos essa <code>enum</code>. E como o tipo de gate fica nos bits menos significativos do byte <code>type_dpl_present_byte_5</code>, uma opera&#231;&#227;o <em>OR bitwise</em> &#233; suficiente (operador <code>|=</code> ).</p><p>E teremos tamb&#233;m a Classe <code>IDTPointer</code>, e tal qual o GDTPointer, armazena o endere&#231;o da tabela de entradas IDT e o tamanho.</p><pre><code>...  class IDTPointer { public:   uint16_t size{0};   uint32_t entries_address{0};    IDTPointer(uint16_t size, int32_t address)       : size(size), entries_address(address) {} } __attribute__((__packed__));  ...  void install_idt();  ...</code></pre><p>No c&#243;digo acima definimos ainda a fun&#231;&#227;o <code>install_idt</code> que &#233; chamada pelo kernel para instala&#231;&#227;o das entradas, nos mesmos moldes do <code>GDT</code>. Vamos ver o que essa fun&#231;&#227;o faz, ela est&#225; no arquivo idt.cpp:</p><pre><code>#include "include/idt.h" #include "include/exceptions.h"  static IDT entries[256]; static IDTPointer idtp((uint16_t)(sizeof(entries) - 1), (uint32_t)&amp;entries[0]);  extern "C" void (*isr[])(void); extern "C" uint32_t isr_size; extern "C" void default_isr(void);  void install_idt() {   unsigned int i = 0;   while (i &lt; isr_size) {     entries[i].install_idt_entry(isr[i],                                  i &lt; 32 ? TRAP_GATE_32BIT : INT_GATE_32BIT);     i++;   }    while (i &lt; TOTAL_ISR) {     entries[i].install_idt_entry(&amp;default_isr, INT_GATE_32BIT);     i++;   }    asm("lidt %0" : : "m"(idtp)); }</code></pre><p>Uma diferen&#231;a not&#225;vel do <code>IDT</code> em rela&#231;&#227;o ao <code>GDT </code>&#233; que a tabela do <code>IDT </code>tem tamanho fixo, 256 entradas. Lembre-se que o <code>GDT </code>tem tamanho vari&#225;vel a depender de quem o programa.</p><p>O que fazemos aqui &#233; basicamente instalar as 256 entradas do IDT. Para algumas, temos tratadores definidos no vetor de ponteiros de fun&#231;&#227;o <code>isr</code> (que n&#227;o est&#225; aqui e ser&#225; mostrado em um momento oportuno. A vari&#225;vel <code>isr_size</code> tamb&#233;m indica o tamanho desse vetor de ponteiros de fun&#231;&#227;o. Sabemos que  as as primeiras entradas do IDT s&#227;o exce&#231;&#245;es, conforme tabela, ent&#227;o, o tipo de <em>gate </em>&#233; <code>TRAP_GATE_32BIT</code>. O restante ser&#225; interrup&#231;&#245;es de hardware, portanto <code>INT_GATE_32BIT</code>.</p><p>Obs: A informa&#231;&#227;o acima n&#227;o &#233; inteiramente verdade, h&#225; uma entrada no <code>IDT </code>al&#233;m das listadas do tipo <em>Trap Gate</em>: &#233; justamente a entrada que trata <em>syscalls</em>. Quando ela for instalada, fazemos os ajustes necess&#225;rios.</p><p>Depois das entradas conhecidas, preenchemos o restante das entradas com tratadores de interrup&#231;&#227;o que n&#227;o faz nada, no caso, a fun&#231;&#227;o externa <code>default_isr</code>.</p><p>Por fim, carregamos o registrador <code>IDTR </code>e instalamos o <code>IDT </code>usando a instru&#231;&#227;o especial, que s&#243; pode ser usada no <em>Ring 0</em>, <code>lidt</code>.</p><p>E &#233; isso, IDT instalado. F&#225;cil n&#233;?</p><h3>Ei, espera um minuto&#8230;</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AiRE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AiRE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 424w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 848w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AiRE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg" width="1456" height="818" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:818,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The Hilarious Detail You Never Noticed About Futurama's Blu-Rays And DVDs&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The Hilarious Detail You Never Noticed About Futurama's Blu-Rays And DVDs" title="The Hilarious Detail You Never Noticed About Futurama's Blu-Rays And DVDs" srcset="https://substackcdn.com/image/fetch/$s_!AiRE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 424w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 848w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!AiRE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd988ddba-ad79-4132-ab70-dda34acfe8f2_1600x899.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.looper.com/341868/the-hilarious-detail-you-never-noticed-about-futuramas-blu-rays-and-dvds/</figcaption></figure></div><p>Muito suspeito aquelas declara&#231;&#245;es externas ali. Por que esse c&#243;digo n&#227;o est&#225; ai junto? Qual &#233; a pegadinha?</p><p>Ent&#227;o, de fato tem uma GRANDE pegadinha. Quando uma uma interrup&#231;&#227;o acontece, h&#225; alguns passos que o processador faz antes de realmente chamar a fun&#231;&#227;o que trata a interrup&#231;&#227;o (lembrando que isso vale para x86<em> vanilla</em>. Isso &#233; diferente para x86_64 ou quando h&#225; mudan&#231;a de anel de prote&#231;&#227;o):</p><ol><li><p>O processador empilha o registrador <code>eflags</code></p></li><li><p>O processador empilha o registrador <code>cs</code></p></li><li><p>O processador empilha o registrador <code>eip </code>(se &#233; a instru&#231;&#227;o atual ou a pr&#243;xima, depende da interrup&#231;&#227;o/exce&#231;&#227;o)</p></li><li><p>Se houver um c&#243;digo de erro, o processador empilhar&#225; esse c&#243;digo.</p></li><li><p>O processador carrega o <code>cs:offset</code> da respectiva entrada no <code>IDT </code>e pula para esse c&#243;digo.</p></li></ol><p>Quando tem mudan&#231;a do anel de prote&#231;&#227;o (por exemplo, do <em>Ring 3</em> para <em>Ring 0</em>), antes de empilhar o registrador <code>eflags</code>, o processador empilha os registradores <code>ss </code>e <code>esp</code>, nessa ordem. No nosso caso, o c&#243;digo est&#225; rodando no mesmo anel de prote&#231;&#227;o do kernel ent&#227;o os registradores <code>ss</code> e <code>esp</code> n&#227;o s&#227;o empilhados.</p><p>Assim que o processador come&#231;a a executar o c&#243;digo <code>cs:offset</code>, devemos preservar o estado da tarefa anterior. Diferente da troca de contexto, o registrador <code>eflags </code>j&#225; foi salvo, ent&#227;o &#233; desnecess&#225;rio usar a instru&#231;&#227;o <code>pushf</code>. Mas salvar o restante dos registradores ainda &#233; importante. Portanto as instru&#231;&#245;es <code>pusha</code>/<code>popa </code>ainda ser&#227;o usadas. Por fim, a fun&#231;&#227;o retorna com <code>iret</code>, e n&#227;o <code>ret</code>, como seria um c&#243;digo tradicional.</p><p>Perceba que com todos esses detalhes, &#233; dif&#237;cil usar C/C++ puro pois o c&#243;digo tentar&#225; criar os registros de ativa&#231;&#227;o, retornar com <code>ret</code>, etc. At&#233; d&#225;, mas acredite, o c&#243;digo <em>assembly </em>para tratar disso &#233; mais leg&#237;vel que o c&#243;digo C/C++ equivalente.</p><p>Chega de conversa! Vamos ent&#227;o conferir o c&#243;digo no arquivo <code>isr.asm</code>, mas por partes:</p><pre><code>global isr, isr_size, default_isr extern isr_handlers  ...  %macro isr_no_error 1 isr%1:     push 0     push %1     jmp prepare_isr %endmacro  %macro isr_error 1 isr%1:     push %1     jmp prepare_isr %endmacro  ...</code></pre><p>Primeiro, como h&#225; interrup&#231;&#245;es que empilham c&#243;digo de erro e outras n&#227;o, criamos macros para uniformizar isso: quando o processador n&#227;o empilha um c&#243;digo de erro, n&#243;s empilhamos um valor arbitr&#225;rio (no caso, <code>push 0</code>). Isso servir&#225; para uniformizarmos o tratamento das interrup&#231;&#245;es, todas elas chegar&#227;o com a mesma estrutura de pilha ao tratador. Outra coisa que empilhamos &#233; o n&#250;mero da interrup&#231;&#227;o: isso servir&#225; para acessarmos um vetor de ponteiros de fun&#231;&#227;o com o tratador definitivo. Por exemplo, se a exce&#231;&#227;o for divis&#227;o por zero, ele empilhar&#225; zero. Se for <em>Opcode </em>Inv&#225;lido, ele empilhar&#225; 6 e assim por diante. Depois disso ele pular&#225; para o r&#243;tulo <code>prepare_isr</code>.</p><p>Usamos essa macro assim: pegando como exemplo a divis&#227;o por zero. Ela &#233; identificada pelo &#237;ndice 0. Ent&#227;o fica:</p><pre><code>isr_no_error 0x00 ; Division Error</code></pre><p>Do ponto-e-v&#237;rgula para frente &#233; coment&#225;rio. Ent&#227;o <code>isr_no_error 0x00</code> &#233; traduzido diretamente para:</p><pre><code>isr0x00:     push 0     push 0x00     jmp prepare_isr</code></pre><p>Sacou? A ideia &#233; n&#227;o fica repetindo c&#243;digo. Para definir as 32 exce&#231;&#245;es da tabela previamente apresentada, considerando se tem ou n&#227;o c&#243;digo de erro, fica assim:</p><pre><code>isr_no_error 0x00 ; Division Error isr_no_error 0x01 ; Debug isr_no_error 0x02 ; Non-maskable Interrupt isr_no_error 0x03 ; Breakpoint isr_no_error 0x04 ; Overflow isr_no_error 0x05 ; Bound Range Exceeded isr_no_error 0x06 ; Invalid Opcode isr_no_error 0x07 ; Device Not Available isr_error 0x08 ; Double Fault isr_no_error 0x09 ; Coprocessor Segment Overrun isr_error 0x10 ; Invalid TSS isr_error 0x11 ; Segment Not Present isr_error 0x12 ; Stack-Segment Fault isr_error 0x13 ; General Protection Fault isr_error 0x14 ; Page Fault isr_no_error 0x15 ; Reserved isr_no_error 0x16 ; x87 Floating-Point Exception isr_error 0x17 ; Alignment Check isr_no_error 0x18 ; Machine Check isr_no_error 0x19 ; SIMD Floating-Point Exception isr_no_error 0x20 ; Virtualization Exception isr_error 0x21 ; Control Protection Exception isr_no_error 0x22 ; Reserved isr_no_error 0x23 ; Reserved isr_no_error 0x24 ; Reserved isr_no_error 0x25 ; Reserved isr_no_error 0x26 ; Reserved isr_no_error 0x27 ; Reserved isr_no_error 0x28 ; Hypervisor Injection Exception isr_error 0x29 ; VMM Communication Exception isr_error 0x30 ; Security Exception isr_no_error 0x31 ; Reserved</code></pre><p>De boa n&#233;? Entendendo a ideia da parada, fica mais f&#225;cil de entender o que est&#225; acontecendo. Agora vamos ver o r&#243;tulo <code>prepare_isr</code>:</p><pre><code>prepare_isr:     pusha     mov ebp, esp      mov ebx, [ebp+32] ; isr_nr on the stack     push dword [ebp+36] ; err_code to the handler     call [isr_handlers + 4*ebx]     add esp, 4 ; remove err_code off the stack      popa     add esp, 8 ; remove error code and isr_nr from stack     iret</code></pre><p>Come&#231;amos empilhando os registradores de prop&#243;sito geral. Depois ajustamos o registrador <code>ebp </code>para podermos acessar os par&#226;metros na pilha de uma forma inteligente.</p><p>Para prosseguirmos, precisamos entender como est&#225; o layout da pilha at&#233; esse momento. A imagem abaixo mostra isso.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kUuH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kUuH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 424w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 848w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 1272w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kUuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png" width="1014" height="715" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:715,&quot;width&quot;:1014,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:140737,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kUuH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 424w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 848w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 1272w, https://substackcdn.com/image/fetch/$s_!kUuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be870d9-23cc-4087-8098-2f81244c15f3_1014x715.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Ent&#227;o, o que estamos fazendo afinal? Colocamos em <code>ebx </code>o valor de <code>isr_nr </code>que est&#225; na pilha, ele servir&#225; de &#237;ndice para acessar o tratador da interrup&#231;&#227;o correto (na chamada <code>call [isr_handlers + 4*ebx]</code>). Antes, reempilhamos o valor <code>err_code </code>(<code>push dword [ebp+36]</code>) para o tratador, assim, todos os <em>handlers </em>podem ter a mesma assinatura: <code>void isr_handler (int);</code></p><p>Voc&#234; deve ter notado ainda que o <code>isr_handlers </code>&#233; definido como externo no arquivo isr.asm. Eu mostro esse depois, e esse n&#227;o tem segredo, voc&#234; vai ver. Mas vamos continuar a fun&#231;&#227;o <code>prepare_isr</code>. Depois que a instru&#231;&#227;o <code>call </code>retorna, n&#243;s removemos o err_code da pilha (<code>add esp, 4)</code>, desempilhamos todos os registradores (<code>popa</code>), e desempilhamos <code>isr_nr </code>e <code>err_code </code>(e o <code>err_code </code>&#233; desempilhado por n&#243;s, mesmo se foi o processador quem empilhou!). A instru&#231;&#227;o iret se encarrega de desempilhar os registradores <code>eip</code>, <code>cs </code>e <code>eflags</code>.</p><p>Beleza, mas, se me lembro bem, o <code>install_idt </code>usa uma vari&#225;vel <code>isr </code>(e <code>isr_size</code>)&#8230; voc&#234; ainda n&#227;o mostrou nada relacionado a ela! Ela &#233; usada aqui no arquivo idt.cpp nesse trecho:</p><pre><code>    entries[i].install_idt_entry(isr[i],                                  i &lt; 32 ? TRAP_GATE_32BIT : INT_GATE_32BIT);</code></pre><p>Com as macros definidas, &#233; f&#225;cil definirmos a vari&#225;vel <code>isr</code> no arquivo <code>isr.asm</code>:</p><pre><code>isr: dd   isr0x00, isr0x01, isr0x02, isr0x03, isr0x04,  isr0x05, isr0x06, isr0x07, isr0x08, isr0x09,  dd   isr0x10, isr0x11, isr0x12, isr0x13, isr0x14, isr0x15, isr0x16, isr0x17, isr0x18, isr0x19,  dd   isr0x20, isr0x21, isr0x22, isr0x23, isr0x24, isr0x25, isr0x26, isr0x27, isr0x28, isr0x29,  dd   isr0x30, isr0x31 isr_end:  isr_size: dd (isr_end - isr)/DWORD_SIZE</code></pre><p>S&#243; isso. No fim das contas, como eu havia dito, &#233; um vetor de ponteiros para fun&#231;&#227;o (ou algo similar a isso). S&#227;o esses endere&#231;os que s&#227;o efetivamente instalados no IDT. </p><p>Pode ter ficado confuso, &#233; muito vai-e-volta, mas vamos exemplificar. Suponha que uma divis&#227;o por zero ocorreu. O processador vai fazer aqueles empilhamentos malucos que j&#225; explicitamos, e ele vai carregar o <code>cs:offset</code> do IDT. E qual &#233; esse valor? &#201; <code>0x8:isr0x00.</code> A fun&#231;&#227;o empilha o <code>err_code </code>(zero) e <code>isr_nr </code>(tamb&#233;m zero) e pula para <code>prepare_isr</code>. L&#225;, os registradores s&#227;o empilhados e ele chama a fun&#231;&#227;o definida no vetor <code>isr_handlers </code>na posi&#231;&#227;o zero<code>.</code> Depois ele faz um <em>clean-up</em> e segue a vida.</p><p>Vamos ver o que tem em <code>isr_handlers </code>ent&#227;o. N&#227;o poderia ser mais simples, est&#225; no arquivo <code>isr_handlers.cpp</code>:</p><pre><code>#include "include/exceptions.h"  void (*isr_handlers[])(int) = {     &amp;division_error,      &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;invalid_opcode,      &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler, &amp;default_isr_handler,     &amp;default_isr_handler, &amp;default_isr_handler};</code></pre><p>Como eu disse, e eu espero que voc&#234; tenha acreditado em mim, &#233; literalmente um vetor de ponteiros de fun&#231;&#227;o, e agora sim, os tratadores de verdade das interrup&#231;&#245;es.</p><p>Para esse post, defini apenas 2 exce&#231;&#245;es: erro de divis&#227;o e <em>opcode </em>inv&#225;lido. O restante usa um tratador gen&#233;rico. E agora podemos usar C/C++! Primeiro, o arquivo <code>exceptions.h</code>:</p><pre><code>#ifndef __EXCEPTIONS_H #define __EXCEPTIONS_H  void default_isr_handler(int);  void division_error(int);  void invalid_opcode(int);  #endif</code></pre><p>Fun&#231;&#245;es com a mesma assinatura, h&#227;? E o corpo dessas fun&#231;&#245;es fica assim:</p><pre><code>#include "include/exceptions.h" #include "include/util.h"  void default_isr_handler(int err_code) {   printk("default_isr_handler was called: err_code: %d\n", err_code); }  void division_error(__attribute__((unused)) int err_code) {   panic("Divisior error"); }  void invalid_opcode(__attribute__((unused)) int err_code) {   panic("Invalid Opcode"); }</code></pre><p>O <em>handler default</em> s&#243; imprime o c&#243;digo de erro e retorna. As outras duas fun&#231;&#245;es usam a fun&#231;&#227;o <code>panic</code>, que &#233; um <code>printk </code>que entra em um <em>loop </em>infinito. Isso porque, voc&#234; se recorda, essas exce&#231;&#245;es retornam para a mesma instru&#231;&#227;o que causou o problema, lembra? N&#227;o vou testar isso no contexto de tarefas, vou testar direto no kernel. Ent&#227;o, n&#227;o h&#225; &#8220;processo&#8221; para derrubar. Se retorn&#225;ssemos como seria o fluxo normal, ele tentaria executar novamente as instru&#231;&#245;es problem&#225;ticas, e ficaria chamando para sempre os tratadores de interrup&#231;&#227;o. N&#227;o se preocupe, isso mudar&#225; depois.</p><p>Outro ponto de aten&#231;&#227;o &#233; que para as fun&#231;&#245;es <code>division_error</code> e <code>invalid_opcode</code>, n&#227;o h&#225; raz&#227;o para usarmos o par&#226;metro err_code. Por esse motivo, instru&#237;mos o compilador a n&#227;o reclamar pelo fato de n&#227;o o usarmos. Coisa besta, mas que deixa o c&#243;digo mais robusto e gera menos <em>warnings </em>na sa&#237;da do compilador.</p><h2>&#201; isso?</h2><p>Agora sim, isso &#233; tudo. Pelo menos, da parte que queria apresentar nesse post. Voc&#234; deve ter notado que n&#227;o temos tratadores para as IRQ ainda. Fique calmo que logo elas vem.</p><p>Para testar isso, fiz dois testes. Logo ap&#243;s instalar o <code>IDT</code>, causei uma divis&#227;o por zero:</p><pre><code>...  extern "C" void _start() {   _init();   clear_screen();    install_gdt();   install_idt();   *(uint32_t *)(USER_ENTRY_POINT) = (uint32_t)&amp;kernel_entry;    volatile int a = 3;   volatile int b = 0;   printk("%d\n", a / b);</code></pre><p>e o resultado &#233;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5MkN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5MkN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 424w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 848w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 1272w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5MkN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png" width="689" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:689,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10703,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5MkN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 424w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 848w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 1272w, https://substackcdn.com/image/fetch/$s_!5MkN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcd19e66-0781-4bb9-8426-37a3352e591e_689x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Para o <em>opcode </em>inv&#225;lido:</p><pre><code>...  extern "C" void _start() {   _init();   clear_screen();    install_gdt();   install_idt();   *(uint32_t *)(USER_ENTRY_POINT) = (uint32_t)&amp;kernel_entry;    ...    asm("ud2 " : :);</code></pre><p>o resultado &#233;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9d2m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9d2m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 424w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 848w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 1272w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9d2m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png" width="761" height="470" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:470,&quot;width&quot;:761,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15360,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9d2m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 424w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 848w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 1272w, https://substackcdn.com/image/fetch/$s_!9d2m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca46b361-4206-440a-8b2d-ec6b691986b4_761x470.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>E &#233; isso ai, tudo funcionando!</p><p>No pr&#243;ximo post pretendo tratar pelo menos da <em>IRQ0</em>, que trata das interrup&#231;&#245;es do timer do sistema. Essa &#233; a principal ferramenta usada para fazer um kernel preemptivo, pois &#233; um temporizador que de tempos em tempos interrompe o processador, e usamos isso para fazer a troca de contexto das tarefas.</p><p>Enquanto isso n&#227;o ocorre, fique com o c&#243;digo desse post, que est&#225; dispon&#237;vel no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p3-v1">github</a>.</p><p>Queria agradecer &#224;s p&#225;ginas <a href="https://wiki.osdev.org/Interrupts">OSDev </a>e <a href="http://skelix.net/skelixos/tutorial04_en.html">Skelix</a>, em que baseei boa parte do conte&#250;do aqui apresentado. Em especial &#224; OSDev, h&#225; muito conte&#250;do complementar relacionado que sugiro a leitura<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> <a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> <a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> <a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a> <a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a> <a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a>:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/apanhando-do-rdtsc?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/apanhando-do-rdtsc?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/interrupcoes-de-hardware-e-concurrency&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/interrupcoes-de-hardware-e-concurrency"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://wiki.osdev.org/Security#Rings</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>https://wiki.osdev.org/I_Can%27t_Get_Interrupts_Working#Problems_with_IDTs</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>https://wiki.osdev.org/Interrupt_Service_Routines</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>https://wiki.osdev.org/Interrupts_Tutorial</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>https://wiki.osdev.org/8259_PIC#Programming_the_PIC_chips</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>https://wiki.osdev.org/Interrupt_Descriptor_Table</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Apanhando do RDTSC]]></title><description><![CDATA[Porque toda falha &#233; um sucesso, de algum modo...]]></description><link>https://blog.rodrigobranco.net/p/apanhando-do-rdtsc</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/apanhando-do-rdtsc</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Sun, 19 Jan 2025 16:32:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SV69!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SV69!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SV69!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 424w, https://substackcdn.com/image/fetch/$s_!SV69!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 848w, https://substackcdn.com/image/fetch/$s_!SV69!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 1272w, https://substackcdn.com/image/fetch/$s_!SV69!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SV69!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png" width="568" height="335" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:335,&quot;width&quot;:568,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SV69!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 424w, https://substackcdn.com/image/fetch/$s_!SV69!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 848w, https://substackcdn.com/image/fetch/$s_!SV69!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 1272w, https://substackcdn.com/image/fetch/$s_!SV69!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F321b3011-d099-41d6-bb1c-29b1e7be0d7e_568x335.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Antes de iniciar esse post, preciso complementar uma informa&#231;&#227;o que faltou no <a href="https://blog.rodrigobranco.net/p/fake-userland?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=false">post anterior</a>. O m&#233;todo de chamada de sistema daquele post se parece muito em como as fun&#231;&#245;es virtuais funcionam em C++. Fun&#231;&#245;es virtuais podem ser sobrecarregadas, significando que o endere&#231;o da fun&#231;&#227;o original na classe base &#233; alterada pelo novo m&#233;todo. Como isso &#233; resolvido dentro do compilador? Bom, todos os objetos que possuem m&#233;todos virtuais possuem uma estrutura chamada VTABLE, que contempla os ponteiros das fun&#231;&#245;es virtuais. </p><p>Quando um objeto de classe derivada &#233; constru&#237;do e atribu&#237;do a uma refer&#234;ncia da classe base, o compilador troca o endere&#231;o da m&#233;todo da classe base para este objeto. O c&#243;digo continua chamando os m&#233;todos da classe base, mas o compilador agora tem um ponteiro de ponteiro: ele sabe o endere&#231;o da VTABLE desse objeto, que cont&#233;m um outro ponteiro do m&#233;todo sobrescrito. Por este motivo, esse m&#233;todo de despacho de ponteiros de ponteiro de fun&#231;&#227;o se parece com mecanismo usado para <em>syscall </em>aqui. Se voc&#234; est&#225; construindo um compilador que compila c&#243;digos orientados a objeto, agora sabe como fazer sobrescrita de m&#233;todos.</p><p>Por que estou falando disso? Porque est&#225; no momento de fazer o cr&#233;dito extra do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>, que pede:</p><div class="pullquote"><p>For extra credit, write a fair scheduler. This means that the scheduler always chooses as the next task to run the one that has had the least amount of time on the CPU thus far. Do <em>not</em> include the time it takes to do a context switch when keeping track of run time thus far. Prove that your scheduler is fair by writing tasks that show execution time on the CPU is fair to within the longest interval between yields.</p></div><p>Ent&#227;o &#233; hora de fazer um escalonador justo, que sempre escolhe os processos que tiveram o menor tempo de CPU a cada rodada. Pra isso a gente precisa saber quanto tempo cada tarefa levou, e o lugar para armazenar essa informa&#231;&#227;o, como voc&#234; j&#225; deve ter deduzido, &#233; no PCB. Tomei a liberdade de medir 4 coisas:</p><pre><code>...
class PCB {
...
  unsigned long long kernel_cpu_time_last_sched{0};
  unsigned long long user_cpu_time_last_sched{0};
  unsigned long long total_kernel_cpu_time{0};
  unsigned long long total_user_cpu_time{0};</code></pre><p>Isso para medir o tempo de CPU desde o &#250;ltimo escalonamento da tarefa, tanto do kernel no contexto do processo ou para as threads de kernel, quanto o tempo de cpu de usu&#225;rio, v&#225;lido apenas para tarefas de usu&#225;rio (processos).</p><p>Fiz assim para evitar que tarefas que estejam executando a muuuuuito tempo, quando outra nova tarefa seja adicionada, esta n&#227;o fique rodando sozinha at&#233; que ela iguale o tempo da tarefa antiga.</p><p>Com isso, nosso PCB ganha novos m&#233;todos:</p><pre><code>  void set_kernel_cpu_time(unsigned long long time) {
    this-&gt;kernel_cpu_time_last_sched += time;
    this-&gt;total_kernel_cpu_time += time;
  };
  void set_user_cpu_time(unsigned long long time) {
    this-&gt;user_cpu_time_last_sched += time;
    this-&gt;total_user_cpu_time += time;
  };

  void clear_last_cpu_time() {
    this-&gt;kernel_cpu_time_last_sched = 0;
    this-&gt;user_cpu_time_last_sched = 0;
  }

  unsigned long long get_cpu_time() {
    return this-&gt;kernel_thread ? this-&gt;kernel_cpu_time_last_sched
                               : this-&gt;user_cpu_time_last_sched;
  }</code></pre><p>Os dois primeiros m&#233;todos s&#227;o autoexplicativos, eles incrementam os contadores de tempo locais e globais, do kernel ou do usu&#225;rio. O terceiro zera o tempo do &#250;ltimo escalonamento quando a tarefa &#233; escolhida da fila de tarefas prontas para execu&#231;&#227;o. O &#250;ltimo m&#233;todo retorna o tempo de cpu do &#250;ltimo escalonamento, diferenciando processos e threads de kernel para que a compara&#231;&#227;o entre eles seja justa.</p><p>Fiz uma pequena altera&#231;&#227;o na classe <code>Scheduler</code>:</p><pre><code>class Scheduler {
...
public:
  virtual void sched(QueueNode&lt;PCB&gt; *);
...
};</code></pre><p>Voc&#234; pode ver que transformei o m&#233;todo <code>sched </code>em virtual, para poder criar uma nova classe derivada:</p><pre><code>class FairScheduler : public Scheduler {
public:
  void sched(QueueNode&lt;PCB&gt; *);
};</code></pre><p>Afinal, nosso objetivo &#233; &#250;nica e exclusivamente alterar o m&#233;todo <code>sched</code>, para que ele passe a considerar o tempo de execu&#231;&#227;o da tarefa.</p><p>Agora, para declarar o escalonador, basta fazermos assim:</p><pre><code><code>FairScheduler fairSched;
Scheduler *sched = &amp;fairSched;</code></code></pre><p>que o restante do c&#243;digo fica todo intacto! <em>God bless the OOP</em>! E isso se liga ao assunto da VTABLE e tabela de despacho da abertura desse post.</p><p>Acabou? Logicamente que n&#227;o, crian&#231;a. Vamos ver o que o m&#233;todo <code>sched </code>dessa nova classe faz.</p><pre><code>void FairScheduler::sched(QueueNode&lt;PCB&gt; *task) {
  ...
  queue_insert_ordered(this-&gt;ready_queue, task, &amp;comparePCB);

  ...
}</code></pre><p>S&#243; isso, o resto &#233; c&#243;digo pra ajudar a debugar (voc&#234; logo vai entender o motivo). Quem faz todo o trabalho sujo &#233; a fun&#231;&#227;o <code>queue_insert_ordered</code>. Vamos a ela:</p><pre><code>template &lt;class T&gt;
void queue_insert_ordered(QueueNode&lt;T&gt; *&amp;queue, QueueNode&lt;T&gt; *node,
                          int (*compare)(T *, T *)) {
  if (queue == nullptr) {
    queue = node;
    return;
  }

  QueueNode&lt;T&gt; *tmp = queue;
  while (tmp != queue-&gt;previous) {
    if (compare(&amp;node-&gt;get(), &amp;tmp-&gt;get()) &lt; 0) {
      break;
    }
    tmp = tmp-&gt;next;
  }

  if (compare(&amp;node-&gt;get(), &amp;tmp-&gt;get()) &lt; 0) {
    tmp = tmp-&gt;previous;
  }

  tmp-&gt;next-&gt;previous = node;
  node-&gt;next = tmp-&gt;next;
  tmp-&gt;next = node;
  node-&gt;previous = tmp;

  if (compare(&amp;node-&gt;get(), &amp;queue-&gt;get()) &lt; 0) {
    queue = node;
  }
}</code></pre><p>Ele &#233; muito parecido com o <code>queue_insert</code>, a diferen&#231;a &#233; que ele uma uma fun&#231;&#227;o de compara&#231;&#227;o para saber onde inserir o novo elemento. A fun&#231;&#227;o &#233; gen&#233;rica de prop&#243;sito, afinal, estamos usando templates, e o usu&#225;rio que a invocar deve passar essa fun&#231;&#227;o de compara&#231;&#227;o como argumento. Na chamada da fun&#231;&#227;o, voc&#234; perceber&#225; que eu passei o endere&#231;o de <code>comparePCB</code>. Aqui est&#225; essa fun&#231;&#227;o:</p><pre><code>static int comparePCB(PCB *a, PCB *b) {
  ...
  if (a-&gt;get_cpu_time() &lt; b-&gt;get_cpu_time()) {
    return -1;
  } else if (a-&gt;get_cpu_time() &gt; b-&gt;get_cpu_time()) {
    return 1;
  } else {
    return 0;
  }
}</code></pre><p>N&#227;o &#233; muito diferente das fun&#231;&#245;es <code>compareTo </code>do Javinha.</p><p>E como medimos o tempo? A gente cria uma vari&#225;vel de tempo corrente, e fun&#231;&#245;es para iniciar e parar um timer:</p><pre><code>unsigned long long curr_time = 0;

...

extern "C" void start_timer() {
  curr_time = get_timer();
  ...
}
extern "C" void stop_kernel_timer() {
  unsigned long long tmp = get_timer();
  unsigned long long diff = tmp - curr_time;
  ...
  current_task-&gt;get().set_kernel_cpu_time(diff);
  curr_time = tmp;
  ...
}

extern "C" void stop_user_timer() {
  unsigned long long tmp = get_timer();
  unsigned long long diff = tmp - curr_time;
  current_task-&gt;get().set_user_cpu_time(diff);
  curr_time = tmp;
  ...
}</code></pre><p>Onde essas fun&#231;&#245;es s&#227;o chamadas? Nas trocas de contexto (de usu&#225;rio ou kernel):</p><pre><code>...
extern current_task, scheduler, syscall_operations, returning_kernel_entry, start_timer, stop_kernel_timer, stop_user_timer

...

kernel_entry:
    ...
    call stop_user_timer
    ...

    call start_timer
    mov ebx, [syscall_op]
    call [syscall_operations + 4*ebx]

returning_kernel_entry:  
    call stop_kernel_timer
    ...

    call start_timer
    ...
    ret


scheduler_entry:
    ...
    call stop_kernel_timer
    ...
    call scheduler
    ...
    call start_timer
    ...
    ret</code></pre><p>Basicamente, paramos e iniciamos os timers dentro dessas fun&#231;&#245;es acima. Um pouco antes de liberar a cpu para a pr&#243;xima tarefa, tamb&#233;m, paramos o timer para que a fun&#231;&#227;o <code>sched </code>possa usar o tempo nas compara&#231;&#245;es.</p><pre><code>void do_yield() {
  stop_kernel_timer();
  current_task-&gt;get().ready();
  sched-&gt;sched(current_task);
  start_timer();
  scheduler_entry();
} </code></pre><p>Por fim, quando uma nova tarefa &#233; escalonada, o escalonador limpa os valores pr&#233;vios:</p><pre><code>extern "C" void scheduler() {
  sched-&gt;inc_count();
  current_task = sched-&gt;get_ready_task();
  current_task-&gt;get().clear_last_cpu_time();
  current_task-&gt;get().run();
}</code></pre><p>H&#225; outras pequenas atividades que devem ser feitas, que &#233; instanciar o template para usar o PCB, e fazemos isso no arquivo queue-impl-pcb.cpp:</p><pre><code>template void queue_insert_ordered(QueueNode&lt;PCB&gt; *&amp;, QueueNode&lt;PCB&gt; *,
                                   int (*)(PCB *, PCB *));</code></pre><p>Esse tipo de coisa eu n&#227;o mais farei nos pr&#243;ximos posts, pois &#233; repetitivo. S&#243; se aparecer algo muito diferente que valha a pena mencionar.</p><p>Isso tudo que foi dito at&#233; aqui &#233; suficiente para fazer esse escalonador justo, considerando os tempos de execu&#231;&#227;o das tarefas. S&#243; faltou um pequeno detalhe: a fun&#231;&#227;o <code>get_timer</code>, invocada pelas fun&#231;&#245;es <code>start_timer, stop_kernel_timer</code> e <code>stop_user_timer</code> acima.</p><h1>Come&#231;ando o pesadelo</h1><p>Retomando a descri&#231;&#227;o do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>:</p><div class="pullquote"><p>The function util.c:get_timer() returns the number of instructions that have been executed since boot.</p></div><p>S&#243; isso? Oxi, t&#225; f&#225;cil hein. Que instru&#231;&#227;o x86 faz isso? A <a href="https://www.felixcloutier.com/x86/rdtsc">RDTSC</a>:</p><div class="pullquote"><p>Reads the current value of the processor&#8217;s time-stamp counter (a 64-bit MSR) into the EDX:EAX registers. The EDX register is loaded with the high-order 32 bits of the MSR and the EAX register is loaded with the low-order 32 bits. (On processors that support the Intel 64 architecture, the high-order 32 bits of each of RAX and RDX are cleared.)</p><p>The processor monotonically increments the time-stamp counter MSR every clock cycle and resets it to 0 whenever the processor is reset. See &#8220;Time Stamp Counter&#8221; in Chapter 18 of the Intel<sup>&#174;</sup> 64 and IA-32 Architectures Software Developer&#8217;s Manual, Volume 3B, for specific details of the time stamp counter behavior.</p></div><p>Quando mexi com esse trabalho, em 2020, essa parte do c&#243;digo j&#225; estava pronto. Confesso que nem me preocupei em como isso era feito. Lembre-se que esses trabalhos s&#227;o acad&#234;micos, com o intuito de exercitar conceitos bem espec&#237;ficos. Mexer com temporiza&#231;&#227;o no x86 n&#227;o era um desses conceitos, e vinha pronto no c&#243;digo fornecido para n&#243;s.</p><p>Ent&#227;o, chumbei a instru&#231;&#227;o <code>rdtsc </code>na minha fun&#231;&#227;o <code>get_timer</code>. Note tamb&#233;m que os c&#243;digos que usam essa fun&#231;&#227;o j&#225; retornam para vari&#225;veis <code>unsigned long long</code>. A instru&#231;&#227;o <code>rdtsc</code> coloca os valores nos registradores <code>edx:eax</code>, mas o compilador &#233; inteligente o suficiente para trabalhar bem com esses valores de 64bit. Ent&#227;o tudo certo!</p><p>Ser&#225; mesmo? Bom, quando comecei a mexer com essa parte, os valores que retornavam eram malucos. Pior, quando chamava a rdtsc na sequ&#234;ncia, na v&#227; esperan&#231;a de retornar valores compat&#237;veis, minha sanidade come&#231;ou a esvair pelo ralo.</p><p>A partir de agora, o que vir&#225; &#233; um relato de v&#225;rias tentativas para tentar entender o que estava acontecendo. N&#227;o consigo afirmar com certeza qual altera&#231;&#227;o foi efetiva, ou mesmo se alguma outra coisa deveria ter sido feita. Mas pelo menos cheguei em uma resposta &#8220;plaus&#237;vel&#8221;. Vamos l&#225;.</p><h1>Sistema de virtualiza&#231;&#227;o</h1><p>Come&#231;o o primeiro post (<a href="https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga">VEJA AQUI</a>) avisando que n&#227;o usaria o emulador <em>Bochs</em>, mas sim o <em>QEMU</em>. Mais do que isso, rodo o <em>QEMU </em>direto no meu <em>Ubuntu</em>, que roda no meu <em>WSL2 </em>no meu <em>Windows 11</em>. Percebe onde quero chegar?</p><p>Est&#225;vamos chamando o QEMU assim:</p><pre><code>/usr/bin/qemu-system-i386 -machine accel=kvm ... -cpu host ...</code></pre><p>Isso estava fazendo o QEMU rodar direto na CPU virtualizado pelo KVM, usando como CPU o processador do meu host. Isso significa que ele estava pegando os valores do timestamp do meu CPU, que est&#225; rodando diversas outras coisas, como o pr&#243;prio <em>QEMU</em>, <em>VSCode</em>, <em>WSL</em>, <em>Windows</em>, <em>Red Dead Redemp</em>&#8230;. ops, esse n&#227;o. Pior, os valores n&#227;o eram consistentes entre as chamadas, pois &#233; prov&#225;vel que o processo do <em>QEMU </em>esteja executando em CPUs diferentes, que possuem <em>timestamps </em>diferentes.</p><p>Ent&#227;o, a primeira altera&#231;&#227;o foi alterar o m&#233;todo de acelera&#231;&#227;o para uma emula&#231;&#227;o embutida no QEMU, e dizer que estamos usando apenas uma CPU:</p><pre><code>/usr/bin/qemu-system-i386 -smp cpus=1 -machine accel=tcg ...</code></pre><p>Resolvido? N&#227;o. Volte um pouco e veja a cita&#231;&#227;o do P2, que diz que a <code>get_timer </code>retorna o n&#250;mero de instru&#231;&#245;es que foram executadas desde o boot. S&#243; que os n&#250;meros que a <em>rdtsc </em>continuavam n&#227;o fazendo sentido. Ao executar duas <code>rdtsc </code>na sequ&#234;ncia, deveria vir apenas 1 de diferen&#231;a para o valor anterior. Ok, 2, 3, no m&#225;ximo 5 instru&#231;&#245;es, considerando uma arquitetura superescalar em que h&#225; pipelines e execu&#231;&#245;es fora de ordem, mas n&#227;o deveria ser muito diferente disso. O problema &#233; que o valor retornado girava na casa de 70 mil!</p><h1>Diferen&#231;as de TSC entre processadores</h1><p>Se voc&#234; for na <a href="https://en.wikipedia.org/wiki/X86_instruction_listings">p&#225;gina da wikipedia sobre as instru&#231;&#245;es x86</a> encontrar&#225; o seguinte:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dVnZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dVnZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 424w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 848w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 1272w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dVnZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png" width="1092" height="678" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:678,&quot;width&quot;:1092,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91671,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dVnZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 424w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 848w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 1272w, https://substackcdn.com/image/fetch/$s_!dVnZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8aa9e88d-33f2-43e1-861a-0e83679ad0b7_1092x678.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://en.wikipedia.org/wiki/X86_instruction_listings</figcaption></figure></div><p>Ent&#227;o, antigamente o TSC era incrementado de 1 mesmo, o que era previsto pelo trabalho. Mas agora, processadores mais modernos n&#227;o s&#227;o mais assim. Mais do que isso, aquela nota de rodap&#233; [m] da imagem acima diz:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Xt3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Xt3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 424w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 848w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 1272w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Xt3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png" width="720" height="683" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:683,&quot;width&quot;:720,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:169975,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9Xt3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 424w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 848w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 1272w, https://substackcdn.com/image/fetch/$s_!9Xt3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff9cc0c1-448e-4135-9e40-c43be2a586ae_720x683.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://en.wikipedia.org/wiki/X86_instruction_listings#cite_note-116</figcaption></figure></div><p>Bom, diante disso, assumi que o valor era incrementado, e de alguma forma era proporcional ao n&#250;mero de instru&#231;&#245;es executadas, mesmo sem saber exatamente quando. E ai come&#231;ou o segundo problema.</p><h1>O compilador tamb&#233;m n&#227;o colabora!</h1><p>Observe o c&#243;digo abaixo:</p><pre><code>void thread1() {
  int x = 0;
  for (int i = 0; i &lt; 10000; i++) {
    x += i * 2;
  }
  printk("t1 10000 x=%d\n", x);
  printk("t1 sleeping 10 second\n");
  do_yield();
  printk("t1 exiting\n");
  do_exit();
}</code></pre><p>Meu objetivo ai em cima &#233; s&#243; fazer o processador gastar tempo calculando nada. Outras threads tinham um c&#243;digo parecido, mas variando o valor de <code>i</code>. Ao executar o c&#243;digo, as threads levavam quase o mesmo tempo, independente do valor do la&#231;o <em>for</em>. Era hora de invocar o <em>gdb </em>e verificar o que estava acontecendo.</p><p>O problema &#233; que o compilar &#233; muito mais inteligente que eu (n&#227;o &#233; muito dif&#237;cil, mas enfim). O compilador v&#234; um c&#243;digo desse e pensa: &#8220;poxa, mas eu consigo calcular isso ai de antem&#227;o, o c&#243;digo dele n&#227;o precisa iterar nesse la&#231;o NEM UMA &#218;NICA VEZ!". E ele est&#225; certo. S&#243; que agora eu n&#227;o quero efici&#234;ncia e otimiza&#231;&#227;o, eu estou testando a temporiza&#231;&#227;o das <em>threads</em>, caraca! Bom, isso nem &#233; t&#227;o dif&#237;cil assim de resolver, basta enfiar um <code>volatile </code>(<code>volatile</code> <code>int x = 0;</code>) que o compilador &#233; for&#231;ado a ler o valor da mem&#243;ria e assim, iterar no loop. Percebe-se que coisas dif&#237;ceis n&#227;o s&#227;o f&#225;ceis.</p><p>Mesmo corrigindo o c&#243;digo acima, a execu&#231;&#227;o n&#227;o estava satisfat&#243;ria. Precisei apelar: at&#233; o momento, eu n&#227;o havia consultado nenhuma vez o c&#243;digo original. Mas estava chegando em um beco sem sa&#237;da. Afinal, o que o c&#243;digo original que eu tinha acesso faz?<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZSl6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZSl6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZSl6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg" width="470" height="202" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:202,&quot;width&quot;:470,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14293,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZSl6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ZSl6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F813253cf-8d6b-4f91-a6c1-53d269fb835f_470x202.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: c&#243;digo privado da Universidade de Princeton</figcaption></figure></div><p>E o meu c&#243;digo estava assim (arquivo <code>util.h</code>):</p><pre><code>#include &lt;x86intrin.h&gt;

...

inline unsigned long long get_timer() {
  ...
  return __rdtsc();
};</code></pre><p>A tradu&#231;&#227;o dos dois c&#243;digos resulta na mesma coisa, a instru&#231;&#227;o <code>rdtsc </code>em x86. Aproveitei e vi a fun&#231;&#227;o <code>delay </code>do arquivo deles:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ho1p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ho1p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ho1p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg" width="392" height="163" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:163,&quot;width&quot;:392,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13090,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ho1p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Ho1p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c04bdb7-7a9a-4e59-a443-9e8434659491_392x163.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: c&#243;digo privado da Universidade de Princeton</figcaption></figure></div><p>E o que &#233; esse MHZ ai? </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zpjj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zpjj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zpjj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg" width="405" height="85" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:85,&quot;width&quot;:405,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7125,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zpjj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zpjj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffca4a768-f406-4ecb-8412-abf25932899f_405x85.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: c&#243;digo privado da Universidade de Princeton</figcaption></figure></div><p>Ah&#225;, tem um valor chumbado no c&#243;digo. Eles prepararam esse c&#243;digo para as m&#225;quinas do laborat&#243;rio <em>fishbowl </em>de <em>Princeton</em>. Esse valor n&#227;o bate com nosso ambiente de desenvolvimento.</p><p>Nesse momento, eu troquei aquele c&#243;digo de loop e copiei essa fun&#231;&#227;o de <em>delay</em>. E fiquei testando valores de <code>MHZ </code>para ver se conseguia gerar um <em>delay </em>de uns 10 segundos.</p><p>Quando n&#227;o obtive sucesso, o pr&#243;ximo passo foi apelar.</p><h1>Usando o Bochs</h1><p>Cansado de apanhar da vida e de todos, resolvi usar o <em>Bochs </em>para comparar as diferen&#231;as entre os dois. Primeiro, instalei o <em>Bochs </em>via <code>apt-get</code>:</p><pre><code>sudo apt-get install bochs bochsbios vgabios bochs-x</code></pre><p>Na minha distro, ele instalou a vers&#227;o 2.7 do <em>Bochs</em>.</p><p>Depois, criei o arquivo ./util/bochsrc abaixo.</p><pre><code>megs: 16
#needs package bochsbios
romimage: file=/usr/share/bochs/BIOS-bochs-legacy
#needs package vgabios
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
vga: extension=vbe
floppya: 1_44=./build/boringos.img, status=inserted
boot: floppy
log: /tmp/bochsout.txt
mouse: enabled=0
cpu: count=1, ips=1000000, reset_on_triple_fault=1
#vga_update_interval: 150000
#i440fxsupport: enabled=1
#needs package bochs-x
display_library: x
log: /dev/null
magic_break: enabled=1
</code></pre><p>Agora, basta comentar a linha que chama o QEMU para chamar o Bochs:</p><pre><code>#!/bin/sh -ex
...

CURRDIR=`pwd`

#/usr/bin/qemu-system-i386 ...
bochs -q -f $CURRDIR/util/bochsrc</code></pre><p>Ao executar o arquivo <code>./util/VM_BoringOS.sh</code>, recebi o erro <code>bx_dbg_read_linear: physical memory read error (phy=0x000100000000, lin=0x0000000100000000)</code>. Os endere&#231;os de mem&#243;ria n&#227;o eram esses, mas o erro era. Depois de muito pesquisar, a sugest&#227;o foi instalar a vers&#227;o 2.8. Ough. L&#225; vai:</p><pre><code>wget https://github.com/bochs-emu/Bochs/archive/refs/tags/REL_2_8_FINAL.tar.gz
mv REL_2_8_FINAL.tar.gz bochs_2_8.tar.gz
tar -zxvf bochs_2_8.tar.gz
cd Bochs-REL_2_8_FINAL/bochs/
./configure --with-all-libs -enable-plugins --enable-debugger --enable-smp --enable-x86-debugger
make
sudo make install</code></pre><p>No fim das contas, consegui executar meu kernel no Bochs. De cara descobri que:</p><ol><li><p>A diferen&#231;a entre dois timestamps do rdtsc gira em torno de 3, 4 ou 5 instru&#231;&#245;es</p></li><li><p>Havia um erro no meu c&#243;digo do delay, estava <code>unsigned long long deadline = millis * 1000 * MHZ;</code> quando deveria ser <code>unsigned long long deadline = get_timer() + (millis * 1000 * MHZ);</code>.</p></li></ol><p>Com essas constata&#231;&#245;es e corre&#231;&#245;es, planejei o seguinte c&#243;digo para testes do escalonador justo. O arquivo <code>tasks.cpp:</code></p><pre><code>...
void thread1() {
  printk("t1 sleeping 10 second\n");
  delay(10000);
  do_yield();
  printk("t1 exiting\n");
  do_exit();
}

void thread2() {
  printk("t2 sleeping 1 second\n");
  delay(1000);
  do_yield();
  printk("t2 exiting\n");
  do_exit();
}

void thread3() {
  printk("t3 sleeping 4 second\n");
  delay(4000);
  do_yield();
  printk("t3 exiting\n");
  do_exit();
}

void thread4() {
  printk("t4 sleeping 2 second\n");
  delay(2000);
  do_yield();
  printk("t4 exiting\n");
  do_exit();
}</code></pre><p>E o <code>process1.cpp</code>:</p><pre><code>...

int main() {
  set_display_position(20, 0);
  printk("p1 sleeping 0.5 second\n");
  delay(500);
  yield();
  printk("p1 exiting\n");
  return 0;
}</code></pre><p>Os processos s&#227;o adicionados na ordem listada, ent&#227;o a <code>thread1 </code>&#233; o PID 0, thread2 &#233; o PID 1, at&#233; o processo 1 que tem PID 4. Todos come&#231;am com tempo de cpu 0, que vai mudando conforme a tarefa vai fazendo yield e vai sendo reinserida na lista de tarefas prontas. A ordem de execu&#231;&#227;o dos PIDs deve ser ent&#227;o: 0, 1, 2, 3, 4, (neste momento, todas as tarefas j&#225; executaram um pouco e foram reinseridas na fila), 4, 1, 3, 2, 0. A cada reinser&#231;&#227;o da tarefa na fila, para debugar, pedi para imprimir o n&#243;, com o PID e seu tempo de cpu. E, voil&#225;, &#233; isso que temos:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fREz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fREz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 424w, https://substackcdn.com/image/fetch/$s_!fREz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 848w, https://substackcdn.com/image/fetch/$s_!fREz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 1272w, https://substackcdn.com/image/fetch/$s_!fREz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fREz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png" width="733" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18747,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fREz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 424w, https://substackcdn.com/image/fetch/$s_!fREz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 848w, https://substackcdn.com/image/fetch/$s_!fREz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 1272w, https://substackcdn.com/image/fetch/$s_!fREz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8c7cf6a-c587-45f3-945c-e01d3eaea862_733x480.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Perfeito. Depois disso, fiquei ajustando o valor do MHZ e cronometrando a execu&#231;&#227;o. Como &#233; esperado que t1 execute por 10 segundos, cheguei no valor de 85 MHZ para o <em>Bochs</em>.</p><p>Executando o mesmo c&#243;digo no QEMU, com esse mesmo valor de 85 MHZ, o resultado em termos de valores apresentados s&#227;o muito pr&#243;ximos no quesito ordem de grandeza, confira:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SKg1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SKg1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 424w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 848w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 1272w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SKg1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png" width="719" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:719,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17002,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SKg1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 424w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 848w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 1272w, https://substackcdn.com/image/fetch/$s_!SKg1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d190a72-1541-4a6c-b11b-bad74896cac6_719x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Mas a execu&#231;&#227;o &#233; quase imediata, t1 n&#227;o leva 10 segundos. Tentei alterar o MHZ e cronometrar, mas a tarefa foi infrut&#237;fera. Al&#233;m de n&#227;o conseguir chegar a um valor fact&#237;vel, por algum motivo a ordem das tarefas foi alterada, o que n&#227;o faz sentido. Parece que para o QEMU, ainda falta configura&#231;&#245;es que eu ainda n&#227;o estou ciente. Faz parte, n&#227;o d&#225; pra ganhar todas.</p><p>Como de praxe, o c&#243;digo para esta parte do nosso trabalho est&#225; no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v7">github</a>.</p><h1>No fringir dos ovos&#8230;</h1><p>A gente acabou esse post com mais perguntas do que respostas. Mas &#233; assim que a gente aprende no fim das contas. Se voc&#234; n&#227;o acredita no tamanho da encrenca dessa instru&#231;&#227;o <code>rdtsc</code>, veja <a href="https://www.suse.com/c/cpu-isolation-nohz_full-troubleshooting-tsc-clocksource-by-suse-labs-part-6/">essa galera do SUSE analisando isolamento de CPU no kernel do Linux</a>.</p><p>Mas chega de <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>! Nos pr&#243;ximos posts vamos come&#231;ar o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project3/p3.html">P3</a> e nosso kernel preemptivo! Minha esperan&#231;a &#233; que usando o <a href="https://wiki.osdev.org/Programmable_Interval_Timer">PIT</a> n&#243;s consigamos detectar a velocidade da CPU, talvez usando o <a href="https://en.wikipedia.org/wiki/High_Precision_Event_Timer">HPET</a>. Mas n&#227;o conte com isso, n&#227;o prometo nada :D</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/fake-userland?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/fake-userland?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/prontos-para-serem-interrompidos?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Eu possuo o c&#243;digo original. Contudo, esse c&#243;digo foi feito pela universidade de Princeton, sem permiss&#227;o de distribui&#231;&#227;o. N&#227;o tenho permiss&#227;o para apresentar o c&#243;digo aqui, eles s&#227;o bem rigorosos com plagiarismo. A <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/">p&#225;gina do projeto tem alguns contatos</a>, voc&#234; pode tentar a sorte se quiser obter tal c&#243;digo por vias regulares.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Fake Userland]]></title><description><![CDATA[D&#225; pra ter Userland sem User Mode? D&#225; sim, se o conceito for amplo]]></description><link>https://blog.rodrigobranco.net/p/fake-userland</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/fake-userland</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Mon, 13 Jan 2025 20:22:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!OH4c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OH4c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OH4c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 424w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 848w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OH4c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg" width="474" height="455" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:455,&quot;width&quot;:474,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Are you running in kernel mode? Because you have unrestricted access to ...&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Are you running in kernel mode? Because you have unrestricted access to ..." title="Are you running in kernel mode? Because you have unrestricted access to ..." srcset="https://substackcdn.com/image/fetch/$s_!OH4c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 424w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 848w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!OH4c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5109875-5078-4b06-a7ad-898d22a24018_474x455.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: http://www.quickmeme.com/meme/3sn8cu</figcaption></figure></div><p>Esse <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a> n&#227;o acaba, hein? Enquanto no <a href="https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=false">&#250;ltimo post</a> tratamos de primitivas de sincroniza&#231;&#227;o para as threads, agora vamos adentrar em uma &#225;rea que praticamente todos n&#243;s lidamos diariamente: Processos e Modo Usu&#225;rio.</p><p>Quer dizer, mais ou menos. Fazer isso de modo completo exigiria interrup&#231;&#245;es, pagina&#231;&#227;o e mudan&#231;a de permiss&#245;es do processador, e n&#227;o temos nenhuma das duas ainda. N&#227;o por neglig&#234;ncia ou desleixo, uma parte disso ser&#225; feita no <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project3/p3.html">pr&#243;ximo trabalho</a>. Mas se n&#227;o temos nada disso, como podemos falar em Modo Usu&#225;rio?</p><p>Vamos ver o que &#233; pedido no <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a> sobre isso:</p><div class="pullquote"><p>In future projects, processes will have their own protected address spaces and run in a less privileged protection ring than the kernel. For now, however, there are only slight differences between threads and processes. &#8230; Moreover, process code is not linked with the kernel, thus the need for the single entry-point mechanism (see how syslib.S:kernel_entry is called).</p></div><p>Ent&#227;o, para esse trabalho, um processo n&#227;o &#233; muito diferente de uma thread. O processo ser&#225; compilado de forma &#8220;aut&#244;noma&#8221;. N&#227;o temos nada de interrup&#231;&#245;es, ent&#227;o n&#227;o temos o conceito de carregar o execut&#225;vel do disco. O que vamos fazer &#233; definir os endere&#231;os de <em>entrypoint </em>dos processos, e alterar o utilit&#225;rio <code>createimage </code>para &#8220;col&#225;-los&#8221; na imagem do kernel.</p><p>A beleza da coisa &#233; que, tanto na ida quanto na volta, a &#250;nica informa&#231;&#227;o que o kernel tem do execut&#225;vel do processo &#233; o seu <em>entrypoint</em>. E de forma similar, o processo s&#243; conhece um ponto de entrada para o kernel, que no trabalho eles chamaram de chamada de sistema.</p><p>Nesse trabalho, no momento, temos as quatro threads do post anterior e adicionaremos dois processos. O layout da mem&#243;ria ficar&#225; assim:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GGun!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GGun!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 424w, https://substackcdn.com/image/fetch/$s_!GGun!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 848w, https://substackcdn.com/image/fetch/$s_!GGun!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 1272w, https://substackcdn.com/image/fetch/$s_!GGun!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GGun!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png" width="519" height="649" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:649,&quot;width&quot;:519,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61256,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GGun!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 424w, https://substackcdn.com/image/fetch/$s_!GGun!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 848w, https://substackcdn.com/image/fetch/$s_!GGun!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 1272w, https://substackcdn.com/image/fetch/$s_!GGun!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c4ad4bd-1419-41f4-96ea-4fce1cce4e3e_519x649.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><p>O <code>createimage </code>espera receber agora os execut&#225;veis do <code>bootloader</code>, <code>kernel </code>e processos, ordenados pelo <code>entrypoint</code>, conforme imagem acima. A imagem &#233; ent&#227;o muito maior do que o c&#243;digo efetivo; isso porque o <code>createimage </code>inserir&#225; <em>padding </em>do fim do kernel at&#233; o in&#237;cio do processo 1, do fim do processo 1 at&#233; o in&#237;cio do processo 2 e assim por diante.</p><p>O createimage acabou ficando mais simples, j&#225; que ele corre o argumento do argv lendo o ELF e juntando tudo. Segue um trecho do arquivo alterado, e se quiser ver completo, visite meu <a href="https://github.com/rodrigogbranco/boring-os/blob/p2-v6/src/createimage.cpp">github</a>:</p><pre><code>...

int main(int argc, char *argv[]) {
  bool extended = false;
  std::ostringstream output_string;
  std::vector&lt;u_int8_t&gt; bytearray;
  int image_counter = 0;
  for (int c = 1; c &lt; argc; c++) {
    std::string arg = std::string(argv[c]);
    if (arg.compare("--extended") == 0) {
      extended = true;
    } else {
      std::ifstream exec_if(arg, std::ios::binary);
      if (exec_if.fail()) {
        std::cerr &lt;&lt; "Error: Can't open ELF file: " &lt;&lt; arg &lt;&lt; std::endl;
        return 1;
      }

      std::vector&lt;Elf32_Phdr&gt; exec_hs = read_exec_file(exec_if);
      extract_segments(arg, exec_hs, exec_if, output_string, bytearray);

      exec_if.close();
    }
  }

...</code></pre><p>Depois, escrevemos os processos. Segue o <code>process1.cpp</code>:</p><pre><code>#include "include/syslib.h"
#include "include/util.h"

class Test {

public:
  int x;
  Test() : x{15} {};
};

Test y;

int main() {
  set_display_position(20, 0);
  Test t;
  printk("Hello World! t.x %d - ", t.x);
  printk("Hello World! y.x %d - ", y.x);
  t.x = t.x + 100 + y.x;
  printk("Hello World! t.x %d\n", t.x);
  printk("process1 is yielding\n");
  yield();
  printk("process1 woke up and is exiting...\n");
  return 0;
}</code></pre><p>E o <code>process2.cpp</code>:</p><pre><code>#include "include/syslib.h"
#include "include/util.h"

int main() {
  set_display_position(23, 0);
  printk("process2 ");
  int i = 0;
  while (i++ &lt; 15000) {
    set_display_position(23, 9);
    printk("%d", i);
    yield();
  }
  printk("\nprocess2 finished!");
  return 0;
}</code></pre><p>Se voc&#234; &#233; perspicaz (e voc&#234; &#233;, e eu tamb&#233;m, como diria o Cortella), percebeu duas coisas nos c&#243;digos acima: 1) usamos a fun&#231;&#227;o <code>main</code> como fun&#231;&#227;o principal; e 2) h&#225; a invoca&#231;&#227;o da <em>syscall </em><code>yield</code>, mas n&#227;o da <code>exit</code>. Pode isso, Arnaldo?</p><p>Pois &#233;, isso n&#227;o est&#225; no P2, mas como estou usando C++ em tudo, me perguntei se conseguiria usar classes, ver se os construtores est&#227;o funcionando etc. Obviamente, quando comecei a fazer percebi que n&#227;o estavam :D mas consegui preparar o c&#243;digo at&#233; que isso fosse vi&#225;vel. &#8220;E como voc&#234; fez isso?&#8221;, voc&#234; me pergunta. &#211;tima pergunta, ali&#225;s.</p><p>Bom, na real n&#227;o &#233; muito diferente de como fizemos no kernel. Temos que envolver os c&#243;digos objetos dos processos nos nossos velhos conhecidos <code>crti.o crtbeg.o &lt;OBJETO&gt; crtend.o crtn.o</code>. Assim conseguimos invocar as fun&#231;&#245;es <code>_init </code>e <code>_fini</code>, que, voc&#234; j&#225; sabe, invoca os construtores e destrutores. Mas quem invoca essas fun&#231;&#245;es?</p><p>Ah, essa &#233; a beleza da coisa. Enquanto, no caso do kernel, nosso pr&#243;prio kernel &#201; o entry point e deve chamar tais fun&#231;&#245;es, agora cada processo deve ter um processo de inicializa&#231;&#227;o, mas que ainda assim, seja transparente para ele, como &#233; nos c&#243;digos acima.</p><p>E com isso, criei o crt0.cpp:</p><pre><code>#include "include/syslib.h"
#include "include/util.h"

extern int main();

extern "C" void _start() {
  _init();
  main();
  _fini();
  exit();
}</code></pre><p>Voc&#234; viu a beleza da coisa? Voc&#234; percebe como a natureza &#233; maravilhosa? Quando Deus desenhou o processador, ele estava namorando (j&#225; no caso do x86, ele estava de ressaca com certeza, mas isso n&#227;o vem ao caso). Esse &#233; o nosso verdadeiro <em>entrypoint</em>, chama o construtor, chama a <code>main </code>(fun&#231;&#227;o externa &#224; unidade de compila&#231;&#227;o <code>crt0.cpp</code>, afinal, a main est&#225; nos arquivos <code>process1.cpp</code> e <code>process2.cpp</code>). Ele finaliza executando a lista de destrutores na fun&#231;&#227;o <code>_fini</code>, e por fim, chama a <em>syscall </em><code>exit</code>. Perfeito!</p><p>Para voc&#234; entender como isso &#233; montado no <code>Makefile</code>, veja abaixo um exemplo para o <code>process1.cpp</code>. &#201; igual para o <code>process2.cpp</code> e demais processos que venham a surgir.</p><pre><code>...
UOBJS:=syslib.o util.o screen.o

CRTI_OBJ=crti.o
CRTBEGIN_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtend.o)
CRTN_OBJ=crtn.o

...
UOBJ_LINK_LIST_BEG:=crt0.o  $(CRTI_OBJ) $(CRTBEGIN_OBJ) 
UOBJ_LINK_LIST_END:=$(UOBJS) $(CRTEND_OBJ) $(CRTN_OBJ)

...

process1: $(UOBJ_LINK_LIST_BEG) process1.o $(UOBJ_LINK_LIST_END)
&#9;cd $(OUTPUTDIR) &amp;&amp; ld -O2 -g -m elf_i386 -T../linker.ld -Ttext 0x10000 -z noexecstack -o $@ $(UOBJ_LINK_LIST_BEG) process1.o $(UOBJ_LINK_LIST_END)</code></pre><p>Usamos o mesmo arquivo do linker do kernel (<code>-T../linker.ld</code>), definimos o entrypoint do processo (<code>-Ttext 0x10000</code>), e envolvemos o c&#243;digo objeto do processo com os outros c&#243;digos objetos <code>$(UOBJ_LINK_LIST_BEG) process1.o $(UOBJ_LINK_LIST_END)</code>. Ao executar o comando make, essa linha resulta em:</p><pre><code>cd build &amp;&amp; ld -O2 -g -m elf_i386 -T../linker.ld -Ttext 0x10000 -z noexecstack -o process1 crt0.o  crti.o /usr/lib/gcc/x86_64-linux-gnu/11/32/crtbegin.o  process1.o syslib.o util.o screen.o /usr/lib/gcc/x86_64-linux-gnu/11/32/crtend.o crtn.o</code></pre><p>E os <code>UOBJS</code>? Bom, util.o e screen.o s&#227;o exatamente os mesmos do kernel, eles escrevem no endere&#231;o 0xB8000, ou seja, a mem&#243;ria de v&#237;deo. Mas tive que alterar e voltar a posi&#231;&#227;o do cursor e cores para vari&#225;veis globais no arquivo screen.o. Isso porque antes eu tinha colocado no PCB (cada thread/processo teria sua pr&#243;pria posi&#231;&#227;o e cores), mas o processo n&#227;o tem informa&#231;&#227;o nenhuma do kernel, e isso inclui o PCB&#8230; Precisei voltar a como estava. O screen.cpp agora est&#225; assim:</p><pre><code>#include "include/screen.h"

static DisplayChar *video_memory = (DisplayChar *)SCREEN_ADDR;

static int display_position = 0;
static char current_color = (GRAY &amp; 0x0f) | (BLACK &lt;&lt; 4);
...</code></pre><p>Mas h&#225; uma consequ&#234;ncia nisso. No c&#243;digo do kernel, h&#225; um <code>screen.o</code> ligado. Mas agora h&#225; um <code>screen.o</code> ligado ao <code>process1.o</code> e outro ao <code>process2.o</code>. Significa que as <em>threads </em>do <em>kernel </em>compartilham essas vari&#225;veis globais, mas cada processo tem suas pr&#243;prias vari&#225;veis.</p><p>E o que tem em syslib.cpp? Vejamos:</p><pre><code>#define SYSCALL_YIELD 0
#define SYSCALL_EXIT 1

#include "include/util.h"

void (**kernel_entry_point)(int) = (void (**)(int))0x00F00;

void yield() { (**kernel_entry_point)(SYSCALL_YIELD); }

void exit() { (**kernel_entry_point)(SYSCALL_EXIT); }</code></pre><p>MEU DEUS QUE C&#211;DIGO PROFANO &#201; ESSE? Voc&#234; &#233; muito previs&#237;vel, se acalme que eu j&#225; explico. Vamos ver o que o P2 fala sobre syscalls:</p><div class="pullquote"><p>This project uses a dispatch mechanism to overcome the difficulty of processes not knowing the addresses of do_yield() and do_exit(). kernel.h defines a spot in memory called ENTRY_POINT at which _start() writes the address of the function label kernel_entry (in entry.S) at run-time. When a process calls yield() or exit() (in syslib.S), SYSCALL(i) (in the same file) gets called with an argument that represents which system call the caller wants (yield or exit), similar to how a number was stored in %ah before initiating a BIOS interrupt. SYSCALL(i) in turn calls kernel_entry, whose address was saved at ENTRY_POINT. kernel_entry saves the process's context to its PCB and then transfers control to either of the previously "unreachable" do_yield() or do_exit() functions. Like threads, something must restore the processes' context after it is chosen to run again by scheduler.</p></div><p>Lembre-se da imagem acima:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gW1C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gW1C!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 424w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 848w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 1272w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gW1C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png" width="607" height="228" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:228,&quot;width&quot;:607,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19017,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gW1C!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 424w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 848w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 1272w, https://substackcdn.com/image/fetch/$s_!gW1C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3336f2d5-73e5-4b63-950f-8f3a33c159ae_607x228.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><p>A &#250;nica coisa que os processos sabem sobre a mem&#243;ria &#233; isso ai, o endere&#231;o do <em>entrypoint </em>para o <em>kernel</em>. Mas se voc&#234; &#233; esperto (e voc&#234; &#233;, e eu tamb&#233;m), sabe que quando o <code>_start</code> do <em>kernel </em>&#233; invocado, n&#227;o tem nada &#250;til nesse endere&#231;o. Afinal, o <code>bootloader</code> joga o <code>kernel </code>a partir do endere&#231;o <code>0x1000</code>, que &#233; maior que <code>0xf00</code>. Acontece que a pr&#243;pria _start acessa o endere&#231;o <code>0xf00</code> e coloca um outro endere&#231;o nessa mem&#243;ria, que &#233; o endere&#231;o da fun&#231;&#227;o kernel_entry!</p><pre><code>...
#define USER_ENTRY_POINT 0x00F00
...

extern "C" void _start() {
...
  *(uint32_t *)(USER_ENTRY_POINT) = (uint32_t)&amp;kernel_entry;
...</code></pre><p>Ou seja, a posi&#231;&#227;o <code>0x00f00</code> &#233; um ponteiro para um ponteiro de fun&#231;&#227;o, e a fun&#231;&#227;o &#233; a <code>kernel_entry</code>. Por isso, os dois <code>**</code> na declara&#231;&#227;o:</p><pre><code>void (**kernel_entry_point)(int) = (void (**)(int))0x00F00;</code></pre><p>Se voc&#234; &#233; meio burro (e voc&#234; &#233;, e eu tamb&#233;m), talvez a imagem abaixo facilite o entendimento:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sRAD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sRAD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 424w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 848w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 1272w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sRAD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png" width="752" height="230" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:230,&quot;width&quot;:752,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33277,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sRAD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 424w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 848w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 1272w, https://substackcdn.com/image/fetch/$s_!sRAD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c39e1a2-e1ed-4c55-9717-95b790c158d4_752x230.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Depois n&#243;s vemos certinho como <code>(**kernel_entry_point)(SYSCALL_YIELD)</code> e <code>(**kernel_entry_point)(SYSCALL_EXIT)</code> s&#227;o executadas. Antes disso, vamos ver o que &#233; necess&#225;rio alterar no PCB para comportar a execu&#231;&#227;o de processos.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cG38!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cG38!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 424w, https://substackcdn.com/image/fetch/$s_!cG38!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 848w, https://substackcdn.com/image/fetch/$s_!cG38!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 1272w, https://substackcdn.com/image/fetch/$s_!cG38!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cG38!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png" width="921" height="408" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21bec616-da6f-432c-9332-817dc8534a53_921x408.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:408,&quot;width&quot;:921,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81341,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cG38!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 424w, https://substackcdn.com/image/fetch/$s_!cG38!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 848w, https://substackcdn.com/image/fetch/$s_!cG38!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 1272w, https://substackcdn.com/image/fetch/$s_!cG38!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21bec616-da6f-432c-9332-817dc8534a53_921x408.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><p>E:</p><div class="pullquote"><p>kernel_entry saves the process's context to its PCB and then transfers control to either of the previously "unreachable" do_yield() or do_exit() functions.</p></div><p>Ent&#227;o, n&#243;s salv&#225;vamos o contexto na scheduler_entry para as threads, e agora precisamos salvar logo ap&#243;s entrar em kernel_entry tamb&#233;m. Apesar que isso n&#227;o &#233; obrigat&#243;rio NESTE trabalho, porque:</p><div class="pullquote"><p>Threads only run in one context: the kernel. Processes have two contexts: user and kernel. You have an option in this project to decide how you want to deal with this. One option is to make room in your PCB for both contexts. The other option is to only leave room for one context and lose any kernel context for each process after crossing the user-kernel boundary. This is ok because there is not state that needs to be kept within the kernel for processes. However, if you choose to explicity save both, it is ok to "waste" space in the PCB for threads that won't use the user context area.</p></div><p>Mas estou construindo este kernel baseado em um trabalho escolar. No pr&#243;ximo trabalho, quando interrup&#231;&#245;es de software estiverem habilitadas, uma chamada do sistema do usu&#225;rio poder&#225; ser interrompida. Ent&#227;o, vai por mim, &#233; melhor j&#225; deixar isso pronto agora.</p><p>N&#227;o h&#225; grandes altera&#231;&#245;es no PCB, a gente reserva espa&#231;o para salvar o contexto do usu&#225;rio:</p><pre><code>...

class PCB {
  uint32_t kregs[9]; // EDI, ESI, EBP, original ESP, EBX, EDX, ECX, EAX, EFLAGS
                     // (KERNEL MODE)
  uint32_t uregs[9]; // EDI, ESI, EBP, original ESP, EBX, EDX, ECX, EAX, EFLAGS
                     // (USER MODE)
...</code></pre><p>E agora, a parte delicada do trabalho, feito em <em>assembly</em>. Vamos adentrar no covil da <code>kernel_entry</code>. E, de novo, depois de pronto, parece f&#225;cil, mas perdi um temp&#227;o tentando depurar um problema de estouro de pilha. Se a pilha n&#227;o for restaurada corretamente entre as chamadas e salvamento de contexto, qualquer la&#231;o de 10, 15 mil itera&#231;&#245;es que chamem troca de contexto, usando <code>yield </code>por exemplo, com pilhas de tamanho 4KB, o estouro de pilha vem e voc&#234; nem percebe.</p><p>O fluxo de chamadas segue ent&#227;o a imagem abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f8AG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f8AG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 424w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 848w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 1272w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f8AG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png" width="767" height="187" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:187,&quot;width&quot;:767,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22254,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f8AG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 424w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 848w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 1272w, https://substackcdn.com/image/fetch/$s_!f8AG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb20d386-2b16-4cd7-ba65-378cfa975365_767x187.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Enquanto as threads de <em>kernel </em>tem acesso direto a fun&#231;&#227;o <code>do_yield</code>, o processo precisa fazer a chamada de sistema yield, que invoca a <code>kernel_entry</code>, e esta &#233; respons&#225;vel por invocar as fun&#231;&#245;es de kernel, no caso, a <code>do_yield</code>.</p><p>Mas e agora, como se faz para salvar o contexto e restaurar o pr&#243;ximo? Aqui as coisas come&#231;am a ficar interessantes. Para as threads de <em>kernel</em>, nada &#233; alterado, isso j&#225; est&#225; funcionando. Para os processo ao entrar na fun&#231;&#227;o <code>kernel_entry</code>, estamos no contexto do usu&#225;rio, com a pilha do usu&#225;rio. Devemos nesse momento chavear para as pilhas (e registradores) de <em>kernel </em>(em nome desse processo. N&#227;o das outras tarefas do <em>kernel</em>). Nisso, a chamada de sistema chamar&#225; ou a <code>do_yield </code>ou <code>do_exit</code>. Essas fun&#231;&#245;es, voc&#234; j&#225; viu: elas invocar&#227;o a <code>scheduler_entry</code>, e essa fun&#231;&#227;o salva o contexto de <em>kernel </em>do processo. Nisso, o escalonador escolhe outra tarefa, restaurando seu contexto de <em>kernel</em>. Caso essa tarefa seja um processo, significa que ele obrigatoriamente chegou at&#233; aqui via <code>kernel_entry</code>. Portanto, salvamos novamente o contexto de <em>kernel </em>do processo, e restauramos o contexto de usu&#225;rio, e retornamos da chamada de sistema. Ufa!</p><p>Confuso? Talvez uma imagem ajude a ilustrar melhor. Essa parte &#233; enjoada mesmo, leve seu tempo para entender o que est&#225; acontecendo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9p6g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9p6g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 424w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 848w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 1272w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9p6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png" width="1288" height="572" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:572,&quot;width&quot;:1288,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:145657,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9p6g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 424w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 848w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 1272w, https://substackcdn.com/image/fetch/$s_!9p6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a559359-0627-4423-b2f8-6c7a1949e8d1_1288x572.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>O fluxo preto &#233; de quando um processo de executando, enquanto o laranja &#233; de uma <em>thread </em>de <em>kernel</em>. Ao passar pelo escalonador, uma nova tarefa &#233; escolhida, e pode ser uma <em>thread </em>o <em>kernel </em>ou um processo, seguindo pela mesma ideia das cores. O que est&#225; em vermelho s&#227;o fun&#231;&#245;es/etapas que ocorrem dentro do kernel.</p><p>Antes de apresentar a tenebrosa <code>kernel_entry</code>, vamos refletir sobre uma coisa: temos um ponto de entrada &#250;nico, mas diversos servi&#231;os (<code>yield</code>, <code>exit </code>e o que mais surgir). Ao observar novamente o arquivo <code>syslib.cpp</code>:</p><pre><code>void yield() { (**kernel_entry_point)(SYSCALL_YIELD); }

void exit() { (**kernel_entry_point)(SYSCALL_EXIT); }</code></pre><p>Perceba que &#233; a mesma fun&#231;&#227;o, o que muda &#233; o argumento dela, o que faz sentido pelo design que estamos analisando. Dentro da fun&#231;&#227;o <code>kernel_entry</code>, ent&#227;o, ele deve &#8220;selecionar&#8221; a fun&#231;&#227;o correta de acordo com o par&#226;metro informado pelo chamador. Se tratarmos esse &#8220;par&#226;metro&#8221; como um &#237;ndice em um vetor de ponteiros para fun&#231;&#227;o, nossos problemas est&#227;o resolvidos (por enquanto). Assim, eu criei o seguinte vetor no arquivo scheduler.cpp:</p><pre><code>void (*syscall_operations[])() = {&amp;do_yield, &amp;do_exit};</code></pre><p>Pronto, temos um <em>array </em>de ponteiros de fun&#231;&#227;o, com as fun&#231;&#245;es que &#8220;servimos&#8221; ao processo. Se o processo chamar o <code>kernel_entry </code>com o valor 0, ele invocar&#225; a <code>do_yield</code>. Se for 1, ser&#225; <code>do_exit</code>, e assim por diante.</p><p>Ap&#243;s muito enrolar, vamos olhar a <code>kernel_entry</code>, que est&#225; no arquivo <code>entry.asm</code>. Como eu fiz algumas mudan&#231;as na <code>scheduler_entry </code>para parametriz&#225;-la melhor, vou mostrar o arquivo inteiro.</p><pre><code>global scheduler_entry, kernel_entry
extern current_task, scheduler, syscall_operations, returning_kernel_entry

%define ESP_OFFSET (3*4)
%define K_REGS_LIMIT (9*4)
%define U_REGS_LIMIT (18*4)
%define ESP_OFFSET_FROM_LIMIT (6*4)

syscall_op dd 0
old_esp dd 0

kernel_entry:
    push ebp
    mov ebp, esp
    mov esp, [current_task]
    lea esp, [esp + U_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp

    mov ebx, [ebp+8]
    mov [syscall_op], ebx

    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]

    mov ebx, [syscall_op]
    call [syscall_operations + 4*ebx]

returning_kernel_entry:  
    mov [old_esp], esp
    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov ebx, [old_esp]
    mov [esp + ESP_OFFSET], ebx  

    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]    
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]

    pop ebp
    ret


scheduler_entry:
    push ebp
    mov ebp, esp
    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp
    mov esp, ebp
    call scheduler
    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]
    pop ebp
    ret</code></pre><p>O segredo todo, assim como foi com a <code>scheduler_entry</code>, &#233; posicionar o registrador <code>esp </code>na posi&#231;&#227;o certa do PCB para poder fazer os <code>pushs </code>e <code>pops </code>do lugar certo. A fun&#231;&#227;o come&#231;a salvando o contexto de usu&#225;rio:</p><pre><code>    push ebp
    mov ebp, esp
    mov esp, [current_task]
    lea esp, [esp + U_REGS_LIMIT]
    pushfd
    pushad
    mov [esp + ESP_OFFSET], ebp</code></pre><p>Depois, como vamos chaver o contexto, precisamos salvar o par&#226;metro que passaram ao chamar a kernel_entry. Lembra-se que a chamamos passando um argumento, que &#233; o servi&#231;o a ser executado? Ent&#227;o. Esse par&#226;metro est&#225; na pilha do contexto do usu&#225;rio, e como esse contexto vai mudar, j&#225; que vamos chaver para o contexto de kernel desse processo, precisamos salv&#225;-lo antes:</p><pre><code>    mov ebx, [ebp+8]
    mov [syscall_op], ebx</code></pre><p>Ok, o par&#226;metro foi salvo na vari&#225;vel <code>syscall_op</code>. Agora a gente restaura o contexto de kernel do processo:</p><pre><code>    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]</code></pre><p>Estamos no contexto do kernel do processo. S&#243; falta chamar o servi&#231;o desejado. Basta recuperar o valor de <code>syscall_op</code> e us&#225;-lo como &#237;ndice no <em>array </em><code>syscall_operations</code>:</p><pre><code>    mov ebx, [syscall_op]
    call [syscall_operations + 4*ebx]</code></pre><p>Show de bola! Isso chamar&#225; a <code>do_yield</code> e <code>do_exit</code>, que chamar&#225; a <code>scheduler_entry</code>&#8230; <em>You know the drill</em>. Possivelmente, esse processo ser&#225; posto pra dormir (mas lembre-se que ele est&#225; no contexto de kernel do processo). Quaaaaando esse processo for acordado, ele ir&#225; ir retornando das chamadas, e retornando da <code>do_yield </code>(se fosse do_exit, esse processo n&#227;o retornaria mais, n&#227;o &#233; mesmo? :D ), ele continuar&#225; logo ap&#243;s <code>call [syscall_operations + 4*ebx]</code>. E o que a gente precisa fazer agora?</p><p>Bom, todo o servi&#231;o do contexto de kernel para esse processo foi feito. Agora, a gente salva esse contexto:</p><pre><code>    mov [old_esp], esp
    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]
    pushfd
    pushad
    mov ebx, [old_esp]
    mov [esp + ESP_OFFSET], ebx  </code></pre><p>Perceba que, como precisamos alterar o valor de <code>esp </code>para fazer o procedimento, a gente salva ele provisoriamente em <code>old_esp</code> para salvar o valor correto tamb&#233;m.</p><p>Depois disso, a gente s&#243; restaura o contexto do usu&#225;rio:</p><pre><code>    mov esp, [current_task]
    lea esp, [esp + K_REGS_LIMIT]    
    popad
    popfd
    mov esp, [esp - ESP_OFFSET_FROM_LIMIT]

    pop ebp
    ret</code></pre><p>E ao fim do c&#243;digo acima, ele j&#225; restaura a pilha e retorna para quem chamou <code>yield</code>.</p><p>Pera l&#225; um pouquinho! Voc&#234; acha que me engana? Muito suspeito aquela declara&#231;&#227;o <code>returning_kernel_entry</code> no meio da fun&#231;&#227;o <code>kernel_entry</code>! O que ela faz?</p><p>Ent&#227;o jovem, como sempre eu mostrei o caminho feliz. Mas a vida &#233; uma caixinha de surpresas, n&#227;o &#233; esse algod&#227;o-doce que voc&#234; est&#225; pensando ai n&#227;o! Temos um <em>corner case</em> importante que n&#227;o tratamos ainda: o primeiro escalonamento para execu&#231;&#227;o do processo.</p><p>Pense no seguinte: o PCB do processo est&#225; na fila de tarefas prontas. Quando o processo &#233; escolhido pelo escalonador, quem fez isso foi a <code>scheduler_entry</code>, que invoca o <code>scheduler</code>, lembra?</p><p>Significa que estamos no contexto de <em>kernel </em>do processo, mas nosso <code>entrypoint </code>est&#225; no contexto de usu&#225;rio! Como pulamos para l&#225;?</p><p>Usamos da boa e velha gambiarra! O que fazemos &#233; enganar o processo, e n&#227;o vamos colocar o <em>entrypoint </em>do processo diretamente para execu&#231;&#227;o, vamos fingir que estamos retornando de uma chamada do sistema, para ele ir restaurando o contexto necess&#225; rerio e acabar no entrypoint do processo mas no contexto de usu&#225;rio! E pra fazer isso &#233; bem f&#225;cil na real (depois que voc&#234; sabe o que fazer), fazemos uma pequena altera&#231;&#227;o no m&#233;todo <code>config </code>da classe <code>PCB</code>:</p><pre><code>void PCB::config(int pcb_index, void (*entry_point)(), uint32_t pid,
                 bool kernel_thread) {
  this-&gt;pid = pid;
  this-&gt;kernel_thread = kernel_thread;
  uint32_t stack = START_STACKS_ADDRESS + 2 * pcb_index * STACK_SIZE;
  if (stack &gt; STACK_MAX) {
    panic("Stack overflow\n");
  }
  this-&gt;kregs[3] = stack - 8;
  this-&gt;kregs[2] = *(uint32_t *)(stack - 8) = stack;
  *(uint32_t *)(stack - 4) =
      kernel_thread ? (uint32_t)entry_point : (uint32_t)&amp;returning_kernel_entry;
...

  if (!kernel_thread) {
    stack += STACK_SIZE;
    if (stack &gt; STACK_MAX) {
      panic("Stack overflow\n");
    }
    this-&gt;uregs[3] = stack - 8;
    this-&gt;uregs[2] = *(uint32_t *)(stack - 8) = stack;
    *(uint32_t *)(stack - 4) = (uint32_t)entry_point;
  }
  this-&gt;status = READY;
}</code></pre><p>Reservamos duas pilhas para o PCB, independente se for uma <em>kernel thread</em> ou processo. Para <em>kernel threads</em>, esse espa&#231;o adicional &#233; desperdi&#231;ado, mas como s&#227;o 9 registradores de 4 bytes, estou ok em desperdi&#231;ar 36 bytes nesse caso.</p><p>Note contudo que fazemos um teste para definir o <em>entrypoint</em>: se for uma <em>thread kernel</em>, nada muda, informamos o <em>entrypoint </em>da thread. Se for um processo, ai informamos o endere&#231;o de <code>returning_kernel_entry</code>. Isso porque quando o <code>scheduler_entry </code>terminar, ele vai fazer um <code>ret </code>para esse endere&#231;o. O que a <code>returning_kernel_entry</code> faz dali pra frente &#233; restaurar o contexto do usu&#225;rio e ele vai retornar. Para onde? Agora sim, para o <code>entry_point </code>do processo.</p><p>Novamente, usamos o funcionamento de pilhas do x86 para que ele fa&#231;a o trabalho sujo todo para n&#243;s. Ardiloso!</p><p>E como ficou o resultado? Olha ai jovem.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;e92986be-6110-4367-a600-74b4cd359c09&quot;,&quot;duration&quot;:null}"></div><p>E como voc&#234; j&#225; sabe, para conferir o c&#243;digo at&#233; esse ponto, visite meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v6">github</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/apanhando-do-rdtsc?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/apanhando-do-rdtsc?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[Dando um tempo com Exclusão Mútua]]></title><description><![CDATA[Vamos desacelerar e ver algo mais leve dessa vez, trabalhando com Locks!]]></description><link>https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Sun, 05 Jan 2025 02:56:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HIdT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HIdT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HIdT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HIdT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:334793,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HIdT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!HIdT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdb71e35-bfe4-47c4-9d17-66b7e6398dcf_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Os textos dessa imagem que a IA gerou ficaram bem esquisitos, mas como eu n&#227;o fa&#231;o melhor que ela&#8230;. :D</figcaption></figure></div><p>Depois do <a href="https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de">post anterior</a>, &#233; hora de dar uma respirada para apaziguar os &#226;nimos (autocr&#237;tica). Do ponto que estamos, acredito que a parte mais f&#225;cil &#233; agora implementar o <em>lock </em>que as threads usar&#227;o, como exigido pelo <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>. Mas afinal, o que &#233; para ser feito? Na <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">p&#225;gina do P2</a> &#233; solicitado:</p><div class="pullquote"><p><strong>Mutual exclusion:</strong> What's your plan for implementing mutual exclusion?</p></div><p>Certo, antes de entrar nos meandros, vale fazer uma breve recapitula&#231;&#227;o. Longe de querer que esse post seja uma refer&#234;ncia em sistemas concorrentes, ele n&#227;o &#233;, h&#225; milhares de outros materiais melhores para isso. Mas para garantirmos estar na mesma p&#225;gina nessa discuss&#227;o, &#233; v&#225;lido estabelecer alguns pontos.</p><p>Temos v&#225;rias tarefas concorrentes executando no mesmo processador e, por enquanto, acessando a mesma &#225;rea de endere&#231;amento na mem&#243;ria. Em especial as threads de <em>kernel</em>, elas acessam podem acessar as mesmas vari&#225;veis, e devido ao comportamento aleat&#243;rio que as tarefas executam, a ordem das opera&#231;&#245;es pode alterar o resultado.</p><p>Pior, em sistemas verdadeiramente preemptivos (n&#227;o &#233; o nosso caso. AINDA), &#233; poss&#237;vel que uma tarefa seja interrompida bem no momento do acesso a uma &#225;rea importante da mem&#243;ria, mas o dado j&#225; foi lido para o registrador. A outra tarefa pode manipular essa regi&#227;o de mem&#243;ria, e ao retornar para a tarefa anterior, ela est&#225; com um valor desatualizado no registrador e ir&#225; processar informa&#231;&#245;es de forma errada.</p><p>Acredite em mim, fazer depura&#231;&#227;o em sistemas concorrentes &#233; um pesadelo, pois &#233; pouco prov&#225;vel que tenhamos algum controle sobre o escalonamento das tarefas, que &#233; feito pelo Sistema Operacional.</p><p>Mesmo que aqui N&#211;S somos o Sistema Operacional (Yay!), ainda assim &#233; uma tarefa dif&#237;cil, pois em teoria o algoritmo de escalonamento est&#225; certo. O que pode estar errado &#233; a forma como voc&#234; programou suas threads, de forma que elas acessam a mem&#243;ria compartilhada entre elas de forma an&#225;rquica.</p><p>E olha que legal, mesmo estando trabalhando com um <em>kernel </em>n&#227;o preemptivo neste <em>post</em>, ainda assim precisamos de primitiva de sincroniza&#231;&#227;o para podermos for&#231;ar determinada ordem de execu&#231;&#227;o das threads.</p><p>A forma como voc&#234; implementa exclus&#227;o m&#250;tua para evitar condi&#231;&#245;es de corrida no kernel do Linux, por exemplo, dependem de quanto tempo voc&#234; vai passar na regi&#227;o cr&#237;tica. Para curt&#237;ssimos tempos, um <em>spinlock</em> &#233; suficiente. Se voc&#234; levar um tempo consider&#225;vel, talvez seja interessante bloquear a thread e coloc&#225;-la para dormir, at&#233; que o <em>lock</em> seja resolvido.</p><p>Vamos retomar alguns conceitos primeiro. N&#227;o seremos aderentes a conceitos e nomenclaturas cient&#237;ficas, esse n&#227;o &#233; o objetivo. O objetivo aqui &#233; dar uma ideia do problema e como podemos resolver para o nosso caso, e talvez conhecer alguns outros mais.</p><h1>Regi&#227;o Cr&#237;tica</h1><p>A regi&#227;o cr&#237;tica &#233; aquela parte do c&#243;digo ou &#225;rea de mem&#243;ria em que devem ser acessadas exclusivamente, em um determinado tempo, por uma tarefa, e somente por ela. &#201; uma arte definir exatamente as regi&#245;es cr&#237;ticas de um c&#243;digo e sua extens&#227;o, pois se mais de uma tarefa est&#225; tentando acessar a regi&#227;o cr&#237;tica, se ela for longa demais, as outras tarefas v&#227;o ficar esperando.</p><p>No livro <a href="https://www.amazon.com.br/Linux-Kernel-Development-Robert-Love/dp/0672329468">Linux Kernel Development</a>, Robert Love &#233; claro em dizer que voc&#234; deve proteger os dados (&#225;reas de mem&#243;ria compartilhada) e n&#227;o os fluxos de execu&#231;&#227;o, ou seja, seu c&#243;digo. Tenha isso em mente ao projetar as regi&#245;es cr&#237;ticas de seu c&#243;digo</p><h1>Condi&#231;&#227;o de Corrida</h1><p>Se mais de uma thread conseguir acessar uma regi&#227;o cr&#237;tica, elas estar&#227;o em condi&#231;&#227;o de corrida. Desse ponto em diante, &#233; dif&#237;cil prever o comportamento das tarefas, afinal, elas n&#227;o deveriam conseguir acessar a regi&#227;o cr&#237;tica ao mesmo tempo. &#201; seguro dizer que se duas tarefas est&#227;o em condi&#231;&#227;o de corrida, o comportamento delas ser&#225; indeterminado. Fuja de condi&#231;&#245;es de corrida como o diabo foge da cruz!</p><h1>Exclus&#227;o M&#250;tua</h1><p>Exclus&#227;o m&#250;tua s&#227;o as premissas e propriedades que voc&#234; deve garantir para que duas tarefas n&#227;o entrem em condi&#231;&#227;o de corrida em uma regi&#227;o cr&#237;tica. Para quem &#233; de banco de dados, lembrar&#225; do ACID e de serializa&#231;&#227;o de transa&#231;&#245;es conflitantes, exatamente para evitar que elas rodem ao mesmo tempo.</p><h1>E eu com isso?</h1><p>Como dito anteriormente, h&#225; algumas formas de se implementar exclus&#227;o m&#250;tua, e em geral isso depende de suporte do hardware. </p><h2>Desabilitar interrup&#231;&#245;es</h2><p>Para sistemas preemptivos que s&#227;o interrompidos pelo <a href="https://en.wikipedia.org/wiki/Programmable_interval_timer">PIT</a> (<em>Programmable interval timer</em>), o c&#243;digo abaixo pode funcionar (cont&#233;m pegadinha):</p><pre><code>    cli
    mov eax, [critical_region]
    inc eax
    mov [critical_region], eax
    sti</code></pre><p>O c&#243;digo acima recupera um valor da mem&#243;ria, incrementa-o e devolve para a mem&#243;ria. Ao desabilitar as interrup&#231;&#245;es (e reabilitar logo em seguida), garantimos que o <em>PIT</em> n&#227;o nos incomodar&#225; e esse c&#243;digo executar&#225; completamente nesse processador&#8230;</p><p>&#8230; nesse processador &#233; importante, porque esse &#233; justamente o problema desse c&#243;digo. As instru&#231;&#245;es <code>cli</code>/<code>sti </code>s&#243; desabilitam as interrup&#231;&#245;es para o processador em que esse c&#243;digo est&#225; executando. Nada impede que outro processador acesse <code>[critical_region]</code> nesse momento, e ai sua exclus&#227;o m&#250;tua n&#227;o &#233; garantida.</p><p>Claro que h&#225; casos de uso disso. H&#225; estruturas de dados que notadamente s&#227;o acess&#237;veis apenas por um processador e nesses casos, essa solu&#231;&#227;o funciona bem.</p><p>No nosso caso, sinto dizer, isso n&#227;o vai funcionar. Estamos usando apenas um processador, ok, mas as interrup&#231;&#245;es j&#225; est&#227;o desabilitadas, e n&#227;o as reativaremos enquanto n&#227;o instalarmos o ISR (<em>Interruption Service Routine</em>), que s&#243; acontecer&#225; no pr&#243;ximo trabalho. No nosso caso, a tarefa adquire o <em>lock </em>para entrar na regi&#227;o cr&#237;tica e cede o processador no meio do processo. Desabilitar interrup&#231;&#245;es em um kernel n&#227;o preemptivo n&#227;o muda nada no fim das contas.</p><h2>Opera&#231;&#245;es at&#244;micas</h2><p>Se voc&#234; notou bem, o problema todo do exemplo anterior &#233; porque a opera&#231;&#227;o toda na verdade levou tr&#234;s instru&#231;&#245;es: uma para trazer o dado da mem&#243;ria para o registrador, outra para incrementar o registrador e a &#250;ltima para devolver o dado para a mem&#243;ria. Se houvesse uma forma de fazer tudo isso de uma vez de forma garantida, j&#225; ter&#237;amos meio caminho andado.</p><p>De forma conceitual, h&#225; previs&#227;o de que o hardware forne&#231;a algum tipo de instru&#231;&#227;o <em><a href="https://en.wikipedia.org/wiki/Test-and-set">Test and Set</a></em>. Essa instru&#231;&#227;o deve setar o valor da mem&#243;ria, em geral para o valor 1, e devolve o valor antigo. E como isso &#233; &#250;til para garantir a Exclus&#227;o M&#250;tua, voc&#234; me pergunta? Bom, podemos implementar um <em>Spinlock </em>com isso.</p><h2>Spinlock</h2><p>A util&#237;ssima p&#225;gina do <a href="https://wiki.osdev.org/Synchronization_Primitives">OSDev</a> tem um exemplo bem legal de um Spinlock, que chupinharei (afinal eu estou dando os devidos cr&#233;ditos). L&#225; vai:</p><pre><code>#include &lt;stdatomic.h&gt;

void acquire_mutex(atomic_flag* mutex)
{
&#9;while(atomic_flag_test_and_set(mutex))
&#9;{
&#9;&#9;__builtin_ia32_pause();
&#9;}
}

void release_mutex(atomic_flag* mutex)
{
&#9;atomic_flag_clear(mutex);
}</code></pre><p>E como isso funciona? Bom, partiremos da premissa que o mutex &#233; um valor booleano inicialmente definido como falso.</p><p>A primeira tarefa tentar&#225; adquirir o <em>lock</em>, invocando a fun&#231;&#227;o <code>acquire_mutex</code>. Essa, por sua vez, chama a fun&#231;&#227;o <code>atomic_flag_test_and_set</code>, que define o novo valor de mutex para verdadeiro, e retorna o valor antigo (falso). Com falso, o loop while nem inicia. Pronto, a primeira tarefa &#8220;adquiriu&#8221; o <em>lock</em>.</p><p>As pr&#243;ximas tarefas far&#227;o a mesma coisa. Mas quando eles invocarem a fun&#231;&#227;o <code>atomic_flag_test_and_set</code>, ela novamente ir&#225; definir o mutex para verdadeiro, mas isso &#233; irrelevante. O que importa mesmo &#233; que a fun&#231;&#227;o retorna, atomicamente, o valor definido pela primeira tarefa, que &#233; verdadeiro no caso. Com isso, a condi&#231;&#227;o do la&#231;o <code>while </code>se torna verdadeira, e essa tarefa ficar&#225; rodando no la&#231;o (por isso <em>spinlock</em>. Sacou? Sacou?) at&#233; que a primeira tarefa chame a fun&#231;&#227;o <code>release_mutex</code>, que atomicamente ir&#225; definir o <em>lock </em>como falso. Agora, dentro da condi&#231;&#227;o do la&#231;o <code>while</code>, a segunda tarefa novamente chamar&#225; a fun&#231;&#227;o <code>atomic_flag_test_and_set</code>, que setar&#225; o <code>mutex </code>como verdadeiro (&#233; o que ela est&#225; tentando fazer desde o in&#237;cio!!) mas o valor retornado ser&#225; falso, j&#225; que a primeira tarefa j&#225; liberou o <em>lock</em>.</p><p>Note, contudo, que esse tipo de <em>spinlock </em>n&#227;o garante ordem. Se mais de uma tarefa estiver esperando pelo <em>lock</em>, a primeira escalonada logo ap&#243;s a libera&#231;&#227;o ser&#225; a pr&#243;xima a adquirir o <em>lock</em>, independente da ordem que as tarefas chegaram a esse ponto (estou considerando um kernel preemptivo em que as tarefas podem ser interrompidas em qualquer momento). Em geral, para tarefas que n&#227;o possuem ordem de execu&#231;&#227;o, essa solu&#231;&#227;o &#233; satisfat&#243;ria. Se a ordem &#233; importante, essa solu&#231;&#227;o n&#227;o pode ser usada dessa forma.</p><p>Outra considera&#231;&#227;o &#233; que se a tarefa que estiver bloqueando as outras levar muito tempo para liberar o <em>lock</em>, h&#225; desperd&#237;cio de CPU das tarefas bloqueadas rodando no loop em v&#227;o.</p><p>Para encerrar esse t&#243;pico, na arquitetura x86 n&#227;o temos bem uma instru&#231;&#227;o <em>Test and Set</em>, mas temos uma instru&#231;&#227;o que faz algo parecido atomicamente: a instru&#231;&#227;o <em>xchg</em>. Essa instru&#231;&#227;o troca dois operandos de forma at&#244;mica. Portanto, se um dos operandos for 1 (nosso valor verdadeiro do spinlock), o outro &#233; o valor antigo que deve ser testado. Funciona da mesma forma.</p><p>Para um kernel n&#227;o-preemptivo, contudo, n&#227;o podemos usar essa solu&#231;&#227;o. Afinal, ningu&#233;m vai tirar a tarefa de execu&#231;&#227;o se ela mesmo n&#227;o o fizer usando usando <em>yield</em>. Vamos ent&#227;o para a pr&#243;xima solu&#231;&#227;o, que &#233; a usada no nosso kernel.</p><h2>Filas de tarefas bloqueadas</h2><p>O melhor exemplo &#233; a pr&#225;tica, ent&#227;o vamos aprender fazendo. O primeiro passo &#233; adicionar um estado dentre os poss&#237;veis por nosso <code>PCB</code>: <code>BLOCKED</code>. Na classe PCB, adicionamos o m&#233;todo <code>block </code>abaixo:</p><pre><code>...
enum TASK_STATUS { READY, RUNNING, EXITED, BLOCKED };

class PCB {
...
  void block() { status = BLOCKED; };
...</code></pre><p>Espero que o c&#243;digo acima seja autoexplicativo. Agora, adicionamos a nova classe no arquivo <code>kernel.h</code>:</p><pre><code>...
#include &lt;atomic&gt;
...

class Lock {
  std::atomic_bool mutex{false};
  Datastructure::QueueNode&lt;PCB&gt; *blocked{nullptr};

public:
  void lock_acquire();
  void lock_release();
  void block(Datastructure::QueueNode&lt;PCB&gt; *task) {
    ...
    if (blocked == nullptr) {
      blocked = task;
    } else {
      blocked-&gt;insert(task);
    }
  }
  Datastructure::QueueNode&lt;PCB&gt; *unblock() {
    Datastructure::QueueNode&lt;PCB&gt; *tmp = blocked;
    ...
    this-&gt;blocked = blocked-&gt;remove(tmp);
    return tmp;
  }
};</code></pre><p>Aqui, demos aquela roubada b&#225;sica e usamos o tipo <code>atomic_bool </code>do <em>namespace </em><code>std</code>, padr&#227;o do compilador. Como a pr&#243;pria p&#225;gina do OSDev informa:</p><div class="pullquote"><p>If you are using GCC or Clang, you have access to <a href="https://en.cppreference.com/w/c/thread#Atomic_operations">the freestanding C11 header stdatomic.h</a>, which can be used to implement a spinlock.</p></div><p>Ent&#227;o maravilha, estamos em um ambiente <em>freestanding </em>(sem <code>stdlib</code>), e ainda assim nosso c&#243;digo vai funcionar. Quando chegar o ponto exato, eu mostro o c&#243;digo <em>assembly </em>gerado pelo compilador, matando assim a cobra e mostrando a cobra, como diria alguns. N&#227;o achei que mostrar o pau fosse apropriado, se contenha.</p><p>Note tamb&#233;m que temos uma fila de <code>PCB </code>chamada <code>blocked</code>. Espero que o nome seja explicativo o suficiente, &#233; isso mesmo que voc&#234; est&#225; pensando. Quando uma tarefa &#233; bloqueada por n&#227;o obter o <em>lock</em>, ele vem para essa fila aqui.</p><p>Mas que blasf&#234;mia! Quer dizer que o escalonador n&#227;o tem controle sobre os processos bloqueados pelos <em>locks</em>? Quem tem ger&#234;ncia sobre isso. Ent&#227;o, pequeno gafanhoto, &#233; isso ai mesmo. Quem tem controle sobre os processos bloqueados por n&#227;o se obter o <em>lock </em>&#233; a pr&#243;pria classe <code>Lock</code>.</p><p>Os m&#233;todos <code>block </code>e <code>unblock </code>apenas manipulam a fila de tarefas bloqueadas por esse <em>lock</em>, seja inserindo-a na fila ou devolvendo a primeira tarefa &#8220;desbloqueada&#8221;. Note j&#225; que aqui, a ordem de aquisi&#231;&#227;o de <em>locks </em>&#233; preservada. <em>We&#8217;ve halfway there</em>.</p><p>Vamos ver os outros dois m&#233;todos, que est&#227;o no arquivo lock.cpp:</p><pre><code>#include "include/kernel.h"
#include "include/util.h"
#include &lt;atomic&gt;

extern Scheduler sched;

void Lock::lock_acquire() {
  if (this-&gt;mutex.exchange(true)) {
    sched.block(this);
  }
}
...</code></pre><p>Parece simples. A primeira coisa diferente de outros lugares que voc&#234; ver&#225; por ai &#233; que outras solu&#231;&#245;es chamam um m&#233;todo chamado <code>lock_init</code> (o pr&#243;prio <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a> prev&#234; isso, v&#225; l&#225; checar!). No nosso caso, n&#227;o precisamos, afinal estamos usando C++, programa&#231;&#227;o orientada a objetos (COF COF) e, bem, o construtor j&#225; fez isso pra gente:</p><pre><code>std::atomic_bool mutex{false};</code></pre><p>Indo para as fun&#231;&#245;es de aquisi&#231;&#227;o e libera&#231;&#227;o do <em>lock</em>, perceba que ela &#233; muito parecida com a do <em>spinlock</em>. A diferen&#231;a no <code>lock_acquire </code>&#233; que apenas um <code>if </code>&#233; suficiente. Se o mutex j&#225; tiver sido adquirido por outra tarefa, solicitamos ao escalonador que bloqueie a tarefa atual. O <code>this </code>do <code>sched.block(this)</code> n&#227;o &#233; a tarefa, observe a classe do m&#233;todo em quest&#227;o. Na verdade solicitamos ao escalonador que bloqueie a tarefa atual e a insira na fila de bloqueados deste Lock(<code>this</code>).</p><p>E o que o block do escalonador faz? Vamos olhar:</p><pre><code>void Scheduler::block(Lock *lock) {
  current_task-&gt;get().block();
  lock-&gt;block(current_task);
  // Util::printk("Blocking task %d\n", current_task-&gt;get().get_pid() + 1);
  scheduler_entry();
}</code></pre><p>Ele altera o estado da tarefa atual e a insere na fila de bloqueados desse lock. Ap&#243;s isso, a tarefa atual n&#227;o tem mais condi&#231;&#245;es de continuar. Por isso, o escalonador invoca a <code>scheduler_entry</code>, que como vimos anteriormente, invoca a fun&#231;&#227;o <code>scheduler</code>, que &#233; quem escolhe a nova tarefa para execu&#231;&#227;o. A tarefa bloqueada, quando liberada, continua a execu&#231;&#227;o de onde parou, ou seja, a linha logo ap&#243;s <code>sched.block(this);</code> da fun&#231;&#227;o <code>Lock::lock_acquire</code>. Como n&#227;o h&#225; nada mais ali para ser executado, essa fun&#231;&#227;o s&#243; retorna e a tarefa continua executando normalmente.</p><p>E a fun&#231;&#227;o at&#244;mica que voc&#234; me prometeu hein, voc&#234; est&#225; me enrolando! Calma, pequeno <em>padawan</em>, se colocarmos um <em>breakpoint </em>na linha <code>this-&gt;mutex.exchange(true):</code></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sBuM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sBuM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 424w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 848w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 1272w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sBuM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png" width="797" height="391" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:391,&quot;width&quot;:797,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:196257,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sBuM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 424w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 848w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 1272w, https://substackcdn.com/image/fetch/$s_!sBuM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e74d647-af2e-4704-b191-504ed7b0f3d2_797x391.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>H&#225;! olha ali na mem&#243;ria <code>0x1dc8</code> a instru&#231;&#227;o <code>xchg</code>, <em>cqd</em>.</p><p>E quando a tarefa em quest&#227;o n&#227;o precisa mais do lock? Ai ela invoca <code>Lock::lock_release</code>. </p><pre><code>...
void Lock::lock_release() {
  if (this-&gt;blocked != nullptr) {
    sched.unblock(this);
  } else {
    ...
    this-&gt;mutex.store(false);
  }
}</code></pre><p>Note que se h&#225; tarefas bloqueadas na fila, ele desbloqueia a tarefa mas n&#227;o libera o lock ainda!!! Quem vai fazer isso &#233; a &#250;ltima tarefa da fila de lock, que faz isso de forma at&#244;mica na linha <code>this-&gt;mutex.store(false);</code>.</p><p>Vamos ver o que ocorre na <code>sched.unblock(this);</code>.</p><pre><code>...
void Scheduler::unblock(Lock *lock) {
  Datastructure::QueueNode&lt;PCB&gt; *tmp = lock-&gt;unblock();
  tmp-&gt;get().ready();
  // Util::printk("Unblocking task %d\n", tmp-&gt;get().get_pid() + 1);
  this-&gt;resched(tmp);
}</code></pre><p>A diferen&#231;a not&#225;vel aqui &#233; que primeira tarefa da fila <code>blocked </code>do <code>Lock </code>em quest&#227;o s&#243; muda de fila; ela sai da fila do <em>lock </em>e vai para a fila <code>ready_queue </code>do escalonador. Mas, diferente de <code>lock_acquire</code>, o escalonador n&#227;o &#233; invocado! A tarefa que liberou o lock possivelmente liberou outra, mas ela continua a execu&#231;&#227;o normalmente, afinal, ela ainda n&#227;o fez <code>do_yield </code>e tampouco <code>do_exit</code>. &#201; isso.</p><h2>Juntando a parada toda</h2><p>O <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a> apresenta 4 threads que usam um lock, e eles projetaram de uma forma que s&#243; h&#225; uma ordem de execu&#231;&#227;o desses comandos. Fiz uma pequena altera&#231;&#227;o e impress&#245;es no original para vermos informa&#231;&#245;es &#250;teis na tela. Nossas threads est&#227;o assim:</p><pre><code>#include "include/tasks.h"
#include "include/kernel.h"
#include "include/screen.h"
#include "include/util.h"

Lock lock;
int order = 0;

void thread1() {
  Screen::set_pos(0, 0);
  Util::printk("#1 started (%d) and is trying to acquire the lock\n", order++);
  lock.lock_acquire();
  Util::printk("#1 acquired the lock and yielded (%d).\n", order++);
  do_yield();
  Util::printk("#1 woke up (%d).\n", order++);
  lock.lock_release();
  Util::printk("#1 released the lock and exited (%d).\n", order++);
  do_exit();
}

void thread2() {
  int thread2_order = 0;
  Screen::set_pos(5, 0);
  Util::printk("#2 started (%d).\n", order++);
  while (true) {
    Util::printk("                      \n");
    Util::printk("                      \n");
    Screen::set_pos(6, 0);
    Util::printk("#2 yielded (t2 %d).\n", thread2_order++);
    do_yield();
    Util::printk("#2 woke up (t2 %d).\n", thread2_order++);
    Screen::set_pos(6, 0);
  }
}

void thread3() {
  Screen::set_pos(9, 0);
  Util::printk("#3 started and yielded (%d).\n", order++);
  do_yield();
  Util::printk("#3 woke up (%d) and is trying to obtain the lock.\n", order++);
  lock.lock_acquire();
  Util::printk("#3 acquired the lock (%d).\n", order++);
  lock.lock_release();
  Util::printk("#3 released the lock and exited (%d).\n", order++);
  do_exit();
}

void thread4() {
  Screen::set_pos(14, 0);
  Util::printk("#4 started (%d) and is trying to obtain the lock.\n", order++);
  lock.lock_acquire();
  Util::printk("#4 acquired the lock (%d).\n", order++);
  lock.lock_release();
  Util::printk("#4 released the lock and exited (%d).\n", order++);
  do_exit();
}</code></pre><p>Um teste de mesa aqui &#233; bem &#250;til para voc&#234; saber o desenrolar da execu&#231;&#227;o. N&#227;o &#233; uma din&#226;mica t&#227;o extensa, e sabendo que as tarefas s&#227;o inseridas nessa ordem na fila de tarefas prontas, voc&#234; consegue saber certinho como fica a execu&#231;&#227;o. A tarefa dois atrapalha um pouco pois ela n&#227;o participa do Lock e fica sendo removida e reinserida na fila de prontos a todo momento. Voc&#234; pode ignor&#225;-la para este prop&#243;sito.</p><p>De li&#231;&#227;o de casa, compare a sua execu&#231;&#227;o do teste de mesa com o print abaixo. Os n&#250;meros entre par&#234;nteses indicam a ordem dos comandos. Com essa primitiva de sincroniza&#231;&#227;o, podemos considerar conclu&#237;do mais uma etapa do P2, faltando apenas v&#225;rias V&#193;RIAS outras, mas quem est&#225; reclamando?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RVdC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RVdC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 424w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 848w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 1272w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RVdC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png" width="448" height="342" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:342,&quot;width&quot;:448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13676,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RVdC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 424w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 848w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 1272w, https://substackcdn.com/image/fetch/$s_!RVdC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79c5922a-4977-4241-b8cd-dbf6fe65b40b_448x342.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Esse c&#243;digo, assim como todos os anteriores, est&#225; no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v5">github</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/fake-userland?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/fake-userland?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[O problema Inception da troca de contexto]]></title><description><![CDATA[Ou: como trocar o motor com o carro andando]]></description><link>https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Fri, 03 Jan 2025 16:42:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SxR_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SxR_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SxR_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SxR_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:215727,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SxR_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!SxR_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba507907-bb7b-46d4-84f8-a70b83283632_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A demora do <a href="https://blog.rodrigobranco.net/p/habemus-printk?r=2jdzwu">&#250;ltimo post</a> para este n&#227;o foi em v&#227;o. Neste post, seguindo o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>, come&#231;aremos a mexer com troca de contexto de tarefas. Ainda estamos em n&#237;vel de threads do kernel, portanto nada de <em>syscall</em> ainda, mas a demora vem justamente da dificuldade em fazer algo que em teoria &#233; simples mas que na pr&#225;tica &#233; diferente da teoria.</p><p>J&#225; ouviu falar do ovo de Colombo? Existe uma hist&#243;ria que Colombo (aquele mesmo) apostava se algu&#233;m conseguia colocar um ovo em p&#233;. Na negativa de todos, para os incautos que se atreviam apostar contra, estes se deparavam com o Colombo quebrando um peda&#231;o da base do ovo, permitindo que ele assim ficasse em p&#233;. Nisso, obviamente todos falavam &#8220;Ah, mas se fosse pra fazer assim, eu fazia!&#8221;. Pois &#233;, e n&#227;o fez por que, cara p&#225;lida?</p><p>Enfim, aqui acontece a mesma coisa. Depois que voc&#234; ver a solu&#231;&#227;o, voc&#234; vai ficar com cara de trouxa, com todo respeito aos trouxas, amo muito todos eles. E voc&#234; pode at&#233; pensar &#8220;Hum, eu faria f&#225;cil isso (ou talvez at&#233; melhor)&#8221;. Longe de duvidar de voc&#234;, mas h&#225; muitas formas de resolver isso, e se voc&#234; tentar procurar alguma solu&#231;&#227;o na internet, pouco prov&#225;vel que tenha alguma que seja aderente &#224; narrativa proposta pelo P2. Solu&#231;&#245;es da internet em geral trabalham com TSS e troca de contexto em n&#237;vel de hardware, que ainda n&#227;o estamos usando. Sem conhecer a solu&#231;&#227;o por completo, solu&#231;&#245;es parciais talvez n&#227;o sejam t&#227;o f&#225;ceis de se adaptar para nosso contexto.</p><p>Duvida? Tente partir do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a> e do nosso <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v3">&#250;ltimo c&#243;digo</a> e tente fazer uma troca de contexto sozinho. Eu fiz esse trabalho em 2020, com v&#225;rias partes do c&#243;digo j&#225; feita pelos professores, n&#243;s precisar&#237;amos completar o c&#243;digo pr&#233;-existente. Ainda assim, sem consultar esse c&#243;digo original, demorou um tempo para eu fazer funcionar.</p><p>E se voc&#234; j&#225; teve (e voc&#234; deve ter tido) contato com o b&#225;sico de sistemas operacionais, j&#225; deve ter ouvido falar de troca de contexto: quando uma tarefa &#233; interrompida, devemos salvar o &#8220;estado&#8221; dessa tarefa para retomar do ponto interrompido posteriormente. N arquitetura x86, por estamos estamos nos referindo aos registradores (incluindo o important&#237;ssimo registrador EFLAGS). O problema &#233; que, tal qual o <em>Inception</em>, precisamos executar instru&#231;&#245;es no processador para salvar tais registradores. Percebe onde quero chegar? &#201; quase como trocar o motor de um avi&#227;o com ele voando.</p><p>Bem, quase isso. Obviamente se este post est&#225; sendo escrito, significa que h&#225; como fazer isso. Tal qual Jack, vamos por partes.</p><p>Antes de adentrarmos nos meandros, o P2 diz isso na se&#231;&#227;o de <em>Hints</em>:</p><div class="pullquote"><p>One of the first things you will need to do is to implement a queue data structure. gdb is a much nicer environment than bochs in which to debug, so we strongly recommend you that you test your data structure code in user-space first.</p></div><p>Ent&#227;o, vamos fazer nossa fila. A fila ser&#225; &#250;til para v&#225;rias coisas (v&#225;rias mesmo), mas para nosso momento, teremos uma fila de tarefas &#8220;prontas&#8221; e toda vez que precisarmos escolher a pr&#243;xima tarefa que ser&#225; executada pelo processador, recorreremos a essa fila.</p><p><em>Obs</em>: falamos bastante de pilha at&#233; esse momento, e agora fila. Se n&#227;o ficou claro, estruturas de dados s&#227;o muito importantes em Ci&#234;ncia da Computa&#231;&#227;o e agregados, e no desenvolvimento de Sistemas Operacionais isso n&#227;o &#233; diferente. N&#227;o entrarei nos detalhes de tais implementa&#231;&#245;es, sugiro que voc&#234; chegue neste ponto com tais conceitos dominados.</p><p>O arquivo <code>queue.h</code> (final_revisado_v2_AGORA_VAI.txt) est&#225; assim:</p><pre><code>#ifndef __QUEUE_H
#define __QUEUE_H

namespace Datastructure {
template &lt;class T&gt; class QueueNode {
public:
  T data;
  QueueNode&lt;T&gt; *next, *previous;
  constexpr QueueNode&lt;T&gt;() : next(this), previous(this){};
  constexpr explicit QueueNode&lt;T&gt;(T data)
      : data(data), next(this), previous(this){};

  void insert(QueueNode&lt;T&gt; *);
  QueueNode&lt;T&gt; *remove(QueueNode&lt;T&gt; *);
  void print();
  constexpr T &amp;get() { return data; }
};
} // namespace Datastructure

#endif</code></pre><p>Aqui, algumas observa&#231;&#245;es. N&#227;o tenho acesso aos operadores <code>new </code>ou <code>delete </code>(tampouco <code>malloc </code>e <code>free</code>), pois n&#227;o temos <code>stdlib</code>. Tais estruturas j&#225; estar&#227;o pr&#233;-alocadas em algum lugar quando esses ponteiros forem usados.</p><p>Outro ponto de aten&#231;&#227;o &#233; que estou usando <em>templates</em>, notou? Isso porque j&#225; sei que usarei tal estrutura em v&#225;rias situa&#231;&#245;es futuras. E para o momento, testei com o tipo <code>int </code>e com a estrutura <code>PCB</code>, local onde armazenarei o estado do processo e detalharei melhor posteriormente.</p><p>Note que isso &#233; uma lista circular duplamente ligada. Quando o n&#243; &#233; criado, os ponteiros <code>next </code>e <code>previous </code>apontam para o pr&#243;prio n&#243; (<code>this</code>). Temos as op&#231;&#245;es de <code>insert </code>(insere no fim da fila) e <code>remove </code>(retira do in&#237;cio), como de costume. O m&#233;todo <code>get </code>retorna a refer&#234;ncia para o dado em si. H&#225; tamb&#233;m o m&#233;todo auxiliar <code>print</code>, para <em>debug</em>, que percorre a lista e vai imprimindo os elementos.</p><p>A implementa&#231;&#227;o dos m&#233;todos fica no arquivo queue.cpp, e se voc&#234; j&#225; implementou uma fila duplamente ligada, j&#225; deve ter feito algo similar:</p><pre><code>#include "include/queue.h"
#include "include/kernel.h"
#include "include/util.h"

using namespace Datastructure;

template &lt;class T&gt; void QueueNode&lt;T&gt;::insert(QueueNode&lt;T&gt; *node) {
  this-&gt;previous-&gt;next = node;
  node-&gt;previous = this-&gt;previous;

  this-&gt;previous = node;
  node-&gt;next = this;
...
}

template &lt;class T&gt; QueueNode&lt;T&gt; *QueueNode&lt;T&gt;::remove(QueueNode&lt;T&gt; *node) {
  if (this == node &amp;&amp; this-&gt;next == this) {
...
    return nullptr;
  }

  QueueNode&lt;T&gt; *tmp = this-&gt;next;
  node-&gt;previous-&gt;next = node-&gt;next;
  node-&gt;next-&gt;previous = node-&gt;previous;

...

  return this == node ? tmp : this;
}

template &lt;class T&gt; void QueueNode&lt;T&gt;::print() {
  QueueNode&lt;T&gt; *tmp = this;
  do {
    Util::printk("%d ", tmp-&gt;data);
    tmp = tmp-&gt;next;
  } while (tmp != this);
  Util::printk("\n");
}</code></pre><p>Os <code>&#8230;</code> s&#243; omitem c&#243;digos comentados, que coloquei para fazer debug. Se quiser ver o que tem nesses trechos, v&#225; at&#233; o meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v4">github</a>.</p><p>E aqui come&#231;ou os meus problemas. O fato de usar <em>templates </em>e C++ sem ter dom&#237;nio me fez encarar problemas dos mais variados quando instanciando os tipos <code>QueueNode&lt;int&gt;</code> e <code>QueueNode&lt;PCB&gt;</code>, com o <em>linker </em>reclamando mais que filhote de passarinho com fome.</p><p>Gra&#231;as ao meu bom e velho amigo Dr. Renan Marks, professor da UFMS (visite o site dele: <a href="https://renanmarks.net/">https://renanmarks.net/</a>), o mesmo me enviou uma entrada no <a href="https://stackoverflow.com/a/3011940">StackOverflow </a>que resolveu o meu problema: eu deveria instruir o compilador e mostrar as implementa&#231;&#245;es dos <em>templates </em>para cada tipo espec&#237;fico. Por este motivo s&#243;rdido, temos dois arquivos de implementa&#231;&#245;es, <code>queue-impl-int.cpp</code> e <code>queue-impl-pcb.cpp</code>, que no fim das contas s&#227;o praticamente iguais.</p><pre><code>#include "queue.cpp"

template void Datastructure::QueueNode&lt;int&gt;::print();

template void
Datastructure::QueueNode&lt;int&gt;::insert(Datastructure::QueueNode&lt;int&gt; *);

template Datastructure::QueueNode&lt;int&gt; *
Datastructure::QueueNode&lt;int&gt;::remove(Datastructure::QueueNode&lt;int&gt; *);</code></pre><pre><code>#include "queue.cpp"

template void Datastructure::QueueNode&lt;PCB&gt;::print();

template void
Datastructure::QueueNode&lt;PCB&gt;::insert(Datastructure::QueueNode&lt;PCB&gt; *);

template Datastructure::QueueNode&lt;PCB&gt; *
Datastructure::QueueNode&lt;PCB&gt;::remove(Datastructure::QueueNode&lt;PCB&gt; *);</code></pre><p>Nesse caso, tais arquivos &#8220;incluem&#8221; o arquivo .cpp. Estranho n&#233;? Tamb&#233;m achei. Agora, em vez de adicionarmos o arquivo objeto queue.o, adicionamos os arquivos objetos das implementa&#231;&#245;es diretamente, <code>queue-impl-int.o </code>e <code>queue-impl-pcb.o</code>.</p><p>Com a fila, <em>templates </em>e C++ superados, vamos para a pr&#243;xima etapa. Estamos trabalhando com um kernel n&#227;o preemptivo. Isso significa que as tarefas precisam explicitamente informar que concedem o processador, possivelmente para colaborar com outras tarefas. Elas tamb&#233;m podem encerrar a execu&#231;&#227;o. Embora isso seja impens&#225;vel em um sistema operacional moderno, onde cada tarefa, tal qual o Quico, acha que o processador &#233; s&#243; seu e tem toda a mem&#243;ria a sua disposi&#231;&#227;o, aqui vamos em uma abordagem mais simples. Calma que no futuro isso mudar&#225;. Por enquanto, assuma as premissas que estou colocando aqui.</p><p>Esses <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf">slides do P2</a> mostram bem como &#233; o comportamento das aplica&#231;&#245;es dessa forma:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-vAm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-vAm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 424w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 848w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 1272w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-vAm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png" width="660" height="388" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:388,&quot;width&quot;:660,&quot;resizeWidth&quot;:660,&quot;bytes&quot;:58849,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-vAm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 424w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 848w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 1272w, https://substackcdn.com/image/fetch/$s_!-vAm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07763ff7-e539-447c-a5f5-098b6afcebcb_660x388.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Kj35!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Kj35!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 424w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 848w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 1272w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Kj35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png" width="639" height="383" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:383,&quot;width&quot;:639,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83166,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Kj35!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 424w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 848w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 1272w, https://substackcdn.com/image/fetch/$s_!Kj35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1894a3b9-cf62-4527-97ad-15b1d6c7ecd9_639x383.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><p>Pelas imagens acima, perceba que as tarefas precisam conceder o processador (invocar a fun&#231;&#227;o <code>yield</code>). Quando elas encerram, elas chamam a fun&#231;&#227;o <code>exit</code>. Para as tarefas de kernel, chamamos as tarefas <code>do_yield</code> e <code>do_exit</code>.</p><p>No nosso caso, as tarefas est&#227;o no arquivo <code>tasks.cpp</code>, listadas abaixo.</p><pre><code>#include "include/tasks.h"
#include "include/kernel.h"
#include "include/screen.h"
#include "include/util.h"

void thread1() {
  Screen::set_pos(0, 0);
  Screen::set_colors(Screen::BLACK, Screen::WHITE);
  Util::printk("Thread 1\n");
  unsigned int i = 0;
  while (i &lt; 20000) {
    Util::printk("                        ");
    Screen::carriage_return();
    Util::printk("%d", i++);
    do_yield();
  }
  Util::printk("\nThread 1 exited!\n");
  do_exit();
}

void thread2() {
  Screen::set_pos(13, 0);
  Screen::set_colors(Screen::WHITE, Screen::BLACK);
  Util::printk("Thread 2\n");
  unsigned int i = 0;
  while (i &lt; 10000) {
    Util::printk("                        ");
    Screen::carriage_return();
    Util::printk("%d", i++);
    do_yield();
  }
  Util::printk("\nThread 2 exited!\n");
  do_exit();
}</code></pre><p>As tarefas s&#227;o simples, apenas para ver o funcionamento da troca de contexto. Cada tarefa entra em um loop, imprimindo um contador. Quando o contador atinge um determinado valor, o loop &#233; encerrado e a tarefa informa que terminou. Os contadores s&#227;o propositalmente assim&#233;tricos, para notarmos quando uma tarefa encerra e a outra n&#227;o, e quando ambas terminam. Isso &#233; &#250;til para validarmos a fila e a troca de contexto de forma correta (o que deve ocorrer se n&#227;o h&#225; mais tarefas a serem executadas?).</p><p>Bom, quando as tarefas forem interrompidas, onde armazenaremos o estado da tarefa? A resposta j&#225; foi dita acima, e na estrutura conhecida como <code>PCB</code>, ou <em>Process Control Block</em>. Vamos analis&#225;-lo.</p><pre><code>#ifndef __KERNEL_H
#define __KERNEL_H

#include "queue.h"
#include "screen.h"
#include "util.h"
#include &lt;cstdint&gt;

#define NUM_TASKS 2

#define STACK_SIZE 0x1000
#define START_STACKS_ADDRESS 0x41000
enum TASK_STATUS { READY, RUNNING, EXITED };

class PCB {
  uint32_t regs[9]; // EDI, ESI, EBP, original ESP, EBX, EDX, ECX, EAX, EFLAGS
  uint32_t pid;
  TASK_STATUS status;
  bool kernel_thread;
  int display_position = 0;
  char current_color;

public:
  void exit() { status = EXITED; };
  bool is_exited() { return status == EXITED; };
  void ready() { status = READY; };
  void run() { status = RUNNING; };
  void config(void (*)(), uint32_t, uint32_t, bool);
  [[nodiscard]] constexpr int get_display_position() {
    return display_position;
  };
  constexpr void set_display_position(int pos) { this-&gt;display_position = pos; }
  constexpr void set_display_color(Screen::Colors foreground,
                                   Screen::Colors background) {
    this-&gt;current_color = (foreground &amp; 0x0f) | (background &lt;&lt; 4);
  }
  [[nodiscard]] constexpr char get_display_color() {
    return this-&gt;current_color;
  };
...
  PCB() {
    this-&gt;status = EXITED;
    this-&gt;kernel_thread = false;
    this-&gt;display_position = 0;
    this-&gt;set_display_color(Screen::GRAY, Screen::BLACK);
  };
};</code></pre><p>O primeiro ponto important&#237;ssimo &#233; que o primeiro membro da classe N&#195;O PODE SER ALTERADO. Estou falando no <code>uint32_t regs[9]</code>. Esse vetor guardar&#225; o estado dos registradores, e o c&#243;digo que faz isso manipula um ponteiro para PCB e vai tentar fazer isso nesse endere&#231;o espec&#237;fico, e com deslocamento esperado do in&#237;cio da estrutura/classe. Os demais membros n&#227;o tem grandes mist&#233;rios. Temos um identificador do processo (<code>pid</code>), o estado da tarefa (para controle do escalonador), se essa tarefa &#233; do kernel ou do usu&#225;rio. Por fim, cada tarefa armazenar&#225; sua pr&#243;pria posi&#231;&#227;o e cores para impress&#227;o da <code>printk</code>.</p><p>Dos m&#233;todos de manipula&#231;&#227;o do PCB, perceba que v&#225;rios tratam do estado da tarefa ou de manipula&#231;&#227;o de posi&#231;&#245;es e cores do display. O que destoa dos demais &#233; justamente o mais importante: <code>config</code>. Vamos ver a cadeia de chamadas para entender o que &#233; feito, pois aqui o neg&#243;cio come&#231;a a complicar. O arquivo principal, kernel.cpp adiciona as tarefas.</p><pre><code>  sched.add_task(&amp;thread1, true);
  sched.add_task(&amp;thread2, true);</code></pre><p><code>sched </code>&#233; um objeto do tipo <code>Scheduler</code> que iremos detalhar depois, mas entraremos nessa fun&#231;&#227;o add_task, pois isso &#233; importante agora (arquivo <code>scheduler.cpp</code>).</p><pre><code>void Scheduler::add_task(void (*entry_point)(), bool kernel_thread) {
  int i = 0;
  while (i &lt; NUM_TASKS) {
    if (this-&gt;pcbs[i].get().is_exited()) {
      break;
    }
    i++;
  }

  if (i &gt;= NUM_TASKS) {
    Util::panic("No more PCB available\n");
  }

  this-&gt;pcbs[i].get().config(entry_point, this-&gt;current_stack_address,
                             this-&gt;current_pid++, kernel_thread);
  this-&gt;current_stack_address += STACK_SIZE;

  if (this-&gt;ready_queue == nullptr) {
    this-&gt;ready_queue = &amp;this-&gt;pcbs[i];
  } else {
    this-&gt;ready_queue-&gt;insert(&amp;this-&gt;pcbs[i]);
  }
}</code></pre><p>O objeto <code>sched </code>possui um <em>array </em>de <code>PCB</code>. Para adicionar uma nova tarefa, precisamos percorrer o vetor e verificar que entrada n&#227;o est&#225; sendo usada (ou seja, a tarefa j&#225; terminou, e seu estado &#233; <code>EXITED</code>). Note, isso N&#195;O &#233; a fila de tarefas prontas, s&#227;o coisas diferentes! Esse vetor &#233; est&#225;tico, e se as tarefas encerram de forma aleat&#243;ria, precisamos encontrar as entradas desocupadas. </p><p>Se o vetor for todo percorrido e uma entrada adequada for encontrada, o kernel entra em p&#226;nico e congela. Caso contr&#225;rio, adicionaremos essa tarefa nessa entrada vaga do vetor de <code>PCB</code>. Ent&#227;o:</p><pre><code><code>  this-&gt;pcbs[i].get().config(entry_point, this-&gt;current_stack_address,
                             this-&gt;current_pid++, kernel_thread);</code></code></pre><p>O trecho acima solicita a configura&#231;&#227;o da nova tarefa, no <code>entry_point </code>determinado (nos exemplos, foi <code>&amp;thread1</code> e <code>&amp;thread2</code>). O escalonador mant&#233;m um controle das pilhas usadas, e informa isso nessa chamada. Os <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf">slides</a> mostram onde devemos coloc&#225;-las (a partir do endere&#231;o 0x40000, cada pilha com tamanho de 4KB ou 0x1000 bytes).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VNld!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VNld!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 424w, https://substackcdn.com/image/fetch/$s_!VNld!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 848w, https://substackcdn.com/image/fetch/$s_!VNld!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 1272w, https://substackcdn.com/image/fetch/$s_!VNld!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VNld!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png" width="424" height="535" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:535,&quot;width&quot;:424,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63842,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!VNld!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 424w, https://substackcdn.com/image/fetch/$s_!VNld!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 848w, https://substackcdn.com/image/fetch/$s_!VNld!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 1272w, https://substackcdn.com/image/fetch/$s_!VNld!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e1dbe2d-c788-4f1e-95cf-a6c9e757b6be_424x535.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/precept2-slides-2015.pdf</figcaption></figure></div><p>O escalonador mant&#233;m ainda um controle do contador de <code>pid</code> para novas tarefas. Quem chamou o m&#233;todo <code>add_task </code>deve informar se essa tarefa &#233; uma tarefa de kernel ou do usu&#225;rio (<code>kernel_thread</code>). No nosso exemplo, tanto a <code>thread1 </code>quanto a <code>thread2</code> s&#227;o <em>threads </em>de <em>kernel</em>.</p><p>E o que esse m&#233;todo <code>config </code>faz? Vamos analis&#225;-lo.</p><pre><code>void PCB::config(void (*entry_point)(), uint32_t stack, uint32_t pid,
                 bool kernel_thread) {
  this-&gt;pid = pid;
  this-&gt;regs[3] = stack - 8;
  this-&gt;regs[2] = *(uint32_t *)(stack - 8) = stack;
  *(uint32_t *)(stack - 4) = (uint32_t)entry_point;
  this-&gt;kernel_thread = kernel_thread;
  this-&gt;status = READY;
}</code></pre><p>Acredito n&#227;o haver mist&#233;rio para os campos <code>pid</code>, <code>kernel_thread </code>e <code>status</code>, certo? Mas o que est&#225; acontecendo nas linhas intermedi&#225;rias? Aqui come&#231;a a beleza da coisa. Vamos trabalhar com exemplos? suponha que o <code>entry_point </code>seja <code>0x1720</code> e a pilha seja <code>0x40000</code>. O quarto registrador (<code>regs[3]</code>) recebe o valor <code>0x3FFF8</code> (<code>stack - 8</code>). O terceiro registrador (<code>regs[2]</code>) e o endere&#231;o apontado por <code>0x3FFF8 </code>recebem o valor da pilha (<code>0x40000</code>). O endere&#231;o apontado pelo endere&#231;o <code>0x3FFFC</code> recebe o <em>entry point</em>, ou seja, <code>0x1720</code>. Mas afinal, pra qu&#234; isso? Bom, eu ainda n&#227;o falei, mas o <code>regs[3]</code> &#233; o <code>esp</code> e o <code>regs[2] </code>&#233; o <code>ebp</code>. Isso porque a fun&#231;&#227;o que usaremos para empilhar os registradores &#233; a <code>pushad</code>, que empilha os registradores em uma ordem espec&#237;fica<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. Quando esses dados forem carregados do estado salvo (isso que estamos preenchendo agora) para os registradores, a ideia &#233; que eles e a mem&#243;ria estejam conforme a imagem abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VPUm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VPUm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 424w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 848w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 1272w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VPUm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png" width="691" height="341" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a008907b-7774-4614-a762-e00824b49943_691x341.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:341,&quot;width&quot;:691,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34023,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VPUm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 424w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 848w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 1272w, https://substackcdn.com/image/fetch/$s_!VPUm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa008907b-7774-4614-a762-e00824b49943_691x341.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>O truque aqui &#233; que o escalonador, quando selecionar essa tarefa para execu&#231;&#227;o (lembre-se que &#233; a primeira vez dela) recarregar&#225; o estado, mas ele continuar&#225; a execu&#231;&#227;o como se nada tivesse acontecido at&#233; terminar o escopo de sua fun&#231;&#227;o. Ao final, ele restaurar&#225; o registro de ativa&#231;&#227;o como j&#225; bem sabemos: <code>pop ebp</code>, <code>ret</code>. N&#243;s ent&#227;o, malandramente, posicionamos o ponteiro do topo da pilha para o endere&#231;o onde essas a&#231;&#245;es ir&#227;o acontecer. Quando <code>pop ebp</code> for executado, <code>esp </code>ficar&#225; com o valor <code>0x3FFC</code> e <code>ebp </code>receber&#225; o valor do a instru&#231;&#227;o pop, que pela imagem no nosso exemplo, &#233; <code>0x40000</code>. Depois, a instru&#231;&#227;o ret &#233; executada e ela faz um <code>pop </code>mas para o registrador <code>eip</code>! Nesse ponto, temos os registradores ebp e esp apontando para o mesmo lugar (<code>0x40000</code>) e <code>eip </code>possui agora o <code>entry point</code> da tarefa. A tarefa agora executar&#225; normalmente: <code>push ebp/mov ebp, esp</code>/etc. Pronto! Para a primeira tarefa, j&#225; temos o fluxo de execu&#231;&#227;o. E se voc&#234; foi atento (e eu espero que tenha sido), notou que n&#227;o armazenamos o endere&#231;o do <em>entry point</em> no <code>PCB </code>em momento nenhum! N&#243;s s&#243; utilizamos os mecanismos da arquitetura x86 contra ela mesma. Esse tipo de estrat&#233;gia garantia a consist&#234;ncia da pilha entre as chamadas.</p><p>Mas e para as tarefas em andamento? Como salvamos a tarefa em execu&#231;&#227;o e recuperamos uma que esteja pronta? Bom, para isso criei a classe Scheduler abaixo no arquivo <code>kernel.h</code>.</p><pre><code>class Scheduler {
  Datastructure::QueueNode&lt;PCB&gt; pcbs[NUM_TASKS];
  Datastructure::QueueNode&lt;PCB&gt; *ready_queue;
  uint32_t current_pid{0};
  uint32_t scheduler_count{0};
  uint32_t current_stack_address{START_STACKS_ADDRESS};

public:
  void resched(Datastructure::QueueNode&lt;PCB&gt; *);
  void inc_count() { this-&gt;scheduler_count++; };
  Datastructure::QueueNode&lt;PCB&gt; *get_ready_task();
  void add_task(void (*)(), bool);
};</code></pre><p>O escalonador possui aquele vetor de PCB dito anteriormente, bem como a fila de tarefas prontas. Ele mant&#233;m aquelas informa&#231;&#245;es de PID atual, contagem de escalonamentos e o endere&#231;o da pilha v&#225;lido para a pr&#243;xima nova tarefa que for criada.</p><p>Como m&#233;todos, j&#225; tratamos do <code>add_task</code>. <code>inc_count</code> acredito que tamb&#233;m dispensa coment&#225;rios. Vamos olhar os outros dois que faltam, come&#231;ando com <code>get_ready_task.</code></p><pre><code>Datastructure::QueueNode&lt;PCB&gt; *Scheduler::get_ready_task() {
  if (this-&gt;ready_queue == nullptr) {
    Util::printk("!!!No more tasks to run!!!\n");
    while (true) {
      /*NO TASKS TO RUN - BUSY WAIT*/
    }
  } else {
    Datastructure::QueueNode&lt;PCB&gt; *tmp = ready_queue;
    this-&gt;ready_queue = ready_queue-&gt;remove(tmp);
    ...
    return tmp;
  }
}</code></pre><p>Essa fun&#231;&#227;o apenas remove primeiro elemento da fila. O que ela faz de diferente &#233; que se n&#227;o houver mais tarefas aptas para execu&#231;&#227;o, ele fica em um loop infinito, afinal, n&#227;o h&#225; o que executar.</p><p>O m&#233;todo <code>resched </code>&#233; apresentado abaixo.</p><pre><code>void Scheduler::resched(Datastructure::QueueNode&lt;PCB&gt; *task) {
  if (this-&gt;ready_queue != nullptr) {
    this-&gt;ready_queue-&gt;insert(task);
  } else {
    this-&gt;ready_queue = task;
    ...
  }
}</code></pre><p>Aqui, a mesma coisa. Se a fila estiver vazia, a tarefa que deve ser reescalonada vira a primeira. Caso contr&#225;rio, ela &#233; inserida no fim da fila.</p><p>Mas em que momento o escalonador &#233; invocado? Pois &#233;, ainda n&#227;o mostramos isso. Nossa premissa de <em>kernel</em> n&#227;o preemptivo implica que ou a tarefa concede a CPU ou ela termina sua execu&#231;&#227;o. Nos dois casos, o escalonador &#233; invocado e &#233; feito nas fun&#231;&#245;es <code>do_yield </code>e <code>do_exit</code>, no arquivo <code>scheduler.cpp</code>.</p><pre><code>void do_yield() {
  current_task-&gt;get().ready();
  sched.resched(current_task);
  scheduler_entry();
}
void do_exit() {
  current_task-&gt;get().exit();
  scheduler_entry();
}</code></pre><p>S&#227;o as fun&#231;&#245;es mais bestas do universo. A primeira, <code>do_yield</code>, coloca a tarefa em execu&#231;&#227;o do status RUNNING para READY. Ele ent&#227;o reescalona e tarefa e chama a fun&#231;&#227;o <code>scheduler_entry</code>. Suspeito.</p><p>J&#225; para a fun&#231;&#227;o <code>do_exit</code>, ele coloca o status da tarefa em <code>EXITED </code>(para assim aproveitar seu <code>PCB </code>para novas tarefas) e novamente chama a fun&#231;&#227;o <code>scheduler_entry</code>. Muito suspeito.</p><p>Afinal, o que essa <code>scheduler_entry </code>faz? Muita calma, pois esse &#233; o cora&#231;&#227;o da troca de contexto, e qualquer vacilo faz com que o kernel pare de funcionar (acredite em mim).</p><p>Esse &#233; o caminho cr&#237;tico, &#233; nesse trecho que h&#225; o salvamento e restaura&#231;&#227;o da do estado das tarefas. O problema &#233; salvar o estado, usando instru&#231;&#245;es do processador que n&#227;o alterem o estado sendo salvo.</p><p>N&#227;o entendeu? A maioria das instru&#231;&#245;es alteram o estado do processador, e por estado eu digo o registrador <code>EFLAGS</code>. Fez uma opera&#231;&#227;o matem&#225;tica e deu overflow? O Campo <code>OF</code> (<em>Overflow Flag</em>) &#233; alterado. Fez uma opera&#231;&#227;o matem&#225;tica e deu zero? O campo <code>ZF </code>(<em>Zero Flag</em>) &#233; alterado. Fez opera&#231;&#245;es que teve o vai-um no &#250;ltimo bit? O campo <code>CF </code>(<em>Carrier Flag</em>) &#233; alterado. Fez opera&#231;&#245;es de movimenta&#231;&#227;o de bytes? O campo <code>DF </code>(<em>Direction Flag</em>) pode ser alterado. Um simples c&#225;lculo de deslocamento de bytes dentro de uma estrutura pode mudar o estado do processador, dependendo de como &#233; feito.</p><p>Por sorte, algumas instru&#231;&#245;es n&#227;o mudam o estado: <code>push</code>/<code>pop</code>, <code>mov</code>, <code>lea</code>. Essas podemos usar. Ent&#227;o, meu algoritmo para salvar o estado &#233; o seguinte:</p><ol><li><p>Come&#231;amos criando o registro de ativa&#231;&#227;o da fun&#231;&#227;o scheduler_entry, como de costume. Portanto, <code>push ebp</code>/<code>mov ebp, esp</code>.</p></li><li><p>Preciso salvar o endere&#231;o de esp em algum ponto. Esse &#233; o endere&#231;o da pilha da tarefa em execu&#231;&#227;o, e voc&#234; j&#225; vai entender o motivo. Por sorte, o registor de ativa&#231;&#227;o j&#225; fez isso pra gente, esse valor est&#225; em <code>ebp </code>agora.</p></li><li><p>Enquanto conseguimos salvar alguns registradores individualmente com opera&#231;&#245;es <code>push </code>e <code>mov</code>, isso n&#227;o &#233; poss&#237;vel para o EFLAGS. A &#218;NICA forma de se fazer isso &#233; usando a instru&#231;&#227;o <code>pushfd</code>. E isso &#233; feito na pilha. J&#225; que essa &#233; a sa&#237;da, temos uma instru&#231;&#227;o que salva todos os registradores de prop&#243;sito geral de uma vez: a instru&#231;&#227;o <code>pushad</code>.</p></li><li><p>Mas executar isso com a pilha desse jeito n&#227;o me adianta, eu preciso salvar em um lugar espec&#237;fico para restaura&#231;&#227;o posterior: no PCB da tarefa ativa. Por sorte, essa estrutura est&#225; na vari&#225;vel <code>current_task</code>.</p></li><li><p>Eu preciso enganar est&#227;o o processador, apontar <code>esp </code>para essa estrutura e fazer as opera&#231;&#245;es de <code>push</code>. Na verdade, lembre-se que a pilha cresce para baixo. Eu preciso calcular quantos bytes essas instru&#231;&#245;es pushfd e pushad salvam, de modo que ao final desses dois pushs, o endere&#231;o apontado por esp seja igual ao do in&#237;cio da estrutura PCB ativa. No nosso caso, s&#227;o salvos 9 registradores de 32 bits (<code>EDI, ESI, EBP, original ESP, EBX, EDX, ECX, EAX, EFLAGS</code>). Portanto, 9 vezes 4. Nesse ponto, esses 9 registradores est&#227;o salvos em uma &#225;rea da mem&#243;ria, especificamente no PCB da tarefa em execu&#231;&#227;o.</p></li><li><p>Note no passo anterior que ele est&#225; salvado o <code>esp </code>original da chamada da instru&#231;&#227;o <code>pushad</code>. Contudo, quando executo essa instru&#231;&#227;o, <code>esp</code> est&#225; apontando para o <code>PCB</code>, e n&#227;o para uma pilha v&#225;lida. Mas por sorte temos esse valor, ele est&#225; em <code>ebp </code>como dito anteriormente. Salvamos esse valor tamb&#233;m no <code>PCB</code>.</p></li><li><p>A tarefa est&#225; completamente salva. Restaure o endere&#231;o v&#225;lido da pilha, para que as pr&#243;ximas instru&#231;&#245;es possam utilizar de forma correta. Novamente, esse endere&#231;o est&#225; em <code>ebp</code>.</p></li><li><p>Chame a fun&#231;&#227;o <code>scheduler </code>para escolher a pr&#243;xima tarefa apta.</p></li></ol><p>A fun&#231;&#227;o de salvar o estado est&#225; completa, e mostrarei ela logo mais. Para melhor entendimento, vamos ver o que essa fun&#231;&#227;o scheduler faz.</p><pre><code>extern "C" void scheduler() {
  sched.inc_count();
  current_task = sched.get_ready_task();
  current_task-&gt;get().run();
}</code></pre><p>Ent&#227;o essa fun&#231;&#227;o s&#243; incrementa o contador do escalonador, pega uma nova tarefa apta e a coloca para &#8220;rodar&#8221; (na real ele s&#243; altera o status para <code>RUNNING</code>). O segredo aqui &#233; que, ao final dessa fun&#231;&#227;o, a vari&#225;vel <code>current_task</code> foi alterada para uma nova tarefa!</p><p>E se uma nova tarefa foi escolhida, &#233; hora de restaurarmos o estado dela. Como fazemos isso? Siga o algoritmo abaixo:</p><ol><li><p>Quando a fun&#231;&#227;o <code>scheduler </code>encerra, <code>esp </code>ainda est&#225; apontando para a pilha da tarefa anterior. Fazemos o mesmo truque e apontamos <code>esp </code>para o <code>PCB </code>da tarefa ativa (<code>current_task</code>).</p></li><li><p>Faremos a opera&#231;&#227;o inversa, usando instru&#231;&#245;es <code>popad </code>e <code>popfd</code>. Dessa vez, apontamos para o in&#237;cio da estrutura mesmo. As instru&#231;&#245;es <code>pop </code>incrementam o valor de <code>esp </code>e portanto esse endere&#231;o parte do in&#237;cio do <code>PCB </code>e vai at&#233; onde salvamos todos os registradores (note a import&#226;ncia desse primeiro membro da estrutura <code>PCB </code>- <code>regs[9]</code>).</p></li><li><p>EM TEORIA, os registradores j&#225; possuem todos os valores restaurados. Em teoria, pois se voc&#234; ver o manual da instru&#231;&#227;o <code>popad</code><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, ver&#225; que esp n&#227;o vem do <code>PCB</code>, afinal, a pr&#243;pria instru&#231;&#227;o <code>popad </code>manipula esse registrador. N&#227;o tem problema. Depois do fim da execu&#231;&#227;o de <code>popad </code>e <code>popfd</code>, temos certeza que esp est&#225; apontando para <code>&amp;PCB + sizeof(regs[9])</code>. Se fizermos <code>[esp - (6*4)]</code>, pegaremos o valor salvo de <code>regs[3]</code>, que &#233; o nosso <code>esp </code>salvo.</p></li></ol><p>E &#233; isso. Ao final desse processo, temos o <code>esp </code>apontando para o registro de ativa&#231;&#227;o da tarefa atual, que empilhou o endere&#231;o de retorno (com a instru&#231;&#227;o <code>call</code>) e o <code>ebp </code>antigo (com a instru&#231;&#227;o <code>push ebp</code>, no come&#231;o da fun&#231;&#227;o para estabelecimento do registro de ativa&#231;&#227;o). A fun&#231;&#227;o termina fazendo <code>pop ebp</code> e <code>ret</code>, retornando para a tarefa que foi escolhida pelo escalonador.</p><p>Eu apresentei algoritmos at&#233; agora pois esses passos s&#227;o feitos em assembly. Segue o conte&#250;do do arquivo <code>entry.asm</code>.</p><pre><code>global scheduler_entry
extern current_task, scheduler

scheduler_entry:
    push ebp
    mov ebp, esp
    mov esp, [current_task]
    lea esp, [esp + (9*4)]
    pushfd
    pushad
    mov [esp + (3*4)], ebp
    mov esp, ebp
    call scheduler
    mov esp, [current_task]
    popad
    popfd
    mov esp, [esp - (6*4)]
    pop ebp
    ret</code></pre><p>Depois que est&#225; pronto, at&#233; parece simples. Mas o segredo &#233; o valor de <code>current_task </code>quando a fun&#231;&#227;o inicia n&#227;o &#233; o mesmo de quando ela termina. Tanto essa vari&#225;vel como a fun&#231;&#227;o <code>scheduler </code>est&#227;o definidos no arquivo <code>scheduler.cpp</code> e por isso s&#227;o marcados como externos.</p><p>Para finalizar, temos apenas que ter cuidado com a primeira vez que a fun&#231;&#227;o <code>scheduler_entry </code>&#233; invocada. Afinal, quando isso acontece, n&#227;o h&#225; nenhuma tarefa ativa escolhida pelo escalonador, quem est&#225; chamando essa fun&#231;&#227;o &#233; a fun&#231;&#227;o principal <code>_start</code> do kernel.</p><p>Para resolver isso, criei um PCB espantalho, e j&#225; inicio o <code>current_task</code> apontando para ele.</p><pre><code>Datastructure::QueueNode&lt;PCB&gt; dummyPCB;
Datastructure::QueueNode&lt;PCB&gt; *current_task = &amp;dummyPCB;</code></pre><p>Assim, quando a scheduler_entry &#233; invocada a primeira vez, a fun&#231;&#227;o ir&#225; salvar os valores dos registradores e pilha em <code>dummyPCB</code>. Como n&#227;o h&#225; inten&#231;&#227;o de retornar a execu&#231;&#227;o de _start depois que o escalonador for invocado, a fun&#231;&#227;o <code>scheduler_entry</code> salvar&#225; o estado em <code>dummyPCB</code>, mas depois que a fun&#231;&#227;o <code>scheduler </code>for invocada, uma tarefa v&#225;lida j&#225; ter&#225; sido escolhida.</p><p>Voc&#234; poderia se perguntar: n&#227;o seria mais f&#225;cil usar uma flag e testar se a primeira vez? O problema disso &#233; justamente que as instru&#231;&#245;es de desvio dependem de altera&#231;&#227;o das EFLAGS (&#233; assim que elas funcionam inclusive). Portanto, mas simples e direto &#233; mandar salvar os registradores em um &#225;rea morta mas a l&#243;gica global n&#227;o &#233; alterada.</p><p>No fim das contas ent&#227;o, a fun&#231;&#227;o _start adiciona as tarefas e chama a fun&#231;&#227;o <code>do_exit</code>. Essa fun&#231;&#227;o altera o estado da tarefa corrente para <code>EXITED </code>(e a tarefa corrente est&#225; apontando para <code>dummyPCB</code>). <code>do_exit</code>, por sua vez, invoca a <code>scheduler_entry</code>, como j&#225; falamos anteriormente. A fun&#231;&#227;o <code>_start </code>ficou assim ent&#227;o:</p><pre><code>extern Scheduler sched;

extern "C" void _start() {
  _init();
  GDT::install_gdt();

  Screen::clear_screen();
  // test_queue();

  sched.add_task(&amp;thread1, true);
  sched.add_task(&amp;thread2, true);

  do_exit();

  while (true) {
    /* BUSY LOOP*/
  }

  /*If code has landed here, something very wrong happened...*/
  _fini();
}</code></pre><p>Achou f&#225;cil? Pois eu que fiz n&#227;o achei. S&#227;o muitos detalhes s&#243;rdidos para que isso funcione a contento. O resultado pode ser visto no v&#237;deo abaixo.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;6e0f3475-c1fb-43d5-ab0f-262b78be6df7&quot;,&quot;duration&quot;:null}"></div><p>A lista de objetos no Makefile aumentou, agora temos:</p><pre><code>OBJS:=screen.o gdt.o util.o tasks.o scheduler.o entry.o queue-impl-int.o queue-impl-pcb.o</code></pre><p>Mas perto do que acabamos de mostrar, isso ai &#233; fichinha e foi s&#243; para conhecimento. O c&#243;digo completo pode ser visto no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v4">github</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/habemus-printk?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/habemus-printk?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/dando-um-tempo-com-exclusao-mutua?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://www.felixcloutier.com/x86/pusha:pushad</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>https://www.felixcloutier.com/x86/popa:popad</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Habemus printk?]]></title><description><![CDATA[Trabalhando com fun&#231;&#245;es com argumentos vari&#225;veis]]></description><link>https://blog.rodrigobranco.net/p/habemus-printk</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/habemus-printk</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Sat, 07 Dec 2024 00:46:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!H4Bd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H4Bd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H4Bd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H4Bd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188202,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!H4Bd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!H4Bd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ccff2e4-537e-4d82-bb5d-6f1d7ad6aaee_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu">No post anterior</a> n&#243;s conseguimos resolver o problema dos construtores. Agora me sinto mais confiante para usar outros recursos da linguagem C++, como <em>namespaces </em>etc. Aproveitei e dei uma organizada no c&#243;digo, e conto com o compilador para me impedir coisas que n&#227;o posso (como RTTI, exce&#231;&#245;es, etc).</p><p>O meu c&#243;digo est&#225; bem longe do que &#233; cobrado no <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>, mas precisamos de um arcabou&#231;o de ferramentas para nos ajudar quando precisarmos colocar a m&#227;o na massa de verdade. E na parte de <em>Hints </em>&#233; dito &#8220;<em>Adding print_int and print_str to your program can help you debug.</em>&#8221;.</p><p>Eu n&#227;o poderia concordar mais. Consigo me virar bem com o GDB, mas nem sempre o c&#243;digo que vejo em C bate com o que eu faria em <em>assembly</em>, especialmente por causa das otimiza&#231;&#245;es (par&#226;metro <code>-O2</code> no <code>g++</code> e <code>ld</code>). Uma fun&#231;&#227;o que mostra endere&#231;os e n&#250;meros na tela ajudaria bastante.</p><p>E se vamos fazer <code>print_int</code><em> e </em><code>print_str</code><em>, </em>por que n&#227;o fazer logo um clone (humilde, acalme-se) da fun&#231;&#227;o <code>printf</code>? E como estamos em <em>kernel mode</em>, da ent&#227;o nomeada <code>printk</code>!</p><p>E se estou escrevendo um post para isso, significa que h&#225; coisas a serem ditas sobre. Se voc&#234; fez faculdade de computa&#231;&#227;o, &#233; poss&#237;vel que voc&#234; j&#225; saiba do que eu estou falando e isso n&#227;o seja novidade para voc&#234;. Caso contr&#225;rio, &#233; uma &#243;tima oportunidade para voc&#234; entender de verdade como funcionam as fun&#231;&#245;es com par&#226;metros vari&#225;veis.</p><p>N&#227;o &#233; coisa de outro mundo, mas se a linguagem n&#227;o permitir, voc&#234; n&#227;o consegue fazer esse tipo de implementa&#231;&#227;o. No Java por exemplo, o <code>printf </code>s&#243; apareceu na vers&#227;o 1.5 e foi necess&#225;rio fazer altera&#231;&#245;es na arquitetura da JVM para acomodar essa mudan&#231;a<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>Mas ent&#227;o, qual &#233; a treta? Lembrando que tudo o que eu vou falar aqui vale para a arquitetura x86 de 32 bits.</p><p>A assinatura da fun&#231;&#227;o <code>printk </code>&#233; a seguinte:</p><pre><code>void printk(const char *, ...);</code></pre><p>E um uso dessa fun&#231;&#227;o seria, por exemplo:</p><pre><code>printk("\tTesting line feed! %c %x %o\n%s", 'X', 0xb8000, 0700, test);</code></pre><p>Se voc&#234; nunca viu uma <code>printf </code>antes, calma que vou explicar tudo. Observe que o primeiro par&#226;metro &#233; obrigatoriamente uma <code>string</code> (no caso, um ponteiro de caracteres: <code>"\tTesting line feed! %c %x %o\n%s"</code>). Mas os outros par&#226;metros podem ser qualquer coisa: <em>string</em>, inteiro, caracteres. Como voc&#234; programa uma fun&#231;&#227;o sem saber de antem&#227;o quais s&#227;o os par&#226;metros, ou, pior ainda, como acess&#225;-los?</p><p>Bom, primeiro veja que o primeiro par&#226;metro dita o n&#250;mero de par&#226;metros que vir&#227;o a seguir, e mais do que isso, seu tipo. Os par&#226;metros no primeiro par&#226;metro s&#227;o identificados pelo caractere <code>%</code> seguido do tipo. Ent&#227;o, em nosso exemplo, temos os par&#226;metros:</p><ul><li><p><code>%c</code> &#233; o caractere <code>'X'</code></p></li><li><p><code>%x</code> &#233; o n&#250;mero hexadecimal <code>0xb8000</code></p></li><li><p><code>%o</code> &#233; o n&#250;mero octal <code>0700</code></p></li><li><p><code>%s</code> &#233; a cadeia de caracteres armazenada na vari&#225;vel <code>test. </code>No meu c&#243;digo, eu defini essa vari&#225;vel um pouco antes dessa forma<code>: char test[] = {'t', 'e', 's', 't', '\0'};</code></p></li></ul><p>Al&#233;m desses par&#226;metros, ainda seria poss&#237;vel usar mais dois: %d para n&#250;meros decimais e <code>%%</code> para o imprimir caractere <code>&#8216;%&#8217;</code>. Isso tudo &#233; arbitr&#225;rio, eu que defini que seria dessa forma, mas tentei manter um padr&#227;o parecido com a fun&#231;&#227;o <code>printf </code>original do C. Na fun&#231;&#227;o original do C, por exemplo, h&#225; v&#225;rios outros tipos, como o tipo <code>%f</code> para n&#250;meros de ponto flutuante.</p><p>Ok, e e o que fazemos com isso? Bom, o algoritmo b&#225;sico &#233; basicamente percorrer a <em>string </em>do primeiro par&#226;metro imprimindo os caracteres. Caso voc&#234; encontre um caractere especial (digamos, <code>\n,</code> <code>\t</code> ou <code>%</code>) ai &#233; necess&#225;rio fazer coisas adicionais. Vamos para os mais f&#225;ceis primeiro.</p><p>Para o <code>\t</code>, defini que a tabula&#231;&#227;o equivale a quatro espa&#231;os em branco na tela. Ent&#227;o, se um <code>\t</code> for encontrado, nada mais simples do que imprimir <code>&#8216; &#8216;</code> quatro vezes:</p><pre><code>...
    case '\t':
      for (int i = 0; i &lt; 4; i++) {
        Screen::print_char(' ');
      }
      break;
...</code></pre><p>Para o \n, estou usando o padr&#227;o do Linux. Significa que ele faz um <em>Line Feed</em> e um <em>Carrier Return</em> ao mesmo tempo. Dada uma posi&#231;&#227;o do cursor na tela, se voc&#234; somar a essa posi&#231;&#227;o o n&#250;mero de colunas do display, voc&#234; obrigatoriamente parar&#225; na pr&#243;xima linha. Depois, basta recuar para a posi&#231;&#227;o zero dessa linha (recua o n&#250;mero de caracteres igual a posi&#231;&#227;o atual menos o resto da divis&#227;o da posi&#231;&#227;o atual com o n&#250;mero de colunas. Fica assim:</p><pre><code>util.cpp
...
    case '\n':
      Screen::line_feed();
      break;
...

screen.cpp
void Screen::line_feed() {
  current_position += NUM_COLUMNS;
  current_position -= current_position % NUM_COLUMNS;
  current_position = current_position % (NUM_ROWS * NUM_COLUMNS);
}</code></pre><p>A &#250;ltima linha &#233; necess&#225;ria quando o cursor estoura o tamanho m&#225;ximo do display, e no caso ele &#233; recolocado na tela.</p><p>F&#225;cil? At&#233; agora n&#227;o foi necess&#225;rio acessar par&#226;metro nenhum adicional, al&#233;m do primeiro. Vamos dificultar um pouco. Se encontrarmos um <code>&#8216;%&#8217;</code>, precisamos avan&#231;ar e ver o pr&#243;ximo caractere, para identificar o tipo do par&#226;metro. E para desvendar o mist&#233;rio sem mostrar o c&#243;digo, precisamos relembrar de algumas coisas no que diz respeito a ABI dos compiladores C/C++ para a arquitetura x86 de 32 bits:</p><ol><li><p>A pilha cresce para baixo</p></li><li><p>Os par&#226;metros s&#227;o empilhados na ordem inversa da declara&#231;&#227;o</p></li><li><p>Cada elemento na pilha ocupa 32 bits (4 bytes)</p></li></ol><p>Com base nisso, vamos ver como est&#225; a pilha quando a fun&#231;&#227;o &#233; invocada com os par&#226;metros do nosso exemplo na imagem abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rv8Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rv8Z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 424w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 848w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 1272w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rv8Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png" width="973" height="401" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:401,&quot;width&quot;:973,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74211,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rv8Z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 424w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 848w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 1272w, https://substackcdn.com/image/fetch/$s_!rv8Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5784d6a8-f7ad-45d6-9a4b-197095848a7c_973x401.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Ent&#227;o, quando chamamos <code>printk("\tTesting line feed! %c %x %o\n%s", 'X', 0xb8000, 0700, test);</code>, o compilador:</p><ol><li><p>Empilha o endere&#231;o da vari&#225;vel <code>test</code></p></li><li><p>Empilha o valor <code>0700</code> (octal)</p></li><li><p>Empilha o valor <code>0xb8000</code> (hexadecimal)</p></li><li><p>Empilha o caractere <code>&#8216;X&#8217;</code>. Observe que o caractere <code>&#8216;X&#8217;</code> s&#243; ocupa 1 byte. Ainda assim, 4 bytes s&#227;o usados e o restante dos 24 bits mais significativos s&#227;o zerados</p></li><li><p>Empilha o endere&#231;o da <code>string "\tTesting line feed! %c %x %o\n%s"</code></p></li><li><p>Chama a fun&#231;&#227;o <code>printk</code>. A instru&#231;&#227;o <code>call </code>automaticamente empilha o endere&#231;o de retorno </p></li><li><p>J&#225; na fun&#231;&#227;o <code>printk</code>, a primeira coisa que &#233; feita &#233; ajustar a pilha, ou seja criar o registro de ativa&#231;&#227;o dessa nova fun&#231;&#227;o. A fun&#231;&#227;o empilha o endere&#231;o base da fun&#231;&#227;o que chamou (<em>caller </em><code>ebp</code> &#8594; instru&#231;&#227;o <code>push ebp</code>) e altera seu valor para o mesmo do topo da pilha (<code>callee esp</code> &#8594; <code>mov ebp, esp</code>). Esse &#233; o novo endere&#231;o base da pilha da fun&#231;&#227;o <code>printk</code> (<code>ebp</code>) e permanece inalterado at&#233; a fun&#231;&#227;o retornar. J&#225; o ponteiro do topo da pilha (<code>esp</code>) pode ser alterado (e provavelmente vai, se houver vari&#225;veis locais ou chamadas de outras fun&#231;&#245;es).</p></li></ol><p>O segredo todo est&#225; em apontar para o endere&#231;o da &#250;nica vari&#225;vel que temos certeza que existe, a primeira. Como o <code>ebp </code>agora &#233; a nossa &#226;ncora da pilha, observe na imagem abaixo os endere&#231;os indexados pelo registrador <code>ebp</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kPtA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kPtA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 424w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 848w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 1272w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kPtA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png" width="973" height="401" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:401,&quot;width&quot;:973,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86108,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kPtA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 424w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 848w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 1272w, https://substackcdn.com/image/fetch/$s_!kPtA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd65d42b8-ddc4-4cc1-95fa-4c0f9989fadd_973x401.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>O segredo &#233; portanto definir uma &#226;ncora no &#250;nico par&#226;metro que temos certeza, o <code>fmt address [ebp+8]</code>. Ao percorrer a string <code>fmt</code>, toda vez que encontrarmos um novo <code>%</code> indicando ser um par&#226;metro, basta pegar essa &#226;ncora e incrementar 4 para ir voltando na pilha. Assim, partindo do <code>fmt address [ebp+8]</code>, para chegar em <code>&#8216;X&#8217;</code>, incrementamos 4 e chegamos em <code>[ebp+12]</code>. Para chegar em <code>0xb8000</code>, incrementamos 4 e chegamos em <code>[ebp+16]</code> e assim por diante.</p><p>O problema todo &#233; que n&#227;o conseguimos manipular diretamente a pilha em C, pelo menos n&#227;o da forma como programamos. Inclusive, esse era o problema de n&#227;o ter <code>printf </code>no Java antes da vers&#227;o 1.5.</p><p>E como a gente resolve isso? Uma alternativa &#233; trabalhar com o endere&#231;o da vari&#225;vel <code>fmt</code>. Note, n&#227;o &#233; o endere&#231;o para onde <code>fmt </code>aponta, mas sim o endere&#231;o do <code>fmt </code>em si. Isso porque o endere&#231;o dele, como vimos, &#233; a pilha. Voc&#234; pode trabalhar com aritm&#233;tica de ponteiros para isso, vai funcionar. O cuidado que se precisa ter &#233; que h&#225; alguns tipos de dados que podem ocupar mais que 4 bytes (um <code>long long </code>talvez?).</p><p>Para facilitar, h&#225; algumas macros que nos auxiliam nisso, chamadas <code>variadic functions</code><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, que s&#227;o macros declaradas no arquivo <code>stdarg.h</code> ou <code>cstdarg</code> para C++, que &#233; o nosso caso.  Faremos tal qual eu disse antes. Primeiro, declaramos a vari&#225;vel &#226;ncora.</p><pre><code>std::va_list args;</code></pre><p>Essas macros s&#227;o independentes de arquitetura e por isso o *USO* deve ser tal qual eu vou mostrar aqui, mesmo que no fim das contas, algumas macros n&#227;o fa&#231;am nada na nossa arquitetura. Isso porque existem arquiteturas que guardam alguns par&#226;metros em registradores e outros na pilha, e h&#225; arquiteturas que possuem tantos registradores que &#233; bem poss&#237;vel que a pilha nem seja usada. Dessa forma. se usarmos como manda o manual, n&#227;o teremos problema. De qualquer forma, explicarei o que acontece na nossa arquitetura x86 32bit.</p><p>Voltando ent&#227;o, por tr&#225;s dos panos, na nossa arquitetura, essa declara&#231;&#227;o expande para um <code>char*</code><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. Por enquanto, ela n&#227;o armazena endere&#231;o nenhum. Precisamos agora obter nossa &#226;ncora:</p><pre><code>va_start(args, fmt);</code></pre><p>Essa macro, na nossa arquitetura, armazena o endere&#231;o de <code>fmt </code>na vari&#225;vel <code>args</code>, ou seja, temos em <code>args </code>o valor <code>ebp+8</code>.</p><p>Quando precisarmos do pr&#243;ximo elemento, basta chamar a macro <code>va_arg</code>, passando a &#226;ncora e o tipo do dado. Por exemplo, se o pr&#243;ximo par&#226;metro &#233; um <code>int</code>, ent&#227;o:</p><pre><code>n = va_arg(args, int);</code></pre><p>Simples assim. A vari&#225;vel <code>n</code> conter&#225; o dado solicitado, e a &#226;ncora &#233; atualizada, e ficar&#225; pronta para o pr&#243;ximo par&#226;metro. Digamos que agora queiramos o pr&#243;ximo par&#226;metro, que &#233; uma <em>string</em>. Assim, basta fazer:</p><pre><code>char *s = va_arg(args, char *)</code></pre><p>E o processo se repete. Quando tivermos percorrido todos os par&#226;metros na pilha, precisamos encerrar o processo chamando <code>va_end(args);</code>.</p><p>Na arquitetura x86, essa macro pode n&#227;o fazer nada. Ou pode anular o valor de <code>args </code>propositalmente para que novos acessos a ele sejam inv&#225;lidos. Isso vai depender do compilador. O fato &#233; que, por quest&#245;es de compatibilidade com outras arquiteturas e ader&#234;ncia ao padr&#227;o proposto, invocamos essa macro tamb&#233;m. &#201; inclusive bom para deixar o c&#243;digo leg&#237;vel e ver os limites da utiliza&#231;&#227;o dessa vari&#225;vel no c&#243;digo. O in&#237;cio da fun&#231;&#227;o fica como a seguir, e o restante &#233; s&#243; repeti&#231;&#227;o mas para tipos de dados diferentes.</p><pre><code>void Util::printk(const char *fmt, ...) {
  std::va_list args;
...
  va_start(args, fmt);
  for (const char *c = fmt; *c != NULL; ++c) {
    switch (*c) {
    case '%':
      switch (*++c) {
      case 's':
        for (const char *s = va_arg(args, const char *); *s != NULL; ++s) {
          Screen::print_char(*s);
        }
        break;
...</code></pre><p>A m&#225;gica perdeu o encanto? Excelente, essa &#233; a ideia. S&#243; tem um detalhezinho que ainda n&#227;o abordamos: Se o par&#226;metro for um n&#250;mero (decimal, hexadecimal, octal, que seja), como a fun&#231;&#227;o imprime esse valor?</p><p>N&#227;o entendeu a pergunta? Eu te explico: Quando falamos de mem&#243;ria de v&#237;deo nesse artigo <a href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode">AQUI</a>, dissemos que passamos dois bytes para cada caractere: um para o caractere em si, outro para o atributo de cores de frente e fundo. Tudo muito bonito, mas estamos trabalhando com n&#250;meros de 32 bits (4 bytes) na pilha e nos registradores. Como encaixamos isso em um byte para escrever na mem&#243;ria de v&#237;deo?</p><p>Mais do que isso, n&#227;o podemos escrever o &#8220;valor&#8221; do caractere diretamente. Isso porque a mem&#243;ria de v&#237;deo obedece a tabela <a href="https://www.ascii-code.com/pt">ASCII</a>. Se voc&#234; quiser escrever o caractere zero (<code>0</code>) na tela, na verdade o valor do byte deve ser <code>48</code> ou <code>0x30</code>.</p><p>Precisamos de um algoritmo para transformar um n&#250;mero de 32 bits em uma cadeia de caracteres que seja a representa&#231;&#227;o desse n&#250;mero. Se voc&#234; trabalha com computa&#231;&#227;o, voc&#234; j&#225; deve ter aprendido o algoritmo de mudan&#231;a de base. Por exemplo, para transformar o n&#250;mero 159 em bin&#225;rio, basta aplicar divis&#245;es sucessivas pela base (na base bin&#225;ria, por 2) e recuperar os restos da divis&#227;o em ordem contr&#225;ria. O mesmo serve para a convers&#227;o para hexadecimal ou octal. Observe a imagem abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!peoz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!peoz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 424w, https://substackcdn.com/image/fetch/$s_!peoz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 848w, https://substackcdn.com/image/fetch/$s_!peoz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 1272w, https://substackcdn.com/image/fetch/$s_!peoz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!peoz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png" width="1084" height="323" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:323,&quot;width&quot;:1084,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56874,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!peoz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 424w, https://substackcdn.com/image/fetch/$s_!peoz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 848w, https://substackcdn.com/image/fetch/$s_!peoz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 1272w, https://substackcdn.com/image/fetch/$s_!peoz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a14b3db-fa5e-4b70-8d3a-57b0bebc8d98_1084x323.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Observe que para hexadecimal h&#225; uma pegadinha, que voc&#234; j&#225; deve saber mas que n&#227;o custa falar <em>anyway</em>. A base 16 indica que temos dezesseis s&#237;mbolos que a representam. Contudo, s&#243; temos 10 s&#237;mbolos para n&#250;meros: de 0 a 9. Portanto, para a base 16, quando temos d&#237;gitos que seriam de 10 a 15, pegamos emprestado do alfabeto as primeiras letras: 10 vira A, 11 vira B, e vai assim at&#233; 15 virar F.</p><p>Criamos ent&#227;o a fun&#231;&#227;o <code>itoa </code>(<em>int to ascii</em>). Essa fun&#231;&#227;o provavelmente est&#225; em toda fun&#231;&#227;o de biblioteca, de v&#225;rias linguagens diferentes. Mas como essa fun&#231;&#227;o <a href="https://cplusplus.com/reference/cstdlib/itoa/">n&#227;o &#233; definida em ANSI-C e n&#227;o &#233; parte do C++</a> (apesar de ser suportada por alguns compiladores), n&#243;s criamos n&#243;s mesmos a fun&#231;&#227;o. Veja o c&#243;digo abaixo.</p><pre><code>char *Util::itoa(int number, int radix, char *tmpBuff) {
  int i = 0;
  int j = 0;
  char tmp[100];
  if (number &lt; 0) {
    tmpBuff[i++] = '-';
    number *= -1;
  }
  if (radix == 8 || radix == 16) {
    tmpBuff[i++] = '0';
  }
  if (radix == 16) {
    tmpBuff[i++] = 'x';
  }

  do {
    char c = number % radix;
    if (radix == 16 &amp;&amp; c &gt;= 10) {
      c = c + 'A' - 10;
    } else {
      c = c + '0';
    }
    tmp[j++] = c;
    number /= radix;
  } while (number &gt; 0);

  while (--j &gt;= 0) {
    tmpBuff[i++] = tmp[j];
  }
  if (radix == 2) {
    tmpBuff[i++] = 'b';
  }

  tmpBuff[i++] = '\0';
  return tmpBuff;
}</code></pre><p>Come&#231;amos verificando se o n&#250;mero &#233; negativo. Afinal, &#233; importante o sinal de menos quando isso acontece certo? Se sim, adicionamos esse s&#237;mbolo em um vetor tempor&#225;rio de caracteres. E depois, invertemos o n&#250;mero para prosseguir com o algoritmo.</p><p>Depois, verificamos a base. Por convers&#227;o, n&#250;meros na base octal recebem um zero antes, e n&#250;meros hexadecimais, <code>0x</code>, e n&#250;meros bin&#225;rios possuem um <code>b</code> ao final (por isso seu teste &#233; feito ao final).</p><p>Por fim, aplicamos o algoritmo da imagem acima. Pegamos o n&#250;mero inicial e obtemos o resto. Com esse resto, descobrimos o equivalente da tabela ASCII. Para os n&#250;meros normais de 0 a 9, caso eu some a esse n&#250;mero o valor de &#8216;0&#8217; na tabela (48), vamos resultar com o caractere desejado. Por exemplo, caso eu deseje escrever o caractere 4 na tela, de posse do n&#250;mero 4, ao somar &#8216;0&#8217; (portanto 48) resulta em 52. Veja que 52 decimal na tabela ASCII &#233; igual ao caractere 4.</p><p>Para os caracteres hexadecimais, se o n&#250;mero for 12 por exemplo, n&#227;o basta aplicar o mesmo racioc&#237;nio e somar <code>&#8216;A&#8217;</code> (65). Isso vai resultar em 77 que na tabela ASCII &#233; igual ao <code>&#8216;M&#8217;.</code> Basta tirar 10, que chegamos em 67 e ao caractere <code>&#8216;C&#8217;</code>, agora sim, correto.</p><p>Depois de armazenar o resto, atualizamos o n&#250;mero para o divisor da divis&#227;o anterior. E repetimos o processo at&#233; o n&#250;mero ser igual a zero.</p><p>Acabou? N&#227;o, observe a imagem, esse vetor de caracteres tempor&#225;rios est&#225; guardando os caracteres de tr&#225;s pra frente. Somente quando o n&#250;mero chega a zero que temos o primeiro d&#237;gito. Ent&#227;o, basta percorrer o vetor de tr&#225;s para frente e ir copiando os dados para o destino.</p><p>Pronto, terminamos. O resultado do c&#243;digo da fun&#231;&#227;o <code>kernel.cpp</code> abaixo</p><pre><code>extern "C" void _start() {
  _init();
  GDT::install_gdt();

  char test[] = {'t', 'e', 's', 't', '\0'};

  Screen::set_colors(Screen::RED, Screen::YELLOW);
  Screen::clear_screen();
  Util::printk("Hello %s %d!\n", "Rodrigo", -42);
  Util::printk("\tTesting line feed! %c %x %o\n%s\n", 'X', 0xb8000, 0700, test);
  Util::printk("%d in binary is %b\n", 75, 75);

  while (true) {
    /* BUSY LOOP*/
  }

  /*If it reaches here, something very wrong happened...*/
  _fini();
}</code></pre><p>resulta em</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!612T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!612T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 424w, https://substackcdn.com/image/fetch/$s_!612T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 848w, https://substackcdn.com/image/fetch/$s_!612T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 1272w, https://substackcdn.com/image/fetch/$s_!612T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!612T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png" width="730" height="458" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:458,&quot;width&quot;:730,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:9266,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!612T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 424w, https://substackcdn.com/image/fetch/$s_!612T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 848w, https://substackcdn.com/image/fetch/$s_!612T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 1272w, https://substackcdn.com/image/fetch/$s_!612T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bf59e8c-1d0a-4edb-9e7e-7863c22ad5da_730x458.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Essa nem foi t&#227;o dif&#237;cil, at&#233; porque tem pouca coisa de Sistemas Operacionais ou <em>kernel</em>. Os pr&#243;ximos posts voltar&#227;o para o t&#243;pico de interesse. O c&#243;digo at&#233; o momento pode ser visto <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v3">AQUI</a>. At&#233; mais!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/o-problema-inception-da-troca-de?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://en.wikipedia.org/wiki/Printf</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>https://en.cppreference.com/w/cpp/utility/variadic</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>https://en.cppreference.com/w/cpp/utility/variadic/va_list</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Quem constrói os construtores? Eu!]]></title><description><![CDATA[Ok, tivemos uma (GRANDE) ajuda do compilador]]></description><link>https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Wed, 04 Dec 2024 00:36:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!k0M_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k0M_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k0M_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k0M_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:248546,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k0M_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!k0M_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22e6b36b-1198-43a7-bbc7-e63256a01ab0_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Depois de muito quebrar a cabe&#231;a no <a href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode">post anterior</a>, finalmente consegui fazer os construtores globais funcionar no nosso c&#243;digo. Passei dias no <code>readelf </code>e <code>objdump </code>tentando entender o que o compilador fazia (ou n&#227;o fazia) e o que foi necess&#225;rio alterar para que isso acontecesse.</p><p>Eu alterei o c&#243;digo das classes <code>GDT </code>e <code>GDTPointer </code>para que as constru&#237;ssemos atrav&#233;s de construtores. Tamb&#233;m adicionei um destrutor na classe <code>GDTPointer </code>para fins did&#225;ticos e de testes, uma vez que tudo estiver funcionando esse destrutor ser&#225; removido. No momento, ele s&#243; chama a fun&#231;&#227;o <code>printk </code>para sabermos se o destrutor est&#225; sendo invocado. As classes ficaram assim:</p><pre><code>class GDT {
public:
  uint16_t limit_bytes_0_1 = 0;
  uint16_t base_address_bytes_2_3 = 0;
  uint8_t base_address_byte_4 = 0;
  uint8_t type_access_byte_5 = 0;
  uint8_t limit_flags_byte_6 = 0;
  uint8_t base_address_byte_7 = 0;

  GDT(uint32_t base_address, uint32_t limit, uint8_t type, uint8_t flags) {
    this-&gt;limit_bytes_0_1 = limit &amp; 0xffff;
    this-&gt;base_address_bytes_2_3 = base_address &amp; 0xffff;
    this-&gt;base_address_byte_4 = (base_address &gt;&gt; 16) &amp; 0xff;
    this-&gt;type_access_byte_5 = type;
    this-&gt;limit_flags_byte_6 = (limit &gt;&gt; 16) &amp; 0xf;
    this-&gt;limit_flags_byte_6 |= flags;
    this-&gt;base_address_byte_7 = (base_address &gt;&gt; 24) &amp; 0xff;
    printk((char *)" GDT() ", YELLOW, BLUE);
  }
  __attribute__((constructor));
} __attribute__((__packed__));

class GDTPointer {
public:
  uint16_t size = 0;
  uint32_t gdt_entries_address = 0;
  ~GDTPointer() { printk((char *)" ~GDTPointer() ", RED, YELLOW); }

  GDTPointer(uint16_t size, uint32_t address) {
    this-&gt;size = size;
    this-&gt;gdt_entries_address = address;
    printk((char *)" GDTPointer() ", RED, YELLOW);
  }
  __attribute__((constructor));
} __attribute__((__packed__));</code></pre><p>A declara&#231;&#227;o das vari&#225;veis globais mudou para usar os construtores no arquivo <code>gdt.cpp</code>, e a fun&#231;&#227;o <code>install_gdt </code>foi simplificada de tabela. Esse trecho ficou portanto:</p><pre><code>GDT gdt_entries[] = {
    // Null descriptor
    GDT(0,0,0,0),
    // Kernel Code Descriptor
    GDT(0x00000000, 0xfffff,
      GDT_ACCESS_CODE_SEG_READ | GDT_TYPE_CODE_SEG_READ |
          GDT_TYPE_CODE_SEG_NOT_CONFIRMING | GDT_TYPE_CODE_SEG |
          GDT_TYPE_DESCRIPTOR_CODE_OR_DATA | GDT_RING_00 | GDT_TYPE_PRESENT,
      GDT_FLAG_USER_DEFINED | GDT_LONG_MODE_DISABLED | GDT_32BIT_FLAG |
          GDT_GRANULARITY_FLAG),
    // Kernel Data Descriptor          
    GDT(0x00000000, 0xfffff,
      GDT_ACCESS_DATA_SEG_WRITE | GDT_TYPE_DATA_SEG_WRITE |
          GDT_TYPE_DATA_SEG_GROW_UPSIDE | GDT_TYPE_DATA_SEG |
          GDT_TYPE_DESCRIPTOR_CODE_OR_DATA | GDT_RING_00 | GDT_TYPE_PRESENT,
      GDT_FLAG_USER_DEFINED | GDT_LONG_MODE_DISABLED | GDT_32BIT_FLAG |
          GDT_GRANULARITY_FLAG)
};
GDTPointer gdtp((uint16_t)(sizeof(GDT) * GDT_ENTRIES),
                (uint32_t)&amp;gdt_entries[0]);

void install_gdt() {
  GDTPointer testing(0, 0);
    
  asm("lgdt %0" : : "m"(gdtp));
  asm("ljmp %0, $continue_load_gdt_register \n\t"
      "continue_load_gdt_register: \n\t" ::"i"(GDT_KCS_SEL * 0x8));
  asm("mov %0, %%eax \n\t"
      "mov %%ax, %%ds \n\t"
      "mov %%ax, %%es \n\t"
      "mov %%ax, %%fs \n\t"
      "mov %%ax, %%gs \n\t"
      "mov %%ax, %%ss \n\t" ::"i"(GDT_KDS_SEL * 0x8));
}</code></pre><p>O trecho <code>GDTPointer testing(0, 0); </code>est&#225; ai apenas para testar os construtores e destrutores locais. Uma vez que o teste tenha sido validado, ele ser&#225; removido no futuro.</p><p>Para emitir outro construtor em outro arquivo, para fins de teste tamb&#233;m, adicionei a vari&#225;vel global <code>GDT test(0, 0, 0, 0); </code>no in&#237;cio do arquivo screen.cpp. A compila&#231;&#227;o desses arquivos resulta nessas fun&#231;&#245;es, que s&#227;o os construtores das vari&#225;veis globais:</p><pre><code>$ objdump -D build/kernel | grep '_GLOBAL__sub_I'
000012d0 &lt;_GLOBAL__sub_I_test&gt;:
000012f0 &lt;_GLOBAL__sub_I_gdt_entries&gt;:</code></pre><p>Perceba que a constru&#231;&#227;o da vari&#225;vel <code>test </code>ficou na fun&#231;&#227;o <code>_GLOBAL__sub_I_test</code> (arquivo <code>screen.cpp</code>), e a constru&#231;&#227;o das vari&#225;veis <code>gdt_entries</code> e <code>gdtp </code>ficou na fun&#231;&#227;o <code>_GLOBAL__sub_I_gdt_entries </code>(arquivo <code>gdt.cpp</code>). O comportamento &#233; esse mesmo, a constru&#231;&#227;o de vari&#225;veis globais s&#227;o agrupadas por unidade de compila&#231;&#227;o, no nosso caso, cada arquivo <code>.cpp</code>.</p><p>Partindo do que foi constatado at&#233; o momento, devemos visitar esse artigo <a href="https://wiki.osdev.org/Calling_Global_Constructors#Using_crti.o,_crtbegin.o,_crtend.o,_and_crtn.o_in_a_Kernel">AQUI</a> para entender como esses construtores s&#227;o invocados.  </p><p>A inicializa&#231;&#227;o de objetos em um compilador GCC/G++ compat&#237;vel com a ABI do <em>System V</em> utiliza 5 tipos de arquivos especiais: <code>crt0.o</code>, <code>crti.o</code>, <code>crtbegin.o</code>, <code>crtend.o</code>, and <code>crtn.o</code>. Esses arquivos possuem c&#243;digos que s&#227;o executados antes da <code>main()</code> iniciar e depois que ela finaliza. Mas isso ocorre para c&#243;digo de usu&#225;rios, quando voc&#234; compila seu programa no <code>gcc </code>para rodar no seu Linux. Como estamos programando um kernel, h&#225; uma matem&#225;gica necess&#225;ria que possamos fazer isso. Por exemplo, nosso kernel funcionar&#225; como o arquivo <code>crt0.o</code>, e portanto &#233; nossa responsabilidade saber como vamos invocar os construtores.</p><p>Vale deixar bem claro que o que vou descrever daqui para frente &#233; dependente de arquitetura, vers&#227;o do compilador etc. No fim das contas o compilador gerar&#225; um vetor de ponteiros para fun&#231;&#227;o que armazena os endere&#231;os dos construtores (e outro vetor para os destrutores). Nas minhas primeiras tentativas meu compilador estava gerando um vetor oculto chamado <code>__frame_dummy_init_array_entry</code>, mas que deveria ser chamado pela fun&#231;&#227;o <code>_init()</code> e por algum motivo isso n&#227;o acontecia. Algumas frustra&#231;&#245;es e muito caf&#233; depois, lendo <a href="https://wiki.osdev.org/Calling_Global_Constructors#Using_crti.o,_crtbegin.o,_crtend.o,_and_crtn.o_in_a_Kernel">ESSE</a> artigo cheguei nesse trecho:</p><blockquote><p><em>In this case things are slightly different. The system ABI mandates the use of special sections called .init_array and .fini_array, rather than the common .init and .fini sections. This means that crtbegin.o and crtend.o, as provided by your cross-compiler, does not insert instructions into the .init and .fini sections. The result is that if you follow the method from Intel/AMD systems, your _init and _fini functions will do nothing. Your cross-compiler may actually come with default crti.o and crtn.o objects, however they also suffer from this ABI decision, and their _init and _fini functions will also do nothing.</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></blockquote><p>O trecho acima diz que o procedimento que eu estava tentando utilizar n&#227;o se aplicava &#224; arquitetura ARM. Oras, mas eu n&#227;o estou usando ARM, estou usando Intel/AMD&#8230; </p><p>De toda sorte, tentei o procedimento para ARM e fui bem sucedido! Ent&#227;o &#233; esse que vou explicar aqui.</p><p>Primeiro, o compilador fornece os arquivos <code>crtbegin.o </code>e<code> crtend.o.</code> Em especial o <code>crtbegin.o</code>, ele possui especialmente um vetor chamado <code>_init_array_start </code>(e o <code>_fini_array_start </code>para os destrutores), que armazenar&#225; os endere&#231;os dos construtores, e o compilador/linker o ir&#225; complementar quando a compila&#231;&#227;o completa acontecer. Temos portanto um vetor de ponteiros de fun&#231;&#227;o (tal qual o <code>__frame_dummy_init_array_entry</code>  dito acima).</p><p>Nossa miss&#227;o &#233; portanto criar os arquivos <code>crti.cpp</code> e <code>crtn.cpp</code>, respectivamente o pre&#226;mbulo e ep&#237;logo dos arquivos <code>crtbegin.o </code>e<code> crtend.o</code>. No arquivo <code>crti.cpp </code>n&#243;s dizemos que os s&#237;mbolos <code>_init_array_start</code>, <code>_init_array_end</code>, <code>_fini_array_start</code> e <code>_fini_array_end</code> est&#227;o definidos em outro lugar, mas que vamos referenci&#225;-los. N&#243;s sabemos a fronteira de tais vetores pois o compilador malandramente sabe onde come&#231;a e termina as se&#231;&#245;es <code>.init_array</code> (para os construtores) e <code>.fini_array</code> (para os destrutores) no arquivo ELF, portanto, ao iterar por um vetor de ponteiros para fun&#231;&#227;o come&#231;ando por <code>_init_array_start</code>, quando nosso iterator alcan&#231;ar <code>_init_array_end</code>, sabemos que o vetor terminou. Se n&#227;o ficou claro, observe o trecho de interesse da sa&#237;da do comando <code>objdump -D build/kernel</code>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xiwc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xiwc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 424w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 848w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 1272w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xiwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png" width="497" height="208" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:208,&quot;width&quot;:497,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8143,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xiwc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 424w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 848w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 1272w, https://substackcdn.com/image/fetch/$s_!Xiwc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f51f05-3c18-4eed-92dd-e661e14a25cb_497x208.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ignore as instru&#231;&#245;es em assembly do lado direito. Isso &#233; um vetor de ponteiros para fun&#231;&#227;o, com tr&#234;s valores, sendo eles: <code>0x00001150</code>, <code>0x000012d0</code> e <code>0x000012f0</code> (agrupe de quatro em quatro bytes, e considere a nota&#231;&#227;o <em>Little Endian</em> - <em>byte </em>menos significativo primeiro). E o que esses valores significam? Isso:</p><pre><code>$ objdump -D build/kernel | grep '00001150\|000012d0\|000012f0'
00001150 &lt;frame_dummy&gt;:
000012d0 &lt;_GLOBAL__sub_I_test&gt;:
000012f0 &lt;_GLOBAL__sub_I_gdt_entries&gt;:</code></pre><p>AH&#193;, olhe nossos construtores ai! A primeira entrada diz respeito a coisas que o compilador colocou, isso &#233; o endere&#231;o da fun&#231;&#227;o <code>frame_dummy</code>, que por sua vez chama a fun&#231;&#227;o <code>register_tm_clones&#8230; </code>para mais detalhes dessa cadeia de chamadas, veja <a href="https://stackoverflow.com/questions/34966097/what-functions-does-gcc-add-to-the-linux-elf">AQUI</a>. As outras duas entradas dizem respeito aos nossos construtores, ditos anteriormente.</p><p>E como a gente acessa esse vetor e invoca essas fun&#231;&#245;es? Ai &#233; que est&#225; a m&#225;gica do neg&#243;cio. Pegando como exemplo os construtores (a analogia &#233; a mesma para os destrutores, apenas a se&#231;&#227;o que &#233; diferente). Primeiro, declaramos o tipo de ponteiro para fun&#231;&#227;o <code>func_ptr</code><strong>.</strong></p><pre><code>typedef void (*func_ptr)(void);</code></pre><p>Declaramos as vari&#225;veis <code>_init_array_start </code>e <code>_init_array_end</code>, dizendo que elas s&#227;o do tipo <code>func_ptr</code>, ou seja, um <em>array </em>de ponteiros para fun&#231;&#227;o, e dizemos que o endere&#231;o delas n&#227;o est&#225; nesse arquivo <code>.cpp</code> (ou seja, s&#227;o externas).</p><pre><code>extern func_ptr _init_array_start[0], _init_array_end[0];</code></pre><p>Vetor de tamanho zero? &#201; isso ai jovem, isso indica para o compilador que &#233; um vetor, mas ele n&#227;o efetivamente &#8220;ocupa&#8221; espa&#231;o na mem&#243;ria, &#233; apenas um marcador para a posi&#231;&#227;o de mem&#243;ria correspondente. Isso &#233; muito &#250;til e usado em estrutura de dados de tamanho vari&#225;vel, como o encapsulamento de dados nas camadas de rede. Para um explica&#231;&#227;o simples do motivo disso, veja se esse artigo <a href="https://codare.aurelio.net/2009/05/16/c-cpp-vetores-de-tamanho-zero/">AQUI</a> consegue esclarecer essa artimanha.</p><p>Apontamos o <code>_init_array_start </code>para o in&#237;cio da se&#231;&#227;o <code>.init_array</code>:</p><pre><code>func_ptr _init_array_start[0] __attribute__((used, section(".init_array"),
                                             aligned(sizeof(func_ptr)))) = {};</code></pre><p>e o <code>_init_array_end </code>para o fim da se&#231;&#227;o (&#233; a mesma coisa, mas isso est&#225; no arquivo <code>crtn.cpp</code>, o rodap&#233; portanto):</p><pre><code>func_ptr _init_array_end[0] __attribute__((used, section(".init_array"),
                                           aligned(sizeof(func_ptr)))) = {};</code></pre><p>Agora, no arquivo <code>crti.cpp</code>, chamar tais construtores &#233; t&#227;o simples quanto iterar de <code>_init_array_start</code> at&#233; <code>_init_array_end</code>, invocando cada um dos ponteiros no processo:</p><pre><code>extern "C" void _init(void) {
  for (func_ptr *func = _init_array_start; func != _init_array_end; func++)
    (*func)();
}</code></pre><p>Basta ent&#227;o declarar a fun&#231;&#227;o <code>_init()</code> no arquivo kernel.cpp e invoc&#225;-la antes de tudo:</p><pre><code>extern "C" void _init(void);
...

extern "C" void _start() {
  _init();
...
}</code></pre><p>&#201; isso! Dif&#237;cil? Eu achei.</p><p>Ainda n&#227;o acabou. Para tudo isso funcionar, voc&#234;s notaram que os arquivos <code>crti.cpp</code> e <code>crtn.cpp</code> trabalham com as se&#231;&#245;es <code>.init_array</code> e <code>.fini_array</code> no arquivo ELF. Ent&#227;o, ao inv&#233;s de passar par&#226;metros de se&#231;&#245;es diretamente no <em>linker</em>, criamos o arquivo <code>linker.ld</code> com o conte&#250;do abaixo:</p><pre><code>ENTRY(_start)

SECTIONS
{
&#9;. = 0x1000;

&#9;.text BLOCK(4K) : ALIGN(4K)
&#9;{
&#9;&#9;*(.text)
&#9;} &#9;

&#9;/* Read-only data. */
&#9;.rodata BLOCK(4K) : ALIGN(4K)
&#9;{
&#9;&#9;*(.rodata)
&#9;}

&#9;/* Read-write data (initialized) */
&#9;.data BLOCK(4K) : ALIGN(4K)
&#9;{
&#9;&#9;*(.data)
&#9;}

&#9;/* Read-write data (uninitialized) and stack */
&#9;.bss BLOCK(4K) : ALIGN(4K)
&#9;{
&#9;&#9;*(COMMON)
&#9;&#9;*(.bss)
&#9;}

&#9;/* The compiler may produce other sections, by default it will put them in
&#9;   a segment with the same name. Simply add stuff here as needed. */  

&#9;.preinit_array     :
&#9;{
&#9;&#9;PROVIDE_HIDDEN (__preinit_array_start = .);
&#9;&#9;KEEP (*(.preinit_array))
&#9;&#9;PROVIDE_HIDDEN (__preinit_array_end = .);
&#9;}
&#9;.init_array     :
&#9;{
&#9;&#9;PROVIDE_HIDDEN (__init_array_start = .);
&#9;&#9;KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
&#9;&#9;KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
&#9;&#9;PROVIDE_HIDDEN (__init_array_end = .);
&#9;}
&#9;.fini_array     :
&#9;{
&#9;&#9;PROVIDE_HIDDEN (__fini_array_start = .);
&#9;&#9;KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
&#9;&#9;KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
&#9;&#9;PROVIDE_HIDDEN (__fini_array_end = .);
&#9;}  
}</code></pre><p>Descartamos coisas no linker como <code>-Ttext 0x1000</code>, essa informa&#231;&#227;o est&#225; no arquivo <code>linker.ld</code> agora. A invoca&#231;&#227;o fica assim:</p><pre><code>...

kernel:  kernel.o $(OBJ_LINK_LIST)
&#9;cd $(OUTPUTDIR) &amp;&amp; ld -O2 -g -m elf_i386 -T../linker.ld -z noexecstack -o $@ kernel.o $(OBJ_LINK_LIST)

...</code></pre><p> A vari&#225;vel <code>OBJ_LINK_LIST </code>&#233; uma concatena&#231;&#227;o cuidadosa de nossos arquivos .o, adicionados aos exigidos pelo compilador para gera&#231;&#227;o dos construtores:</p><pre><code>OBJS:=screen.o gdt.o

CRTI_OBJ=crti.o
CRTBEGIN_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtend.o)
CRTN_OBJ=crtn.o

OBJ_LINK_LIST:=$(CRTI_OBJ) $(CRTBEGIN_OBJ) $(OBJS) $(CRTEND_OBJ) $(CRTN_OBJ)</code></pre><p>E n&#227;o esque&#231;a de adicionar as flags <code>-fno-exceptions</code> <code>-fno-use-cxa-atexit</code>, caso contr&#225;rio voc&#234; ter&#225; problemas com o g++:</p><pre><code>...

%.o: $(SRCDIR)/%.cpp
&#9;g++ -g -m32 -c $&lt; -o $(OUTPUTDIR)/$@ -O2 -Wall -Wextra -ffreestanding -fno-rtti -nostdlib -fno-exceptions -fno-use-cxa-atexit 

...</code></pre><p>&#201; isso. Ao compilar, qual &#233; o resultado? Esse da imagem abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vK2n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vK2n!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 424w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 848w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 1272w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vK2n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png" width="728" height="461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:461,&quot;width&quot;:728,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13918,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vK2n!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 424w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 848w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 1272w, https://substackcdn.com/image/fetch/$s_!vK2n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a2088aa-3b43-4c68-8300-62486d0b6ced_728x461.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Note que o construtor da classe <code>GDT </code>foi invocado quatro vezes, tr&#234;s pelas entradas da vari&#225;vel global <code>gdt_entries </code>no arquivo <code>gdt.cpp</code>, e uma pelo teste da vari&#225;vel <code>test </code>no arquivo <code>screen.cpp</code>. O construtor da classe <code>GDTPointer</code> &#233; invocado duas vezes, uma para a vari&#225;vel global <code>gdtp</code>, outra para a vari&#225;vel local <code>testing </code>dentro da fun&#231;&#227;o <code>install_gdt</code><em>. </em>A vari&#225;vel <code>testing </code>inclusive &#233; a &#250;nica que est&#225; dentro de um contexto que &#233; encerrado, ao fim da fun&#231;&#227;o <code>install_gdt </code>o destrutor &#233; invocado. Por fim a fun&#231;&#227;o <code>printk </code>&#233; invocada dentro da fun&#231;&#227;o _start do arquivo kernel.cpp emitindo a mensagem <code>" Hello Protected Mode! "</code>, como j&#225; havia antes.</p><p>Depois que voc&#234; v&#234; o c&#243;digo pronto e funcionando, tudo parece simples e &#243;bvio. Mas foi muito dif&#237;cil chegar a essa solu&#231;&#227;o, em especial por desconhecer esses detalhes do compilador, e constru&#231;&#245;es como <code>__attribute__((used, section(".init_array"),                                            aligned(sizeof(func_ptr))))</code>. </p><p>Pouco prov&#225;vel que eu conseguisse fazer isso sozinho, ou pelo menos ia precisar de outras solu&#231;&#245;es e gambiarras criativas para obter o endere&#231;o de <code>_init_array_start</code>. Esse nem seria o problema, mas sim saber o tamanho desse vetor. A artimanha de posicionar c&#243;digos de pre&#226;mbulo e ep&#237;logo na se&#231;&#227;o <code>.init_array</code> &#233; bem inteligente, eu teria feito de outra forma muito menos sutil, talvez lendo o arquivo ELF ou outra coisa do tipo.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/habemus-printk?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/habemus-printk?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://wiki.osdev.org/Calling_Global_Constructors#Using_crti.o,_crtbegin.o,_crtend.o,_and_crtn.o_in_a_Kernel</p></div></div>]]></content:encoded></item><item><title><![CDATA[A20 Gate Hell e Protected Mode]]></title><description><![CDATA[Ou: as dificuldades que a retrocompatibilidade nos imp&#245;e para usar 32bit e 4GB de mem&#243;ria]]></description><link>https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Fri, 29 Nov 2024 00:54:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cHJt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cHJt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cHJt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cHJt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:326684,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cHJt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!cHJt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a6269c4-bd9c-46c5-8014-cb2be0079e31_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>O <a href="https://blog.rodrigobranco.net/p/usando-arquivos-elf">post anterior</a> finalizou o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">P1</a> criando uma imagem boot&#225;vel a partir de arquivos ELF. Agora, vamos iniciar o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>. S&#243; que tem uma pegadinha, observe o que &#233; dito na &#225;rea de Hints:</p><ul><li><p><em>The boot loader provided to you for this project does more than the one you wrote last project. Specifically, it enables address line 20 and enters protected mode.</em></p></li></ul><p>Ok, esse trabalho tem uma parte do c&#243;digo que j&#225; vem pronta e n&#227;o especifica muito o que &#233; feito. Como n&#243;s estamos construindo tudo do zero, pois n&#227;o estamos acessando o c&#243;digo original, &#233; nossa miss&#227;o fazer essas etapas. E isso n&#227;o &#233; dito ou explicado no trabalho como &#233; ou deveria ser feito. Vamos ent&#227;o entender o problema e ver como solucionamos.</p><h1>A20 gate</h1><p>Muito antigamente, no tempo de guaran&#225; de rolha, os processadores da arquitetura x86 (8086, 8088, 80186, 80188 e variantes) eram da arquitetura 16bit com endere&#231;amento de 20bit. Como voc&#234; armazena um endere&#231;o de 20 bits em um registrador de 16? Voc&#234; j&#225; sabe a resposta, e a m&#225;gica &#233; usar registradores de segmentos para compor o endere&#231;o: com um registrador de segmentos de 16bit. O maior endere&#231;o poss&#237;vel para 20 bits &#233; 2^20 = 1048576 - 1 (j&#225; que o endere&#231;o come&#231;a em zero), ou <code>0x100000</code>. Isso pode ser representado pela combina&#231;&#227;o de segmento <code>0xf800</code> e offset <code>0x8000</code> (<code>0xf800</code> * 16 + <code>0x8000</code>).</p><p>At&#233; aqui ok, certo? Ai surgiu o processador 80286. Esse processador trouxe o advento do famigerado Modo Protegido, que explicarei mais a frente. Esse processador tamb&#233;m trouxe uma expans&#227;o do endere&#231;amento, podendo agora usar endere&#231;os de 24 bits (e 30bits no modo protegido com MMU, mas n&#227;o nos avancemos muito. Foquemos nos 24bits).</p><p>Contudo, olha a cagada: esses processadores eram vendidos como retrocompat&#237;veis com os sistemas antigos, ou seja, ele deveria emular um 8086 antigo em modo real 16bit, at&#233; que voc&#234; dissesse para ele fazer o contr&#225;rio, assim, programas antigos escritos para a outra arquitetura continuavam funcionando. Isso na teoria.</p><p>Porque, na pr&#225;tica, um programa antigo ao acessar o endere&#231;o <code>0xf800</code>:<code>0x8000</code> esperaria que o processador acessasse o endere&#231;o f&#237;sico <code>0x000000</code>, afinal, pra ele o endere&#231;o <code>0x100000</code> n&#227;o existe. Mas o processador 80286 original n&#227;o fazia nenhum tipo de corre&#231;&#245;es nesse acesso, e programa antigo capotava ao acessar um endere&#231;o inv&#225;lido sem ter muito o que fazer para corrigir o problema.</p><p>A solu&#231;&#227;o veio na mais pura e cristalina gambiarra, o pessoal decidiu resolver isso direto na placa-m&#227;e. Um <em>gate </em><code>AND </code>l&#243;gico foi adicionado nesse &#250;ltimo bit do barramento de endere&#231;os da mem&#243;ria (ou o vig&#233;simo bit, ou o <em>20th address bit</em>, e dai o nome <em>A20</em>), de modo que ele viria com uma porta l&#243;gica trabalhando como chave: se o bit de controle estiver zerado, o bit de mem&#243;ria era tamb&#233;m zerado, caso o bit estivesse ligado, o endere&#231;o de mem&#243;ria (zero ou um) seria preservado.</p><p>E como &#233; que ligamos ou desligamos esse bit? Ah, ai que a coisa come&#231;a a ficar divertida. O pessoal notou que o controlador 8042, respons&#225;vel pelo teclado, tinha um pino sobrando. Ent&#227;o, foi soldado esse pino no <em>A20 gate</em>, e se voc&#234; enviar os comandos certos para o controlador do teclado, voc&#234; consegue habilitar ou desabilitar essa porta l&#243;gica. O diagrama l&#243;gico dessa parte do sistema fica assim portanto:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9T3j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9T3j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 424w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 848w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 1272w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9T3j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png" width="574" height="735" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:735,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9T3j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 424w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 848w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 1272w, https://substackcdn.com/image/fetch/$s_!9T3j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f89bd3-2673-46ba-8f4f-42de0a20e1a2_574x735.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.quora.com/What-is-the-A20-gate-in-a-CPU</figcaption></figure></div><p>Ok, e como ativamos o <em>A20 gate</em>? Bom, eu n&#227;o contei a hist&#243;ria inteira ainda: n&#227;o existe uma forma &#8220;uniforme e padronizada&#8221; de fazer essa ativa&#231;&#227;o. At&#233; porque, existem sistemas embarcados x86 que n&#227;o possuem controladores de teclado, s&#227;o acess&#237;veis via rede, porta serial, ou algum outro tipo de m&#233;todo de entrada.</p><p>Bom, para encurtar a hist&#243;ria, HOJE em dia nas CPUs mais modernas h&#225; uma fun&#231;&#227;o da BIOS para isso, a <code>BIOS 15H</code> fun&#231;&#227;o <code>0x2401</code>. Se essa fun&#231;&#227;o n&#227;o estiver dispon&#237;vel (se voc&#234; invocar essa interrup&#231;&#227;o e a flag CF estiver setada) voc&#234; precisa emitir comandos diretamente para o controlador do teclado (porta <code>0x64</code>), ou usar comandos na porta der controle A (porta <code>0x92</code>). Leia <a href="https://aeb.win.tue.nl/linux/kbd/A20.html">AQUI</a> para quais sistemas j&#225; se tem mapeado quais m&#233;todos funcionam, o buraco &#233; muito mais embaixo do que parece.</p><p>No nosso caso, o qemu-system-i386 aceita comandos da BIOS 15H. Ent&#227;o, ser&#225; esse que usaremos. Deixei um coment&#225;rio proposital para voc&#234; completar o c&#243;digo caso a BIOS 15H n&#227;o funcione para voc&#234;:</p><pre><code>...   
    ; Let's enable A20 gate
    mov ax, BIOS_INT_15H_ENABLE_A20
    int BIOS_INT_15H
    jnc a20_success

    ; write here code for Keyboard Controller or 0x92 Port!!!

a20_success:
...</code></pre><p>Com sorte, ap&#243;s a execu&#231;&#227;o da instru&#231;&#227;o <code>INT</code>, a flag <code>CF</code> estar&#225; zerada e o sistema entender&#225; que o <em>gate A20</em> est&#225; ativo.</p><p>Agora &#233; s&#243; mudar para o modo protegido e nossa vida est&#225; ganha? T&#225; achando que a vida &#233; f&#225;cil jovem? Nada disso. </p><p>De fato, para mudar para o modo protegido, basta ativarmos o bit 0 no registrador <code>CR0</code> (<em>Control Register</em>). S&#243; que ao ativarmos o modo protegido, a gente recebe de brinde um monte de coisas legais que esse modo proporciona: endere&#231;amento de 32bit, poderemos especificar endere&#231;os de mem&#243;ria onde o kernel vai rodar (<em>Ring </em>0) ou o usu&#225;rio (<em>Ring </em>3), prote&#231;&#227;o de mem&#243;ria, onde indicamos quais &#225;reas s&#227;o somente leitura (para os c&#243;digos) e escrita (dados/pilha) e no futuro, at&#233; pagina&#231;&#227;o!</p><p>O problema &#233; que tudo isso que eu disse &#233; configur&#225;vel, e o processador n&#227;o assume nada por default. Ao executar em modo protegido, o processador vai buscar o que pode ou n&#227;o ser feito nesse modo em um registrador espec&#237;fico para esse fim, que armazena informa&#231;&#245;es sobre o infame GDT. Aperte os cintos que a jornada vai ser turbulenta.</p><h1>Global Descriptor Table</h1><p>GDT significa <em>Global Descriptor Table</em>, ou tabela de descritores global. Cada entrada dessa tabela possui 8 <em>bytes</em>, portanto 64 bits. A interpreta&#231;&#227;o da entrada depende do que ela se refere, e no caso vamos analisar entradas para c&#243;digo privilegiado de <em>kernel </em>para c&#243;digo e dados.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pwKI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pwKI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 424w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 848w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 1272w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pwKI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png" width="917" height="209" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:209,&quot;width&quot;:917,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49362,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pwKI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 424w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 848w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 1272w, https://substackcdn.com/image/fetch/$s_!pwKI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2fd12a4f-2163-4922-80b0-9862661cb464_917x209.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>As informa&#231;&#245;es em vermelho s&#227;o a numera&#231;&#227;o dos bits da entrada, indo de 0 a 63. Note que as informa&#231;&#245;es em verde e azul dizem respeito as informa&#231;&#245;es de endere&#231;o base e limite da regi&#227;o de mem&#243;ria apontada por essa entrada. O limite tem ent&#227;o 20 bits (indo dos bits 0 a 15 e 48 a 51) e o endere&#231;o base 32 bits (indo dos bits 16 a 31, 32 a 39 e 56 a 63). N&#227;o me pergunte porque o endere&#231;o base n&#227;o pode ser cont&#237;guo, por ex, dos bits 0 a 31, com certeza &#233; coisa do projeto do processador (assim espero!)</p><p>Se voc&#234; est&#225; atento, notou que o endere&#231;o base pode ter qualquer endere&#231;o dentro do espa&#231;o de endere&#231;amento de 32bit, mas o limite s&#243; tem 20. Ser&#225; que essa entrada n&#227;o consegue representar todo os 4GB (2^32) que os 32 bits nos permitem? A resposta &#233; que sim! Devemos usar esses valores em conjunto com o bit 55, o G na figura acima, que significa granularidade. Assim, caso setado, ele especifica que o limite &#233; representado como em unidades de 4KB (multiplicando 4KB por 1MB - os 20 bits do limite, chegamos nos 4GB). Se esse bit estiver zerado, significa que a unidade &#233; 1 byte, e portanto essa entrada do GDT endere&#231;a apenas 1MB.</p><p>Vamos verificar o restante dos campos dessa entrada:</p><ul><li><p>O bit 40 &#233; o bit de acesso. Ele &#233; usado pela CPU ao acessar o segmento, e coloca 0 quando o segmento &#233; lido, ou 1 quando o segmento &#233; escrito. Tentativas de escrever em um segmento somente leitura (como &#233; o caso de segmento de c&#243;digo) tentar&#225; setar esse bit e falhar&#225; causando uma falha de segmenta&#231;&#227;o ou <em>page fault</em> se a pagina&#231;&#227;o j&#225; estiver habilitada.</p></li><li><p>Os pr&#243;ximos 4 bits (41 a 44) dizem respeito ao tipo de segmento que essa entrada referencia. O bit 43 indica se esse &#233; um segmento de c&#243;digo (1) ou dados (0). Se for um segmento de c&#243;digo, o bit 41 indica se esse segmento de c&#243;digo pode ser lido (1). Se for um segmento de dados/pilha, esse mesmo bit indica se esse segmento pode ser escrito (1). O bit 42, para segmentos de dados/pilha, indica a dire&#231;&#227;o da expans&#227;o. Se estiver setado, indica que o segmento cresce para baixo, ou seja, que o offset do endere&#231;o &#233; maior que o limite. Do contr&#225;rio, endere&#231;o base + <em>offset </em>&lt; limite, que &#233; o nosso caso. Para entender isso &#233; melhor verificar como &#233; feita a tradu&#231;&#227;o do segmento na figura abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oB6S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oB6S!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 424w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 848w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 1272w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oB6S!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif" width="640" height="300" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:300,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oB6S!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 424w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 848w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 1272w, https://substackcdn.com/image/fetch/$s_!oB6S!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1092d647-57bb-4af4-aaa1-90040c6538b4_640x300.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://pdos.csail.mit.edu/6.828/2005/readings/i386/s05_01.htm</figcaption></figure></div></li><li><p>O bit 44 &#233; setado, quando esse segmento &#233; referente a segmentos de c&#243;digo ou dados (nosso caso). Do contr&#225;rio, zero significa que &#233; um segmento TSS (<em>Task State Segment</em>, ser&#225; apresentado em algum momento futuro).</p></li><li><p>Os bits 45 e 46 referem-se ao DPL (<em>Descriptor Privilege Level</em>). Voc&#234; pode ter ouvindo falar dos an&#233;is de privil&#233;gio de execu&#231;&#227;o do c&#243;digo em outros sistemas operacionais. Quanto maior o n&#237;vel, menor o privil&#233;gio. Por esse motivo, geralmente c&#243;digos do kernel rodam no n&#237;vel 0 (bits 00) e c&#243;digo do usu&#225;rio rodam no n&#237;vel menos privilegiado, ou seja, 3 (bits 11). Por enquanto, rodaremos no n&#237;vel 0. C&#243;digos que executam em Ring 3 por exemplo n&#227;o podem executar certas instru&#231;&#245;es, como <code>IN</code>/<code>OUT </code>(manipula&#231;&#227;o de portas de <em>hardware</em>).</p></li><li><p>O bit 47 diz se o segmento est&#225; presente. Obviamente deixaremos esse bit setado para nossas entradas.</p></li></ul><p>Os bits 52 a 55 s&#227;o os bits de flags, definidos abaixo:</p><ul><li><p>O bit 52 &#233; reservado, deixe este zerado.</p></li><li><p>O bit 53 &#233; o bit do modo longo (modo de 64 bits). Como estamos trabalhando como 32 bits, deixe esse bit zerado.</p></li><li><p>O bit 54 indica se estamos trabalhando com 16 (bit zerado) ou 32 bits (bit setado). Pois &#233;, &#233; poss&#237;vel trabalhar no modo protegido em 16 bits (&#233; o caso do processador 80286). No nosso caso, como estamos em modo protegido 32 bits, deixe esse bit setado.</p></li><li><p>O bit 55 j&#225; foi explicado acima, &#233; o bit de granularidade. Quando zerado, o segmento descrito por esse seletor possui no m&#225;ximo 1MB, pois a unidade usada &#233; de 1 byte. Caso contr&#225;rio (nosso caso), a unidade &#233; 4KB e nosso segmento pode ter tamanho m&#225;ximo de 4GB.</p></li></ul><p>No fim das contas, dado um endere&#231;o base de 32 bits, o limite de 20 bits (que pode ser armazenado em um registrador de 32 sem perdas) e os bytes de tipo e flags, &#233; quest&#227;o de coreografia de shifts e m&#225;scaras para acomodar tais valores no formato previsto do GDT.</p><p>Tudo o que foi dito at&#233; agora &#233; referente a apenas <strong>UMA </strong>entrada da da tabela de descritores globais. Precisamos de algumas. Por enquanto definiremos tr&#234;s, mas j&#225; sabendo que no futuro vamos precisar de mais. Precisamos de um descritor nulo (os 64 bits da entrada zerados), por exig&#234;ncias da especifica&#231;&#227;o do processador. Precisamos ainda de um descritor para o segmento de c&#243;digo do kernel e outro para o segmento de dados (no momento, os endere&#231;os f&#237;sicos se sobrep&#245;em, acessando os mesmos endere&#231;os de 0 a 4GB de mem&#243;ria). Depois, precisaremos de um descritor para o segmento de c&#243;digo do usu&#225;rio e outro para o segmento de dados, no menor n&#237;vel de privil&#233;gio (ring 3). Ainda haver&#225; um descritor TSS, que auxilia na troca de contexto a n&#237;vel de <em>hardware</em>. Por enquanto, apenas  a entrada verde (descritor nulo) e as entradas pretas da imagem abaixo est&#227;o presentes no c&#243;digo atual.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cWFG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cWFG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 424w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 848w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 1272w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cWFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png" width="922" height="474" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:474,&quot;width&quot;:922,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57936,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cWFG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 424w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 848w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 1272w, https://substackcdn.com/image/fetch/$s_!cWFG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fe07acb-3d16-4987-a39f-41c0ad73a276_922x474.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>O GDT &#233; carregado atrav&#233;s da instru&#231;&#227;o <code>LGDT</code>, e passamos o endere&#231;o de uma estrutura especial em mem&#243;ria de 48 bits. Essa estrutura possui os 16 primeiros bits relacionado a quantos bytes a tabela ocupa, e pode ser calculada como o n&#250;mero de entradas multiplicado pelo tamanho da entrada (8 bytes ou 64 bits). Os pr&#243;ximos 32 bits s&#227;o o endere&#231;o em mem&#243;ria do in&#237;cio da tabela, conforme apresentado na figura acima.</p><p>Definimos algumas constantes em <em>assembly </em>para representar os dois segmentos, de c&#243;digo e dados do kernel. </p><pre><code>%define GDT_KCS_LIMIT 0xfffff
%define GDT_KCS_BASE 0x00000000
%define GDT_KCS_MIDDLE_LIMIT  (GDT_KCS_LIMIT &gt;&gt; 16) &amp; 0x0f ; lower 4 bits
%define GDT_KCS_FLAGS (1100b &lt;&lt; 4)  ; 0 - 0 - (1) 32bit -  (1) 4Kb unit ; upper 4 bits

%define GDT_KCS_LIMIT_BYTES_0_1  GDT_KCS_LIMIT &amp; 0xffff
%define GDT_KCS_BASE_BYTES_2_3  GDT_KCS_BASE &amp; 0xffff
%define GDT_KCS_BASE_BYTE_4  (GDT_KCS_BASE &gt;&gt; 16) &amp; 0xff
%define GDT_KCS_ACCESS_BYTE_5 10011010b ; (0) not used now - (1) readable - (0) user code can run here? - (1) code segment - (1) not system segment - (00) DPL/ring 0 - (1) present
%define GDT_KCS_MIDDLE_LIMIT_FLAGS_BYTE_6 GDT_KCS_MIDDLE_LIMIT | GDT_KCS_FLAGS
%define GDT_KCS_BASE_BYTE_7 (GDT_KCS_BASE &gt;&gt; 24) &amp; 0xff

%define GDT_KDS_LIMIT GDT_KCS_LIMIT
%define GDT_KDS_BASE GDT_KCS_BASE
%define GDT_KDS_MIDDLE_LIMIT  GDT_KCS_MIDDLE_LIMIT
%define GDT_KDS_FLAGS GDT_KCS_FLAGS

%define GDT_KDS_LIMIT_BYTES_0_1  GDT_KCS_LIMIT_BYTES_0_1
%define GDT_KDS_BASE_BYTES_2_3  GDT_KCS_BASE_BYTES_2_3
%define GDT_KDS_BASE_BYTE_4  GDT_KCS_BASE_BYTE_4
%define GDT_KDS_ACCESS_BYTE_5 10010010b ; 0 (not used now) - (1) writable - (0) expand down - (0) data segment - (1) not system segment - (00) DPL/ring 0 - (1) present
%define GDT_KDS_MIDDLE_LIMIT_FLAGS_BYTE_6 GDT_KCS_MIDDLE_LIMIT_FLAGS_BYTE_6
%define GDT_KDS_BASE_BYTE_7 GDT_KCS_BASE_BYTE_7</code></pre><p>N&#227;o se assuste com as opera&#231;&#245;es de <em>shift </em>e m&#225;scara, n&#227;o &#233; t&#227;o dif&#237;cil assim de entender. Por exemplo, a constante <code>GDT_KCS_MIDDLE_LIMIT. </code>Eu pretendo colocar esse valor nos primeiros 4 bits do byte representado pelos bits 48 a 55. O interesse &#233; pegar os bits 16 a 19 do valor original de limite (<code>0xfffff</code>), que &#233; o primeiro f mais a esquerda desse n&#250;mero. Seria ent&#227;o o <code>0xf0000</code>. Mas esse <code>f</code> est&#225; na posi&#231;&#227;o errada, ele precisa estar nos primeiros 4 bits, portanto a opera&#231;&#227;o <em>shift right</em> 16: <code>GDT_KCS_LIMIT &gt;&gt; 16</code>. Por fim, chegamos ao valor <code>0x0000f</code>, a opera&#231;&#227;o est&#225; encerrada. Contudo, se o n&#250;mero fosse maior que <code>0xfffff </code>(por exemplo, se algu&#233;m usasse todo os 32 bits de um registrador e definisse o limite como <code>0xffffffff</code>), poderia haver bits mais significativos que n&#227;o comp&#245;e o n&#250;mero original. Para garantir que isso n&#227;o vai ocorrer, fazemos uma opera&#231;&#227;o de AND bitwise com o valor <code>0x0f</code>. Assim, preservamos os 4 primeiros bits e o restante &#233; zerado. Ent&#227;o a opera&#231;&#227;o abaixo</p><pre><code>%define GDT_KCS_MIDDLE_LIMIT  (GDT_KCS_LIMIT &gt;&gt; 16) &amp; 0x0f ; lower 4 bits</code></pre><p>descara os 16 primeiros bits menos significativos, e desse novo n&#250;mero resultante, ele preserva os 4 primeiros bits menos significativos e zera os outros. Conseguimos ent&#227;o carregar esse byte nos bits 48 a 55 da entrada do GDT, sendo que os que possuem valor de fato s&#227;o os bits 48 a 51, que s&#227;o os bits de limite. Esse valor vai ser composto com a constante <code>GDT_KCS_FLAGS </code>para compor o valor do byte completo.</p><p>Outro ponto interessante de notar &#233; que os valores de segmento de c&#243;digo do kernel s&#227;o id&#234;nticos ao segmento de dados, com exce&#231;&#227;o do byte 5, que altera o tipo de segmento.</p><p>Definimos a estrutura do GDT, seus valores e o ponteiro para essa tabela no arquivo bootloader.asm da seguinte forma:</p><pre><code>gdt:

gdt_null:
    dq 0

gdt_kcs:
    dw GDT_KCS_LIMIT_BYTES_0_1, GDT_KCS_BASE_BYTES_2_3
    db GDT_KCS_BASE_BYTE_4, GDT_KCS_ACCESS_BYTE_5 , GDT_KCS_MIDDLE_LIMIT_FLAGS_BYTE_6, GDT_KCS_BASE_BYTE_7

gdt_kds:
    dw GDT_KDS_LIMIT_BYTES_0_1, GDT_KDS_BASE_BYTES_2_3
    db GDT_KDS_BASE_BYTE_4, GDT_KDS_ACCESS_BYTE_5 , GDT_KDS_MIDDLE_LIMIT_FLAGS_BYTE_6, GDT_KDS_BASE_BYTE_7

gdt_end:

gdt_pointer:
    dw gdt_end - gdt - 1
    dd gdt+(NEW_BOOTLOADER_SEGMENT &lt;&lt; 4)</code></pre><p>Aqui tamb&#233;m, sem surpresa. Temos o descritor nulo, e os descritores do segmento de c&#243;digo e dados do kernel, com base nas constantes que mostramos antes. Definimos ent&#227;o o ponteiro do gdt, definindo o tamanho em bytes e o ponteiro para a tabela. Mas temos uma pegadinha: note que o endere&#231;o foi adicionado a um valor. <code>NEW_BOOTLOADER_SEGMENT </code>&#233;<code> 0x8000, NEW_BOOTLOADER_SEGMENT &lt;&lt; 4 </code>&#233;<code> 0x80000. </code>Isso &#233; porque o GDT precisa do endere&#231;o absoluto na mem&#243;ria. Se usarmos s&#243; o endere&#231;o gdt, o assembly tentar&#225; calcular esse deslocamento relativo ao c&#243;digo atual. Isso s&#243; funcionaria se nosso c&#243;digo come&#231;asse no endere&#231;o 0, mas esse c&#243;digo &#233; o bootloader, que movemos para o endere&#231;o <code>0x80000</code>.</p><p>N&#227;o est&#225; no c&#243;digo, mas se voc&#234; quisesse chumbar os valores direto, voc&#234; teria algo do tipo.</p><pre><code>gdt:

gdt_null:
    dq 0

gdt_kcs:
    dq 0x00cf9a000000ffff

gdt_kds:
    dq 0x00cf92000000ffff

gdt_end:

gdt_pointer:
    dw gdt_end - gdt - 1
    dd gdt+(NEW_BOOTLOADER_SEGMENT &lt;&lt; 4)</code></pre><p>Eu acho pior dessa forma pois &#233; dif&#237;cil decodificar esses <em>magic numbers</em> depois. Mas ai vai de voc&#234;.</p><p>Para finalizar, temos que carregar o GDT, ativar o modo protegido, recarregar os registradores de segmentos para que eles apontem para os descritores do GDT e fazer um <em>far jump</em> para o <em>kernel</em>. Importante, as interrup&#231;&#245;es precisam estar desabilitadas para esse procedimento. E depois que pousarmos no modo protegido no kernel, n&#227;o teremos mais interrup&#231;&#245;es da BIOS dispon&#237;veis, e estaremos por conta pr&#243;pria.</p><pre><code>...
a20_success:
   ; clear interruptions. BIOS INT will not be accessible anymore!
    cli

    lgdt [gdt_pointer]

    mov eax, cr0
    or eax, 0x1
    mov cr0, eax

    mov ax, gdt_kds - gdt
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, (STACK_SEG_BOOTLOADER &lt;&lt; 4) + STACK_POINTER_BOOTLOADER
    mov ebp, esp    

    jmp gdt_kcs - gdt:KERNEL_INIT</code></pre><p>Se tudo der certo, o c&#243;digo do kernel j&#225; pode ser escrito em C/C++! Meu objetivo aqui &#233; s&#243; saber se a configura&#231;&#227;o est&#225; certa, e estou escrevendo uma mensagem na tela. O arquivo kernel.cpp ficou assim.</p><pre><code>#include "include/gdt.h"
#include "include/screen.h"

extern "C" void _start() {
  install_gdt();

  const char *kernelMsg = "Hello Protected Mode!";

  clear_screen(RED, YELLOW);

  printk((char *)kernelMsg, RED, YELLOW);

  while (true) {
    /* BUSY LOOP*/
  }
}</code></pre><p>Ignorem o arquivo <code>gdt.h</code> e <code>install_gdt()</code> por enquanto. O c&#243;digo &#233; simples: a gente define uma mensagem que ser&#225; mostrada, limpamos a tela e escrevemos tal mensagem na tela. Depois, ficamos em um loop infinito. O <code>extern &#8220;C&#8221;</code> solicita ao compilador C++ para exportar o nome da fun&#231;&#227;o dessa forma mesmo _start, para o linker o encontrar. Isso porque no C++ existe um neg&#243;cio chamado Name Mangling, para evitar o conflito e colis&#227;o de nomes as fun&#231;&#245;es nos c&#243;digo objeto s&#227;o alteradas. A fun&#231;&#227;o <code>printk(char*, CharColors, CharColors)</code> se torna <code>_Z6printkPc10CharColorsS0_.</code> Isso &#233; suficiente para decodificar a fun&#231;&#227;o e seus argumentos, inclusive quando m&#233;todos de uma classe. O utilit&#225;rio <code>c++filt</code> ajuda nessa decodifica&#231;&#227;o, teste no seu <em>shell </em>os comandos abaixo, e voc&#234; perceber&#225; o padr&#227;o:</p><pre><code>$ c++filt -n _Z12clear_screen10CharColorsS_
clear_screen(CharColors, CharColors)

$ c++filt -n _ZN3GDT17install_gdt_entryEjjhh
GDT::install_gdt_entry(unsigned int, unsigned int, unsigned char, unsigned char)</code></pre><p>Para testar nos seus programas C++ compilados, execute o objdump -D e veja os nomes das fun&#231;&#245;es e decodifique usando o <code>c++filt.</code></p><p>Vale a pena verificar as fun&#231;&#245;es <code>clear_screen</code> e <code>printk</code>, j&#225; que voc&#234; estava atento e sabe que n&#227;o podemos usar a <code>BIOS INT 13H</code> mais. Mas voc&#234; tem sorte, se escrevermos em certos endere&#231;os da mem&#243;ria (no caso, a partir do endere&#231;o <code>0xB8000</code>), o que for escrito l&#225; aparece na tela. Por padr&#227;o, o v&#237;deo vem configurado em modo texto, e cada dois bytes a partir do endere&#231;o <code>0xB8000 </code>representam um caractere (primeiro byte) e seus atributos como cor de frente e fundo (segundo byte). Essa mem&#243;ria de v&#237;deo pode ser encarada como uma matrix de 80 linhas por 25 colunas, dois bytes por elemento. Para limpar a tela como &#233; feito na fun&#231;&#227;o <code>clear_screen</code>, basta criar dois la&#231;os e colocar o caracter &#8216; &#8216; na posi&#231;&#227;o deseja, como fiz no c&#243;digo abaixo.</p><pre><code>void clear_screen(CharColors foreground, CharColors background) {
  reset_current_position();
  for (int i = 0; i &lt; NUM_ROWS; i++) {
    for (int j = 0; j &lt; NUM_COLUMNS; j++) {
      *current_position++ = ' ';
      *current_position++ = get_char_attr(foreground, background);
    }
  }
  reset_current_position();
}</code></pre><p>A fun&#231;&#227;o <code>reset_current_position </code>apenas posiciona o ponteiro para o valor inicial de <code>SCREEN_POINTER </code>(<code>0xB8000</code>).</p><pre><code>inline void reset_current_position() {
  current_position = (char *)SCREEN_POINTER;
}</code></pre><p>A fun&#231;&#227;o <code>printk </code>AINDA n&#227;o &#233; similar a fun&#231;&#227;o printf da libC, ou seja, ela n&#227;o processa o formato da mensagem, mas isso ser&#225; feito eventualmente. Atualmente s&#243; percorremos a string at&#233; encontrar o caractere nulo.</p><pre><code>void printk(char *msg, CharColors foreground, CharColors background) {
  char *currentMsg = msg;
  do {
    if (*currentMsg == NULL) {
      break;
    }

    *current_position++ = *currentMsg++;
    *current_position++ = get_char_attr(foreground, background);
  } while (*currentMsg != NULL);
}</code></pre><p>Por fim, a fun&#231;&#227;o <code>get_char_attr </code>prepara o byte de atributos, dado que especifiquemos as cores de frente e fundo do caractere. Os 4 primeiros bits (os menos significativos) s&#227;o a cor de frente, e os quatro &#250;ltimos (3 na verdade, o &#250;ltimo bit mais significativo &#233; uma outra coisa que n&#227;o vem ao caso agora) representam a cor de fundo.</p><pre><code>inline char get_char_attr(CharColors foreground, CharColors background) {
  return (foreground &amp; 0x0f) | (background &lt;&lt; 4);
}</code></pre><p>Se s&#227;o 4 bits, ent&#227;o podemos ter 16 combina&#231;&#245;es diferentes de cores? Isso ai. 0000 &#233; preto, 0001 &#233; azul, 0010 &#233; verde e assim por diante. Fiz uma enumera&#231;&#227;o para facilitar nossa vida.</p><pre><code>enum CharColors {
  BLACK,
  BLUE,
  GREEN,
  CYAN,
  RED,
  PURPLE,
  BROWN,
  GRAY,
  DARK_GRAY,
  LIGHT_BLUE,
  LIGHT_GREEN,
  LIGHT_CYAN,
  LIGHT_RED,
  LIGHT_PURPLE,
  YELLOW,
  WHITE
};</code></pre><p>S&#243; faltou o bode na sala, a fun&#231;&#227;o <code>install_gdt()</code> na fun&#231;&#227;o <code>_start</code>, no arquivo <code>kernel.cpp</code>. O GDT instalado no <em>bootloader </em>era tempor&#225;rio, mas nada o impedia de ser definitivo se adicion&#225;ssemos as entradas de interesse l&#225;. O problema na real &#233; que o GDT l&#225; estava na regi&#227;o de mem&#243;ria <code>0x80000</code>, mesma regi&#227;o do <em>bootloader</em>. Depois que passamos o controle para o kernel, essa mem&#243;ria pode (e vai) ser sobrescrevida pelos c&#243;digos do kernel e usu&#225;rio. </p><p>Uma solu&#231;&#227;o seria copiar aquela regi&#227;o de mem&#243;ria para uma estrutura de dados nos arquivos novos do kernel, mas ter&#237;amos que saber o endere&#231;o correto, e isso pode mudar com altera&#231;&#245;es do arquivo bootloader.asm. E como no futuro vamos instalar um GDT parrudo, para usu&#225;rios e TSS tamb&#233;m, o melhor &#233; recriarmos a instala&#231;&#227;o do GDT, mas agora usando os benef&#237;cios de uma linguagem de alto n&#237;vel.</p><p>Assim, eu criei um arquivo de cabe&#231;alho gdt.h para declarar duas classes: GDT e GDTPointer, conforme o c&#243;digo a seguir:</p><pre><code>class GDT {
public:
  uint16_t limit_bytes_0_1 = 0;
  uint16_t base_address_bytes_2_3 = 0;
  uint8_t base_address_byte_4 = 0;
  uint8_t type_access_byte_5 = 0;
  uint8_t limit_flags_byte_6 = 0;
  uint8_t base_address_byte_7 = 0;

  void install_gdt_entry(uint32_t, uint32_t, uint8_t, uint8_t);
} __attribute__((__packed__));

class GDTPointer {
public:
  uint16_t size = 0;
  uint32_t gdt_entries_address = 0;
} __attribute__((__packed__));</code></pre><p>Perceba que o GDT &#233; muito &#8220;similar&#8221; &#224; discuss&#227;o que tivemos em assembly, mas agora com classes e m&#233;todo. A declara&#231;&#227;o <code>__attribute__((__packed__))</code> solicita que o compilador gentilmente ignore o alinhamento dos tipos de dados da estrutura, ou seja, evita que o compilador adicione <em>paddings. </em>Se voc&#234; n&#227;o sabe do que eu estou falando, <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/ELF_Format.pdf">volte ao PDF do formato ELF</a>, especificamente nesse trecho abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!r8ln!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!r8ln!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 424w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 848w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 1272w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!r8ln!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png" width="1033" height="499" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:499,&quot;width&quot;:1033,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139348,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!r8ln!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 424w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 848w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 1272w, https://substackcdn.com/image/fetch/$s_!r8ln!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84bc1e01-fb78-41dd-8f88-0e4ad9e78bbd_1033x499.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Enquanto nas estruturas do arquivo ELF &#233; previsto que exista <em>padding </em>se necess&#225;rio, de forma nenhuma isso pode ocorrer com nossa estrutura GDT, pois &#233; esperado pelo hardware do processador que ela tenha esse formato r&#237;gido.</p><p>No arquivo gdt.cpp definimos as vari&#225;veis globais abaixo, garantindo portanto que essas vari&#225;veis estejam no dom&#237;nio de mem&#243;ria do kernel.</p><pre><code>GDT gdt_entries[GDT_ENTRIES];
GDTPointer gdtp;</code></pre><p>A instala&#231;&#227;o de uma entrada &#233; aquela coreografa de shifts e m&#225;scaras dito anteriormente.</p><pre><code>void GDT::install_gdt_entry(uint32_t base_address, uint32_t limit, uint8_t type,
                            uint8_t flags) {
  this-&gt;limit_bytes_0_1 = limit &amp; 0xffff;
  this-&gt;base_address_bytes_2_3 = base_address &amp; 0xffff;
  this-&gt;base_address_byte_4 = (base_address &gt;&gt; 16) &amp; 0xff;
  this-&gt;type_access_byte_5 = type;
  this-&gt;limit_flags_byte_6 = (limit &gt;&gt; 16) &amp; 0xf;
  this-&gt;limit_flags_byte_6 |= flags;
  this-&gt;base_address_byte_7 = (base_address &gt;&gt; 24) &amp; 0xff;
}</code></pre><p>A fun&#231;&#227;o <code>install_gdt</code><em>, </em>&#233;, portanto, instalar as tr&#234;s primeiras entradas do GDT (descritores nulo, c&#243;digo e dados do <em>kernel</em>), carregar a estrutura do <code>GDTPointer</code> e executar as instru&#231;&#245;es <em>assembly inline</em> para instalar esse novo GDT.</p><pre><code>void install_gdt() {
  // NULL descriptor (gdt_entries[GDT_NULL_SEL]) is constructed by default

  // Kernel Code segment
  gdt_entries[GDT_KCS_SEL].install_gdt_entry(
      0x00000000, 0xfffff,
      GDT_ACCESS_CODE_SEG_READ | GDT_TYPE_CODE_SEG_READ |
          GDT_TYPE_CODE_SEG_NOT_CONFIRMING | GDT_TYPE_CODE_SEG |
          GDT_TYPE_DESCRIPTOR_CODE_OR_DATA | GDT_RING_00 | GDT_TYPE_PRESENT,
      GDT_FLAG_USER_DEFINED | GDT_LONG_MODE_DISABLED | GDT_32BIT_FLAG |
          GDT_GRANULARITY_FLAG);
  // Kernel Data segment
  gdt_entries[GDT_KDS_SEL].install_gdt_entry(
      0x00000000, 0xfffff,
      GDT_ACCESS_DATA_SEG_WRITE | GDT_TYPE_DATA_SEG_WRITE |
          GDT_TYPE_DATA_SEG_GROW_UPSIDE | GDT_TYPE_DATA_SEG |
          GDT_TYPE_DESCRIPTOR_CODE_OR_DATA | GDT_RING_00 | GDT_TYPE_PRESENT,
      GDT_FLAG_USER_DEFINED | GDT_LONG_MODE_DISABLED | GDT_32BIT_FLAG |
          GDT_GRANULARITY_FLAG);

  // User code, data segments and TSS goes here

  // Load GDT
  gdtp.size = (uint16_t)(sizeof(GDT) * GDT_ENTRIES);
  gdtp.gdt_entries_address = (uint32_t)gdt_entries;

  asm("lgdt %0" : : "m"(gdtp));
  asm("ljmp %0, $continue_load_gdt_register \n\t"
      "continue_load_gdt_register: \n\t" ::"i"(GDT_KCS_SEL * 0x8));
  asm("mov %0, %%eax \n\t"
      "mov %%ax, %%ds \n\t"
      "mov %%ax, %%es \n\t"
      "mov %%ax, %%fs \n\t"
      "mov %%ax, %%gs \n\t"
      "mov %%ax, %%ss \n\t" ::"i"(GDT_KDS_SEL * 0x8));
}</code></pre><p>Se voc&#234; tem d&#250;vidas de que isso funciona, experimente comentar as chamadas <code>gdt_entries[GDT_KCS_SEL].install_gdt_entry</code><em> </em>e <code>gdt_entries[GDT_KDS_SEL].install_gdt_entry </code>e execute o c&#243;digo, para verificar uma falha de segmenta&#231;&#227;o ao vivo e em cores, a n&#237;vel de kernel!</p><p>Fiz uma pequena altera&#231;&#227;o no Makefile, pois agora temos 3 arquivos cpp do kernel. Precisamos compilarmos e linkarmos, garantindo que o arquivo kernel.o seja o primeiro para que ele fique no endere&#231;o 0x1000 como inicialmente previsto.</p><pre><code>OBJS:=screen.o gdt.o
OBJ_LINK_LIST:=kernel.o $(OBJS)</code></pre><p>Para os arquivos <code>.cpp</code> do <em>kernel</em>, precisamos indicar ao compilador que ele de forma alguma use <em>runtime</em>, <em>stdlib </em>ou similares, j&#225; que n&#227;o h&#225; suporte a tais firulas quando o computador inicia.</p><pre><code>%.o: $(SRCDIR)/%.cpp
&#9;g++ -g -m32 -c $&lt; -o $(OUTPUTDIR)/$@ -ffreestanding -O2 -Wall -Wextra -fno-exceptions -nostdlib -fno-rtti -nostartfiles

...

kernel:  $(OBJ_LINK_LIST)
&#9;cd $(OUTPUTDIR) &amp;&amp; ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000  -o $@ $(OBJ_LINK_LIST)</code></pre><p>Por fim, todo aquele malabarismo para fazer o gdb mostrar as informa&#231;&#245;es em modo real j&#225; n&#227;o nos servir&#225; (voc&#234; pode voltar sempre que precisar debugar o bootloader). O arquivo debug_BoringOS.sh fica bem mais simples agora:</p><pre><code>gdb -ex 'target remote localhost:1234' -ex 'hbreak *0x7c00' -ex 'set confirm off' -ex "add-symbol-file $CURRDIR/build/bootloader 0x80000" -ex "add-symbol-file $CURRDIR/build/kernel" -ex 'set confirm on' -ex 'c'</code></pre><p>Contudo, ainda acho a visualiza&#231;&#227;o default do gdb bem ruim. Por isso, criei um arquivo ~/.gdbinit e coloquei esse c&#243;digo <a href="https://github.com/gdbinit/Gdbinit/blob/master/gdbinit">DAQUI</a>. Fica bem melhor para ver as informa&#231;&#245;es. Essa visualiza&#231;&#227;o fica mais ou menos como a imagem abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LCnC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LCnC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 424w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 848w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 1272w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LCnC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png" width="819" height="880" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:880,&quot;width&quot;:819,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121075,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LCnC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 424w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 848w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 1272w, https://substackcdn.com/image/fetch/$s_!LCnC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6b2ff6d-5a42-4a20-977d-17311c9c9d89_819x880.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Se tudo deu certo, voc&#234; ser&#225; agraciado com a seguinte tela no QEMU.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sLYt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sLYt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 424w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 848w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 1272w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sLYt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png" width="730" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:730,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8016,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sLYt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 424w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 848w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 1272w, https://substackcdn.com/image/fetch/$s_!sLYt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe6c06be5-6375-4da5-b590-e7cf27dbd7f8_730x459.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Ufa, longa jornada hein? Agora &#233; sobra e &#225;gua fresca? Nada disso. As interrup&#231;&#245;es ainda desabilitadas, e assim que as habilitarmos, se n&#227;o tivermos instalado o IDT (<em>Interruption Descriptor Table</em>, uma tabela de descritores muito parecido com o GDT, mas para o tratamento das interrup&#231;&#245;es), qualquer interrup&#231;&#227;ozinha disparada (por exemplo, teclar uma tecla no teclado) vai fazer seu kernel capotar. Tem muita coisa a ser feita ainda, mas n&#227;o nesse artigo. Acesso o c&#243;digo descrito at&#233; o momento <a href="https://github.com/rodrigogbranco/boring-os/tree/p2-v1">AQUI</a>.</p><h1>Quem constr&#243;i os construtores?</h1><p>Esse artigo terminou, mas fiz algumas tentativas infrut&#237;feras que quero compartilhar. Inicialmente havia colocado um construtor no GDTPointer da seguinte forma:</p><pre><code>class GDTPointer {
public:
  uint16_t size = 0;
  uint32_t gdt_entries_address = 0;

  GDTPointer(uint16_t size, uint32_t address) {
    this-&gt;size = size;
    this-&gt;gdt_entries_address = address;
  }
} __attribute__((__packed__));</code></pre><p>Coisa boba n&#233;? Depois, alterei a declara&#231;&#227;o do objeto GDTPointer no arquivo gdt.cpp da seguinte forma:</p><pre><code>GDTPointer gdtp((uint16_t)(sizeof(GDT) * GDT_ENTRIES), (uint32_t)gdt_entries);</code></pre><p>Nada demais. Mas ao fazer isso, o c&#243;digo para de funcionar. O motivo inicial &#233; que apareceu uma fun&#231;&#227;o no endere&#231;o 0x1000, e a fun&#231;&#227;o _start foi deslocada:</p><pre><code>Symbol table '.symtab' contains 22 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS gdt.cpp
     2: 00001228     0 NOTYPE  LOCAL  DEFAULT    1 continue_load_gd[...]
     3: 00001000    35 FUNC    LOCAL  DEFAULT    1 _GLOBAL__sub_I_g[...]
     4: 00000000     0 FILE    LOCAL  DEFAULT  ABS kernel.cpp
     5: 00000000     0 FILE    LOCAL  DEFAULT  ABS screen.cpp
     6: 00000000     0 FILE    LOCAL  DEFAULT  ABS 
     7: 00003ff4     0 OBJECT  LOCAL  DEFAULT    5 _GLOBAL_OFFSET_TABLE_
     8: 000010e0   157 FUNC    GLOBAL DEFAULT    1 _Z12clear_screen[...]
     9: 0000117d     0 FUNC    GLOBAL HIDDEN     1 __x86.get_pc_thunk.ax
    10: 0000400c    24 OBJECT  GLOBAL DEFAULT    7 gdt_entries
    11: 00001181     0 FUNC    GLOBAL HIDDEN     1 __x86.get_pc_thunk.dx
    12: 00001030    56 FUNC    GLOBAL DEFAULT    1 _start
    13: 00001068     0 FUNC    GLOBAL HIDDEN     1 __x86.get_pc_thunk.bx
    14: 00004000     4 OBJECT  GLOBAL DEFAULT    6 current_position
    15: 00004004     0 NOTYPE  GLOBAL DEFAULT    7 __bss_start</code></pre><p>Note que agora h&#225; a fun&#231;&#227;o <code>_GLOBAL__sub_I_gdt_entries</code> no endere&#231;o <code>0x1000</code>, e a fun&#231;&#227;o <code>_start</code> foi para o endere&#231;o<code> 0x1030</code>. Pelo nome nem parece ser o construtor de <code>GDTPointer</code><em>. </em>Poder&#237;amos alterar o <code>createimage.cpp</code> para ler a tabela de s&#237;mbolos e obter esse novo endere&#231;o e escrever no <em>bootloader</em>, tal qual fazemos com a vari&#225;vel <code>os_size</code>, mas o problema &#233; mais profundo que isso. Na verdade, s&#243; com essas altera&#231;&#245;es, se voc&#234; mudar <code>jmp gdt_kcs - gdt:0x1000</code> para <code>jmp gdt_kcs - gdt:0x1030</code>, o c&#243;digo n&#227;o funciona, e o motivo &#233; que o construtor do <code>GDTPointer </code>n&#227;o &#233; invocado.</p><p>Para usarmos construtores C++, at&#233; no <em>kernel</em>, precisamos fazer algumas altera&#231;&#245;es como dito <a href="https://wiki.osdev.org/Calling_Global_Constructors">AQUI</a>, tal como fornecer arquivos <code>crti.asm</code> e <code>crtn.asm</code>. Ainda precisamos dos arquivos crtbegin.o e crtend.o fornecidos pelo compilador. At&#233; instalei o pacote g++-multilib pois do contr&#225;rio ele usar&#225; a vers&#227;o de 64 bits por padr&#227;o e o linker ir&#225; reclamar:</p><pre><code>sudo apt-get install g++-multilib</code></pre><p>Fazendo o c&#243;digo abaixo (adaptado <a href="https://wiki.osdev.org/Calling_Global_Constructors">DAQUI</a>):</p><pre><code>SRCDIR=src
OUTPUTDIR=build

OBJS:=screen.o gdt.o

CRTI_OBJ=crti.o
CRTBEGIN_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell g++ -m32 $(CFLAGS) -print-file-name=crtend.o)
CRTN_OBJ=crtn.o

OBJ_LINK_LIST:=$(CRTI_OBJ) $(CRTBEGIN_OBJ) $(OBJS) $(CRTEND_OBJ) $(CRTN_OBJ)

all: $(OUTPUTDIR) kernel bootloader createimage
&#9;./$(OUTPUTDIR)/createimage --extended ./$(OUTPUTDIR)/bootloader ./$(OUTPUTDIR)/kernel

$(OUTPUTDIR):
&#9;mkdir $@

%.o: $(SRCDIR)/%.asm
&#9;nasm -wall -O2 -f elf32 -F dwarf -g -o $(OUTPUTDIR)/$@ $&lt;

%.o: $(SRCDIR)/%.cpp
&#9;g++ -g -m32 -c $&lt; -o $(OUTPUTDIR)/$@ -ffreestanding -O2 -Wall -Wextra -fno-exceptions -nostdlib -fno-rtti -nostartfiles -lg++

bootloader: bootloader.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x0 -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;

kernel:  kernel.o $(OBJ_LINK_LIST)
&#9;cd $(OUTPUTDIR) &amp;&amp; ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000 --section-start .init=0x5000  -o $@ kernel.o $(OBJ_LINK_LIST)

createimage: $(SRCDIR)/createimage.cpp
&#9;g++ -o $(OUTPUTDIR)/$@ $&lt;

clean:
&#9;rm -rf $(OUTPUTDIR)/*</code></pre><p>Ainda assim n&#227;o funcionou, o <em>linker </em>n&#227;o encontra a fun&#231;&#227;o <code>_init()</code>:</p><pre><code>$ make clean &amp;&amp; make
rm -rf build/*
g++ -g -m32 -c src/kernel.cpp -o build/kernel.o -ffreestanding -O2 -Wall -Wextra -fno-exceptions -nostdlib -fno-rtti -nostartfiles -lg++
nasm -wall -O2 -f elf32 -F dwarf -g -o build/crti.o src/crti.asm
g++ -g -m32 -c src/screen.cpp -o build/screen.o -ffreestanding -O2 -Wall -Wextra -fno-exceptions -nostdlib -fno-rtti -nostartfiles -lg++
g++ -g -m32 -c src/gdt.cpp -o build/gdt.o -ffreestanding -O2 -Wall -Wextra -fno-exceptions -nostdlib -fno-rtti -nostartfiles -lg++
nasm -wall -O2 -f elf32 -F dwarf -g -o build/crtn.o src/crtn.asm
cd build &amp;&amp; ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000 --section-start .init=0x5000  -o kernel kernel.o crti.o /usr/lib/gcc/x86_64-linux-gnu/13/32/crtbegin.o screen.o gdt.o /usr/lib/gcc/x86_64-linux-gnu/13/32/crtend.o crtn.o
ld: warning: crtn.o: missing .note.GNU-stack section implies executable stack
ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
ld: kernel.o: in function `_start':
/home/p_8410/projects/boring-os/src/kernel.cpp:7:(.text+0x10): undefined reference to `_init()'
make: *** [Makefile:29: kernel] Error 1</code></pre><p>Deve ser coisa boba, mas como n&#227;o consegui resolver isso em um tempo razo&#225;vel, se algu&#233;m souber como resolver isso, por favor me avise!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/usando-arquivos-elf?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/usando-arquivos-elf?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/quem-constroi-os-construtores-eu?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[Usando arquivos ELF]]></title><description><![CDATA[Ou: como colar dois execut&#225;veis ELF com cuspe e maisena]]></description><link>https://blog.rodrigobranco.net/p/usando-arquivos-elf</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/usando-arquivos-elf</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Tue, 19 Nov 2024 22:45:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R6tW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R6tW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R6tW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R6tW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156749,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R6tW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!R6tW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed64f4bc-9338-4771-8bcb-76d30a4855cb_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Logo logo o <em>Dummy Kernel</em> (<a href="https://blog.rodrigobranco.net/p/big-big-dummy-kernel">veja o post anterior</a>) vai dar lugar a um <em>Kernel </em>que fa&#231;a algo de verdade. E quando isso acontecer, o arquivo n&#227;o vai mais ser escrito em <em>Assembly</em>, mas em C/C++. Conforme o projeto vai ficando mais complexo, o formato bin&#225;rio que estamos usando deixa de ser atraente da forma como est&#225;, pois este formato perde os s&#237;mbolos e outras informa&#231;&#245;es relevantes (lembra que para debugar estamos usando o arquivo objeto .o? Pois &#233;).</p><p>O <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">P1</a> espera que voc&#234; consiga extrair o &#8220;c&#243;digo&#8221; dos arquivos ELF do <em>bootloader </em>e do <em>Kernel</em>, juntar os dois e criar uma nova imagem boot&#225;vel. Obviamente h&#225; um car&#225;ter pedag&#243;gico aqui, voc&#234; pode aprender muito lendo o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/ELF_Format.pdf">belo manual</a> e entender do que se trata cada informa&#231;&#227;o. Faremos isso, mas antes de prosseguir, informo que &#233; poss&#237;vel fazer de uma forma mais f&#225;cil: voc&#234; pode usar o utilit&#225;rio <em><a href="https://stackoverflow.com/questions/3925075/how-to-extract-only-the-raw-contents-of-an-elf-section">objcop</a>y</em>, extrair o conte&#250;do relevante dos arquivos execut&#225;veis ELF, juntar os dois e depois sobrescrever os bytes 2, 3, 4 e 5 desse arquivo com o tamanho do kernel (talvez usando <em>awk</em>? &#201; s&#243; uma sugest&#227;o :D ), considerando a unidade n&#250;mero de setores do disco (considere ainda o <em>byte order, </em>que no caso do x86 &#233; <em>little endian</em>). Se voc&#234; fizer isso, parab&#233;ns, trabalho conclu&#237;do (mas voc&#234; n&#227;o ganharia nota). At&#233; por isso, deixo isso como exerc&#237;cio.</p><p>N&#243;s vamos pelo caminho mais dif&#237;cil: Faremos um programa em C/C++ para abrir os arquivos bin&#225;rios ELF, extrair as informa&#231;&#245;es, colar elas mal e porcamente com cuspe e maisena e gerar uma imagem boot&#225;vel, tal qual &#233; pregado no P1.</p><p>Antes, vamos deixar nosso kernel um pouquinho mais complexo. Vamos adicionar se&#231;&#245;es <code>.bss</code>, <code>.data</code> e <code>.rdata</code>. Isso nos obrigar&#225; a fazer um parser mais elaborado. O final do arquivo kernel.asm fica assim:</p><pre><code>...
big_big_msg db "Big Big Dummy Kernel Loaded!", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER   


SECTION .bss
bsssegtest  resb 50

SECTION .data
datasegtest db 'X'

SECTION .rdata
teste db 'readonlydata'</code></pre><p>Depois veremos no que isso resultar&#225;.</p><p>O primeiro passo &#233; alterar o <code>Makefile </code>para que ele gere arquivos ELF. Os trechos de gera&#231;&#227;o os targets <code>booloader </code>e <code>kernel </code>eram assim:</p><pre><code>bootloader: bootloader.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x0 -s --oformat binary -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;

kernel: kernel.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000 -s --oformat binary -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;</code></pre><p>e ficou assim:</p><pre><code>bootloader: bootloader.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x0 -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;

kernel: kernel.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000 -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;</code></pre><p>Mais simples n&#233;? Isso porque o formato ELF &#233; o padr&#227;o no Linux. Al&#233;m disso, removemos a flag <code>-s</code> pois isso remove os s&#237;mbolos de debug, o que est&#225; longe de ser nosso objetivo.</p><p>Aproveitando que estamos no <code>Makefile</code>, vamos criar o target <code>createimage</code>, que &#233; um programa que ler&#225; os ELFs e os unir&#225;.</p><pre><code>createimage: $(SRCDIR)/createimage.cpp
&#9;g++ -o $(OUTPUTDIR)/$@ $&lt;</code></pre><p>Aqui, uma diferen&#231;a em rela&#231;&#227;o ao c&#243;digo fornecido no trabalho P1: l&#225;, esse programa era escrito em C. At&#233; para diferenciar, resolvi fazer diferente. </p><p>Pensei em fazer em <em>Rust</em>, mas lembrei que n&#227;o sei <em>Rust</em>, pareceu pouco produtivo aprender outra linguagem de programa&#231;&#227;o para fazer s&#243; isso (NOTA DO EDITOR: <em>Rust </em>ser&#225; aprendida, eventualmente. Mas n&#227;o agora e n&#227;o para isso).</p><p>Parti ent&#227;o para o <em>Python</em>, e a manipula&#231;&#227;o de arquivos bin&#225;rios foi bem frustrante. Poss&#237;vel, mas frustrante. N&#227;o vale o esfor&#231;o. Decidi fazer ent&#227;o com um mix de C e C++ (ou como dizia meu professor, C+/-).</p><p>N&#227;o abri o c&#243;digo original, o c&#243;digo est&#225; estruturado para que os alunos alterem partes espec&#237;ficas e completem as fun&#231;&#245;es:</p><pre><code>read_exec_file(): Reads in an executable file in ELF format.
write_bootblock(): Writes the bootblock to the image file.
write_kernel(): Writes the kernel to the image file.
count_kernel_sectors(): Counts the number of sectors in the kernel.
record_kernel_sectors(): Tells the bootloader how many sectors the kernel has.
extended_opt(): Prints the information for --extended option.</code></pre><p>Eu n&#227;o entendo por exemplo porque h&#225; a fun&#231;&#227;o <code>extended_opt</code>, e o que &#233; feito de diferente se a fun&#231;&#227;o <code>&#8212;extended </code>n&#227;o for usada. Por mim isso nem seria uma op&#231;&#227;o mas o comportamento padr&#227;o do c&#243;digo. Tamb&#233;m n&#227;o sei quais par&#226;metros as fun&#231;&#245;es exigem, por isso vou fazer conforme as vozes da minha cabe&#231;a. Mas n&#227;o vou brigar com a banca, tentarei fazer seguindo essas instru&#231;&#245;es e por isso, em vez de escrever direto na sa&#237;da padr&#227;o (usando <code>cout </code>do C++), escreverei em uma <code>ostringstream</code>, servindo como um <em>string buffer</em>, e s&#243; ao final do processo mando isso para o console.</p><p>Ok, vamos l&#225;. Para abrir o arquivo ELF, entender sua estrutura para poder extrair as informa&#231;&#245;es necess&#225;rias, voc&#234; precisa conhecer as entranhas do cidad&#227;o. &#201; importante ler a <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/ELF_Format.pdf">documenta&#231;&#227;o</a>, mas adianto que n&#227;o &#233; necess&#225;rio ler tudo. Uma boa parte do conte&#250;do diz respeito a como um Sistema Operacional deve &#8220;ler&#8221; para carregar o execut&#225;vel na mem&#243;ria, incluindo bibliotecas compartilhadas, liga&#231;&#227;o din&#226;mica, a biblioteca padr&#227;o do C&#8230; Crian&#231;as, nada disso est&#225; dispon&#237;vel quando a m&#225;quina liga, n&#227;o h&#225; um SO que carregar&#225; tais componentes, afinal, n&#243;s somos o SO! Ent&#227;o, precisamos de duas coisas: ler o cabe&#231;alho do arquivo ELF, encontrar os cabe&#231;alhos do programa e com base neles, carregar os segmentos de interesse. Nem todo segmento possui um c&#243;digo execut&#225;vel, ent&#227;o precisamos tamb&#233;m identificar isso. Com base no que eu disse, vamos dar uma olhada no conte&#250;do dos arquivos ELF usando o utilit&#225;rio <code>readelf</code>. </p><p>Come&#231;ando pelo <em>Bootloader</em>:</p><pre><code>readelf -a ./build/bootloader
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          5132 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         1
  Size of section headers:           40 (bytes)
  Number of section headers:         9
  Section header string table index: 8

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 001000 0000a0 00  AX  0   0 16
  [ 2] .debug_aranges    PROGBITS        00000000 0010a0 000020 00      0   0  1
  [ 3] .debug_info       PROGBITS        00000000 0010c0 000069 00      0   0  1
  [ 4] .debug_abbrev     PROGBITS        00000000 001129 00001d 00      0   0  1
  [ 5] .debug_line       PROGBITS        00000000 001146 00007f 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 0011c8 000120 10      7  14  4
  [ 7] .strtab           STRTAB          00000000 0012e8 0000cc 00      0   0  1
  [ 8] .shstrtab         STRTAB          00000000 0013b4 000056 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x000a0 0x000a0 R E 0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .text 

There is no dynamic section in this file.

There are no relocations in this file.
No processor specific unwind information to decode

Symbol table '.symtab' contains 18 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS src/bootloader.asm
     2: 00000002     2 OBJECT  LOCAL  DEFAULT    1 os_size
     3: 00000006     1 OBJECT  LOCAL  DEFAULT    1 disk_index
     4: 00000007     1 OBJECT  LOCAL  DEFAULT    1 sectors_per_track
     5: 00000008     1 OBJECT  LOCAL  DEFAULT    1 number_of_heads
     6: 00000009     2 OBJECT  LOCAL  DEFAULT    1 current_lba_address
     7: 0000000b     0 NOTYPE  LOCAL  DEFAULT    1 load_kernel
     8: 0000002f     0 NOTYPE  LOCAL  DEFAULT    1 before_jump
     9: 00000034     0 NOTYPE  LOCAL  DEFAULT    1 new_boot_region
    10: 00000039     0 NOTYPE  LOCAL  DEFAULT    1 reset_disk
    11: 00000041     0 NOTYPE  LOCAL  DEFAULT    1 get_disk_parameters
    12: 00000061     0 NOTYPE  LOCAL  DEFAULT    1 read_sector
    13: 0000009b     0 NOTYPE  LOCAL  DEFAULT    1 end_read_sector
    14: 00000000     0 NOTYPE  GLOBAL DEFAULT    1 _start
    15: 00001000     0 NOTYPE  GLOBAL DEFAULT    1 __bss_start
    16: 00001000     0 NOTYPE  GLOBAL DEFAULT    1 _edata
    17: 00001000     0 NOTYPE  GLOBAL DEFAULT    1 _end

No version information found in this file.</code></pre><p>Do que nos interessa, &#233; ler esse cabe&#231;alho (<code>ELF Header</code>). Nele, perceba a informa&#231;&#227;o <code>Start of program headers:          52 (bytes into file)</code>. Isso significa que, partindo do primeiro byte desse arquivo ELF, se eu iniciar a leitura do offset 52 eu come&#231;arei a ler os dados dos cabe&#231;alhos do programa. E quantos bytes eu devo ler para identificar todos os cabe&#231;alhos do programa? Isso est&#225; na informa&#231;&#227;o <code>  Size of program headers:           32 (bytes)</code>.</p><p>Ok, e como lemos esse cabe&#231;alho ELF? O manual apresenta a estrutura que podemos usar:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!olr-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!olr-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 424w, https://substackcdn.com/image/fetch/$s_!olr-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 848w, https://substackcdn.com/image/fetch/$s_!olr-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 1272w, https://substackcdn.com/image/fetch/$s_!olr-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!olr-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png" width="1073" height="755" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:755,&quot;width&quot;:1073,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123395,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!olr-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 424w, https://substackcdn.com/image/fetch/$s_!olr-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 848w, https://substackcdn.com/image/fetch/$s_!olr-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 1272w, https://substackcdn.com/image/fetch/$s_!olr-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1369d4ba-15e4-43c9-82a7-f9a36e483fa3_1073x755.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Ent&#227;o, voc&#234; pode copiar essa estrutura ai, <em><strong>OOOOOOU</strong></em> voc&#234; faz igual eu fiz e uso a estrutura declarada no arquivo <code>elf.h</code>. No arquivo C/C++ basta declarar:</p><pre><code>#include &lt;elf.h&gt;</code></pre><p>Declarei portanto a fun&#231;&#227;o <code>read_exec_file</code><em> </em>que recebe o <code>std::ifstream exec_file </code>(lembre-se que estou usando C++). Eu declaro uma vari&#225;vel local <code>Elf32_Ehdr ehdr</code>, reservando portanto o espa&#231;o para lermos os dados do cabe&#231;alho do arquivo. Ao lermos a quantidade de bytes equivalente ao tamanho da estrutura (<code>sizeof(Elf32_Ehdr)</code>) e armazenando na vari&#225;vel <code>ehdr</code>, temos os dados que precisamos.</p><p>Ai basta rebobinar o arquivo (sabe o que &#233; isso jovem?) e, come&#231;ando do in&#237;cio do arquivo (<code>std::ios_base::beg</code>), posicionamos a cabe&#231;a de leitura imagin&#225;ria bem no ponto onde come&#231;am os cabe&#231;alhos do programa (<code>ehdr.e_phoff</code>). Essa parte inicial fica portanto assim:</p><pre><code>  exec_file.read(reinterpret_cast&lt;char *&gt;(&amp;ehdr), sizeof(Elf32_Ehdr));
  exec_file.seekg(ehdr.e_phoff, std::ios_base::beg);</code></pre><p>Porque usamos o <code>reinterpret_cast</code>? A fun&#231;&#227;o<code> read </code>de um objeto <code>std::ifstream </code>espera receber um ponteiro de char. Poder&#237;amos sim usar um <em>cast </em>normal, j&#225; que a estrutura <code>Elf32_Ehdr</code> n&#227;o &#233; um objeto C/C++ com comportamentos etc. Ent&#227;o, <code>(char *)&amp;ehdr funcionaria</code>, mas como estamos no maravilho mundo do C++, eu quero que a leitura comece a cuspir bytes na estrutura sem reclama&#231;&#245;es adicionais. Para mais informa&#231;&#245;es, veja <a href="https://en.cppreference.com/w/cpp/language/reinterpret_cast">aqui</a>.</p><p>Agora que estamos com a bala na agulha para ler os cabe&#231;alhos de programa, como fazemos isso? Vamos voltar &#224; sa&#237;da do nosso bom e velho <code>readelf </code>do <code>bootloader</code>:</p><pre><code>Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00000000 0x00000000 0x000a0 0x000a0 R E 0x1000</code></pre><p>N&#227;o parece t&#227;o complicado certo? N&#227;o t&#227;o r&#225;pido. Vamos ver os mesmos dados, mas para o <code>kernel</code>:</p><pre><code>Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x000b4 0x000b4 R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x60031 0x60031 R E 0x1000
  LOAD           0x062000 0x00062000 0x00062000 0x0000c 0x0000c R   0x1000
  LOAD           0x06200c 0x0006300c 0x0006300c 0x00001 0x00038 RW  0x1000</code></pre><p>Hum, ai come&#231;a a complicar. O <code>bootloader </code>possui 1 cabe&#231;alho de programa, enquanto o <code>kernel </code>possui 4. Um dos motivos dessa diferen&#231;a &#233; justamente aquelas se&#231;&#245;es que hav&#237;amos adicionado anteriormente, lembra? As se&#231;&#245;es <code>.bss</code>, <code>.data</code> e <code>.rdata</code>. Como ainda n&#227;o apresentamos a sa&#237;da do <code>readelf</code> para o <code>kernel</code>, faremos isso agora.</p><pre><code>readelf -a ./build/kernel
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x1000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          402300 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         4
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00001000 001000 060031 00  AX  0   0 16
  [ 2] .rdata            PROGBITS        00062000 062000 00000c 00   A  0   0  1
  [ 3] .data             PROGBITS        0006300c 06200c 000001 00  WA  0   0  4
  [ 4] .bss              NOBITS          00063010 06200d 000034 00  WA  0   0  4
  [ 5] .debug_aranges    PROGBITS        00000000 06200d 000020 00      0   0  1
  [ 6] .debug_info       PROGBITS        00000000 06202d 000065 00      0   0  1
  [ 7] .debug_abbrev     PROGBITS        00000000 062092 00001d 00      0   0  1
  [ 8] .debug_line       PROGBITS        00000000 0620af 00008f 00      0   0  1
  [ 9] .symtab           SYMTAB          00000000 062140 000130 10     10  15  4
  [10] .strtab           STRTAB          00000000 062270 0000a1 00      0   0  1
  [11] .shstrtab         STRTAB          00000000 062311 000068 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x000b4 0x000b4 R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x60031 0x60031 R E 0x1000
  LOAD           0x062000 0x00062000 0x00062000 0x0000c 0x0000c R   0x1000
  LOAD           0x06200c 0x0006300c 0x0006300c 0x00001 0x00038 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .text 
   02     .rdata 
   03     .data .bss 

There is no dynamic section in this file.

There are no relocations in this file.
No processor specific unwind information to decode

Symbol table '.symtab' contains 19 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS src/kernel.asm
     2: 00001002     0 NOTYPE  LOCAL  DEFAULT    1 print_char
     3: 00001016     0 NOTYPE  LOCAL  DEFAULT    1 print_string
     4: 00001020     0 NOTYPE  LOCAL  DEFAULT    1 loop_print_string
     5: 0000102c     0 NOTYPE  LOCAL  DEFAULT    1 end_print_string
     6: 00001031     0 NOTYPE  LOCAL  DEFAULT    1 kernel_entry
     7: 00001046     1 OBJECT  LOCAL  DEFAULT    1 msg
     8: 00031000     0 NOTYPE  LOCAL  DEFAULT    1 big_dummy_kernel
     9: 00031015     1 OBJECT  LOCAL  DEFAULT    1 big_msg
    10: 00061000     0 NOTYPE  LOCAL  DEFAULT    1 big_big_dummy_kernel
    11: 00061012     1 OBJECT  LOCAL  DEFAULT    1 big_big_msg
    12: 00063010     1 OBJECT  LOCAL  DEFAULT    4 bsssegtest
    13: 0006300c     1 OBJECT  LOCAL  DEFAULT    3 datasegtest
    14: 00062000     1 OBJECT  LOCAL  DEFAULT    2 teste
    15: 00001000     0 NOTYPE  GLOBAL DEFAULT    1 _start
    16: 00063010     0 NOTYPE  GLOBAL DEFAULT    4 __bss_start
    17: 0006300d     0 NOTYPE  GLOBAL DEFAULT    3 _edata
    18: 00063044     0 NOTYPE  GLOBAL DEFAULT    4 _end

No version information found in this file.</code></pre><p>Note que temos informa&#231;&#245;es ligando os cabe&#231;alhos de programa &#224;s se&#231;&#245;es. Veja abaixo:</p><pre><code>Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x000b4 0x000b4 R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x60031 0x60031 R E 0x1000
  LOAD           0x062000 0x00062000 0x00062000 0x0000c 0x0000c R   0x1000
  LOAD           0x06200c 0x0006300c 0x0006300c 0x00001 0x00038 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .text 
   02     .rdata 
   03     .data .bss </code></pre><p>Ent&#227;o, temos 4 cabe&#231;alhos de programa, e 4 se&#231;&#245;es de segmento. As se&#231;&#245;es <code>01</code>, <code>02 </code>e <code>03 </code>s&#227;o nossas conhecidas. Note tamb&#233;m as flags no cabe&#231;alho de programa: a se&#231;&#227;o <code>01</code> <code>.text</code> tem flag <code>R E </code>(Leitura e Execu&#231;&#227;o), a se&#231;&#227;o <code>02 .rdata </code>&#233; uma se&#231;&#227;o somente leitura (dai o nome, <code>rdata </code>&#233; referente a <em>read only data</em>) e possui somente a flag R, e a se&#231;&#227;o <code>03 .data .bss</code> &#233; auto explicativa, e devemos poder ler escrever dela, e dai tamb&#233;m as flags <code>RW</code>. A &#250;nica observa&#231;&#227;o interessante &#233; a fun&#231;&#227;o .bss, que apenas instrui quantos bytes devem ser reservados na mem&#243;ria para dados n&#227;o inicializados. Como isso &#233; apenas uma instru&#231;&#227;o, ele n&#227;o consome dados no <code>FileSiz </code>do segmento (esse <code>0x00001</code> byte &#233; referente &#224; variavel <code>datasegtest </code>no segmento<em> </em><code>.data</code><em>) </em>mas instrui que a mem&#243;ria alocada seja feita para isso (<code>MemSiz</code> igual a <code>0x00038 </code>contempla a mem&#243;ria tanto para as se&#231;&#245;es <code>.data</code> quanto para <code>.bss</code>).</p><p>Mas e quanto ao segmento de se&#231;&#227;o <code>00</code>? Se voc&#234; notar o offset est&#225; <code>0x000000 </code>e possui <code>MemSiz</code>/<code>FileSiz </code>igual a <code>0xb4</code>. O que &#233; isso afinal? Bom, se voc&#234; notar bem, Isso &#233; justamente os dados ocupados pelo ELF Header ( <code>sizeof(Elf32_Ehdr)</code><strong> = </strong>52 bytes<strong>) </strong>juntamente com os 4 cabe&#231;alhos de programa, o pr&#243;prio incluso. Como <code>sizeof(Elf32_Phdr)</code> = 32 bytes, temos que 52 + 4 * 32 = 180 = 0xb4! Ent&#227;o, a regra &#233; que se o cabe&#231;alho de programa tiver offset igual a zero, ele n&#227;o &#233; um c&#243;digo que deve ser extra&#237;do do arquivo ELF e nesse caso o ignoramos. Por que isso n&#227;o apareceu no <code>bootloader</code>, eu n&#227;o sei dizer.</p><p>Como o cabe&#231;alho ELF j&#225; possui quantos cabe&#231;alhos de programas h&#225; (<code>Number of program headers:         4)</code>, est&#225; bem f&#225;cil fazer a leitura desses caras. Basta iterar pelo campo <code>e_phnum </code>da estrutura <code>Elf32_Ehdr </code>e ler a estrutura <code>Elf32_Phdr </code>nos mesmos moldes que fizemos anteriores<strong>. </strong>No fim, a fun&#231;&#227;o<strong> </strong><code>read_exec_file </code>retorna um vetor de<em> </em><code>Elf32_Phdr</code>. A fun&#231;&#227;o completa fica assim:</p><pre><code>std::vector&lt;Elf32_Phdr&gt; read_exec_file(std::ifstream &amp;exec_file) {
  Elf32_Ehdr ehdr;
  exec_file.read(reinterpret_cast&lt;char *&gt;(&amp;ehdr), sizeof(Elf32_Ehdr));
  exec_file.seekg(ehdr.e_phoff, std::ios_base::beg);
  std::vector&lt;Elf32_Phdr&gt; program_headers;
  for (int i = 0; i &lt; ehdr.e_phnum; i++) {
    Elf32_Phdr ph;
    exec_file.read(reinterpret_cast&lt;char *&gt;(&amp;ph), sizeof(Elf32_Phdr));

    if (ph.p_offset &gt; 0) {
      /*offset 0 has ELF Header and Program Headers, it is not a Executable
       Code*/
      program_headers.insert(program_headers.end(), ph);
    }
  }
  return program_headers;
}</code></pre><p>Com o vetor <code>Elf32_Phdr</code> em m&#227;os, o trabalho &#233; iterar por esse vetor, e para cada cabe&#231;alho, localizar o programa no ELF (campo <code>p_offset </code>de <code>Elf32_Phdr</code>) e ler os bytes dispon&#237;veis (campo <code>p_filesz</code>). Jogamos isso em um vetor de bytes (usei o tipo <code>u_int8_t</code>, mas poderia ser<strong> </strong><code>char </code>tamb&#233;m). Se <code>p_memsz </code>for maior que <code>p_filesz</code>, ent&#227;o precisamos alocar mais espa&#231;o (caso da se&#231;&#227;o <code>.bss</code>). Outra informa&#231;&#227;o importante &#233; que os endere&#231;os dos cabe&#231;alhos de programa est&#227;o ordenados. Se dado um cabe&#231;alho de programa que n&#227;o seja o &#250;ltimo, se seu <code>PhysAddr + MemSiz</code> for menor que o <code>PhysAddr </code>do pr&#243;ximo cabe&#231;alho de programa, isso significa que h&#225; um espa&#231;o de <em>padding </em>que precisa ser inclu&#237;do entre os conte&#250;dos. Al&#233;m disso, se for o &#250;ltimo cabe&#231;alho de programa e ele tiver menos de 512 bytes, fazemos um <em>padding</em><code> </code>para atingir esse valor tamb&#233;m.</p><p>A fun&#231;&#227;o de extrair os segmentos para um vetor de bytes ficou assim:</p><pre><code>std::vector&lt;u_int8_t&gt; extract_segments(std::string exec_path,
                                       std::vector&lt;Elf32_Phdr&gt; ph,
                                       std::ifstream &amp;exec_file,
                                       std::ostringstream &amp;extended_string) {
  std::vector&lt;u_int8_t&gt; exec_bytes;

  extended_string &lt;&lt; "0x" &lt;&lt; std::hex &lt;&lt; std::setw(4) &lt;&lt; std::setfill('0')
                  &lt;&lt; ph[0].p_vaddr &lt;&lt; ": " &lt;&lt; exec_path &lt;&lt; std::endl;

  for (int i = 0; i &lt; ph.size(); i++) {
    extended_string &lt;&lt; "\tsegment " &lt;&lt; i &lt;&lt; std::endl;
    extended_string &lt;&lt; "\t\toffset 0x" &lt;&lt; std::hex &lt;&lt; std::setw(4)
                    &lt;&lt; std::setfill('0') &lt;&lt; ph[i].p_offset &lt;&lt; "\t vaddr 0x"
                    &lt;&lt; std::hex &lt;&lt; std::setw(4) &lt;&lt; std::setfill('0')
                    &lt;&lt; ph[i].p_vaddr &lt;&lt; std::endl;
    extended_string &lt;&lt; "\t\tfilesz 0x" &lt;&lt; std::hex &lt;&lt; std::setw(4)
                    &lt;&lt; std::setfill('0') &lt;&lt; ph[i].p_filesz &lt;&lt; "\t memsz 0x"
                    &lt;&lt; std::hex &lt;&lt; std::setw(4) &lt;&lt; std::setfill('0')
                    &lt;&lt; ph[i].p_memsz &lt;&lt; std::endl;

    exec_file.seekg(ph[i].p_offset, std::ios_base::beg);
    uint8_t buff[ph[i].p_filesz];
    exec_file.read(reinterpret_cast&lt;char *&gt;(buff), ph[i].p_filesz);
    exec_bytes.insert(exec_bytes.end(), buff, buff + ph[i].p_filesz);

    if (ph[i].p_filesz &lt; ph[i].p_memsz) {
      exec_bytes.insert(exec_bytes.end(), ph[i].p_memsz - ph[i].p_filesz,
                        uint8_t(0));
    }

    if (i != ph.size() - 1 &amp;&amp;
        ph[i].p_vaddr + ph[i].p_memsz &lt; ph[i + 1].p_vaddr) {
      exec_bytes.insert(exec_bytes.end(),
                        ph[i + 1].p_vaddr - (ph[i].p_vaddr + ph[i].p_memsz),
                        uint8_t(0));
      extended_string &lt;&lt; "\t\tpadding up to 0x" &lt;&lt; std::hex &lt;&lt; std::setw(4)
                      &lt;&lt; std::setfill('0') &lt;&lt; ph[i + 1].p_vaddr &lt;&lt; std::endl;
    } else if (i == ph.size() - 1 &amp;&amp; exec_bytes.size() % SECTOR_SIZE &gt; 0) {
      extended_string &lt;&lt; "\t\tpadding up to 0x" &lt;&lt; std::hex &lt;&lt; std::setw(4)
                      &lt;&lt; std::setfill('0')
                      &lt;&lt; ph[i].p_vaddr + ph[i].p_memsz +
                             (SECTOR_SIZE - (exec_bytes.size() % SECTOR_SIZE))
                      &lt;&lt; std::endl;
      exec_bytes.insert(exec_bytes.end(), SECTOR_SIZE - (exec_bytes.size() % SECTOR_SIZE),
                        uint8_t(0));
    }
  }

  return exec_bytes;
}</code></pre><p>Acabamos com dois vetores de bytes, um representando o bin&#225;rio do <code>bootloader </code>e outro representando o bin&#225;rio do <code>kernel</code>. Precisamos agora ler quantos setores o bin&#225;rio do <code>kernel </code>possui e escrever essa informa&#231;&#227;o, na posi&#231;&#227;o correta no <code>bootloader</code>. Come&#231;ando ent&#227;o pela contagem dos bytes do <code>kernel</code>, n&#227;o h&#225; muito segredo. Dividimos o n&#250;mero de bytes do <code>kernel </code>por 512 (tamanho de um setor) e pegamos a parte inteira da divis&#227;o. Se essa divis&#227;o tiver resto, significa que precisamos ler um setor a mais para contemplar o restante dos dados. Nada de mais portanto. A fun&#231;&#227;o <code>count_kernel_sectors </code>ficou assim:</p><pre><code>uint32_t count_kernel_sectors(std::vector&lt;u_int8_t&gt; &amp;exec_bytes,
                              std::ostringstream &amp;extended_string) {
  uint32_t os_size = exec_bytes.size() % SECTOR_SIZE != 0
                         ? uint32_t(exec_bytes.size() / SECTOR_SIZE) + 1
                         : uint32_t(exec_bytes.size() / SECTOR_SIZE);

  extended_string &lt;&lt; "os_size: " &lt;&lt; std::dec &lt;&lt; os_size &lt;&lt; " sectors"
                  &lt;&lt; std::endl;
  return os_size;
}</code></pre><p>Note que estamos retornando um <code>uint32_t</code>, que &#233; um inteiro de 32 bits sem sinal. Precisamos escrever esse n&#250;mero a partir do byte 2 do <code>booloader </code>(os dois primeiros bytes s&#227;o a instru&#231;&#227;o<code> jmp load_kernel)</code><em>. </em>A gente faz uma gin&#225;stica com os ponteiros, pego o segundo byte do vetor de bytes do <code>bootloader</code>, pego o endere&#231;o desse byte, fa&#231;o um <em>cast </em>para falar que quero um ponteiro para um <code>uint32_t </code>nessa posi&#231;&#227;o, e falo que o conte&#250;do desse endere&#231;o tem na verdade o valor <code>os_size</code><em><strong>. </strong></em>A fun&#231;&#227;o <code>record_kernel_sectors </code>fica assim<em>:</em></p><pre><code>void record_kernel_sectors(uint32_t os_size,
                           std::vector&lt;u_int8_t&gt; &amp;exec_bootloader_bytes) {
  (*(uint32_t *)&amp;exec_bootloader_bytes[2]) = os_size;
}</code></pre><p>A arquitetura &#233; <em>little endian</em>, ent&#227;o o compilador j&#225; se encarrega de escrever os bytes menos significativos primeiro. Isso &#233; o que nosso <em>bootloader </em>espera ent&#227;o est&#225; tudo certo.</p><p>Depois, &#233; s&#243; escrever no arquivo de sa&#237;da <code>boringos.img</code>, primeiro o vetor de bytes do <code>bootloader</code>, e depois o vetor de bytes do <code>kernel</code>. Esse trecho fica assim:</p><pre><code>  std::ofstream kernelimage("./build/boringos.img");
  kernelimage.write(reinterpret_cast&lt;char *&gt;(&amp;bootloader_bytearray[0]),
                    bootloader_bytearray.size());
  kernelimage.write(reinterpret_cast&lt;char *&gt;(&amp;kernel_bytearray[0]),
                    kernel_bytearray.size());</code></pre><p>Ufa, &#233; isso. O c&#243;digo completo est&#225; no meu <a href="https://github.com/rodrigogbranco/boring-os/tree/p1-v6">github</a>. Se voc&#234; rodar um <code>make clean &amp;&amp; make</code>, e rodar o <code>QEMU+gdb,</code> o resultado ser&#225; id&#234;ntico ao trabalho anterior. O que voc&#234; pode fazer de diferente &#233; ver o conte&#250;do da mem&#243;ria dos novos segmentos, em especial o <code>.rdata</code> e <code>.data</code>. Fa&#231;a isso, obviamente, depois que o <code>kernel </code>j&#225; estiver carregado na mem&#243;ria (coloquei um break point em <code>big_big_dummy_kernel </code>com o comando <code>hb *big_big_dummy_kernel</code>):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SD-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SD-c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 424w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 848w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 1272w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SD-c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png" width="828" height="583" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4678cda-90f1-4959-86d5-ed4023809792_828x583.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:583,&quot;width&quot;:828,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79475,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SD-c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 424w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 848w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 1272w, https://substackcdn.com/image/fetch/$s_!SD-c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4678cda-90f1-4959-86d5-ed4023809792_828x583.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Aparentemente, conseguimos ler o arquivo ELF do <em>kernel </em>certinho, o conte&#250;do das se&#231;&#245;es <code>.rdata</code> e <code>.bss</code> &#233; esse mesmo apresentado na imagem acima, como era o nosso objetivo! </p><p>Com isso fechamos o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">P1</a>, e vamos para o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project2/p2.html">P2</a>. Esse pr&#243;ximo trabalho espera que construamos um <em>kernel </em>n&#227;o-preemptivo. Mas j&#225; vi aqui que o <em>bootloader </em>do P2 faz mais do que estamos fazendo no nosso c&#243;digo atual, ele entra em modo protegido e ent&#227;o o <em>kernel </em>j&#225; pode ser escrito em C/C++ com registradores de 32 bits. Mas tem bastante coisa pra fazer antes disso. O quanto, s&#243; botando a m&#227;o na massa pra saber&#8230;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/big-big-dummy-kernel?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/big-big-dummy-kernel?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/a20-gate-hell-e-protected-mode?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[Big Big Dummy Kernel]]></title><description><![CDATA[Nos preparando para carregar um kernel de tamanho arbitr&#225;rio]]></description><link>https://blog.rodrigobranco.net/p/big-big-dummy-kernel</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/big-big-dummy-kernel</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Sun, 10 Nov 2024 17:37:01 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hPVw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hPVw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hPVw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hPVw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:165776,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hPVw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!hPVw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17cc2092-029d-48f2-b487-bc2f2029e9a4_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>No <a href="https://blog.rodrigobranco.net/p/dummy-kernel">artigo anterior</a>, movemos o <em>bootloader </em>para o endere&#231;o <code>0x80000</code> e carregamos um <em>dummy kernel</em> de apenas um setor (512 bytes) no endere&#231;o<code> 0x1000</code>. Neste artigo, vamos engordar esse <em>dummy kernel</em> para que ele tenha muitos setores, de forma que precisaremos carregar muitos setores do disco para o endere&#231;o <code>0x1000</code>.</p><p>E como engordamos nosso <em>kernel</em>? Vou explicar o que fiz e depois explico os detalhes s&#243;rdidos. A primeira parte possui algumas pequenas altera&#231;&#245;es, mas no geral permanece da mesma forma:  as fun&#231;&#245;es <code>print_char</code>, <code>print_string</code> e o ponto de entrada <code>kernel_entry</code>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscrever&quot;,&quot;language&quot;:&quot;pt&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Obrigado por ler Blog do Rodrigo Branco! Subscreva gratuitamente para receber novos posts e apoiar o meu trabalho.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Digite o seu e-mail..." tabindex="-1"><input type="submit" class="button primary" value="Subscrever"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><pre><code>[BITS 16]

%include "src/constants.asm"

global _start

_start:
    jmp kernel_entry

print_char:
    push bp
    mov bp, sp

    push ax
    push bx

    mov ax, [bp+4]
    mov ah, BIOS_INT_10H_OUTPUT
    mov bh, BIOS_INT_10H_PAGE_NUMBER_0
    mov bl, BIOS_INT_10H_FOREGROUND_COLOR_GM
    int BIOS_INT_10H

    pop bx
    pop ax

    pop bp

    ret

print_string:
    push bp
    mov bp, sp

    push ax
    push bx
    push si

    mov si, [bp+6]

    cld
loop_print_string:
    lodsb

    cmp al, NULL_CHARACTER
    je end_print_string

    push ax
    call print_char
    pop ax
    jmp loop_print_string

end_print_string:
    pop si
    pop bx
    pop ax

    pop bp

    retf

kernel_entry:
    mov ax, cs
    mov ds, ax
    mov es, ax

    mov ax, msg
    push ax
    call KERNEL_SEGMENT:print_string
    pop ax

    jmp 0x3000:big_dummy_kernel

msg db "Dummy Kernel Loaded!", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER</code></pre><p>At&#233; aqui tudo bem? O c&#243;digo come&#231;a em _start e pula para <code>kernel_entry</code>. Ali ele corrige os registradores de segmento e invoca a fun&#231;&#227;o <code>print_string </code>(j&#225; explico altera&#231;&#227;o nessa chamada). Depois de corrigir a pilha, ele pula para outro endere&#231;o, bem longe do endere&#231;o <code>0x1000</code> onde esse c&#243;digo est&#225; rodando: ele passa o controle para <code>0x3000:big_dummy_kernel</code>, que &#233; depois do endere&#231;o absoluto <code>0x30000</code>.</p><p>Vamos &#224;s explica&#231;&#245;es das altera&#231;&#245;es ent&#227;o. Primeiro, estamos chamando a fun&#231;&#227;o <code>print_string </code>de uma forma diferente. Onde antes era <code>call print_string</code>, agora fazemos <code>call KERNEL_SEGMENT:print_string</code>, conhecido como <em>far call</em>. Na primeira vers&#227;o, o <code>call </code>chama o r&#243;tulo dentro de 16 bits de deslocamento dentro do mesmo segmento de c&#243;digo. Como pretendemos que o c&#243;digo que est&#225; depois de <code>0x30000</code> tamb&#233;m chame essa fun&#231;&#227;o <code>print_string</code>, o c&#243;digo que est&#225; l&#225; precisa apontar onde est&#225; o segmento de c&#243;digo da fun&#231;&#227;o <code>print_string!</code></p><p>H&#225; mais alguma altera&#231;&#227;o importante nessa chamada? Sim, afinal, quando a fun&#231;&#227;o <code>print_string </code>terminar sua execu&#231;&#227;o, como ele vai saber o segmento original do c&#243;digo que chamou a fun&#231;&#227;o (no nosso exemplo, o c&#243;digo rodando ap&#243;s o endere&#231;o 0x30000)? Essa forma de chamar a instru&#231;&#227;o <code>call </code>(<em>far call</em>) empilha o registrador <code>cs </code>na pilha. Assim, ao retornar da fun&#231;&#227;o, recuperamos essa informa&#231;&#227;o da pilha e restauramos o segmento de c&#243;digo de quem chamou a fun&#231;&#227;o. Isso por si s&#243; inclui duas altera&#231;&#245;es importantes que a fun&#231;&#227;o <code>print_string </code>precisa tratar:</p><ol><li><p>H&#225; agora um argumento adicional na pilha: o registrador <code>cs</code>. A forma de recuperar o argumento do par&#226;metro que ser&#225; impresso na fun&#231;&#227;o &#233; portanto deslocado em dois bytes</p></li><li><p>Ao retornar, precisamos alterar o registrador <code>cs</code>. Por sorte, h&#225; uma instru&#231;&#227;o que faz isso: <code>retf</code>. J&#225; explico como ela funciona.</p></li></ol><p>Antes de prosseguirmos, apresento como fica a pilha quando a fun&#231;&#227;o <code>print_string </code>&#233; invocada junto com a execu&#231;&#227;o das duas primeiras instru&#231;&#245;es (<code>push bp </code>e<code> mov bp, sp</code>).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C-fu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C-fu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 424w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 848w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 1272w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C-fu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png" width="1022" height="271" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:271,&quot;width&quot;:1022,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63171,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C-fu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 424w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 848w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 1272w, https://substackcdn.com/image/fetch/$s_!C-fu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca62376e-c2ed-44e7-bb72-101ae29f429b_1022x271.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Lembrem-se que a pilha cresce para baixo (conforme vamos adicionando elementos na pilha, o endere&#231;o do registrador <code>sp </code>diminui). A imagem mostra que apareceu um elemento adicional na pilha (no caso, o registrador <code>cs</code>). Quando anteriormente acess&#225;vamos o par&#226;metro <code>msg </code>com <code>[bp+4]</code>, como cada par&#226;metro da pilha de 16 bits possui dois bytes, agora acessamos com <code>[bp+6]</code>.</p><p>Outra altera&#231;&#227;o &#233; que a instru&#231;&#227;o de retorno da fun&#231;&#227;o precisa corrigir essa pilha, e mais do que isso, saber para qual segmento de c&#243;digo a execu&#231;&#227;o deve retornar. Por isso, usamos a forma <em>far call</em>: enquanto a fun&#231;&#227;o <code>call </code>normal desempilha o endere&#231;o de retorno (par&#226;metro <code>ret </code>na primeira imagem), o <em>far call</em> desempilha o endere&#231;o de retorno E o segmento de c&#243;digo de retorno (par&#226;metros <code>ret </code>e <code>cs </code>na segunda imagem).</p><p>Uma coisa que voc&#234; pode indagar &#233;: u&#233;, se o c&#243;digo est&#225; em outro segmento, o par&#226;metro msg tamb&#233;m n&#227;o pode estar? E a resposta &#233; sim, veremos que empilhamos um par&#226;metro que est&#225; no mesmo segmento do c&#243;digo. A diferen&#231;a &#233; que nesse caso, ao entrar nesses novos pontos de entrada do kernel (apresentaremos a seguir), os registradores <code>ds </code>e <code>es </code>s&#227;o corrigidos para  o mesmo segmento do c&#243;digo. Isso significa que a instru&#231;&#227;o <em>far call</em> armazena e altera o segmento de c&#243;digo, mas os outros permanecem inalterados. Como as instru&#231;&#245;es que buscam os dados da mem&#243;ria usam tais registradores implicitamente se nenhum segmento for explicitamente informado (como por exemplo, a fun&#231;&#227;o <code>mov</code>), acessamos os endere&#231;os corretos por tabela.</p><p>Temos outra implica&#231;&#227;o desse fato: a fun&#231;&#227;o <code>print_char </code>&#233; invocada pela fun&#231;&#227;o <code>print_string</code>. As duas fun&#231;&#245;es j&#225; est&#227;o no mesmo segmento de c&#243;digo, portanto a fun&#231;&#227;o <code>print_string </code>invoca a fun&#231;&#227;o <code>print_char</code>, usando a instru&#231;&#227;o <code>call </code>que j&#225; conhecemos, e por esse motivo o acesso ao par&#226;metro na pilha permanece <code>[bp+4]</code> e o retorno tamb&#233;m permanece <code>ret</code>.</p><p>Agora que explicamos o funcionamento do c&#243;digo, vamos ver como ele fica depois da fronteira do endere&#231;o <code>0x30000</code>.</p><pre><code>...

msg db "Dummy Kernel Loaded!", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER

TIMES 0x30000-($-$$) DB 0

big_dummy_kernel:
    mov ax, cs
    mov ds, ax
    mov es, ax

    mov ax, big_msg
    push ax
    call KERNEL_SEGMENT:print_string
    pop ax

    jmp 0x6000:big_big_dummy_kernel

big_msg db "Big Dummy Kernel Loaded!", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER   

TIMES 0x60000-($-$$) DB 0

big_big_dummy_kernel:
    mov ax, cs
    mov ds, ax
    mov es, ax

    mov ax, big_big_msg
    push ax
    call KERNEL_SEGMENT:print_string
    pop ax

    jmp $

big_big_msg db "Big Big Dummy Kernel Loaded!", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER</code></pre><p>Perceba que agora que entendemos o funcionamento da fun&#231;&#227;o <code>KERNEL_SEGMENT:print_string</code>, pouco fizemos de diferente comparando com o caso da primeira invoca&#231;&#227;o dessa fun&#231;&#227;o. Depois da string <code>&#8220;Dummy Kernel Loaded!&#8221;</code>, atochamos zeros para completar o c&#243;digo at&#233; o endere&#231;o 0x30000. Ai ajustamos os segmentos, empilhamos uma nova mensagem a ser apresentada (<code>"Big Dummy Kernel Loaded!"</code>) e executamos a instru&#231;&#227;o <em>far call</em> para invocar a <code>print_string</code>. Depois do retorno da fun&#231;&#227;o, pulamos para um endere&#231;o mais longe ainda, o <code>0x60000</code>. E o procedimento &#233; repetido, mas para a mensagem <code>"Big Big Dummy Kernel Loaded!".</code></p><p>Se tudo der certo, o que &#233; esperado &#233; a tela abaixo, que indica que estamos fazendo chamadas <em>cross-segment</em> e que nossa pilha est&#225; sendo corretamente manipulada.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CiyN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CiyN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 424w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 848w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 1272w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CiyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png" width="719" height="463" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:463,&quot;width&quot;:719,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14699,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CiyN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 424w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 848w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 1272w, https://substackcdn.com/image/fetch/$s_!CiyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22f3a7a2-2c4a-44dd-a9e7-fd276eac7084_719x463.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Contudo, pequeno gafanhoto, em que momento esse monte de bytes desse <em>Big Big Dummy Kernel</em> foi carregado do disco para a mem&#243;ria? Pois &#233;, eu ainda n&#227;o mostrei esse c&#243;digo. Isso faz parte do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html#extracredit">cr&#233;dito extra no P1</a>.</p><p>Primeiro, vamos ver qual &#233; o tamanho desse <em>dummy kernel</em>, para saber quantos setores eu preciso carregar do disco para a mem&#243;ria. Depois de compilado, o comando <code>wc build/kernel</code> mostra quantos bytes tem o arquivo.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6atV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6atV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 424w, https://substackcdn.com/image/fetch/$s_!6atV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 848w, https://substackcdn.com/image/fetch/$s_!6atV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 1272w, https://substackcdn.com/image/fetch/$s_!6atV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6atV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png" width="706" height="45" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:45,&quot;width&quot;:706,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6731,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6atV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 424w, https://substackcdn.com/image/fetch/$s_!6atV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 848w, https://substackcdn.com/image/fetch/$s_!6atV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 1272w, https://substackcdn.com/image/fetch/$s_!6atV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9df23e17-a5d9-46b6-8757-774b601fdd7f_706x45.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ok, ent&#227;o esse arquivo possui 393265 bytes. Como cada setor possui 512 bytes, ent&#227;o devemos ler 768,095703125 setores. N&#227;o conseguimos ler um setor de forma parcial, precisaremos ler esse setor inteiro. Ent&#227;o, ler 769 setores do disco &#233; suficiente nesse caso e inclusive facilita nossa vida. A primeira altera&#231;&#227;o portanto &#233; quantos setores do OS/Kernel ser&#227;o lidos, e o arquivo bootloader.asm fica da seguinte forma:</p><pre><code>os_size: ;in sectors
    dw 769, 0</code></pre><p>Alterei o <code>disk_index </code>de <code>db 0xff</code> para <code>db 11111111</code>b. Perceba que <code>0xff</code> &#233; igual a <code>11111111</code>b, ent&#227;o nada muda. Ent&#227;o, para que se importar com isso? O lance aqui &#233; deixar expl&#237;cito que todos os bytes dessa vari&#225;vel est&#227;o setados com 1 quando esse c&#243;digo &#233; executado. &#201; esperado que o <em>bootloader </em>altere essa vari&#225;vel na mem&#243;ria com o valor do registrador <code>dl</code>, e valores comuns s&#227;o <code>0x0 </code>(floppy), <code>0x80 </code>(primeiro HD), <code>0x81 </code>(segundo HD), etc. Assim, fica f&#225;cil acompanhar essa altera&#231;&#227;o no <em>debugger </em>e identificar se h&#225; algum erro nesse processo.</p><p>Agora come&#231;a a complica&#231;&#227;o. Se pud&#233;ssemos tratar o disco como um conjunto cont&#237;guo de bytes na mem&#243;ria, agrupados em blocos de 512 bytes (os famigerados setores), poder&#237;amos pedir para ler depois de 512 bytes (esses primeiros pertencem ao <em>bootloader</em>) at&#233; onde gostar&#237;amos, nesse caso, 769 setores ap&#243;s o primeiro setor. Para dispositivos mais novos, isso j&#225; existe e se chama <a href="https://en.wikipedia.org/wiki/Logical_block_addressing">LBA</a>. O esquema LBA permite endere&#231;ar blocos no disco, come&#231;ando do bloco 0 linearmente at&#233; o fim do disco. BIOS mais novas possuem extens&#245;es da INT 13h que permitem ler discos usando esse esquema. Contudo, controladoras de disco mais antigas e BIOS mais antigas n&#227;o possuem esse luxo. Nesse caso vamos com o bom (bom pra quem?) e velho (bota velho nisso) esquema <a href="https://en.wikipedia.org/wiki/Cylinder-head-sector">CHS</a>.</p><p>N&#243;s sabemos exatamente quais blocos queremos ler. Nesse artigo queremos ler do segundo setor (endere&#231;o LBA 1) at&#233; o fim do arquivo kernel (endere&#231;o LBA 769). Precisamos transformar esses endere&#231;os no padr&#227;o de cilindros, cabe&#231;as, trilha e setores.</p><p>Para quem programou em C/C++, provavelmente voc&#234; j&#225; encarou o problema de acessar um byte arbitr&#225;rio em uma matriz 3D alocada de forma cont&#237;gua. Voc&#234; pode encarar uma matriz 3D como v&#225;rias matrizes 2D dispostas uma ao lado da outra. H&#225; v&#225;rias formas de se encarar esse problema, e v&#225;rias solu&#231;&#245;es poss&#237;veis. Para mais informa&#231;&#245;es, veja <a href="https://acervolima.com/como-alocar-dinamicamente-uma-matriz-3d-em-c/">aqui</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vmHU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vmHU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 424w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 848w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 1272w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vmHU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png" width="825" height="670" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:825,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:141229,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vmHU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 424w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 848w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 1272w, https://substackcdn.com/image/fetch/$s_!vmHU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61a24921-7597-4f77-bbe6-02d9795d2925_825x670.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Arranjo f&#237;sico dos elementos de leitura de um disco. Fonte: https://en.wikipedia.org/wiki/Cylinder-head-sector</figcaption></figure></div><p>Para encontrar um bloco arbitr&#225;rio na estrutura da imagem acima, precisamos identificar em qual setor, em qual trilha, em qual cabe&#231;a e em qual cilindro est&#225; o nosso dado. Precisamos de algumas informa&#231;&#245;es adicionais para isso:</p><ul><li><p>Quantos setores por trilha esse disco possui?</p></li><li><p>Quantas cabe&#231;as esse disco possui?</p></li></ul><p>Com essas informa&#231;&#245;es j&#225; conseguimos fazer um c&#225;lculo LBA para CHS. Definimos portanto mais tr&#234;s vari&#225;veis:</p><pre><code>sectors_per_track:
    db 0

number_of_heads:
    db 0

current_lba_address: ; second sector
    dw 1 </code></pre><p>Come&#231;amos do segundo setor (LBA 1) com a vari&#225;vel <code>current_lba_address</code>. As outras duas vari&#225;veis dizem respeito &#224;s perguntas feitas anteriormente e j&#225; verificamos como conseguimos tais dados.</p><p>Antes, fixamos <code>os_size </code>como 1 e solicitamos a interrup&#231;&#227;o <code>BIOS 13h</code> que lesse apenas um setor, no endere&#231;o CHS 0,0,2 (pois diferente do LBA, os setores s&#227;o indexados a partir de 1). Agora temos um n&#250;mero bem maior em <code>os_size. </code></p><p>Primeiro de tudo, n&#243;s resetamos o sistema do disco:</p><pre><code>    ; let's reset the disk system first
reset_disk:
    mov dl, [disk_index]
    mov ah, BIOS_INT_13H_RESET_DISK_SYSTEM
    jc reset_disk ; reset went wrong. Try again</code></pre><p>Isso serve pois n&#227;o sabemos em que estado est&#225; o hardware do disco, precisamos que ele esteja pronto para receber nossas requisi&#231;&#245;es de leitura. Inclusive, se a leitura for mal sucedida (<em>Carrier Flag</em> esteja setada), saltamos para tentar fazer o reset novamente.</p><p>Depois disso, vamos obter a geometria do disco, ou seja, responder &#224;s perguntas feitas anteriormente:</p><pre><code>    ; let's get disk geometry
    mov ah, BIOS_INT_13H_GET_DISK_GEOMETRY
    push es
    xor di, di
    mov es, di ; hack to get es:di = 0x0000:0x0000
    int BIOS_INT_13H
    pop es</code></pre><p>O comando em si &#233; apenas o <code>mov ah, BIOS_INT_13H_GET_DISK_GEOMETRY e int BIOS_INT_13H.</code> O restante do c&#243;digo est&#225; presente pois algumas BIOS possuem um bug e se os registradores <code>es:di </code>n&#227;o possuirem os valores <code>0x0000:0x0000 </code>essa <em>query </em>retorna valores inv&#225;lidos. Ent&#227;o estou apenas salvando o valor antigo de <em>es</em> e zerando ele junto com o registrador <em>di</em>.</p><p>A essa interrup&#231;&#227;o retorna o &#237;ndice da &#250;ltima cabe&#231;a no registrador <code>dh </code>(iniciando de zero), portanto, ao adicionar 1 nesse valor temos o n&#250;mero total de cabe&#231;as do disco. O registrador <code>cl </code>retorna o n&#250;mero total de setores por trilha (come&#231;ando em um). Contudo, apenas os 6 bits menos significativos desse registrador representam o n&#250;mero de setores por trilha, portanto temos valores v&#225;lidos entre 1 a 63. Os outros dois bits s&#227;o os dois bits mais significativos do &#237;ndice do &#250;ltimo cilindro do disco, que em comp&#245;em esse valor em conjunto com os outros 8 bits do registrador <code>ch</code>. Por sorte, nosso dummy kernel n&#227;o &#233; t&#227;o grande assim para termos que fazer qualquer tipo de checagem de fronteiras no n&#250;mero de cilindros, a ponto de n&#227;o precisarmos nem armazenar esse valor. Temos apenas que garantir que vamos obter apenas os &#250;ltimos 6 bits do registrador cl, e podemos fazer isso com a m&#225;scara <code>BIOS_INT_13H_SECTOR_MASK </code>(valor <code>00111111b</code>) e a instru&#231;&#227;o <code>and</code>. Dessa forma, os &#250;ltimos bits do registrador <code>cl </code>s&#227;o descartados e como n&#227;o vamos us&#225;-los agora, isso &#233; exatamente o que precisamos para o momento. Esse trecho fica portanto assim:</p><pre><code>    mov [number_of_heads], dh
    inc byte [number_of_heads]

    and cl, BIOS_INT_13H_SECTOR_MASK
    mov [sectors_per_track], cl</code></pre><p>Agora, j&#225; sabemos quantos setores por trilha esse disco tem, e quantas cabe&#231;as tamb&#233;m.</p><p>O destino da c&#243;pia voc&#234; j&#225; conhece, vamos copiar os setores para o endere&#231;o <code>es:bx</code>, portanto:</p><pre><code>    ; we'll copy sectors to here
    mov bx, KERNEL_SEGMENT
    mov es, bx</code></pre><p>Agora vem a parte mais dif&#237;cil: indicar para a interrup&#231;&#227;o a partir de qual setor devemos ler. Para exemplificar, vamos usar exemplos n&#250;meros e figuras. Suponha que voc&#234; deseje ler endere&#231;o LBA 105 do disco. Esse disco possui uma geometria com 36 setores por trilha e duas cabe&#231;as (ou seja, &#233; um floppy disc). Ter&#237;amos algo do tipo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1XLs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1XLs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 424w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 848w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 1272w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1XLs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png" width="931" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:490,&quot;width&quot;:931,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:118313,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1XLs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 424w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 848w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 1272w, https://substackcdn.com/image/fetch/$s_!1XLs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F136fa636-0c7b-4983-8ca1-704160c89f91_931x490.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Relembrando um pouquinho das aulas de Matem&#225;tica Discreta e &#193;lgebra, para o setor LBA 105, com 36 setores por trilha, precisamos de 2*36 + 33 setores. Com a opera&#231;&#227;o de m&#243;dulo (resto da divis&#227;o), 105 mod 36 &#233; igual a 33. Contudo, os setores iniciam em 1, ent&#227;o precisamos somar 1 para que a chamada da interrup&#231;&#227;o BIOS 13h ocorra de forma correta.</p><p>Pegando a parte inteira dessa divis&#227;o, n&#243;s obtemos o n&#250;mero da trilha (105 dividido por 36 d&#225; 2 e uns quebrados). Isso bate com nossa figura, track 2. Mas com duas cabe&#231;as, temos os &#237;ndices de cabe&#231;a variando de 0 a 1. Portanto, precisamos pegar o n&#250;mero da trilha e tamb&#233;m usar a opera&#231;&#227;o m&#243;dulo. Assim, 2 (n&#250;mero da trilha) mod 2 (n&#250;mero de cabe&#231;as do disco) &#233; igual a zero, ent&#227;o nossa cabe&#231;a &#233; 0 (head 0 na figura). Para encontrar o cilindro, basta pegar a parte inteira da divis&#227;o do n&#250;mero da trilha com o n&#250;mero de cabe&#231;as do disco: 2 div 2 &#233; igual a 1, portanto, cilindro 1, conforme nossa figura apresenta. Assim, o endere&#231;o LBA 105 &#233; igual ao endere&#231;o CHS (1,0,34) para esta geometria de disco de 36 setores por trilha e 2 cabe&#231;as. Se quiser olhar mais a esse respeito, veja <a href="http://www.osdever.net/tutorials/view/lba-to-chs">aqui</a>.</p><p>Vamos ver como fica nosso c&#243;digo:</p><pre><code>read_sector:
    ; which Logical Block Address do we have to copy now? 
    mov ax, [current_lba_address]

    ; have we reached the end?
    cmp ax, word [<code>os_size</code>]
    jg end_read_sector

    ; not yet, lets get CHS parameters
    mov bl, [sectors_per_track]
    div bl
    inc ah
    mov cl, ah ; here, we know which sector we start
    xor ah, ah ; al has the track number. 

    div byte [number_of_heads]
    mov dh, ah ; now we get the head number...
    mov ch, al ; ... and the cylinder number. We have all we need.</code></pre><p>Come&#231;amos verificando qual endere&#231;o LBA vamos converter (come&#231;a em 1, representando o setor 2 no disco, que &#233; o primeiro setor logo ap&#243;s o bootloader). Depois verificamos se j&#225; chegamos ao fim da leitura, ou seja <code>current_lba_address </code>&#233; igual ao <code>os_size</code>, e <code>current_lba_address</code> &#233; incrementado a cada leitura. Em caso negativo, ainda h&#225; leitura de setores a ser feita.</p><p>Ent&#227;o, ax possui o endere&#231;o LBA. Ao colocar <code>sectors_per_track</code> e executar a instru&#231;&#227;o <code>div bl</code>, o resto da opera&#231;&#227;o fica no registrador <code>ah</code> e o quociente em <code>al</code>. Significa que <code>ah </code>(depois de incrementado em 1) possui o &#237;ndice do setor, e <code>al </code>possui o n&#250;mero da trilha.</p><p>Devemos agora usar o n&#250;mero de trilha para encontrar os &#237;ndices de cabe&#231;a e cilindro. Esse valor deve estar em <code>ax</code>; <code>al </code>j&#225; cont&#233;m essa informa&#231;&#227;o, mas ah est&#225; com o valor sujo e precisamos zer&#225;-lo. Por isso, a instru&#231;&#227;o <code>xor ah, ah</code>.</p><p>Neste ponto, <code>ax </code>j&#225; tem o n&#250;mero de trilha. Dividindo esse valor pelo n&#250;mero de cabe&#231;as do disco (vari&#225;vel <code>number_of_heads</code>), temos ah com o &#237;ndice da cabe&#231;a e <code>al </code>com o &#237;ndice do cilindro.</p><p>Ufa, j&#225; temos todos os valores nos registradores exigidos pela interrup&#231;&#227;o de leitura <code>BIOS 13H</code>. Ou quase todos.</p><p>Ainda falta nos livrarmos de um grande elefante branco no meio da sala: quantos setores devemos ler de uma vez? At&#233; o momento, est&#225;vamos lendo apenas um setor do disco. Um algoritmo ing&#234;nuo diria nos instruiria a ler a maior quantidade de setores poss&#237;veis de uma vez. O problema &#233; que h&#225; restri&#231;&#245;es impostas pelas arquiteturas e controladoras de disco. Vamos discutir algumas delas.</p><p>A primeira limita&#231;&#227;o &#233; a quantidade m&#225;xima te&#243;rica que podemos ler usando a interrup&#231;&#227;o <code>BIOS 13H</code>. A quantidade de setores que gostar&#237;amos de ler em uma chamada da interrup&#231;&#227;o fica armazenada no registrador <code>al</code>. Valores poss&#237;veis ent&#227;o poderiam ser de 1 a 255, mas <a href="https://stanislavs.org/helppc/int_13-2.html">aqui</a> diz que &#233; at&#233; 128. Ainda assim, parece n&#227;o ser poss&#237;vel ler tudo isso de uma vez em um <em>floppy </em>disk, e aqui &#233; dito que em controladoras antigas, pode ser poss&#237;vel ler apenas <a href="https://stackoverflow.com/questions/3645803/bios-int-13h-with-ah-2-can-only-read-72-sectors-each-time-why#:~:text=This%20is%20based%20on%20a%202.88Mb%20floppy%20multi,1.44Mb%20floppy%20is%20a%20maximum%20of%2018%20sectors.">18 setores de uma vez</a>, e quando usando o emulador <em>BOCHS</em>, <a href="https://stackoverflow.com/questions/3645803/bios-int-13h-with-ah-2-can-only-read-72-sectors-each-time-why#:~:text=This%20is%20based%20on%20a%202.88Mb%20floppy%20multi,1.44Mb%20floppy%20is%20a%20maximum%20of%2018%20sectors.">o m&#225;ximo permitido &#233; 72</a>.</p><p>Ainda h&#225; outro problem&#227;o: o endere&#231;o <code>es:bx</code> n&#227;o pode cruzar a fronteira de 64KB de um segmento f&#237;sico na mem&#243;ria durante a leitura. No nosso caso, come&#231;amos no endere&#231;o <code>0x1000</code> (4096 bytes) e vamos at&#233; o endere&#231;o <code>0xfa00</code> (64 KB). Nesse intervalo, temos 59.904 bytes, e com setores com tamanho de 512 bytes cada, temos um total de 117 setores a serem lidos nesse intervalo.</p><p>Pegando um m&#237;nimo denominador comum, voc&#234; pode ir lendo de 18 setores 6 vezes, e no fim leria apenas 9 setores para parar na barreira do segmento f&#237;sico. Ou se for ler 16 setores de uma vez, voc&#234; teria que fazer 7 leituras completas e mais uma com 5 setores e parar na barreira do segmento. Ao cruzar a barreira do segmento f&#237;sico, voc&#234; tem mais 64KB para o pr&#243;ximo segmento. Setores de 512 bytes totalizam 125 setores, um bom n&#250;mero seria um n&#250;mero de cinco, mas menor que 18? Sinceramente, n&#227;o vale a pena. Enquanto n&#227;o precisamos otimizar o c&#243;digo, podemos ler setor por setor que n&#227;o teremos problema nenhum. Portanto,  defini <code>BIOS_INT_13H_SECTOR_COUNT = 1</code><em>.</em></p><p>Invocamos a fun&#231;&#227;o como de costume (lembre-se que o registrador es j&#225; havia sido corretamente definido):</p><pre><code>    mov dl, [disk_index] 
    mov al, BIOS_INT_13H_SECTOR_COUNT ; how many sectors are we reading at once?
    mov ah, BIOS_INT_13H_READ
    mov bx, KERNEL_INIT ; bx will be always the same. es is the register that will change     
    int BIOS_INT_13H

    jc read_sector ; if CF is set, an error occurred. Try again</code></pre><p>Fazemos a leitura, e checamos se a <em>Carrier Flag</em> est&#225; definida. Em caso positivo, houve um erro na leitura, pule para <code>read_sector</code> e repita o processo.</p><p>Em caso negativo, a leitura foi bem sucedida. Malandramente, eu mantenho o registrador <code>bx </code>fixo, calculo quantos bytes foram lidos e incremento apenas o registrador de segmento <code>es</code>. Por exemplo, se apenas um setor foi lido como &#233; o nosso caso (<code>BIOS_INT_13H_SECTOR_COUNT = 1</code><em>)</em>, significa que lemos <code>0x200</code> bytes (512 em decimal), basta fazer um <em>shift right</em> no n&#250;mero hexadecimal <code>0x200</code> para resultar em <code>0x20</code>. Em decimal, basta fazer <code>(SECTOR_SIZE*BIOS_INT_13H_SECTOR_COUNT)/16 </code>(&#233; o valor definido na constante <code>BIOS_INT_13H_SEGMENT_OFFSET </code>no arquivo <code>constants.asm</code>).</p><p>Depois, incrementamos o endere&#231;o LBA com o n&#250;mero de setores lidos, e fazemos um salto para ler mais setores. Quando todos os setores forem lidos, o <em>kernel </em>est&#225; com certeza no endere&#231;o <code>0x0000:0x1000</code>, basta pular para l&#225; e executar o que j&#225; mostramos no come&#231;o desse artigo. O trecho final do c&#243;digo fica assim:</p><pre><code>    mov ax, es
    add ax, BIOS_INT_13H_SEGMENT_OFFSET
    mov es, ax ; we've read BIOS_INT_13H_SECTOR_COUNT*SECTOR_SIZE bytes. Move es to new position (move to segment BIOS_INT_13H_SEGMENT_OFFSET)

    add word [current_lba_address], BIOS_INT_13H_SECTOR_COUNT ; move LBA pointer

    jmp read_sector

end_read_sector:
    ; the kernel is entirely in the memory. Jump to its start address
    jmp KERNEL_SEGMENT:KERNEL_INIT</code></pre><p>O c&#243;digo completo est&#225; no meu github na branch <a href="https://github.com/rodrigogbranco/boring-os/tree/p1-v5">p1-v5</a>. No pr&#243;ximo artigo vamos parar de roubar, nosso Makefile est&#225; fazendo com que o linker gere arquivos raw binary, mas o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">Projeto P1</a> espera que esses arquivos sejam gerados no formato ELF, e precisamos criar um programa que fa&#231;a o <em>parser </em>nesses arquivos e os junte, inclusive alterando o campo campo <code>os_size </code>no arquivo<em> </em><code>bootloader.asm</code> a depender do tamanho do c&#243;digo presente no kernel. Essa ser&#225; a nossa pr&#243;xima miss&#227;o, at&#233; l&#225;.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/dummy-kernel?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/dummy-kernel?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/usando-arquivos-elf?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/usando-arquivos-elf?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[Dummy Kernel]]></title><description><![CDATA[Exercitando a leitura dos setores do disco para a mem&#243;ria]]></description><link>https://blog.rodrigobranco.net/p/dummy-kernel</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/dummy-kernel</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Wed, 30 Oct 2024 16:59:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SkDQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SkDQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SkDQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SkDQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:259953,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SkDQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!SkDQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0fb425f-a9ca-4e41-bc30-0097049101c4_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>No <a href="https://blog.rodrigobranco.net/p/hora-de-nos-mover">artigo anterior</a> n&#243;s mostramos o layout da imagem do SO e tamb&#233;m o layout de mem&#243;ria. Nesse artigo, vamos proceder com a leitura dos dados na imagem para a posi&#231;&#227;o correta do kernel na mem&#243;ria (0x1000).</p><p>Contudo, ainda n&#227;o temos um kernel, ent&#227;o vamos trabalhar com o <em>Dummy Kernel</em>. No fim das contas por enquanto queremos apenas carregar o Kernel na posi&#231;&#227;o 0x1000, e j&#225; cuidamos para que, se ele for muito grande, este n&#227;o sobrescrever&#225; o <em>bootloader</em>, que foi movido da posi&#231;&#227;o 0x7c00 para 0x80000.</p><p>Para este teste, criei um arquivo kernel.asm e movi o c&#243;digo de impress&#227;o de caracteres e <em>strings </em>para ele. Vamos ver o que foi necess&#225;rio para que isso funcione.</p><p>No arquivo booloader.asm, entre os r&#243;tulos <code>_start</code> e <code>load_kernel</code>, adicionamos os seguintes dados:</p><pre><code>os_size:
    dw 1, 0

disk_index: 
    db 0xff</code></pre><p>O primeiro campo, <code>os_size</code>, possui duas palavras e indica o tamanho do Sistema Operacional que deve ser lido do disco, em n&#250;mero de setores. Ao juntar o <em>bootloader </em>e o <em>kernel </em>em artigos posteriores, o utilit&#225;rio ir&#225; alterar esse campo para indicar o tamanho do <em>kernel </em>que deve ser posteriormente lido. No momento, temos um kernel <em>dummy </em>e, neste nosso artigo, sei que tem menos de 512 bytes, portanto, ler um setor &#233; suficiente.</p><p>Note ainda que o defini o 1 na primeira palavra. N&#227;o deveria ser na segunda? N&#227;o, pois o utilit&#225;rio que junta o <em>bootloader </em>e <em>kernel </em>possui 32bit, e 32bit na arquitetura x86 &#233; <em><a href="https://en.wikipedia.org/wiki/Endianness">LITTLE ENDIAN</a></em>. Significa que, do ponto de vista dessa aplica&#231;&#227;o, ela ir&#225; escrever os 32bit de uma vez como um n&#250;mero s&#243;, e os bits menos significativos ficam nos menores bytes na mem&#243;ria, e portanto, aparecem antes.</p><p>Note ainda que se um n&#250;mero de 32bit for escrito nessa regi&#227;o, teremos que nos desdobrar para fazer &#8220;caber&#8221; nos registradores de 16bit. Possivelmente a solu&#231;&#227;o &#233; quebrar esse n&#250;mero grande e fazer v&#225;rias leituras. Mais do que isso, se pretendemos usar a interrup&#231;&#227;o BIOS 13h para fazer a leitura e n&#227;o pudermos ler tudo de uma vez, precisamos saber como ir avan&#231;ando a leitura usando o padr&#227;o <a href="https://en.wikipedia.org/wiki/Cylinder-head-sector">CHS</a> (<em>Cylinder, Head and Sector</em>). Essa convers&#227;o ser&#225; um problema para o nosso eu do futuro.</p><p>O pr&#243;ximo campo, <code>disk_index</code>, guardar&#225; qual disco deve ser lido. O disco de boot pode estar em qualquer um dos dispositivos: <em>Floppy</em>, HD, SSD, CD-Rom, Rede&#8230; De onde devemos ler? Por sorte, ao achar o setor de boot, quando o controle &#233; passado ao <em>bootloader</em>, o registrador dl possui o &#237;ndice do disco que devemos usar, e podemos passar esse valor diretamente para a interrup&#231;&#227;o BIOS 13h. Como podemos perder esse valor se o registrador dx for usado, salvamos esse valor para uso futuro. Voc&#234; pode me perguntar, o que o valor <code>0xff</code> significa? Na realidade, nada. Foi um valor arbitr&#225;rio que defini, pois como estamos usando o primeiro <em>floppy </em>disk no QEMU, esse valor deve ser 0. Assim, eu garanto que essa posi&#231;&#227;o de mem&#243;ria foi corretamente alterada de <code>0xff</code> para 0 e isso facilita nossa depura&#231;&#227;o.</p><p>Aproveitei a oportunidade para deixar o registrador <code>bp</code> em um endere&#231;o bem definido:</p><pre><code>    mov sp, STACK_POINTER_BOOTLOADER
    mov bp, sp</code></pre><p>Isso acompanha aquela ideia do registro de ativa&#231;&#227;o j&#225; explicada anteriormente. Apesar de nossas fun&#231;&#245;es ajustar tais registradores, n&#227;o d&#243;i fazer isso agora.</p><p>Depois, antes de copiar o <em>bootloader </em>para a posi&#231;&#227;o <code>0x80000</code>, salvamos o disco presente no registrador <code>dl</code>, como dito anteriormente:</p><pre><code>    mov [ds:disk_index], dl</code></pre><p>Ap&#243;s j&#225; estar executando na posi&#231;&#227;o nova, fazemos a leitura do <em>kernel</em>:</p><pre><code>new_boot_region:
    mov ax, NEW_BOOTLOADER_SEGMENT
    mov ds, ax

    mov ah, BIOS_INT_13H_READ
    mov al, [ds:os_size]
    mov ch, BIOS_INT_13H_CYLINDER_NUMBER
    mov dh, BIOS_INT_13H_HEAD_NUMBER    
    mov cl, BIOS_INT_13H_SECTOR_NUMBER
    mov dl, [ds:disk_index]
    mov bx, KERNEL_SEGMENT
    mov es, bx
    mov bx, KERNEL_INIT
    int BIOS_INT_13H

    jmp KERNEL_SEGMENT:KERNEL_INIT</code></pre><p>Agora &#233; necess&#225;rio ler o disco para buscar o kernel e posicion&#225;-lo no endere&#231;o <code>0x1000</code>. Vamos ver o que &#233; necess&#225;rio para invocar a interrup&#231;&#227;o BIOS 13h. Dentre todas as fun&#231;&#245;es que podemos fazer com essa interrup&#231;&#227;o (estamos falando de manipula&#231;&#227;o de discos, ent&#227;o podemos ler, escrever, formatar, resetar, etc), nosso interesse &#233; ler do disco, portanto, o valor correto &#233; o <code>BIOS_INT_13H_READ</code> = 0x2<em>. </em>Depois, indico quantos setores eu pretendo ler de uma vez. Se voc&#234; voltar, notar&#225; que eu defini de antem&#227;o o valor para 1 (1 setor - 512 bytes), pois j&#225; sei que agora meu kernel tem menos de 512 bytes<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. </p><p>J&#225; sabemos quantos setores queremos ler, mas come&#231;amos a leitura a partir de onde no disco? O problema &#233; mais ou menos parecido com encontrar uma determinada faixa musical em um LP tocando em uma vitrola<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>No caso da interrup&#231;&#227;o da BIOS 13h, precisamos indicar em qual Cilindro (<em>Cylinder</em>), Cabe&#231;a (<em>Head</em>) e Setor (<em>Sector</em>) vamos iniciar a leitura. Se tiver d&#250;vidas em qual a l&#243;gica por tr&#225;s disso, veja esse v&#237;deo <a href="https://www.youtube.com/watch?v=Ep-yM894mQQ">aqui</a>. No nosso caso, o primeiro setor de todos &#233; nosso <em>bootloader</em>, que fica no Cilindro 0, Cabe&#231;a 0 e Setor 1 (note que o setor n&#227;o come&#231;a no 0). Nosso kernel est&#225; grudado e est&#225; logo na sequ&#234;ncia, portanto queremos come&#231;ar a leitura a partir do Cilindro 0, Cabe&#231;a 0 e Setor 2. Atente-se novamente, se voc&#234; precisar ler uma quantia muito grande de setores, provavelmente precisar&#225; quebrar uma leitura grande em v&#225;rias pequenas, recalculando os &#237;ndices de Cilindro, Cabe&#231;a e Setor no processo.</p><p>Mas a vida, al&#233;m de n&#227;o ser f&#225;cil, ainda &#233; dif&#237;cil. Isso porque os valores de cilindro, cabe&#231;a e setor s&#227;o guardados nos registradores <code>ch</code>, <code>dh </code>e <code>cl</code>, respectivamente. E enquanto n&#227;o temos problemas com rela&#231;&#227;o aos 8 bit que podem representar as cabe&#231;as, de 0 a 255, o mesmo n&#227;o pode ser dito dos cilindros e setores. Isso porque, na verdade o &#237;ndice de cilindro &#233; um n&#250;mero de 10 bits, e o n&#250;mero de setores &#233; um n&#250;mero de 6 bits. Significa que pegamos emprestado dois bits dos setores para compor os cilindros. &#201; confuso, mas acredito que a imagem abaixo possa ajudar no entendimento.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-sq4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-sq4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 424w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 848w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 1272w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-sq4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png" width="985" height="206" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:206,&quot;width&quot;:985,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48761,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-sq4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 424w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 848w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 1272w, https://substackcdn.com/image/fetch/$s_!-sq4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5569fa-051c-49a6-affa-b1288d9b1e4b_985x206.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Sem surpresa ent&#227;o, temos as constantes <code>BIOS_INT_13H_CYLINDER_NUMBER</code> = 0<code>, BIOS_INT_13H_HEAD_NUMBER</code> = 0<code> </code>e <code>BIOS_INT_13H_SECTOR_NUMBER</code> = 2<code>, </code>e n&#227;o precisamos de nenhum malabarismo para encaixar os bits do cilindro e setor. <code>BIOS_INT_13H_SECTOR_NUMBER</code> = 2 usa menos que os 6 bits dispon&#237;veis, <code>BIOS_INT_13H_SECTOR_NUMBER</code> = 2 em bin&#225;rio &#233; <code>00000010</code>, ent&#227;o os dois &#250;ltimos bits j&#225; est&#227;o zerados, e para o cilindro, &#233; s&#243; deixar <code>ch</code> = 0.</p><p>Prosseguindo pelo c&#243;digo, recuperamos o disco que devemos ler e guardamos esse valor no registrador dl, que ser&#225; usado diretamente pela interrup&#231;&#227;o.</p><p>Por fim, s&#243; falta indicar onde deveremos guardar os dados lidos. Lembre-se que queremos colocar o kernel em <code>0x1000</code>, ent&#227;o ES:BX valendo <code>0x0000:0x1000</code> &#233; suficiente para o nosso caso (representado pelas constantes <code>KERNEL_SEGMENT:KERNEL_INIT</code>). </p><p>Assim que a interrup&#231;&#227;o finaliza, saltamos para o endere&#231;o <code>0x0000:0x1000</code> usando a instru&#231;&#227;o <code>jmp KERNEL_SEGMENT:KERNEL_INIT, </code>pousando no endere&#231;o absoluto <code>0x1000</code>, como o esperado.</p><p>Esse endere&#231;o possui o c&#243;digo presente no arquivo kernel.asm, que &#233; basicamente as fun&#231;&#245;es <code>print_char</code> e <code>print_s</code> retiradas do arquivo bootloader.asm. A diferen&#231;a foi que ajustei os registradores ds e es para o mesmo segmento de cs (zero, portanto), e alterei a mensagem a ser impressa para &#8220;Dummy Kernel Loaded!&#8221;. Nada mais &#233; alterado em rela&#231;&#227;o ao que j&#225; existia anteriormente.</p><p>Como agora temos um <em>bootloader </em>e um kernel (<em>cof cof</em>), n&#227;o faz mais sentido carregar a imagem como <em>bootloader</em>, por isso gerei um novo arquivo chamado <code>boringos.img</code>, que &#233; uma am&#225;lgama dos dois anteriores. Na real s&#227;o apenas os bytes copiados em sequ&#234;ncia usando <code>cat</code>.</p><p>O novo Makefile ficou ent&#227;o:</p><pre><code>SRCDIR=src
OUTPUTDIR=build

all: kernel bootloader
&#9;cat $(OUTPUTDIR)/bootloader $(OUTPUTDIR)/kernel &gt; $(OUTPUTDIR)/boringos.img

%.o: $(SRCDIR)/%.asm
&#9;nasm -wall -O2 -f elf32 -F dwarf -g -o $(OUTPUTDIR)/$@ $&lt;

bootloader: bootloader.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x0 -s --oformat binary -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;

kernel: kernel.o
&#9;ld -nostdlib -O2 -g -m elf_i386 -Ttext 0x1000 -s --oformat binary -o $(OUTPUTDIR)/$@ $(OUTPUTDIR)/$&lt;

clean:
&#9;rm -rf $(OUTPUTDIR)/*</code></pre><p>Perceba que deixei a compila&#231;&#227;o dos arquivos .asm de forma gen&#233;rica. O mesmo n&#227;o pode ser dito dos execut&#225;veis <em>bootloader </em>e <em>kernel</em>, j&#225; que estes s&#227;o posicionados em se&#231;&#245;es de texto diferentes (par&#226;metros <code>-Ttext 0x0</code> e <code>-Ttext 0x1000).</code></p><p>O arquivo <code>VM_BoringOS.sh</code> foi alterado para usar o novo arquivo <code>boringos.img</code>. J&#225; no arquivo <code>debug_BoringOS.sh</code> adicionamos os s&#237;mbolos do arquivo <code>kernel.o </code>no endere&#231;o<code> 0x1000</code>. Retirei os s&#237;mbolos do <em>bootloader </em>do endere&#231;o <code>0x7c00</code>, e deixei apenas no endere&#231;o <code>0x80000</code>, para evitar conflitos do mesmo s&#237;mbolo estar em lugares diferentes. Alterei o primeiro breakpoint de <code>hbreak *_start</code> para <code>hbreak *0x7c00</code>, j&#225; que n&#227;o temos mais o s&#237;mbolo <code>_start</code> carregado pelo <code>gdb </code>no endere&#231;o <code>0x7c00</code>&#8230;</p><p>Se tudo der certo, ao iniciar a depura&#231;&#227;o e solicitar ao depurador que continue a execu&#231;&#227;o, voc&#234; deve ver a tela abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QhFN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QhFN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 424w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 848w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 1272w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QhFN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png" width="729" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:729,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11593,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QhFN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 424w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 848w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 1272w, https://substackcdn.com/image/fetch/$s_!QhFN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe03fa7ea-0d49-44a6-aa5b-f42cdeaadd57_729x459.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>OBS: Fique esperto com os segmentos. Inicialmente eu tentei fazer com que <em>KERNEL_SEGMENT:KERNEL_INIT</em> fosse <code>0x0100:0x0000</code>. Embora isso seja igual a <code>0x1000:0x0000</code>, que &#233; igual ao endere&#231;o absoluto <code>0x1000</code>, isso fez com que eu tivesse dor de cabe&#231;a com os <em>helpers </em>do <code>gdb</code>. Nesse caso, o <em>helper </em>do <code>gdb </code>para o modo real vai fazer <code>SIGTRAPs</code> dependendo de onde voc&#234; coloca o <em>breakpoint</em>, e a execu&#231;&#227;o n&#227;o vai para frente com os comandos <code>s</code>, <code>si</code>, <code>n</code>, <code>stepo</code>, etc no <code>gdb</code>. Observe esse exemplo:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZxGP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZxGP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 424w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 848w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 1272w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZxGP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png" width="667" height="181" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:181,&quot;width&quot;:667,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18472,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZxGP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 424w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 848w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 1272w, https://substackcdn.com/image/fetch/$s_!ZxGP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4c7a619-8eb5-49f8-8511-5ffd74834772_667x181.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Logo ap&#243;s o <code>gdb</code> parar a execu&#231;&#227;o no endere&#231;o <code>0x7c00</code>, eu pedi um novo breakpoint em <code>0x1000</code>. Ele informa que o programa parou por algum <em>breakpoint </em>definido, mas n&#227;o por mim. Para prosseguir, tive que fazer um delete e apagar todos os <em>breakpoints </em>presentes. Assim, o si volta a funcionar e voc&#234; pode setar os <em>breakpoints </em>novamente.</p><p>Ajustando os segmentos dos registradores <code>cs</code>, <code>ds</code> e <code>es</code> para <code>0x0000</code>, o problema parou de acontecer.</p><p>O c&#243;digo para essa vers&#227;o est&#227;o <a href="https://github.com/rodrigogbranco/boring-os/tree/p1-v4">aqui</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/hora-de-nos-mover?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/hora-de-nos-mover?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/big-big-dummy-kernel?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/big-big-dummy-kernel?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Perceba que ler muitos setores de uma vez pode ser uma dor de cabe&#231;a. Voc&#234; n&#227;o pode cruzar um segmento f&#237;sico da mem&#243;ria (cada 64KB come&#231;ando do byte 0) em uma leitura &#250;nica. Se estiv&#233;ssemos usando o BOCHS, ainda ter&#237;amos a limita&#231;&#227;o de poder ler menos do que 64 setores, sen&#227;o a leitura falharia. N&#227;o sei se esse problema permanece em vers&#245;es mais novas do BOCHS. Em um c&#243;digo correto e robusto dever&#237;amos verificar o retorno da interrup&#231;&#227;o para saber se a leitura foi bem sucedida, neste caso, verificando os registradores ah, al e a Carrier Flag.  E n&#227;o sei se isso ocorre no QEMU, tampouco pretendo descobrir isso agora.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Se n&#227;o sabe do que eu estou falando, fa&#231;a uma visita ao <a href="https://www.youtube.com/watch?v=Hf2Gv2PXCyw">Manual do Mundo</a>!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Hora de nos mover!]]></title><description><![CDATA[Vamos realocar o bootloader para dar espa&#231;o para o Kernel]]></description><link>https://blog.rodrigobranco.net/p/hora-de-nos-mover</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/hora-de-nos-mover</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Fri, 25 Oct 2024 17:30:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!g9k8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g9k8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g9k8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g9k8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:273284,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g9k8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!g9k8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa76269ce-431b-4a33-9ef2-d0ae1c9fa068_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Continuando a especifica&#231;&#227;o do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html#bootblock">Projeto 1</a> (<a href="https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai">veja o post anterior aqui</a>!), em breve estaremos lendo carregando o kernel para a mem&#243;ria (e ele ainda nem existe no nosso c&#243;digo). Contudo, temos um problema: nos &#233; pedido que o kernel seja carregado no endere&#231;o 0x1000. Se o kernel ultrapassar 27KB, ele vai alcan&#231;ar a regi&#227;o de mem&#243;ria 0x7c00, que foi onde a BIOS colocou o nosso <em>bootloader</em>. Se a BIOS ainda n&#227;o tiver terminado seu trabalho (e ainda h&#225; muito o que fazer antes de passar o controle ao kernel), o c&#243;digo do Kernel sobrescrever&#225; o <em>bootloader</em>, e coisas ruins podem acontecer.</p><p>Temos duas informa&#231;&#245;es <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html#bootblock">importantes</a>:</p><ol><li><p><em>Your bootloader can safely modify memory in the range [0x0a00, 0xa0000) without having to worry about overwriting video memory, the interrupt vector table, or BIOS.</em></p></li><li><p><em>Notice that a loaded larger kernel may overlap with the bootloader, so you will have to relocate the bootloader to a higher address that can't be overwritten before loading the kernel (see <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html#extracredit">extra credit</a>).</em></p></li></ol><p>Portanto, se a gente mover o <em>bootloader </em>para um endere&#231;o alto, pr&#243;ximo da fronteira 0xa0000, n&#227;o deveremos ter problemas. E como esse n&#227;o &#233; um sistema de produ&#231;&#227;o, decidi mover o <em>bootloader </em>para o endere&#231;o 0x80000. Assim, o kernel tem espa&#231;o de sobra para ocupar entre os endere&#231;os 0x1000 e 0x80000.</p><p>Minha ideia &#233; portanto fazer como a imagem abaixo.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jqh9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jqh9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 424w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 848w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 1272w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jqh9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png" width="1330" height="625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1330,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103067,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jqh9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 424w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 848w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 1272w, https://substackcdn.com/image/fetch/$s_!jqh9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9fe8bb4-cc71-4f33-bca1-e1b459bfa6d5_1330x625.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Os passos que descrevem a imagem acima s&#227;o:</p><ol><li><p>Nossa imagem &#233; um bloco cont&#237;guo concatenado do <em>bootloader </em>(512 bytes) e o kernel, que ainda n&#227;o sabemos o tamanho. Se o <em>bootloader </em>exceder os 512 bytes, &#233; necess&#225;rio considerar isso ao ler o disco e mover o <em>bootloader</em>. Mas n&#227;o cuidaremos disso at&#233; que seja necess&#225;rio. Portanto, assumimos que nosso bootloader tem 512 bytes.</p></li><li><p>A BIOS se encarrega de colocar nosso <em>bootloader </em>no endere&#231;o 0x7c00 (1 - BIOS LOADING, na imagem acima). J&#225; tratamos desse procedimento em artigos anteriores.</p></li><li><p>O <em>bootloader </em>corrige os segmentos, e ajusta a pilha para o endere&#231;o 0x9ffff. </p></li><li><p>O <em>bootloader </em>ent&#227;o copia o conte&#250;do de 512 bytes do endere&#231;o 0x7c00 para o endere&#231;o 0x80000 (2 - BOOTLOADER MOVING). Isso significa que h&#225; uma c&#243;pia do <em>bootloader </em>nesse novo endere&#231;o.</p></li><li><p>Fazemos um <em>far jump</em> para a pr&#243;xima instru&#231;&#227;o no segmento 0x8000. Isso implica que estamos continuando o c&#243;digo de nosso bootloader, mas em outro ponto da mem&#243;ria!</p></li><li><p>A partir dai, o <em>bootloader </em>pode fazer o que for necess&#225;rio, por exemplo, ler o <em>kernel </em>do disco e posicion&#225;-lo em 0x1000, sem se preocupar com sobreposi&#231;&#245;es. N&#227;o temos isso pronto ainda, e vamos continuar usando nossas fun&#231;&#245;es <code>print_char</code> e <code>print_string</code> para testes.</p></li></ol><p>O que temos de novo no nosso c&#243;digo? Vamos descobrir!</p><p>Criei mais tr&#234;s constantes. <code>NEW_BOOTLOADER_SEGMENT </code>guarda o segmento da nova posi&#231;&#227;o do <em>bootloader</em>, 0x8000. Se considerarmos que o segmento do <em>bootloader </em>velho &#233; 0x07c0, ent&#227;o podemos usar o mesmo deslocamento para os dois, partindo de <code>BOOTLOADER_INIT, </code>0x0000. Isso resulta nos endere&#231;os absolutos 0x7c00 e 0x80000 para o velho e novo bootloader, respectivamente. Por fim, defini a constante de quantos bytes eu quero mover, e como nosso bootloader tem o tamanho de 1 setor do disco, definimos a constante <code>SECTOR_SIZE </code>= 512.</p><p>Como podemos copiar os bytes do <em>bootloader </em>de 0x7c00 para 0x80000 de forma eficiente? Podemos utilizar a instru&#231;&#227;o <code>rep movsb</code>. Essa instru&#231;&#227;o copia a quantidade de bytes que est&#225; no registrador <code>CX </code>do endere&#231;o <code>DS:SI</code> para o endere&#231;o <code>ES:DI</code>. Para isso ele incrementa automaticamente os registradores <code>SI </code>e <code>DI </code>a cada byte copiado (caso a <em>Flag DF - Direction Flag</em> tenha o valor 0), ou decrementa (caso a <em>Flag DF - Direction Flag</em> tenha o valor 1). Podemos alterar o valor dessa flag com as instru&#231;&#245;es <code>CLD </code>- <em>Clear Direction Flag</em> e <code>STD </code>- <em>Set Direction Flag</em>). Como voc&#234; deve ter notado, precisamos do valor 0 nessa flag, ent&#227;o a instru&#231;&#227;o que devemos usar &#233; <code>CLD</code>.</p><p>Ent&#227;o agora ficou f&#225;cil. Precisamos definir os valores dos registradores <code>DS </code>(segmento de origem - 0x07c0), <code>ES </code>(segmento de destino - 0x8000), endere&#231;os de origem e destino nos segmentos, respectivamente, <code>SI</code> e <code>DI</code> (come&#231;aremos do 0), <code>CX </code>indica quantos bytes ser&#227;o copiados (512), e zeramos o <em>direction flag</em> (<code>CLD</code>). E ai podemos executar a instru&#231;&#227;o <code>rep movsb</code>. Essa parte do c&#243;digo ficou assim:</p><pre><code>load_kernel:
    mov ax, STACK_SEG_BOOTLOADER
    mov ss, ax
    mov sp, STACK_POINTER_BOOTLOADER      

    mov ax, SEGMENTS_BOOTLOADER
    mov ds, ax
    mov ax, NEW_BOOTLOADER_SEGMENT
    mov es, ax

    mov si, BOOTLOADER_INIT
    mov di, BOOTLOADER_INIT

    mov cx, SECTOR_SIZE

    cld
    rep movsb
before_jump:
    jmp word NEW_BOOTLOADER_SEGMENT:new_boot_region
    
new_boot_region:
    mov ax, NEW_BOOTLOADER_SEGMENT
    mov ds, ax</code></pre><p>Depois que a c&#243;pia terminou, podemos &#8220;pular&#8221; para o novo segmento para o r&#243;tulo <code>new_boot_region, </code>ou seja, justamente a pr&#243;xima instru&#231;&#227;o. A pilha j&#225; est&#225; no endere&#231;o certo (SS = 0x9000), os registradores CS e ES j&#225; apontam para o novo segmento 0x8000 (CS foi atualizado na instru&#231;&#227;o <code>jmp</code>). Portanto, o &#250;nico registrador de segmento errado ainda &#233; o DS, e &#233; isso que corrigimos logo ap&#243;s o <code>jmp </code>ser efetuado no c&#243;digo acima.</p><p>Dai pra frente, o c&#243;digo &#233; o mesmo do artigo anterior. Deve aparecer na tela a mensagem &#8220;<em>pHello, world</em>&#8221;. Se voc&#234; executar esse c&#243;digo, tudo funcionar&#225; conforme imaginado.</p><p>Duas observa&#231;&#245;es para esse novo c&#243;digo:</p><p>Primeiro, a instru&#231;&#227;o <code>lodsb</code>, usada na fun&#231;&#227;o <code>print_string</code>, tamb&#233;m usa o <em>Direction Flag</em> para fazer a c&#243;pia dos bytes. Quem sabe faz ao vivo! No nosso caso, estava funcionando sem querer, mas para garantir que funcionar&#225; *sempre*, precisamos executar a instru&#231;&#227;o <code>cld </code>antes da primeira execu&#231;&#227;o da instru&#231;&#227;o <code>lodsb</code>. Isso foi corrigido nessa vers&#227;o.</p><p>Segundo, depois da c&#243;pia do <em>bootloader</em>, os endere&#231;os 0x7c00 e 0x80000 possuem o mesmo c&#243;digo certo? Portanto, para facilitar a depura&#231;&#227;o com o <code>gdb</code>, &#233; &#250;til adicionarmos os s&#237;mbolos no novo endere&#231;o tamb&#233;m no arquivo <em>debug_BoringOS.sh</em>:</p><pre><code>-ex "add-symbol-file $CURRDIR/build/bootloader.o 0x80000"</code></pre><p>Contudo, fazer breakpoints usando os s&#237;mbolos agora n&#227;o funciona mais, pelo menos n&#227;o da forma como se &#233; esperado. Afinal, temos os mesmos s&#237;mbolos em dois endere&#231;os diferentes. Se eu fizer um <code>hbreak *before_jump, </code>onde ele colocar&#225; o breakpoint? Na minha execu&#231;&#227;o aqui, ele colocou aqui:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HfFk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HfFk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 424w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 848w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 1272w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HfFk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png" width="704" height="829" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/01b40298-aa30-4470-aaa4-ae554431a956_704x829.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:829,&quot;width&quot;:704,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96431,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HfFk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 424w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 848w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 1272w, https://substackcdn.com/image/fetch/$s_!HfFk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01b40298-aa30-4470-aaa4-ae554431a956_704x829.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Hum&#8230; ele colocou no endere&#231;o do novo <em>bootloader (</em><code>0x8004f</code><em>)</em>. Acredito que ele sobrescreveu o endere&#231;o do s&#237;mbolo <code>before_jump</code> quando o segundo <code>add-symbol-file</code> foi executado. E o engra&#231;ado &#233; que se eu pedir para continuar a execu&#231;&#227;o agora, esse breakpoint nunca ser&#225; executado, j&#225; que ele est&#225; antes do <code>jmp</code> no segmento 0x8000, mas o <code>jmp</code> pula para o r&#243;tulo <em>new_boot_region, </em>que fica depois<em>. </em>Enfim, isso n&#227;o &#233; nenhum problema, e &#233; o comportamento esperado. </p><p>Para evitar essa situa&#231;&#227;o, se precisar pular para algum s&#237;mbolo do arquivo <em>bootloader.o</em>, o melhor a ser feito &#233; carregar os s&#237;mbolos em apenas um dos dois endere&#231;os. Ou ent&#227;o use breakpoints com endere&#231;os absolutos. Se n&#227;o precisar de breakpoints com s&#237;mbolos, carregar o mesmo s&#237;mbolo nos dois endere&#231;os &#233; uma boa ideia na visualiza&#231;&#227;o da execu&#231;&#227;o no <code>gdb</code>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/dummy-kernel?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/dummy-kernel?r=2jdzwu"><span>Pr&#243;ximo</span></a></p>]]></content:encoded></item><item><title><![CDATA[É andando pra trás que a gente vai pra frente]]></title><description><![CDATA[Hora de reavaliar as escolhas]]></description><link>https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Thu, 24 Oct 2024 19:04:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MuHA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MuHA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MuHA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MuHA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ebace344-692e-4046-9c55-47c16463810c_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:286410,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MuHA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!MuHA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febace344-692e-4046-9c55-47c16463810c_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Se voc&#234; ainda n&#227;o conferiu o post anterior, <a href="https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga">corre l&#225;</a> para preparar o projeto. Sigamos.</p><p>Eu estava meio destreinado em <em>assembly</em>, e uma das etapas do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html#designreview">Projeto 1</a> &#233; fazer o <em>Design Review</em>. Nele &#233; pedido para fazermos as fun&#231;&#245;es <em>print_char </em>e <em>print_string </em>em <em>assembl</em>y. &#211;tima oportunidade! Est&#225;vamos escrevendo um caractere na tela no <a href="https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga?r=2jdzwu">post anterior</a>, mas convenhamos, aquilo n&#227;o &#233; exatamente uma fun&#231;&#227;o certo? Um dos pr&#233;-requisitos de uma fun&#231;&#227;o &#233; ser chamada com a instru&#231;&#227;o CALL, portanto, mudan&#231;as seriam necess&#225;rias.</p><p>Havia outras coisas que eu propositalmente deixei incompleto, no post anterior eu n&#227;o mexia na pilha nem nos registradores de segmento. Mas se agora vamos definir fun&#231;&#245;es formalmente, ent&#227;o &#233; hora tamb&#233;m de ajustarmos tais valores.</p><p>Ao come&#231;ar a mexer no c&#243;digo, tive muito problema pois o c&#243;digo carregado pelos s&#237;mbolos do arquivo <em>bootloader.o</em> n&#227;o correspondiam &#224;s instru&#231;&#245;es que o <em>gdb </em>me mostrava. Isso &#233; o equivalente a traduzir um texto escrito em alem&#227;o com um dicion&#225;rio japon&#234;s. Sem conseguir resolver isso, eu n&#227;o conseguiria avan&#231;ar muito.</p><p>O problema principal &#233; que esse c&#243;digo inicial &#233; um c&#243;digo 16-bit em <a href="https://pt.wikipedia.org/wiki/Modo_real#:~:text=Modo%20Real%20%28tamb%C3%A9m%20conhecido%20como%20Real%20Mode%20ou,de%20mem%C3%B3ria%20ou%20multitarefa%20ao%20n%C3%ADvel%20do%20hardware.">modo real</a>, mas o NASM est&#225; gerando c&#243;digo ELF32. At&#233; ai tudo bem, j&#225; que minhas instru&#231;&#245;es n&#227;o usam registradores de 32bit ainda. O <em>linker </em>tamb&#233;m est&#225; gerando c&#243;digo elf_i386, e enquanto o otimizador n&#227;o fizer nenhuma gracinha, at&#233; aqui estamos bem.</p><p>O problema come&#231;a quando esse c&#243;digo &#233; carregado no QEMU e atachado ao GDB. Estava usando o qemu-system-x86_64, e isso por si s&#243; n&#227;o &#233; um problema devido a retro compatibilidade da arquitetura x86_64, mas o GDB alterava a instru&#231;&#227;o que me era apresentada. Havia ocasi&#245;es em que registradores de 32bit me eram apresentados quando rodava o <em>layout asm</em> no GDB (do nada aparecia um eax), e eu levei muito tempo para entender o que estava acontecendo.</p><p>Primeiro, por enquanto pelo menos, eu alterei o qemu-system-x86_64 para qemu-system-i386. Isso n&#227;o &#233; suficiente. Segundo, preciso indicar para o NASM gerar c&#243;digo de 16bit. Isso &#233; feito com a diretiva [BITS 16] no c&#243;digo bootloader.asm.</p><p>Segundo, a visualiza&#231;&#227;o padr&#227;o do GDB &#233; muito ruim. Ou pelo menos eu achei algo BEM melhor <a href="https://astralvx.com/debugging-16-bit-in-qemu-with-gdb-on-windows/">aqui</a>! Dessa forma conseguimos altera a visualiza&#231;&#227;o do GDB para que ele mostra uma esp&#233;cie de visualiza&#231;&#227;o Real Mode 16bit, exatamente o que n&#243;s queremos!</p><p>Vamos ver as mudan&#231;as ent&#227;o.</p><h1>Makefile</h1><p>Criei uma pasta src, e movi o c&#243;digo fonte para l&#225; (por enquanto o arquivo bootloader.asm). Tamb&#233;m criei uma pasta de build, onde os arquivos objetos e execut&#225;veis s&#227;o colocados. O <em>Makefile </em>foi adaptado para usar essas duas novas pastas.</p><h1>Pasta gdb_util e arquivo debug_BoringOS.sh</h1><p>Os arquivos <em>helper </em>para alterar a visualiza&#231;&#227;o do GDB, obtidos <a href="https://astralvx.com/debugging-16-bit-in-qemu-with-gdb-on-windows/">aqui</a>, foram inclu&#237;dos na pasta <em>gdb_util</em>. O comando que invoca o gdb foi alterado para contemplar tais arquivos:</p><pre><code>gdb -ix "$CURRDIR/gdb_util/gdb_init_real_mode.txt" -ex "set tdesc filename $CURRDIR/gdb_util/target.xml" -ex 'target remote localhost:1234' -ex 'set confirm off' -ex "add-symbol-file $CURRDIR/build/bootloader.o 0x7c00" -ex 'set confirm on' -ex 'hbreak *_start' -ex 'c'</code></pre><p>Observe o antes e depois de usar esses <em>helpers</em>. Antes:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aIz0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aIz0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 424w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 848w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 1272w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aIz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png" width="695" height="119" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab28a8e2-d752-4727-9c44-d1493b586850_695x119.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:119,&quot;width&quot;:695,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13742,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aIz0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 424w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 848w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 1272w, https://substackcdn.com/image/fetch/$s_!aIz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab28a8e2-d752-4727-9c44-d1493b586850_695x119.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Depois:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rhHo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rhHo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 424w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 848w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 1272w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rhHo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png" width="709" height="786" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:786,&quot;width&quot;:709,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87858,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rhHo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 424w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 848w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 1272w, https://substackcdn.com/image/fetch/$s_!rhHo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5a5238-1426-4a41-afc9-cab8bf9198a5_709x786.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A diferen&#231;a &#233; brutal, eu consigo acompanhar muito melhor o conte&#250;do dos registradores e algumas partes da mem&#243;ria.</p><h1>print_char e print_string</h1><p>Indo ao ponto que importa, organizei melhor o c&#243;digo <em>assembly</em>. Defini algumas constantes e as coloquei no arquivo constants.asm. O conte&#250;do desse arquivo est&#225; assim:</p><pre><code>%define STACK_SEG_BOOTLOADER 0x9000
%define STACK_POINTER_BOOTLOADER 0xffff
%define SEGMENTS_BOOTLOADER 0x7c0

%define BIOS_INT_10H 0x10
%define BIOS_INT_10H_OUTPUT 0x0e
%define BIOS_INT_10H_PAGE_NUMBER_0 0x00
%define BIOS_INT_10H_FOREGROUND_COLOR_GM 0x02

%define NULL_CHARACTER 0

%define LINE_FEED 10
%define CARRIER_RETURN 13

%define BOOT_SIGNATURE db 0x55, 0xaa</code></pre><p>Vamos explicar alguns dos valores, mesmo que de forma superficial agora. Primeiro, as duas primeiras constantes dizem respeito &#224; pilha. Segundo o trabalho: &#8220;<em>Your bootloader can safely modify memory in the range [0x0a00, 0xa0000) without having to worry about overwriting video memory, the interrupt vector table, or BIOS.</em>&#8221; Ent&#227;o, eu joguei a pilha para o endere&#231;o 0x9ffff (<code>STACK_SEG_BOOTLOADER:STACK_POINTER_BOOTLOADER</code>), um byte a menos que o valor limite 0xa0000. Como a pilha decresce, temos um bom espa&#231;o sem problemas, inclusive quando realocarmos o <em>bootloader </em>em um endere&#231;o mais alto.</p><p>Estamos ajustando os registradores de segmento tamb&#233;m, com a constante <code>SEGMENTS_BOOTLOADER</code>, em especial os registradores <em>ds</em> e <em>es. </em>Isso porque a fun&#231;&#227;o <em>print_string </em>usa a instru&#231;&#227;o <em>lodsb</em>, que utiliza esses registradores implicitamente. Como os valores buscados est&#227;o no mesmo segmento do c&#243;digo que inicia em 0x7c00, nada mais justo que ajustar tais registradores para esses valores tamb&#233;m.</p><p>As constantes para a chamada de escrita de caractere no v&#237;deo dispensam coment&#225;rios. Em caso de d&#250;vida, sugiro verificar <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/asmtips1.html">aqui</a> ou <a href="https://en.wikipedia.org/wiki/INT_10H">aqui</a>.</p><p>Depois, h&#225; algumas defini&#231;&#245;es para manipula&#231;&#227;o de <em>string </em>(<code>NULL_CHARACTER, LINE_FEED e CARRIER_RETURN), </code>e quem j&#225; trabalhou com <em>strings </em>em C ou similar sabem do que se trata. Na d&#250;vida, consulte alguma <a href="https://en.wikipedia.org/wiki/ASCII">Tabela ASCII</a>.</p><p>Por fim eu defini a constante da assinatura do boot. </p><p>O c&#243;digo bootloader.asm, j&#225; incluindo as constantes, ficou assim:</p><pre><code>[BITS 16]

%include "src/constants.asm"

global _start

_start:
    jmp load_kernel

print_char:
    push bp
    mov bp, sp

    push ax
    push bx

    mov ax, [bp+4]
    mov ah, BIOS_INT_10H_OUTPUT
    mov bh, BIOS_INT_10H_PAGE_NUMBER_0
    mov bl, BIOS_INT_10H_FOREGROUND_COLOR_GM
    int BIOS_INT_10H

    pop bx
    pop ax

    pop bp

    ret

print_string:
    push bp
    mov bp, sp

    push ax
    push bx
    push si

    mov si, [bp+4]

loop_print_string:
    lodsb

    cmp al, NULL_CHARACTER
    je end_print_string

    push ax
    call print_char
    pop ax
    jmp loop_print_string

end_print_string:
    pop si
    pop bx
    pop ax

    pop bp

    ret

load_kernel:
    mov ax, STACK_SEG_BOOTLOADER
    mov ss, ax
    mov sp, STACK_POINTER_BOOTLOADER      

    mov ax, SEGMENTS_BOOTLOADER
    mov ds, ax
    mov es, ax
  
    mov ax, 'p'
    push ax
    call print_char
    pop ax

    mov ax, msg
    push ax
    call print_string
    pop ax

    jmp $

msg db "Hello, world", CARRIER_RETURN, LINE_FEED, NULL_CHARACTER

TIMES 510-($-$$) DB 0

BOOT_SIGNATURE</code></pre><p>O c&#243;digo come&#231;a e j&#225; pula para o <em>label </em><code>load_kernel, </code>desviando da defini&#231;&#227;o das fun&#231;&#245;es <em>print_char </em>e <em>print_string</em>. O c&#243;digo define ent&#227;o os registradores de segmento e ponteiro da pilha.</p><p>Depois, testaremos a fun&#231;&#227;o print_char. Defini que a conven&#231;&#227;o das fun&#231;&#245;es segue o padr&#227;o ABI i386, ou seja, os par&#226;metros s&#227;o passados na pilha. Isso porque no futuro quero ligar minhas fun&#231;&#245;es com c&#243;digo em C, ent&#227;o preciso seguir a conven&#231;&#227;o que os compiladores j&#225; conhecem.</p><p>Ent&#227;o, empilhamos o par&#226;metro &#8216;p&#8217; e invocamos a fun&#231;&#227;o <em>print_char</em>. Para quem n&#227;o sabe, a instru&#231;&#227;o CALL empilha o endere&#231;o da pr&#243;xima instru&#231;&#227;o na pilha e desvia para o <em>label print_char</em>. Para foco, a fun&#231;&#227;o &#233; repetida para melhor entendimento:</p><pre><code>print_char:
    push bp
    mov bp, sp

    push ax
    push bx

    mov ax, [bp+4]
    mov ah, BIOS_INT_10H_OUTPUT
    mov bh, BIOS_INT_10H_PAGE_NUMBER_0
    mov bl, BIOS_INT_10H_FOREGROUND_COLOR_GM
    int BIOS_INT_10H

    pop bx
    pop ax

    pop bp

    ret</code></pre><p>A fun&#231;&#227;o come&#231;a ajustando o <a href="https://edisciplinas.usp.br/pluginfile.php/293355/mod_resource/content/1/21-LeituraComplementar-Pilha-execucao-e-variaveis-locais.pdf">registro de ativa&#231;&#227;o</a> (isto &#233;, ajustando o valor do registrador bp), e como vamos manipular os registrados ax e bx, estes tamb&#233;m s&#227;o empilhados para restaura&#231;&#227;o posterior. O par&#226;metro informado &#233; ent&#227;o recuperado da pilha ([bp+4]) e a BIOS &#233; invocada, como j&#225; visto. Depois que o caractere &#233; impresso, os registradores ax e bx s&#227;o restaurados, e o antigo valor de bp tamb&#233;m &#233; restaurado. A instru&#231;&#227;o <em>RET </em>&#233; executada, o que implica em desempilhar o endere&#231;o da pr&#243;xima instru&#231;&#227;o da pilha (este endere&#231;o havia sido empilhado pela instru&#231;&#227;o CALL, lembra)? Ao retornar, como hav&#237;amos empilhado o par&#226;metro, desempilhamos para que a pilha fique no mesmo estado antes da chamada.</p><p>Observe que a chamada para a fun&#231;&#227;o <em>print_string </em>acontece da mesm&#237;ssima forma. A diferen&#231;a &#233; que, ao inv&#233;s de termos empilhado os &#8220;valores&#8221; que queremos imprimir (como foi o caso do par&#226;metro &#8216;p&#8217;), agora passamos o endere&#231;o de mem&#243;ria de uma <em>string </em>que possui termina&#231;&#227;o nula (0, ou <em>NULL_CHARACTER </em>definido anteriormente), ou seja, a velha conven&#231;&#227;o de <em>strings </em>em C. Focando na fun&#231;&#227;o <em>print_string</em>:</p><pre><code>print_string:
    push bp
    mov bp, sp

    push ax
    push bx
    push si

    mov si, [bp+4]

loop_print_string:
    lodsb

    cmp al, NULL_CHARACTER
    je end_print_string

    push ax
    call print_char
    pop ax
    jmp loop_print_string

end_print_string:
    pop si
    pop bx
    pop ax

    pop bp

    ret</code></pre><p>Perceba que a fun&#231;&#227;o n&#227;o &#233; t&#227;o diferente assim da fun&#231;&#227;o <em>print_char</em>. A diferen&#231;a &#233; que agora vamos usar o registrador si, e por isso ele &#233; empilhado para restaura&#231;&#227;o posterior.</p><p>O endere&#231;o da <em>string </em>&#233; ent&#227;o movido para este endere&#231;o (instru&#231;&#227;o <code>mov si, [bp+4]</code>), e a instru&#231;&#227;o <code>lodsb </code>&#233; executada. Essa instru&#231;&#227;o pega o conte&#250;do da mem&#243;ria presente no endere&#231;o <em>ds:si</em> e coloca no registrador al. Depois disso, si &#233; incrementado, indo portanto para o pr&#243;ximo caractere automaticamente.</p><p>Precisamos testar se o registrador al possui o valor 0/<code>NULL_CHARACTER, </code>indicando que chegamos ao fim da <em>string</em>. Em caso positivo, vamos para o fim da fun&#231;&#227;o para limpeza e retorno. Em caso negativo, h&#225; um caractere v&#225;lido para a impress&#227;o no registrador al. Nesse caso, podemos usar a fun&#231;&#227;o <code>print_char </code>para imprimir esse elemento, certo? Basta apenas empilhar esse par&#226;metro e invocar a fun&#231;&#227;o <code>print_char<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> </code>e retornar para o r&#243;tulo <code>loop_print_string, </code>para continuar carregando mais caracteres.</p><p>Como resultado, temos a <em>string </em>&#8220;pHello, world&#8221; seguindo do cursor na outra linha da tela. &#201; exatamente o que queremos para o momento!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MQyN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MQyN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 424w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 848w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 1272w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MQyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png" width="1456" height="786" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:786,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107667,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MQyN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 424w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 848w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 1272w, https://substackcdn.com/image/fetch/$s_!MQyN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa20f23ae-78f4-491c-9bd6-825d70782cde_1491x805.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>O c&#243;digo pode ser encontrado nessa <a href="https://github.com/rodrigogbranco/boring-os/tree/p1-v2">branch</a> no meu github.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga?r=2jdzwu&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga?r=2jdzwu"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/hora-de-nos-mover?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/hora-de-nos-mover?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>N&#227;o estamos preocupados com desempenho no momento. Obviamente invocar a fun&#231;&#227;o <code>print_char </code>para cada caractere, fazendo manipula&#231;&#245;es de pilha e chamadas custosas como CALL poderiam deteriorar um sistema de produ&#231;&#227;o. Nesse caso, seria melhor duplicar o c&#243;digo da print_char no trecho da chamada da fun&#231;&#227;o da BIOS. Ou mesmo escrever diretamente na mem&#243;ria de v&#237;deo no endere&#231;o 0xB8000. Em todo caso, o importante agora &#233; a legibilidade do c&#243;digo, at&#233; porque esse c&#243;digo deve desaparecer depois.</p></div></div>]]></content:encoded></item><item><title><![CDATA[BoringOS - O início da Saga]]></title><description><![CDATA[Come&#231;ando a configurar o ambiente - QEMU]]></description><link>https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/boringos-o-inicio-da-saga</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Mon, 21 Oct 2024 18:54:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!x5xD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Antes de partir para os finalmentes, gostaria de deixar claro uma coisa: O nome <em>BoringOS</em> n&#227;o tem rela&#231;&#227;o com a <em><a href="https://www.boringcompany.com/">Boring Company</a></em>. Refor&#231;ando, o <em>boring</em> aqui &#233; para indicar que o nosso produto n&#227;o &#233; t&#227;o interessante assim, o legal &#233; construir ele (se &#233; que se pode dizer que &#233; um produto).</p><p>Outra coisa &#233; que n&#227;o tenho a pretens&#227;o de ensinar <em>assembly</em>, C ou qualquer coisa do tipo. &#201; bom que voc&#234; j&#225; tenha uma bagagem disso antes de prosseguir (ou pode aprender no processo). Para <em>assembly</em>, por exemplo, h&#225; outros materiais que recomendo, como os artigos do <a href="https://bsky.app/profile/leandronsp.com">Leandro</a> <a href="https://dev.to/leandronsp/construindo-um-web-server-em-assembly-x86-parte-i-introducao-14p5">aqui</a>.</p><p>Como somos disciplinados, vamos seguir os passos apresentados <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">aqui</a>. O primeiro passo &#233;: &#8220;<em>Review project specs, read the necessary documentation, download the start code.</em>&#8221;. Ok, aceito os termos, quero continuar :D !</p><p>Vamos para o passo dois: &#8220;<em>Complete the <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.html">Quickstart Tutorial</a> to working with Bochs on the lab machines.</em>&#8221;</p><p>Aqui, duas diferen&#231;as importantes. Quero deixar o meu c&#243;digo o mais diferente poss&#237;vel do c&#243;digo dos caras de Princeton, ent&#227;o, al&#233;m de n&#227;o o consultar, ainda propus duas altera&#231;&#245;es, no compilador assembler e no emulador/simulador/virtualizador:</p><ol><li><p>Vamos usar <em><a href="https://nasm.us/">NASM</a></em> em vez do <em><a href="https://en.wikipedia.org/wiki/GNU_Assembler">Gnu Assembler</a></em>; e</p></li><li><p>Vamos usar o <em><a href="https://www.qemu.org/">QEMU</a></em> em vez do <em><a href="https://bochs.sourceforge.io/">Bochs</a></em>.</p></li></ol><p>Em rela&#231;&#227;o ao <em>NASM</em>, na verdade eu j&#225; tinha experi&#234;ncia com ele. O <em>as</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a><em> </em>eu aprendi fazendo o <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html">Projeto 1</a>. J&#225; em rela&#231;&#227;o ao QEMU, confesso que usei muito pouco. Usei muito mais o <em>Bochs</em>, ele tem um mini <em><a href="https://www.onlinegdb.com/">gdb</a></em> integrado e tem coisas legais como <em>magic breakpoint</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>Mas isso n&#227;o vai nos amedrontar certo? Vamos fazer igual o Frank Sinatra, <em>My Way</em> (ou se voc&#234; for <em>Millenium </em>como eu, a refer&#234;ncia &#233; o Limp Bizkit). </p><p>Um ponto importante &#233; que programar um <em>kernel</em> &#233; praticamente um <em>Metroidvania</em>: voc&#234; precisar ir e voltar v&#225;rias vezes, testar, restartar e frequentemente voc&#234; vai quebrar algo que j&#225; estava funcionando. Se eu postei aqui, &#233; porque eu j&#225; passei por essas etapas e j&#225; estou mostrando algo funcional.</p><p>Ok, vamos come&#231;ar. Primeiro vamos entender o que o <em><a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.html">Bochs Quickstart</a> </em>prop&#245;e.</p><h1>Processo de Boot</h1><p>Essa parte do trabalho quer verificar seu ambiente, se o <em>Bochs </em>est&#225; corretamente configurado, se voc&#234; consegue executar o <em>bootloader </em>dado e ver a letra S na tela, etc.</p><p>Vamos recapitular ent&#227;o como &#233; o processo de boot no processador x86. Para detalhes s&#243;rdidos, veja <a href="https://wiki.osdev.org/System_Initialization_(x86)">aqui</a>. Mas vamos resumir: quando o computador liga, o processador n&#227;o faz ideia do que est&#225; ligado nele: perif&#233;ricos, discos, quanto de RAM tem no seu sistema, e assim por diante. Por esse motivo, h&#225; um conjunto de passos padronizados que s&#227;o efetuados:</p><ol><li><p>O processador executa um c&#243;digo de um chip/firmware ROM que faz toda a checagem do sistema, chamado <a href="https://en.wikipedia.org/wiki/Power-on_self-test">POST</a>. A maior parte desse trabalho &#233; de responsabilidade da <a href="https://en.wikipedia.org/wiki/BIOS">BIOS</a>, e em sistemas mais modernos, <a href="https://en.wikipedia.org/wiki/UEFI">UEFI</a>. H&#225; v&#225;rias checagens de hardware que s&#227;o feitas nesses passos, como detec&#231;&#227;o de RAM e outras coisas que n&#227;o nos interessam agora.</p></li><li><p>Ao finalizar os testes de hardware, a BIOS vai tentar localizar o <em>bootloader</em>. Para isso, ele vai varrer a lista de discos<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>, na ordem especificada pelo usu&#225;rio (e na aus&#234;ncia desta ordem, ele usa a default do dispositivo), em busca do disco de boot. A BIOS l&#234; o primeiro setor do disco, a procura de uma assinatura espec&#237;fica (que no caso do x86, &#233; verificar se nos &#250;ltimos dois bytes do primeiro setor (um setor tem 512 bytes) h&#225; o valor 0x55AA. N&#227;o h&#225; nada de especial neste valor em si, mas se voc&#234; transformar em bin&#225;rio, verificar&#225; que &#233; um padr&#227;o <strong>01010101</strong> <strong>10101010. </strong>Isso indica que algu&#233;m intencionalmente escreveu tal padr&#227;o neste setor, indicando para o sistema ser o setor de boot.</p></li><li><p>A BIOS coloca esses 512 bytes em um endere&#231;o absoluto espec&#237;fico e pr&#233;-acordado da arquitetura: <strong>0x7c00</strong>. O porqu&#234; desse eu n&#227;o sei, n&#227;o me pergunte. Mas depois que a BIOS termina esse trabalho, ela faz um <em>far jump</em> para ele e entrega a execu&#231;&#227;o para o bootloader. A partir dai &#233; seu c&#243;digo que est&#225; no controle do equipamento.</p></li></ol><p>O projeto apresenta um c&#243;digo para mostrar um caractere na tela, no passo 2 <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.html">daqui</a> e, se ainda precisar de ajuda, pode consultar algumas dicas <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/asmtips1.html">aqui</a>. Vamos nos basear nesse c&#243;digo ent&#227;o, mas vamos dar uma simplificada.</p><pre><code>global _start

_start:
    mov ah, 0x0e
    mov al, 'S'
    mov bh, 0x00
    mov bl, 0x02
    int 0x10

TIMES 510-($-$$) DB 0

db 0x55, 0xaa</code></pre><p>No c&#243;digo acima, definimos o s&#237;mbolo global <em>_start</em> para que o <em>linker </em>encontre o ponto de entrada do programa. Depois, usamos a fun&#231;&#227;o da BIOS de escrita de caractere na tela. os par&#226;metros s&#227;o:</p><p>ah = 0x0e (sempre)<br>al = caractere a ser escrito (no caso, &#8216;S&#8217;)<br>bh = n&#250;mero da p&#225;gina ativa (usamos 0x00)<br>bl = cor de fundo em modo gr&#225;fico (usamos 0x02)</p><p>Ai &#233; s&#243; executar a instru&#231;&#227;o int 0x10 e correr para o abra&#231;o.</p><p>At&#233; esse ponto, o c&#243;digo acima consumiu alguns bytes, n&#227;o sabemos o quanto necessariamente, nem precisamos (fica de li&#231;&#227;o de casa voc&#234; pegar o manual do ISA x86 e descobrir quantos bytes tem at&#233; o momento). Mas at&#233; a linha 7 acima, esse c&#243;digo n&#227;o representa um setor de boot, que vir&#225; logo em seguida. </p><p>Precisamos de v&#225;rios bytes at&#233; preencher 510, e depois inserir dois bytes da assinatura do setor de boot. Essa &#233; a fun&#231;&#227;o das pr&#243;ximas duas linhas. <code>$-$$ </code>verifica quanto bytes foram gastos do in&#237;cio do arquivo at&#233; a linha anterior, e a diretiva de compila&#231;&#227;o TIMES repete DB 0 bytes quantas vezes quisermos, no caso, 510-($-$$) vezes. Isso garante que tenhamos 510 bytes preenchidos, e ai finalizamos com a cereja do bolo com os &#250;ltimos dois bytes 0x55AA.</p><p>Ok, e como a gente monta isso. Perceba no <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.html">passo 3</a> que eles executam um <em>Makefile </em>que faz v&#225;rias coisas (imagem abaixo). </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x5xD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x5xD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 424w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 848w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 1272w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x5xD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png" width="763" height="466" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3770b49-5d36-4ec8-922a-431c01f72890_763x466.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:466,&quot;width&quot;:763,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61418,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x5xD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 424w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 848w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 1272w, https://substackcdn.com/image/fetch/$s_!x5xD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3770b49-5d36-4ec8-922a-431c01f72890_763x466.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fonte: https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.htm</figcaption></figure></div><p>Por enquanto, estamos s&#243; na primeira parte. Queremos compilar o arquivo para que seja gerado um bin&#225;rio de boot. Portanto, estamos tratando apenas das 2 primeiras linhas do comando. A primeira, <em>gcc -Wall -g -m32 -fomit-frame-pointer -O2 -fno-builtin bootblock.s</em> invoca por baixo dos panos o <em>as. </em>Vamos esclarecer o que esses par&#226;metros invocados no comando significam. </p><p><em>-Wall</em> significa ligar todos os <em>warnings</em>. O compilador &#233; seu amigo, e se ele t&#225; te alertando de algo, &#233; bom ficar esperto. </p><p><em>-g</em> &#233; necess&#225;rio para ativar a depura&#231;&#227;o e para que possamos carregar a tabela de s&#237;mbolos quando usamos um compilador como o <em>gdb</em>. </p><p><em>-m32</em> indica a arquitetura do c&#243;digo gerado, no caso, x86 (n&#227;o compilar para 64bit). </p><p><em>-fomit-frame-pointer</em> tem rela&#231;&#227;o com os registradores de base de pilha, no caso do x86, o bp. Como estamos executando um c&#243;digo em que n&#243;s mesmos precisamos gerenciar a pilha, isso indica ao compilador n&#227;o criar o <a href="https://edisciplinas.usp.br/pluginfile.php/293355/mod_resource/content/1/21-LeituraComplementar-Pilha-execucao-e-variaveis-locais.pdf">registro de ativa&#231;&#227;o</a>. </p><p><em>-O2</em> ativa a otimiza&#231;&#227;o em n&#237;vel de compila&#231;&#227;o (nem sempre &#233; poss&#237;vel ativar essa op&#231;&#227;o, nesse nosso caso n&#227;o far&#225; diferen&#231;a).</p><p><em>-fno-builtin</em> desabilita a utiliza&#231;&#227;o de fun&#231;&#245;es de biblioteca da arquitetura local. Voc&#234; n&#227;o pode usar as fun&#231;&#245;es da <em>stdio.h</em> da <em>libc</em> no kernel por exemplo (j&#225; que no fim das contas, as chamadas acabam invocando <em>system calls</em> do sistema host, mas o seu c&#243;digo n&#227;o tem um SO aceitando <em>system calls</em> ainda&#8230;). Por isso, avisa ao compilador para n&#227;o se preocupar com isso.</p><p>Esse primeiro comando gerar&#225; um arquivo objeto <em>bootblock.o, </em>mas esse arquivo ainda n&#227;o pode ser utilizado dessa forma. O segundo comando executa o linker (ld) para gerar o bin&#225;rio execut&#225;vel final (<em>but not so much</em>, como veremos a seguir). As op&#231;&#245;es passadas para o linker foram:</p><p><em>-nostartfiles -nostdlib</em> tem a mesma fun&#231;&#227;o do <em>-fno-builtin </em>dito anteriormente, n&#227;o usar a libc e similares.</p><p><em>-melf_i386</em> indica o formato do execut&#225;vel, no caso um ELF para x86.</p><p><em>-Ttext 0x0 </em>&#233; um caso interessante, pois este indica o endere&#231;o na mem&#243;ria que o segmento de texto (portanto, o c&#243;digo) deve residir. Contudo, j&#225; foi dito que este primeiro trecho de c&#243;digo &#233; colocado pela BIOS no endere&#231;o absoluto 0x7c00. Ent&#227;o, para que se importar? Primeiro, haver&#225; um pr&#243;ximo passo, n&#227;o abordado nesse artigo, que ir&#225; condensar o bootblock e o kernel em uma &#8220;imagem&#8221; s&#243; que ser&#225; usada. Isso pode ser visto na imagem acima no comando <em><strong>./createimage.given &#8212;extended ./bootblock ./kernel</strong></em>. O segundo motivo &#233; que as instru&#231;&#245;es de <em>jump</em> dentro do c&#243;digo do boot podem ser absolutas ou relativas a instru&#231;&#227;o atual. Dependendo de como voc&#234; faz o jump no c&#243;digo, ele pode ir para um endere&#231;o inv&#225;lido. Mas a real REAL mesmo &#233; que a imagem &#233; uma cole&#231;&#227;o de bytes cont&#237;guos, e como temos o c&#243;digo bootloader + kernel gerados pelo programa <em>createimage.given</em>, iriamos acabar com o bootloader no endere&#231;o 0x7c00 e o kernel no endere&#231;o 0x1000, antes portanto, do pr&#243;prio bootloader! Isso de fato &#233; um problema real para o bootloader, pois se o kernel for muito grande, ele pode come&#231;ar no endere&#231;o 0x1000 e ultrapassar o endere&#231;o 0x7c00, sobreescrevendo o bootloader na mem&#243;ria. Isso &#233; uma das coisas que iremos resolver depois inclusive. Mas, agora, precisamos apenas que o compilador e linker n&#227;o reclamem desses endere&#231;os em tempo de compila&#231;&#227;o, e portanto colocamos o c&#243;digo do bootloader no arquivo ELF no endere&#231;o 0x0.</p><p>E o que a gente faz com todas essas informa&#231;&#245;es? Vamos come&#231;ar a montar nosso Lego.</p><h1>Pr&#233;-requisitos</h1><p>Eu estou usando o Linux no WSL no meu Windows 11. Instalei basicamente os pacotes do QEMU, NASM e GDB com o comando abaixo:</p><pre><code>sudo apt install aqemu qemu-system qemu-system qemu-system-x86 virt-manager bridge-utils nasm gdb</code></pre><p>Infelizmente n&#227;o tenho como garantir que mais algum pacote necess&#225;rio tenha sido instalado anteriormente em outros momentos. Talvez o gcc.</p><p>Mas isso n&#227;o &#233; suficiente para poder rodar o QEMU usando o KVM no WSL. Para isso, ainda &#233; necess&#225;rio seguir os passos <a href="https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware">daqui</a>:</p><ol><li><p>Adicione o seu usu&#225;rio ao grupo kvm com o comando abaixo:</p><pre><code>sudo usermod -a -G kvm ${USER}</code></pre></li><li><p>Altere o grupo default do dispositivo /dev/kvm. Para isso edite o arquivo /etc/wsl.conf e adicione a linha abaixo na se&#231;&#227;o boot:</p><pre><code>[boot]
command = /bin/bash -c 'chown -v root:kvm /dev/kvm &amp;&amp; chmod 660 /dev/kvm'</code></pre><p>Obs: &#233; poss&#237;vel que j&#225; exista outras instru&#231;&#245;es nesse bloco, nesse caso, apenas adicione a linha indicada.</p></li><li><p>Habilite a virtualiza&#231;&#227;o aninhada. Para isso, adicione a seguinte linha no bloco wsl2 no arquivo /etc/wsl.conf (se esse bloco n&#227;o existir, crie-o):</p><pre><code>[wsl2]
nestedVirtualization=true</code></pre></li><li><p>No fim das contas, o meu arquivo /etc/wsl.conf ficou assim (o seu pode ter ficado diferente dependendo do sistema):</p><pre><code>[boot]
systemd=true
command = /bin/bash -c 'chown -v root:kvm /dev/kvm &amp;&amp; chmod 660 /dev/kvm'

[wsl2]
nestedVirtualization=true</code></pre></li><li><p>Feche todos os terminais WSL abertos, abra um Power Shell no windows e reinicie o WSL:</p><pre><code>wsl.exe --shutdown</code></pre><p>Isso foi suficiente para o QEMU funcionar com KVM na minha m&#225;quina.</p></li></ol><h1>Nosso bootloader</h1><p>A primeira altera&#231;&#227;o ser&#225; mudar a extens&#227;o do arquivo de .s para .asm, j&#225; que estamos usando o <em>NASM</em> em vez do <em>Gnu Assembler</em>. O segundo ponto &#233; que eu deliberadamente alterei o nome do arquivo de <em>bootblock.s</em> para <em>bootloader.asm</em>, afinal, <em>why not</em>?</p><p>N&#227;o verifiquei o Makefile da imagem acima, e n&#227;o sou um especialista em <em>Makefiles</em>, ent&#227;o <em>bear with me, please</em>. Nosso <em>Makefile </em>fica assim (por enquanto!):</p><pre><code>all: bootloader

bootloader.o: bootloader.asm
&#9;nasm -wall -O2 -f elf32 -F dwarf -g $&lt;

bootloader: bootloader.o
&#9;ld -nostdlib -g -m elf_i386 -Ttext 0x0 --oformat binary -o $@ $&lt;

clean:
&#9;rm -rf *.o bootloader</code></pre><p>Feio n&#233;? &#201; o que tem pra hoje. Eu queria muito entender daquelas paradas avan&#231;adas de Makefile, .PHONY etc, mas fiz uma busca r&#225;pida aqui para usar algumas coisas pelo menos e por enquanto, vamos usar s&#243; o <code>$@ </code>e<code> $&lt;</code>. Um dia eu fico bom nisso (ou n&#227;o, n&#227;o &#233; minha prioridade :D )</p><p>Vamos ent&#227;o entender esse Makefile. Esse tipo de arquivo &#233; executado de forma recursiva. Come&#231;ando pelo target <em>all, </em>ele buscar&#225; o target <em>bootloader. </em>O <em>bootloader</em>, por sua vez, espera que exista o target <em>bootloader.o</em>. O bootloader.o espera que exista o arquivo bootloader.asm. Esse &#233; diretamente compilado pelo comando  <code>nasm -wall -O2 -f elf32 -F dwarf -g $&lt;</code>. Para qualquer par de targets e pr&#233;-requisitos (neste caso, estamos falando do target <code>bootloader.o </code>e do pr&#233;-requisito <code>bootloader.asm </code>na linha 3 do Makefile, &#233; poss&#237;vel especificar o target com $@ e o primeiro pr&#233;-requisito com $&lt;. Nesse caso ent&#227;o $&lt; &#233; substitu&#237;do pelo primeiro pr&#233;-requisito do target, e no caso s&#243; temos um, <code>bootloader.asm</code>. Se houve mais de um pr&#233;-requisito e se quis&#233;ssemos referenciar todos, usar&#237;amos a diretiva $^. N&#227;o vou entrar a fundo nisso, at&#233; porque n&#227;o tenho o conhecimento necess&#225;rio, mas essas dicas que estou dizendo foram tiradas <a href="https://makefiletutorial.com/">daqui</a>.</p><p>O comando do target <code>bootloader.o </code>n&#227;o &#233; muito diferente do original da imagem acima, com exce&#231;&#227;o do par&#226;metro <code>-F dwarf, </code>que apenas indica o formato para gera&#231;&#227;o de informa&#231;&#245;es de debugging. Para mais detalhes disso, veja com o comando <code>nasm &#8212;help</code>.</p><p>Com o bootloader.o criado, o pr&#243;ximo target executado &#233; o <code>bootloader, </code>que invoca o linker na linha 7. O comando tamb&#233;m &#233; como o anterior, exceto no formato de sa&#237;da: <code>--oformat binary. </code>Ou seja, n&#227;o vamos gerar um ELF, mas sim um <code>binary raw</code> que ser&#225; executado diretamente pelo emulador. Isso por enquanto, essa situa&#231;&#227;o ser&#225; alterada no futuro, e o formato de sa&#237;da desse comando voltar&#225; a ser um ELF.</p><p>Observe ainda o final do comando: <code>-o $@ $&lt;. </code>Isso indica que a sa&#237;da/output do comando ser&#225; o par&#226;metro <code>$@, </code>que como vimos &#233; o target desse trecho do Makefile e no nosso caso, equivale a <code>bootloader. </code>E a diretiva <code>$&lt; </code>&#233; o primeiro dos pr&#233;-requisitos do target, e neste caso s&#243; h&#225; um, <code>bootloader.o. </code>Isso significa que <code>-o $@ $&lt; </code>&#233; diretamente traduzido para <code>-o bootloader bootloader.o.</code></p><p>O target clean serve para fazer as limpezas de praxe. Como esse Makefile s&#243; gera dois arquivos, <em>bootloader.o</em> e <em>bootloader</em>, &#233; suficiente para o nosso caso executar o comando <em>rm -rf *.o bootloader</em>.</p><p>Eu gosto de executar os comandos <em>make clean &amp;&amp; make</em> simultaneamente, para limpar lixo de execu&#231;&#245;es passadas e j&#225; executar uma compila&#231;&#227;o nova. A sa&#237;da desse comando ficou assim:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jsSh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jsSh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 424w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 848w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 1272w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jsSh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png" width="661" height="48" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:48,&quot;width&quot;:661,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4691,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jsSh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 424w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 848w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 1272w, https://substackcdn.com/image/fetch/$s_!jsSh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a66e8b-2e82-42ee-8169-f83ea26f84e8_661x48.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Nesse momento, os arquivos bootloader.o e bootloader devem aparecer no seu sistema de arquivos.</p><p>Temos mais dois arquivos auxiliares para a execu&#231;&#227;o de nosso bootloader. O primeiro &#233; o <em>VM_BoringOS.sh</em>, um arquivo inicialmente criado pelo AQEMU mas que eu adaptei para nosso caso. O conte&#250;do desse arquivo &#233; o seguinte:</p><pre><code>#!/bin/sh
# This script created by AQEMU

CURRDIR=`pwd`

/usr/bin/qemu-system-x86_64 -machine accel=kvm -m 16 -drive file="$CURRDIR/bootloader",index=0,if=floppy,format=raw -boot once=a,menu=on -net nic -net user -rtc base=utc -name "BoringOS" -cpu host -s -S $*</code></pre><p>O comando define a vari&#225;vel de ambiente CURRDIR como o diret&#243;rio do projeto (onde se encontra os arquivos bootloader e bootloader.o). Solicitamos o tipo de virtualiza&#231;&#227;o kvm, e 16MB de RAM. Solicitamos que o arquivo bootloader (nosso execut&#225;vel) seja usado como imagem do floppy disk (disquete, para os &#237;ntimos) em formato <em>raw</em>. Ele define v&#225;rios outros valores desimportantes para o momento, mas precisei adicionar o final do comando: <code>-cpu host -s -S. -cpu host </code>indica que o cpu do meu host seja usado (pois ele possui atributos de virtualiza&#231;&#227;o), -s habilita a depura&#231;&#227;o pela porta padr&#227;o 1234/tcp, e -S congela a execu&#231;&#227;o assim que a m&#225;quina &#233; ligada, aguardando a continua&#231;&#227;o da execu&#231;&#227;o do comando pelo <em>debugger</em>.</p><p>Ao executar o arquivo com o comando ./VM_BoringOS.sh, devemos ver a tela abaixo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RZCw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RZCw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 424w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 848w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 1272w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RZCw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png" width="650" height="539" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:539,&quot;width&quot;:650,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8863,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RZCw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 424w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 848w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 1272w, https://substackcdn.com/image/fetch/$s_!RZCw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F669876e0-3ac8-4fe2-b7d4-29d266170e52_650x539.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Neste momento o QEMU est&#225; pausado aguardando instru&#231;&#245;es. O bootloader ainda nem foi carregado.</p><p>O pr&#243;ximo arquivo auxiliar &#233; o debug_BoringOS.sh. Esse arquivo deve ser executado depois do anterior, para que o gdb possa se atachar ao QEMU e possa emitir comandos.</p><p>O conte&#250;do do arquivo <em>VM_BoringOS.sh</em> &#233; o seguinte:</p><pre><code>#!/bin/sh

gdb -ex 'target remote localhost:1234' -ex 'set confirm off' -ex 'add-symbol-file bootloader.o 0x7c00' -ex 'set confirm on' -ex 'hbreak *_start' -ex 'c'</code></pre><p>Perceba que usamos o gdb para se conectar no QEMU (1234/tcp), desligamos momentaneamente as confirma&#231;&#245;es e adicionamos os s&#237;mbolos de depura&#231;&#227;o do arquivo <code>bootloader.o </code>alinhado no endere&#231;o<code> </code>0x7c00 (lembre-se que na realidade o segmento de texto est&#225; no endere&#231;o 0x0). Depois religamos as confirma&#231;&#245;es e definimos um breakpoint para o endere&#231;o _start. Usamos o <em>hbreak *</em>, que significa hardware assisted breakpoint, pois estamos executando em um ambiente virtualizado do KVM. Se fosse diferente disso, o breakpoint seria definido no endere&#231;o virtual 0x7c00 que est&#225; relacionado ao processo do QEMU, mas n&#227;o ao nosso bootloader virtualizado. Enfim, <code>hbreak *0x7c00 </code>tamb&#233;m funcionaria nesse caso.</p><p>Considerando que o comando ./VM_BoringOS.sh foi executado anteriormente e est&#225; pausando aguardando comandos, executando o comando ./debug_BoringOS.sh, temos:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uuJQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uuJQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 424w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 848w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 1272w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uuJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png" width="1456" height="424" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:424,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87238,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uuJQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 424w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 848w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 1272w, https://substackcdn.com/image/fetch/$s_!uuJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5a8cc3-8240-4111-a16c-769b27fcd8e6_1851x539.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Do lado esquerdo, temos que o QEMU adiciona os s&#237;mbolos do bootloader.o e define o breakpoint de _start. Ele ent&#227;o manda o QEMU continuara execu&#231;&#227;o, e o QEMU, do lado direito, executa o POST/BIOS, busca e encontra o setor de boot no disquete montando (nosso arquivo bootloader). Ele ent&#227;o carrega o conte&#250;do desses 512 bytes a partir do endere&#231;o 0x7c00 e faz um <em>far jump</em> para esse endere&#231;o. Nesse momento, o QEMU encontra nosso breakpoint definido anteriormente, para a execu&#231;&#227;o ai.</p><p>Ao disparar comandos s (ou step) no gdb, navegamos pelos nossos comandos do arquivo bootloader.asm, e o resultado &#233; um S impresso na tela do QEMU, que &#233; o que quer&#237;amos fazer desde o in&#237;cio! </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NUjk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NUjk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 424w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 848w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 1272w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NUjk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png" width="1456" height="426" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:426,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:70500,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NUjk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 424w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 848w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 1272w, https://substackcdn.com/image/fetch/$s_!NUjk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cd23ffd-a243-46a7-869f-eb2793895918_1844x539.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Quanta trabalheira s&#243; para isso. <em>Boring</em>, n&#227;o &#233; mesmo? No pr&#243;ximo artigo, vamos criar o c&#243;digo para juntar o bootloader e um kernel safado, baseado no createimage do <a href="https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/quickstart/quickstart.html">Projeto 1</a>. O c&#243;digo pode ser encontrado nessa <a href="https://github.com/rodrigogbranco/boring-os/releases/tag/p1-v1">tag aqui no github</a> ou nesse <a href="https://github.com/rodrigogbranco/boring-os/commit/bd21156132308bf86b2749339153a9658d177ec7">commit espec&#237;fico</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://open.substack.com/pub/rodrigobranco/p/boring-os-comecando-do-comeco?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true&quot;,&quot;text&quot;:&quot;Anterior&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://open.substack.com/pub/rodrigobranco/p/boring-os-comecando-do-comeco?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true"><span>Anterior</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai?r=2jdzwu&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/p/e-andando-pra-tras-que-a-gente-vai?r=2jdzwu"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>&#201; o nome do execut&#225;vel do <em>Gnu Assembler</em> na linha de comando do Linux</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>&#201; a instru&#231;&#227;o especial <em>xchg bx, bx, </em>que, quando emulado pelo Bochs, automaticamente faz o c&#243;digo parar para depura&#231;&#227;o. At&#233; onde eu sei, o QEMU n&#227;o tem nada similar.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>N&#227;o s&#243; discos, h&#225; outras formas de se encontrar o SO. Por exemplo, voc&#234; pode bootar o computador pela rede usando <em><a href="https://en.wikipedia.org/wiki/Preboot_Execution_Environment">PXE</a></em>.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Boring OS - Começando do começo]]></title><description><![CDATA[Afinal, come&#231;ar do final n&#227;o parece fazer muito sentido]]></description><link>https://blog.rodrigobranco.net/p/boring-os-comecando-do-comeco</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/boring-os-comecando-do-comeco</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Fri, 18 Oct 2024 18:43:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/48579e2c-188c-4054-82e5-eaa8c6fb9cfd_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bZCj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bZCj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bZCj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:190900,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bZCj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!bZCj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd23336f-1678-46eb-ac81-8f4e3ceac3b1_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Eu tive &#243;timos professores na faculdade, e de tudo que eu aprendi de computa&#231;&#227;o, o que eu mais gostava sem d&#250;vida eram mat&#233;rias de programa&#231;&#227;o de baixo n&#237;vel. Meu Professor de Linguagem de Montagem na UFMS, Prof. Ronaldo, lecionava tamb&#233;m mat&#233;rias de Redes de Computadores e at&#233; mesmo Sistemas Operacionais, igualmente interessantes.</p><p>Haviam outros professores igualmente habilidosos, e me recordo como se fosse hoje de aprender <em>quaternions<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> </em>na disciplina de Computa&#231;&#227;o Gr&#225;fica com o Prof. Pagliosa. O motor gr&#225;fico que fizemos (entenda o &#8220;n&#243;s&#8221; aqui como ele - o professor, no fim das contas era um <em>boilerplate</em> onde precis&#225;vamos completar trechos espec&#237;ficos) resultou em um dos trabalhos mais interessantes, e ao mostrar o resultado para a minha namorada &#224; &#233;poca - hoje, esposa - ela n&#227;o pareceu t&#227;o impressionada, e me lembra at&#233; hoje de ter ficado feliz de ter desenhado uma hem&#225;cia em 3D.</p><p>Deixando as digress&#245;es de lado, os trabalhos de Linguagem de Montagem eram fascinantes, para quem gostava obviamente. Nem todos os alunos compartilhavam da minha opini&#227;o de que eram divertidos. &#201; o tipo de mat&#233;ria que se voc&#234; n&#227;o tem interesse ou perdeu alguma aula, pode ficar sem acompanhar o restante da disciplina. Principalmente para um estudante no segundo ano do curso de Ci&#234;ncia da Computa&#231;&#227;o, tais trabalhos eram dif&#237;ceis de entender, assimilar e codificar. Ainda s&#227;o, na real. </p><p>Lembro dos trabalhos que tivemos que fazer at&#233; hoje. O primeiro era um <em>dissassembler</em>: dado um execut&#225;vel em formato <em>raw binary </em>(isso porque existem outros tipos de execut&#225;veis bin&#225;rios, como o <strong>ELF</strong><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> ou <strong>COFF</strong><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>, para citar alguns), a miss&#227;o era ler arquivo bin&#225;rio, identificar as opera&#231;&#245;es e operandos, e imprimir o c&#243;digo equivalente em <em>assembly</em> no formato <strong>NASM</strong><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. Para isso foi necess&#225;rio ler o manual do processador x86<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, descobrir o <em>opcode</em> de cada uma das instru&#231;&#245;es, identificar o tamanho da instru&#231;&#227;o na mem&#243;ria (quantos bytes ocupava), os operandos, etc. Pois &#233;, para a surpresa de ningu&#233;m, a arquitetura CISC dos processadores x86 adicionam uma complexidade para a decodifica&#231;&#227;o de suas instru&#231;&#245;es. Este trabalho todo feito em C, e pela primeira vez, tivemos contato com ponteiros de fun&#231;&#227;o, com o opcode servindo de &#237;ndice para chamarmos a fun&#231;&#227;o que decodifica a instru&#231;&#227;o.</p><p>O segundo foi implementar o tipo <em>BigInteger</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a>, que existe em Java, em <em>assembly</em>. Na &#233;poca, n&#227;o hav&#237;amos tido a disciplina de Java. E o problema em si era, dado um n&#250;mero inteiro de tamanho qualquer, possivelmente maior que os 32bit dos registradores que possu&#237;amos, e fazer as opera&#231;&#245;es b&#225;sicas de adi&#231;&#227;o, subtra&#231;&#227;o, multiplica&#231;&#227;o e divis&#227;o com tais dados.</p><p>O terceiro foi implementar uma lista ligada em <em>assembly</em>.</p><p>O quarto foi o mais interessante. O professor fazia uma mini <em>bootloader </em>e nossa miss&#227;o era salvar o endere&#231;o da interrup&#231;&#227;o da BIOS que fica no vetor de interrup&#231;&#245;es (primeiros endere&#231;os da mem&#243;ria), substitu&#237;amos por uma fun&#231;&#227;o nossa, que era encarregada de mostrar um rel&#243;gio no canto inferior esquerdo da tela. Depois que nossa fun&#231;&#227;o terminava, n&#243;s invoc&#225;vamos a fun&#231;&#227;o original que havia sido salva. Dessa forma, a cada <em>tick</em> do rel&#243;gio, nosso rel&#243;gio era atualizado na tela. Trabalh&#225;vamos em conjunto com a interrup&#231;&#227;o do teclado, para que pud&#233;ssemos escrever coisas na tela e ver o rel&#243;gio funcionando simultaneamente.</p><p>No fim das contas, aqueles eram tempos mais f&#225;ceis. Muito tempo depois, o Prof. Ronaldo ministrou a disciplina de Sistemas Operacionais para a p&#243;s-gradua&#231;&#227;o. Eu h&#225; muito tinha terminado o mestrado, e j&#225; tinha cumprido os cr&#233;ditos do Doutorado. Mas como ele sabia do meu interesse no tema, eu assistia &#224;s aulas como ouvinte, fazendo os trabalhos tamb&#233;m.</p><p>Para a minha surpresa, o prof. aproveitou o curso COS 318 de Princeton<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>, e portanto far&#237;amos um kernel de verdade!</p><p>Fizemos todos os 6 trabalhos, e nunca aprendi tanto sobre SO como nessa ocasi&#227;o. E percebi o quanto que eu achava que sabia, mas que de fato n&#227;o era verdade, ou das coisas que tinha uma ideia de como as coisas funcionavam mas n&#227;o sabia exatamente como era implementado na pr&#225;tica.</p><p>Chegou a hora de revisitar essas p&#225;ginas e fazer um kernel do zero (n&#227;o falei em quanto tempo). J&#225; batizei o rapaz, e ele tem o nome <em><strong>Boring OS</strong></em> por um motivo muito simples:  ele n&#227;o far&#225; nada impressionante, a divers&#227;o est&#225; na constru&#231;&#227;o. Se voc&#234; notar os 6 projetos de Princeton, notar&#225; por exemplo que n&#227;o h&#225; nada de redes, ou interfaces gr&#225;ficas. E como at&#233; chegar l&#225; &#233; um loooooongo caminho, provavelmente aqui tamb&#233;m n&#227;o ter&#225; nada do tipo.</p><p>Um dos desafios auto impostos por mim a mim mesmo &#233; justamente n&#227;o usar nem consultar nada do que fiz na &#233;poca. Isso &#233; um trabalh&#227;o, j&#225; que entre os projetos, h&#225; muito <em>boilerplate</em> de c&#243;digos j&#225; feitos pela galera da universidade americana. Nada de l&#225; ser&#225; usado aqui, at&#233; por quest&#245;es de pl&#225;gio etc. Portanto, vaguearemos no escuro apenas com as instru&#231;&#245;es da p&#225;gina.</p><p>No pr&#243;ximo artigo come&#231;aremos a por a m&#227;o na massa, no Projeto 1: Bootloader<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-8" href="#footnote-8" target="_self">8</a>! Nos vemos l&#225;.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://open.substack.com/pub/rodrigobranco/p/boringos-o-inicio-da-saga?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true&quot;,&quot;text&quot;:&quot;Pr&#243;ximo&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://open.substack.com/pub/rodrigobranco/p/boringos-o-inicio-da-saga?r=2jdzwu&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true"><span>Pr&#243;ximo</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://link.springer.com/book/10.1007/978-1-4471-7509-4</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>https://en.wikipedia.org/wiki/Executable_and_Linkable_Format</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>https://en.wikipedia.org/wiki/COFF</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>https://nasm.us/</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>N&#227;o foi esse o manual que usei na &#233;poca, mas para fins did&#225;ticos, esse aqui serve: https://cdrdv2.intel.com/v1/dl/getContent/671200</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p>https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects.html</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-8" href="#footnote-anchor-8" class="footnote-number" contenteditable="false" target="_self">8</a><div class="footnote-content"><p>https://www.cs.princeton.edu/courses/archive/fall15/cos318/projects/project1/p1.html</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Em breve]]></title><description><![CDATA[Este &#233; o Blog do Rodrigo Branco.]]></description><link>https://blog.rodrigobranco.net/p/coming-soon</link><guid isPermaLink="false">https://blog.rodrigobranco.net/p/coming-soon</guid><dc:creator><![CDATA[Rodrigo Gonçalves de Branco]]></dc:creator><pubDate>Fri, 18 Oct 2024 14:06:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4DXk!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3a96203-0b94-40e3-a18d-cfc4b328aadf_403x407.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Este &#233; o Blog do Rodrigo Branco.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.rodrigobranco.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscreva agora&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.rodrigobranco.net/subscribe?"><span>Subscreva agora</span></a></p>]]></content:encoded></item></channel></rss>