核心三章,第一卷:陷阱
大概前陣子是和朋友聊天時,有人提到這麼一個用Rust寫的教學核心,產生興趣後找來看了才發現訓練營的存在。
我用Rust已經有一段時間了,但多數時候是用來寫應用層面的程式,比如web服務。我對作業系統的理解幾乎停留在理論,也沒有做過系統開發。得知有這麼一個難得的機會,那自然不可錯過了。
我的文章中不會著重講述開發的流程,但會更多地記錄一些我自己遇到的比較獨特的問題和經歷,以及我個人的感想——我自認為我的技術實力是不如許多人的,如果你想找技術上的攻略心得,去看看別人吧。 😋
在二階段前
不巧的是,在一階段開始之後不久,我就遇到了一些生活上的瑣事。我很快發現自己沒有多少時間可以投入到rCore中了。所幸,因為已經有Rust的經驗,速通rustlings也只是一晚上的功夫。
只是,可想而知之後的二階段恐怕沒這麼容易了。
ch3:來自Apple的詛咒
訓練營的rCore(Guide)其實已經是rCore Tutorial的再度簡化版,但即便如此,第一個任務ch3還是打得我措手不及。
此前我對作業系統的理解是泛泛的,大致知道作業系統具備哪些東西,最深入的理解也只是本科課程作業中用C編寫的排程演算法模擬演示。對於一個真正的作業系統,該從哪裡開始都不知道,比如說,在no_std的世界中,stdout從哪裡來?怎麼在螢幕上渲染出日誌?(遺憾的是rCore並沒有回答這個問題,SBI完成了這部分)
要一次性消化這麼多新東西並不容易,特別是當自己以為已經把Tutorial讀得足夠清楚了,一開啟程式碼庫時依舊覺得無從下手,不得不再次回到Tutorial啃。在這種狀況下,我僵持了差不多一個星期才弄清楚ch3究竟應該怎樣完成,或者說,程式碼究竟該寫在哪。
然而,在功能完成後,我的程式碼出現了一個難以理解的錯誤:
Panicked at src/bin/ch3_sleep.rs:16, assertion failed: current_time > 0
有很多人遇到了get_time_ms和get_time_us的精度問題,但我很確定我的問題不屬於此類——就算我的電腦再怎麼快,get_time也絕對不可能是0。
在反覆重寫了幾個不同的實現方式之後,我開始留意到一個驚愕的事實:“get_time為0”這個錯誤是否發生,在時間上不均勻。
有的時候隨便改動一兩行程式碼,第一次編譯可以透過測試,但第二次之後就會遇上這個錯誤。
在探索到深夜時,我發現在get_time加上一個println,就能把這個錯誤的發生機率降到零。
Commit, push, CI… Run failed.
那,把這個println刪了試試吧。刪除之後,在我的機器上又不能透過測試了,但出於好奇,我還是把這個commit推到了遠端。
這一次,測試通過了。
這是一個只會在我的機器上出現的錯誤。
我使用的是QEMU 8,當然也更換了最新的pre-release RustSBI,但這……我確實沒看到有其他人遇到這種問題,也無法理解。
那麼只剩下一種可能了……Apple Silicon。
ch4:困難模式
雖然已經在ch3得到了教訓,我還是沒有在第一時間更換Linux虛擬機器。我想著,時間已經不多了,同樣的問題,或者更詭異的問題出現之後再換虛擬機器吧,還是想貪那兩秒鐘的編譯時間。
幸好,那來自Apple的詛咒之後再沒發生過。
然而ch4的難度直線上升,尤其是對我而言——我對頁表一無所知。在ch4感覺到的壓力,還有那種面對程式碼庫不知所措的感覺,比ch3還要強烈得多。
這時我已經萌生了打退堂鼓的想法,ch4無論是知識本身的難度還是任務難度都讓我有點招架不住。
不過,最終還是研究明白了ch4兩個函式的實現方式,以及需要為它們補上的其他函式,雖然花的時間遠比預期中長。
ch5:遲來的句號
ch4完成後,二階段原定的期限只剩下兩天了,我那時還不知道透過的要求已經放寬到了ch5,在週末啃了ch5文件一天之後,我還是決定離開了。
很遺憾,沒能和你們一起走下去。
……嗎?
在原定的期限一週之後,我發現還有人在衝擊著二階段。
那麼,來畫上一個真正的句號吧。
ch5的難度倒是下降了不少,大概也是因為已經對程式碼庫更加熟悉了。在ch5上花的時間最多的地方竟然是在cherry-pick以前的程式碼上,花了不少時間手動處理合併衝突,直到能透過編譯和透過BASE=1。至於實現兩個功能倒是比較輕鬆愉快,畢竟,現在已經知道程式碼要加在哪了。
階梯
回過頭看,在這個倉庫上寫的程式碼,好像真的不多。但是,對於一個未曾瞭解過作業系統本質的人,可以說是打開了新世界的大門。此刻,作業系統已經變得不再神秘,而rCore Tutorial同樣也是值得反覆精讀的教材。
最後,也感謝老師們提供的資源以及幫助。