模擬Linus Torvalds:從頭開始創建自己的操作系統(III)

我們繼續有關如何創建操作系統的系列文章。 今天,我們將不再關註一個主題,而是從現在開始定義一些有用的功能。 首先,我們將定義3個函數,它們滿足 Memcpy, 記憶集 y 記憶體:

void* ND::Memory::Set(void* buf, int c, size_t len)
{
unsigned char* tmp=(unsigned char*)buf;
while(len--)
{
*tmp++=c;
}
return buf;
}
void* ND::Memory::Copy(void* dest,const void* src, size_t len)
{
const unsigned char* sp=(const unsigned char*)src;
unsigned char* dp=(unsigned char*)dest;
for(;len!=0;len--) *dp++=*sp++;
return dest;
}
int ND::Memory::Compare(const void* p1, const void* p2, size_t len)
{
const char* a=(const char*)p1;
const char* b=(const char*)p2;
size_t i=0;
for(;i<len;i++)
{
if(a[i] < b[i]) return -1; else if(a[i] > b[i])
return 1;
}
return 0;
}

它們都是自我實現的。 這些功能是我從小型C庫中獲取的,通常在所有操作系統中的實現都是相似的。 現在,我們將要做3個模擬功能,但要操縱字符串。 他們將履行以下職能 鍊錶, y 鍊錶.

size_t ND::String::Length(const char* src)
{
size_t i=0;
while(*src--)
i++;
return i;
}
int ND::String::Copy(char* dest, const char* src)
{
int n = 0;
while (*src)
{
*dest++ = *src++;
n++;
}
*dest = '';
return n;
}
int ND::String::Compare(const char *p1, const char *p2)
{
int i = 0;
int failed = 0;
while(p1[i] != '' && p2[i] != '')
{
if(p1[i] != p2[i])
{
failed = 1;
break;
}
i++;
}
if( (p1[i] == '' && p2[i] != '') || (p1[i] != '' && p2[i] == '') )
failed = 1;
return failed;
}
char *ND::String::Concatenate(char *dest, const char *src)
{
int di = ND::String::Length(dest);
int si = 0;
while (src[si])
dest[di++] = src[si++];
dest[di] = '';
return dest;
}

我們現在要使用一些非常有趣的功能。 通過這些功能,我們可以讀寫硬件端口。 這通常是通過ASM完成的,並且對應於(在x86上)說明 in y 。 要輕鬆地從C調用ASM,請使用以下說明 ASM,這帶來了不可移植的危險。 在這句話中,我們添加 揮發物 因此GCC不會嘗試優化該文本。 另一方面,asm指令具有一種奇怪的接受參數的方式,但是我認為通過查看示例可以更好地理解。

void ND::Ports::OutputB(uint16_t port, uint8_t value)
{
asm volatile("outb %1, %0" : : "dN"(port), "a"(value));
}
uint8_t ND::Ports::InputB(uint16_t _port)
{
unsigned char rv;
asm volatile("inb %1, %0" : "=a"(rv) : "dN"(_port));
return rv;
}

到目前為止,在第三篇文章中,今天我們還沒有做任何華麗的事情,但是我們定義了一個可以在將來派上用場的函數。 通知3位用戶我正在修復 錯誤 這會阻止以64位正確編譯。 在下一篇文章中,我們將看到x86體系結構的重要組成部分GDT。


發表您的評論

您的電子郵件地址將不會被發表。 必填字段標有 *

*

*

  1. 負責數據:MiguelÁngelGatón
  2. 數據用途:控制垃圾郵件,註釋管理。
  3. 合法性:您的同意
  4. 數據通訊:除非有法律義務,否則不會將數據傳達給第三方。
  5. 數據存儲:Occentus Networks(EU)託管的數據庫
  6. 權利:您可以隨時限制,恢復和刪除您的信息。

  1.   他說:

    讓我們看看您是否對如何解決該錯誤發表了評論,因為我沒有從第一部分開始。

    1.    O_Pixote_O 他說:

      我認為他們在帖子2的評論中評論了錯誤。如果我沒記錯的話,他們認為這是從grub引起的。

  2.   藍頭骨 他說:

    複製再見?

    1.    藍頭骨 他說:

      顯然,逐字節地...連續兩次失敗都沒有成功。

  3.   ruby232 他說:

    非常感謝您的優秀帖子,我關注它,我有一些疑問:
    1.當您說“從C輕鬆調用ASM時,使用了asm指令,但有可能導致它不能移植的危險”,當您說“有可能導致以下問題的危險:它不是便攜式的嗎?

    2.如果要製作一個“專業”操作系統(可以這麼說),那麼訪問硬件的這一部分將在彙編器中完成。

    3.如何在彙編器中完成?

    1.    阿德里安·阿羅約街 他說:

      感謝您的關注,我將一一解答:
      1-嗯,asm指令的問題在於它在任何C標準中都不存在,因此每個編譯器都以自己的方式實現(如果實現)。 在這種情況下,可以使用GCC和Clang進行編譯(在這方面看起來很像GCC),但是您將無法在其他編譯器(如Intel C)中使用(在ASM中使用Intel語法)。
      2-從專業上講,一個部分和另一部分應該由體系結構和另一公共部分清楚地分開。 不需要在彙編程序中執行此操作(Linux在C中包含它)
      3-在彙編器中也非常簡單,但是您將其保存在單獨的文件中。 另一方面,有了參數,我們必須首先將其傳遞給寄存器,這樣可能會使情況更加混亂,然後調用outb或inb並將函數聲明為全局可見的。 然後,必須從C創建一個標頭,該標頭聲明一個“ extern”函數。 在NASM(英特爾語法)中,將是這樣的:
      出站:
      推息
      mov ebp,esp

      mov eax,[ebp + 12]
      mov edx,[ebp + 8]

      出DX

      mov esp,ebp
      流行音樂
      RET

  4.   Max 他說:

    問題,您使用什麼語法? 我不明白為什麼有這麼多不同的asm xD MASM,FASM,NASM,AT&T ...
    如果有時間,您可以解釋一下這一行:
    asm volatile(“ outb%1,%0” ::“ dN”(端口),“ a”(值));

    在“ asm volatile”之前,我是否了解xD“ outbyte 1,0”?
    還是1->»dN»(端口),0->«a»(值)?
    如果是後者,我不明白什麼是“ dn”和什麼是“ a” ...

    非常感謝您的貢獻! 難以置信!

    1.    阿德里安·阿羅約街 他說:

      我使用的語法是AT&T,這是GCC內部使用的語法,儘管它可以在NASM中毫無問題地完成(適應語法)。 關於asm volatile的複雜聲明,由於GCC,我只能告訴您,因為它使用一些參數來知道應該如何傳遞數據。 例如,“ a”是用於表示a寄存器的特殊x86操作數。 整個列表在這裡: http://gcc.gnu.org/onlinedocs/gcc/Constraints.html#Constraints

  5.   charizardfire52 他說:

    好吧,我真的很需要幫助,我是新手,我完全不知道如何使用終端中編寫的內容,有人可以幫助我嗎?