Aros/開發者/核心基礎
現在序列除錯配置在哪裡處理,因為大多數在 x86-64 上修復的內容似乎已被刪除。arch/all-native/bootconsole。我把這段程式碼移到了共享庫,因為它被載入程式和啟動程式都使用。
如果 grub(例如)現在在記憶體地址 0 處載入模組,正如你在另一篇文章中提到的那樣,它會破壞 rsdp 指標,因此我們無法在記憶體中找到 acpi 表。來自地址 0 的模組。這與我的更改無關。這就是 GRUB 的工作方式。它將模組放置在最適合的記憶體區域中。當然,它應該從可用地址範圍內排除所有 BIOS 資訊。如果你的啟動程式覆蓋了 BIOS 資訊,那麼 GRUB 記憶體管理中存在一個錯誤。以前,啟動程式不是分成小塊。單個大型模組根本無法放入 640KB 的常規記憶體中。
另外,如果在啟動程式之前記憶體頁面受到保護,那麼無論如何我們都無法掃描它。只有兩個區域受到保護
- 從地址 0 開始的一頁。
- 啟動程式的只讀區域(.code + .rodata + struct KrnBootPrivate)。
ACPI/SMP 配置的部分必須在核心資源中完成(主要是表解析等,用於配置 AP,因為它們需要訪問核心資源中使用的結構/程式碼)。我知道這一點。ACPI 解析器似乎在 exec/核心基礎建立之前被呼叫。
你遇到的重啟問題似乎與序列輸出程式碼有關。我從舊的 x86-64 程式碼中複製了它,儘可能少地進行更改。為了證明它會導致錯誤,你可以嘗試在沒有序列除錯的情況下啟動。看起來確實如此 - 我現在可以啟動得更遠一些(但仍然會崩潰,可能是由於我自己的更改),並且可以在螢幕上看到更多除錯輸出,但是新增 debug=serial:0@115200 行會讓它再次在同一位置鎖定(跳轉到核心是最後顯示的輸出)。
文字模式輸出也沒有測試。實際上,我在 EFI GRUB 設定的 VESA(幀緩衝區)模式下執行良好。與 PC 的區別是:Multiboot 資訊不包含 VESA 模式和控制器資訊,而只包含通用幀緩衝區資料。VESA 模式資訊是由載入程式根據它建立的,因為 AROS 啟動程式需要它。也許模式設定中存在一些錯誤。首先,我會確保所有輸出(文字模式螢幕、VBE 模式螢幕和序列埠)在載入程式中都能正常工作。如果在所有模式下你都能夠到達“離開 32 位環境”,那就沒問題,libbootconsole 可以正常工作。啟動程式會重新初始化輸出,它使用相同的程式碼,但使用不同的初始化例程。它會解析引導標記列表而不是 Multiboot 資訊。你也可以在 test/boot 中找到一個對你來說很有用的東西。這是一個測試 libbootconsole 的小程式。如果它無法正常工作,那麼那裡肯定存在問題。標記列表解析器中的錯誤可以透過手動使用硬編碼引數初始化 libbootconsole 來除錯,然後轉儲標記列表和相關結構。這就是我除錯它的方法。
還有一個提示:序列輸出可能會產生中斷。也許這就是問題所在。
好的。在對本機 x86_64 進行了一些緩慢的除錯後(不斷新增 halt 並重新構建以檢視圖形除錯輸出...)似乎到目前為止存在以下問題...kernel/kernel_startup.c
kernel_cstart()
/*
* Fill zero page with garbage in order to detect accesses to it in supervisor mode.
* For user mode we will disable all access to it.
*/
MUNGE_BLOCK(NULL, 0xABADCAFE, PAGE_SIZE);
會導致 GPF,之後...
core_ProtKernelArea(0, PAGE_SIZE, 0, 0, 0);
幾乎任何對記憶體列表的訪問都會導致頁面錯誤。我還沒有對此進行太多研究,但要麼記憶體列表位於第一頁,要麼低記憶體的記憶體頭位於第一頁,因此所有試圖分配等記憶體的操作最終都會命中它並崩潰。
好的,這些問題中的大多數似乎源於使用第一頁記憶體(或在從 mmap 初始化 melist 時註冊它)。我認為最好調整要註冊的區域的起始地址,以確保它們大於 PAGE_SIZE。
至於除錯問題 - 並非只有在我們離開載入程式時序列除錯才會停止 - 如果載入程式的輸出超過 4k,也會發生這種情況。看來從 Grub -> 載入程式 -> 核心傳遞的記憶體列表在傳遞到 kernel.resource 之前被破壞了。我會嘗試更深入地挖掘一下,看看問題出現在哪裡。
如果我在 VMWare 中嘗試 - 在 VESA 模式下啟動會導致 kernel.resource 崩潰。但是,如果我在 VGA 模式下啟動,它只顯示序列除錯輸出的資訊(即前 4k 的除錯,或者直到離開 32 位模式為止) - 似乎沒有其他事情發生(即,vesa 會導致虛擬 CPU 死亡或停止,vga 似乎只是處於掛起狀態)。
你是否有任何自定義配置或編譯器/連結器標誌可能會影響實現 64 -> 32 位交叉編譯所需的標誌?有人知道“i386:x86-64 架構”是什麼意思嗎?據我所知,這意味著它是 64 位。我懷疑 smpboot 檔案已被編譯為 64 位,而它正在嘗試將其連結到 32 位程式碼中。我能看到的唯一真正區別是 rule_compile 預設使用目標編譯器,而 rule_link_binary 使用核心連結器。
軟重啟目前在 pc-i386 上已損壞。當我在進入圖形模式之前進行軟重置時,我可以看到沒有找到模組,並且引導在 SAD 提示符處結束。我添加了一個本地除錯語句,它打印出 exec_RomTagScanner() 開始搜尋的地址:在 QEMU 上,初始啟動時的地址是 0x07e70000,而軟重啟時的地址是 0x07fec170。這正常嗎?不,這很不正常。我需要在 i386 本機執行中新增一些程式碼,它會儲存載入程式中的引導訊息標記列表的副本。沒有它,軟重啟將仍然無法正常工作...
Exec 的量子值是任務可以執行的時間量嗎?這個值是基於 vblank 頻率的嗎?是的,就是這樣。每個 VBlank 量子都會遞減。當它達到零時,就會切換任務。
所以任務可以擁有的最小量子是 1/60 秒嗎?實際上是 1 / 50。(如果它沒有自行放棄控制權)。而且,如果沒有任何任務放棄控制權(並且量子 = 1),最多可以有 60 個“任務”獲得執行的機會?每秒 60 次。不是系統中最多可以有 60 個任務。沒錯,每秒 60 次,“下一個等待”任務將獲得執行的機會。它不依賴於任務數量。只有一個任務運行了 4 個 VBlank。據我所知,情況甚至更糟,因為任務一開始就會獲得量子 = 4,所以每秒只有 15 次任務切換。既對又不對。如果任務沒有進行任何會導致它休眠/等待的作業系統呼叫,那麼它將會很低。不過,為了比較,Linux 以前預設設定高達 100(大約在 100 年前),現在預設設定為 250,並且可以配置為每秒執行高達 1000 次計時器中斷。任務可以獲得比一個量子(在 Linux 中稱為一個 jiffy)更長的時隙。
我還沒有機會研究 vblank 中斷計時器是如何實現的,但我認為我們應該有一些方法讓它註冊一個“A”計時器源(以某種方式記錄其精度),並讓 exec 從可用計時器源中選擇在啟動時使用的計時器。
此外,其他計時器源應該能夠在 exec 選擇了一個計時器源之後註冊,並且它們應該能夠替換當前正在使用的計時器源。
我當時的想法是,正在使用的計時器應該有一個掛鉤,它會儲存(基本上是設定下一個“事件”),並且每次事件觸發時,它都會呼叫這個掛鉤以再次設定。如果另一個計時器(具有更高的精度)載入它,那麼它就可以禁止多工處理,用與它相關的量子值替換量子值,並將指向現有掛鉤的指標替換為一個用於設定它自己的事件的指標。
那麼,先前計時器源的下一個事件將使它恢復活動...
我認為我們還需要使用一些值(類似於 bogomips)以及量子的粒度來決定量子的合適實際值。
如果我的推論是正確的,那麼使用的值(以及量子的粒度)似乎並不特別適合現代處理器 - 因此我想知道是否有辦法為量子設定更精細的粒度?那會很棒。現在發生的情況是,當執行 GL 或 SDL 演示時,系統變得無響應(尤其是在涉及 IO 的任務中,例如開啟 Wanderer 中的抽屜或載入其他軟體)(甚至移動視窗也更慢)。但是,當我將優先順序設定為 -1 時,這些演示的幀率只受到輕微影響,但系統仍然可以完全使用。你需要一個頻率更高的計時器。請注意兩件事
- 你不能提高 VBlank 的頻率,否則你會破壞許多軟體中的延遲。
- 一些架構(目前只有託管的架構)可能具有高頻週期性計時器。它用於透過 timer.device 測量間隔,以及模擬 VBlank。但是,出於相容性原因,量子仍然以 VBlank 衡量。
除了 Amiga 之外,原生架構沒有這樣的計時器,因為它們的硬體(至少 AROS 支援的硬體)只有一個計時器,由 timer.device 控制,timer.device 模擬了 VBlank 本身。Amiga 具有獨立的硬體 VBlank 計時器,可以作為獨立週期性計時器的例子,但是它的頻率無法提高。i386-pc 埠存在問題(因為程式碼沒有合併)。它仍然使用舊的 INTB_TIMERTICK 技巧,實際上是非週期性的(因為 timer.device 的工作方式),並且經過時間在它的處理程式中遞減,而不是在 VBlank 處理程式中遞減。這樣,量子實際上在這個埠上是浮動的,取決於活動的計時器請求。我認為這需要修復。量子應該以一些確定性的單位測量。標準的 Amiga 排程程式以 VBlank 測量它,因此我的通用程式碼使用相同的單位。
這意味著您將不得不透過類似於 VBlank 的方式模擬您的高頻計時器。我聽說過“HPET”(高精度事件計時器),但是我不知道它有什麼硬體功能。再說一次,至少在 UNIX 宿主上,您必須模擬它,因為 UNIX 只有計時器(SIGALRM)。您可以隨意嘗試,這是一個未開發的領域。請記住,kernel.resource 允許使用不同的排程程式(KrnSetScheduler() 函式),因此您可以隨意實現自己的排程程式。HPET 是 x86 和 x86_64 上的標準高精度計時器,是傳統 PC 架構基於 8254 的計時器的演變。
Wikipedia: "[http://software.intel.com/en-us/forums/showthread.php?t=52108 HPET] is meant to supplement and replace the 8254 programmable interval timer and the RTC's periodic interrupt function. Compared to these older timer circuits, the HPET has higher frequency (at least 10 MHz) and wider 64-bit counters (although they can be driven in 32-bit mode).[1]" There is also a specification for high-resolution POSIX timers, the IEEE 1003.1b REALTIME spec.
另一種改進方法是新增一個選項,暫時提升從等待特定型別事件返回的任務。例如,等待埠並喚醒以處理來自高優先順序任務的訊息的任務,可以被分配一個更大的量子,作為一次性處理它(例如,處理來自直覺/輸入處理程式的訊息)。Linux 試圖半途而廢地做到這一點,但他們對“特殊情況”很反感,而且由於在 Linux 中 GUI 是“另一個程序”,因此他們很難以一種沒有醜陋的邊緣情況的方式做到這一點,但如果使用事件來源的知識,您可以讓系統始終(在一定程度上)優先考慮使用者發起的事件。不過,在更高速度的 CPU 上縮短量子的長度仍然是一個好主意。或者使其可配置。
目前正在嘗試清理 x86_64 埠中的 LAPIC 等程式碼(在我的本地樹中),以便我開始使用它。我的第一個“目標”是完成 AP 的配置,以便 APIC、GDT、TLB、PTE 等被配置,並且中斷在相關的核心上被處理。請更新您的樹。我重寫了 x86-64 核心併合並了程式碼。順便說一下,我記得 acpi.resource 正在開發中。我記得在一個分支中。將 ACPI 內容從 kernel.resource 移動到那裡怎麼樣?沒有必要從與載入程式相同的點執行次要核心。
- 使用 XT 計時器作為 timer.device。
- 在 kernel.resource 中使用 HPET 作為高頻週期性計時器。然後,VBlank 將由核心模擬。
核心週期性計時器的當前支援在 kernel_timer.c 中。我已經告訴過您排程程式切換函式。僅此而已。如果需要更多內容,應該由將要實現該內容的人來開發。:)
也許吧。但是這個特定的任務可以用更簡單的方式解決。您只需要一個獨立於 timer.device 的週期性計時器。假設它的頻率是 VBlank 的倍數,您可以使用現有的 kernel.resource 程式碼。在 timer.device 的硬體實現中,VBlank 透過反覆排隊計時器請求來模擬。kernel.resource 的模擬在這些架構上沒有實現。此外,x86-64 timer.device 透過將 KAttr_VBlankEnable 設定為 FALSE 來確保它處於關閉狀態。實際上,所有實現都應該這樣做。順便說一下,您可以嘗試在宿主上透過提高它的預設週期性計時器頻率(目前預設情況下它等於 VBlank)並將其用作排程源來進行實驗。為 exec.library 發明一些演算法來選擇它。您可以使用 KrnGetSystemAttr() 函式和 KAttr_TimerIRQ 屬性向 kernel.resource 查詢此中斷。此計時器的頻率由核心放入 SysBase->ex_EClockFrequency 中,您可以依賴這個事實。這也由通用 timer.device 實現使用。它不驅動任何硬體,只是簡單地計數計時器中斷。
好吧,我使用的是 Gimmearos 指令碼,它執行
export CC=$gccversion" -m32"
"../$srcdir/configure" --target=pc-i386
--with-portssources="$curdir/$portsdir"
第一行應該是沒有必要的。標準配置指令碼在適當的情況下設定“-m32”。雖然我無法看到這會導致您的錯誤,但可能存在其他變數被 gimmearos 覆蓋。
您是否嘗試過更改..
%rule_compile basename=smpbootstrap targetdir=$(OBJDIR)
到..
%rule_compile basename=smpbootstrap targetdir=$(OBJDIR) compiler=kernel
?
在 config/make.tmpl 中的 %rule_link_binary 中是否應該宣告 -melf_i386?至少不在宏中,但可能已傳遞