最初からオペレヌティングシステム。 レベル1䞋半分

このパヌトでは、Rustのスキルを向䞊させ、有甚なナヌティリティずラむブラリをいく぀か䜜成したす。 GPIO、UART、組み蟌みタむマヌ甚のドラむバヌを䜜成したす。 XMODEMプロトコルを実装したす。 これらすべおを䜿甚しお、単玔なシェルずブヌトロヌダヌを䜜成したす。 読む前に、 本を読むこずを匷くお勧めしたす。 少なくずも最初から最埌たで。 怠zyな、しかしもう少し経隓を積んだ人には、 これをお勧めできたす。 ロシア語では、 ここで掘るこずができたす 。


もちろん、 れロレベルをバむパスするこずはたったく䟡倀がありたせん。 たた、この郚分の半分はラズベリヌを必芁ずしたせん。


䟿利な資料



フェヌズ0はじめに


念のため、コヌス互換のファヌムりェアずハ​​ヌドりェアを䜿甚しおいるこずをもう䞀床確認しおください。



さらに、次のプログラムをむンストヌルする必芁がありたす git 、 wget 、 tar 、 screen 、 makeなど、 れロレベルに必芁なすべおのもの。 このパヌトでは、 socatをむンストヌルする必芁がありたす。


前回Windowsで必芁なすべおを実行できた堎合、今回はすべおが動䜜するはずです。 しかし、突然サポヌトがない堎合。 私もオリゞナルの䜜者も、Vendaを手に入れるこずも、掘り䞋げたいずいう欲求も持っおいたせん。


コヌド怜玢


この郚分のコヌドを次のように耇補できたす。


 git clone https://web.stanford.edu/class/cs140e/assignments/1-shell/skeleton.git 1-shell 

自分でリポゞトリの内容を自由に探玢しおください。


ご質問


このラボおよび以䞋のすべおのラボでは、 質問がありたす 。 あなたはネタバレを䜿甚しおコメントで盎接答えるこずができたす。 以䞋に䟋を瀺したす。


他のGPIOピンをどのように構成しお䜿甚したすか [assignment0]

前回は、点滅するLEDの名前に16ピンGPIOを䜿甚したした。 レゞスタGPFSEL1 、 GPSET0およびGPCLR0たす。 ピン27を䜿甚する堎合、どのレゞスタが䟿利ですか そしお、この27 GPIOピンの物理的な接觊は䜕ですか

角括匧は、 questions/ディレクトリ内のファむル名を瀺したす。 コメントで回答する必芁があるため、これは私たちにずっお特に重芁ではありたせん。 自分が答えたず確信できるたで、他人の答えを読たないでください。 そうでなければ、面癜くありたせん。 ただし、これらのタグはスポむラヌのヘッダヌずしお䜿甚できたす。 ただし、これらのファむルに最初に曞き蟌むこずをお勧めしたす。 䟿宜䞊。


フェヌズ1芳芧車しゃれ



ラスタに぀いおの十分な知識が既にある堎合、この郚分は完党にスキップできたす。


トレヌニングのために、わがたたな目的のためにRustのプログラムを線集したす。 䞀郚は線集埌にコンパむルする必芁がありたす。 その他はコンパむルしないでください 。 3番目の堎合、テストは正垞に完了する必芁がありたす。


ferris-wheel/ディレクトリの腞では、以䞋を芋぀けるこずができたす



test.sh test.shはただありtest.sh 。 圌はタスクの正しさをチェックしたす。 実行するず、予想どおりではない堎所ず内容が非垞に䞀般的に説明されたす。 次のようなもの


 $ ./test.sh ERROR: compile-pass/borrow-1.rs failed to compile! ERROR: compile-pass/const.rs failed to compile! ... 0 passes, 25 failures 

さらに、スクリプトは-vフラグを受け入れたす。 このフラグがスクリプトに枡されるず、コンパむラヌが吐き出す゚ラヌが衚瀺されたす。


 $ ./test.sh -v ERROR: compile-pass/borrow-1.rs failed to compile! ---------------------- stderr -------------------------- warning: unused variable: `z` --> /.../ferris-wheel/compile-pass/borrow-1.rs:9:9 | 9 | let z = *y; | ^ | = note: #[warn(unused_variables)] on by default = note: to avoid this warning, consider using `_z` instead error[E0507]: cannot move out of borrowed content --> /.../ferris-wheel/compile-pass/borrow-1.rs:9:13 | 9 | let z = *y; | ^^ | | | cannot move out of borrowed content | help: consider using a reference instead: `&*y` error: aborting due to previous error ... 0 passes, 25 failures 

このスクリプトは、文字列をフィルタヌずしおも䜿甚したす。 䜿甚可胜な堎合、このフィルタヌに䞀臎するファむルパス$ディレクトリ/ $ファむル名のみがチェックされたす。 䟋


 ./test.sh trait ERROR: compile-pass/trait-namespace.rs failed to compile! ERROR: run-pass/trait-impl.rs failed to compile! 0 passes, 2 failures 

䞀方が他方に干枉するこずはなく、フィルタヌず-v組み合わせるこずができたす。 このようなもの ./test.sh -v filter 。


どのくらい倉曎できたすか


各ファむルにはコメントが含たれおおり、コメントがどの皋床損なわれる可胜性があるかを瀺したす差分予算。 ぀たり プログラムを修正するために行うこずができる倉曎の最倧数。 このフレヌムワヌクに適合しない決定は、倱敗したずみなすこずができたす。


䟋ずしお。 ファむルcompile-pass/try.rsコメントがありたす。


 // FIXME: Make me compile. Diff budget: 12 line additions and 2 characters. 

远加できるコヌドは12行たでです空の行も考慮されたす。 そしお、2文字を倉曎 远加/倉曎/削陀したす。 git diffを䜿甚しお、行ごずの倉曎を確認できたす。 そしお、 git diff --word-diff-regex=. 同じですが、文字ごずに。


別の䟋


 // FIXME: Make me compile! Diff budget: 1 line. 

kakbeは、コヌドの1行のみを倉曎 远加/倉曎/拡匵できるこずを瀺しおいたす。


䞀般芏則


倉曎埌、プログラムの意図された機胜は保持されるはずです。 コンパむルするために特定の関数の本䜓を倉曎する必芁がある堎合、 unimplemented!()を远加するだけでは䞍十分だずしたしょうunimplemented!() 。 疑わしい堎合は、できる限りのこずを詊しおください。 さお、たたはコメントでお願いしたす。


これに加えお、次のダヌティメ゜ッドを実行するこずは完党に掚奚されたせん。



すべおのタスクが完了するず、 test.shは25 passes, 0 failuresを出力したす


ヒントファむル名には゜リュヌションのキヌが含たれおいる堎合がありたす。

ヒント この居心地の良いチャットルヌムでは 、Rustに関する質問にすばやく回答できたす 。 この蚘事のコメントよりも速い。

どうした 修理は䜕でしたか なぜ機胜するのですか [ファむル名]

この郚分の各プログラムに぀いお、゜ヌスコヌドの䜕が問題であったかを説明する必芁がありたす。 次に説明する ハヌドコア どのような倉曎が行われたか、これらの修正がなぜ汚い仕事をするのか。 適切な説明を歓迎したす。 あなたはすべおがあなたにずおも明癜であるず思うなら、あなたは曞くこずができたせん。 怠lazなら-あなたはたったく䜕も曞くこずができたせん。

フェヌズ2酞化



この段階では、コマンドラむン甚にいく぀かのラむブラリず1぀のナヌティリティを䜜成したす。 サブディレクトリstack-vec 、 volatile 、 ttywriteおよびxmodemでttywriteしxmodem 。 たた、壊れおいない堎合に回答できる質問がいく぀かありたす。 各郚分は貚物によっお管理されおいたす。 少なくずもこれらのコマンドは䟿利ず呌ぶこずができたす



Cargoに぀いおは、別の小冊子Cargo Bookがありたす。 そこから、すべおが詳现に機胜する方法に぀いお必芁な情報を孊ぶこずができたす。


サブフェヌズAStackVec


オペレヌティングシステムが扱う最も重芁な機胜の1぀は、メモリの割り圓おです。 C、Rust、Java、Python、たたはほがすべおのアプリケヌションが䞀般的にmalloc()呌び出す堎合、十分なメモリがない堎合、システムコヌルが最終的に䜿甚され、オペレヌティングシステムに远加のメモリが芁求されたす。 オペレヌティングシステムは、ただメモリが誰も占有しおいないかどうかを刀断したす。 その堎合、このメモリからOSがプロセッサに少し振りかけたす。


メモリ割り圓お- 非陰茎

すべおのlinupsなどの最新のOSには、メモリ管理に関連する倚くのトリックが含たれおいたす。 たずえば、最適化束葉杖の順序で、䞀定量のメモリが芁求されるず、仮想的に割り圓おられたす。 この堎合、アプリケヌションがこのメモリを䜿甚しようずするたで、物理メモリは割り圓おられたせん。 䞀方、単玔化された配垃の錯芚は、アプリケヌションに察しお䜜成されたす。 オペレヌティングシステムは芋事に嘘を぀くこずができたす 

内郚のVec 、 StringおよびBoxなどの構造䜓は、 malloc()を䜿甚しお独自のニヌズに合わせおメモリを割り圓おたす。 ぀たり、これらの構造にはオペレヌティングシステムのサポヌトが必芁です。 特に、OSがメモリを割り圓おる方法を知っおいる必芁がありたす。 このパヌトはただ始たっおいたせん次のシリヌズを参照ので、メモリ管理は䞀切ありたせん。 したがっお、これらのすべおのVec ただ䜿甚するこずはできたせん。


これはVec集䞭的な混乱であり、あらゆる点で適切な抜象化です これにより、あらゆる皮類の埮劙な点を芚える必芁なく、 .push()および.pop()芳点から考えるこずができたす。 完党なメモリアロケヌタなしでVec䌌たものを取埗できたすか



もちろん。 最初に思い浮かぶのは、メモリの予備割り圓おず、その䞊に必芁な抜象化を実装する特定の構造ぞのその埌の転送です。 バむナリファむルに盎接、たたはスタックのどこかにメモリを静的に割り圓おるこずができたす。 どちらの堎合も、そのようなメモリは、事前に決められた固定サむズでなければなりたせん。


このサブフェヌズでは、 StackVecを実装しStackVec 。これは、 Vecが暙準ラむブラリから提䟛するAPIず同様のAPIを提䟛したす。 ただし、事前に割り圓おられたメモリを䜿甚したす。 この同じStackVec 、コマンドラむンを実装するずきに圹立ちたすフェヌズ3。 stack-vecサブディレクトリで䜜業しstack-vec 。 その䞭には、すでに次のものがありたす。



StackVecむンタヌフェヌス


StackVec<T>は、 StackVec::new()呌び出すこずによっお䜜成されたす。 f-ii new匕数ずしお、タむプTスラむスTたす。 StackVec<T>は、 Vec類䌌のメ゜ッドずほが同じ方法で䜿甚される倚くのメ゜ッドを実装したす。 たずえば、 StackVec<u8>たす。


 let mut storage = [0u8; 1024]; let mut vec = StackVec::new(&mut storage); for i in 0..10 { vec.push(i * i).expect("can push 1024 times"); } for (i, v) in vec.iter().enumerate() { assert_eq!(*v, (i * i) as u8); } let last_element = vec.pop().expect("has elements"); assert_eq!(last_element, 9 * 9); 

StackVec型StackVec既に次のように宣蚀されStackVecいたす。


 pub struct StackVec<'a, T: 'a> { storage: &'a mut [T], len: usize, } 

StackVec理解StackVec


StackVecデバむスに関する質問がいく぀かありたす。


pushがResult返すのはなぜですか [プッシュ倱敗]

暙準ラむブラリにあるVecのpushメ゜ッドには、戻り倀がありたせん。 ただし、 StackVecからのpushはStackVecようなものがありたす。䜕らかの゚ラヌがある可胜性があるこずを瀺す結果を返したす。 Vecず違っおStackVec::push()倱敗するのはなぜですか

T生涯に制限する必芁があるのはなぜですか [寿呜]

コンパむラは、このStackVecを拒吊しStackVec 。
 struct StackVec<'a, T> { buffer: &'a mut [T], len: usize } 


型Tに制玄を远加するず、すべおが機胜したす。
 struct StackVec<'a, T: 'a> { buffer: &'a mut [T], len: usize } 


なぜこの制限が必芁なのですか Rustがこの制限に埓わないずどうなりたすか

StackVec popメ゜ッドにT: Clone必芁なのStackVecなぜですか [clone-for-pop]

Vec<T>暙準ラむブラリのpopメ゜ッドはT実装されたすが、 StackVec popメ゜ッドはTがCloneプロパティを実装する堎合にのみ実装されたす。 なぜそうなのでしょうか この制限を克服するずどうなりたすか

StackVec実装


stack-vec/src/lib.rsすべおのunimplemented!()メ゜ッドをStackVecしstack-vec/src/lib.rs 。 各メ゜ッドにはすでにドキュメントがありたすたずえば、そこから䜕が必芁かは明確です。 これに加えお、 src/tests.rsファむルには、実装が正しいこずを確認するのに圹立぀テストがありたす。 cargo testコマンドを䜿甚しおテストを実行できたす。 さらに、 StackVecクラスのIntoIterator 、 DerefMutおよびIntoIteratorを実装する必芁がありたす。 そしお&StackVec IntoIterator IntoIterator 。 これらの特性を実装しないず、テストは倱敗したす。 実装が正しいこずを確認し、質問に答えられるようになったらすぐに、次のサブフェヌズに進みたす。


どのテストにDeref実装が必芁ですか [deref-in-tests]

str/tests.rsからすべおのテストコヌドを読み取りstr/tests.rs 。 Deref実装がない堎合、どのテストをコンパむルしたくないのですか DerefMutどうですか なんで

実際、テストは完了しおいたせん

提䟛される単䜓テストは基本的な機胜をカバヌしおいたすが、くしゃみをすべおテストするわけではありたせん。 そのようなスペヌスを探し、偉倧な正矩の名の䞋に、テストの神にさらにテストを远加しおください。

ヒントれロフェヌズliftimeゞョブからの゜リュヌションが圹立぀堎合がありたす。

サブフェヌズB volatile



このパヌトでは、揮発性メモリアクセスに぀いお説明し、 volatile/サブディレクトリのコヌドを読み取りたす。 独自のコヌドを曞くこずはしたせんが、セルフテストには疑問がありたす。


兞型的なオペレヌティングシステムず同様に、コンパむラは非垞に巧劙なトリックを巧みに実行したす。 最適化の名においお、圌らはあなたが意図したもののように芋える䜕かをしおいたす。 実際、内郚には非垞に匷力な魔術がありたす。 そのような魔術の良い䟋は、デッドコヌドの削陀です。 コンパむラがコヌドが実行に圱響を䞎えないこずを蚌明できる堎合、デッドコヌドは迅速か぀断定的に切り取られたす。 そのようなコヌドがあるずしたしょう


 fn f() { let mut x = 0; let y = &mut x; *y = 10; } 

コンパむラヌは、蚘録埌に*y読み取られないずいう少し合理的な理由を考えるかもしれたせん。 このため、コンパむラは結果のバむナリファむルからこの郚分を単玔に陀倖できたす。 このように議論を続けるず、コンパむラはy自䜓の宣蚀を切断しおからxを切断するこずが適切であるず刀断したす。 最埌に、 f()ぞの呌び出しはナむフの䞋に行きたす。


この皮の最適化は非垞に䟿利で䟡倀がありたす。 それらのおかげで、プログラムは結果に圱響を䞎えるこずなく加速されたす。 確かに、堎合によっおは、そのような詐欺は予期せぬ結果をもたらす可胜性がありたす。 たずえば、 yは曞き蟌みのみ可胜なレゞスタを指したす。 この堎合、 *yぞの曞き蟌みは、 *yを読み取らなくおも、かなり芳察可胜な効果がありたす。 コンパむラがこれを知らない堎合、最適化段階でこの郚分を取埗するだけで、プログラムは期埅どおりに動䜜したせん。


このようなものの読み取り/曞き蟌みが、居心地の良い䞖界自䜓に圱響を䞎えるこずをコンパむラヌにどのように玍埗させるこずができたすか これはたさに、揮発性メモリアクセスの意味です。 コンパむラは、そのようなサむトぞのアクセスを最適化しないこずを誓いたす。


さびたvolatile


Rustでは、 write_volatileずwrite_volatileを䜿甚しお、生のポむンタヌを読み曞きできたす。


これらはどのような生のポむンタですか

これたで、リンクを密接に知るこずができたしたこれは&Tおよび&mut T 。 Rustのrawポむンタヌ *const Tおよび*mut T は、ボロヌチェッカヌの有効期間を远跡しない基本的に同じリンクです。 これらの生のポむンタヌを䜿甚した読み取り/曞き蟌みは、CおよびC ++の愛奜家でよく芋られる同じ足の負傷に぀ながる可胜性がありたす。 Rustでは、このような操䜜は安党ではないず考えおいたす。 したがっお、このすべおをunsafeタグでマヌクするこずが必須です。 ドキュメントで生のポむンタの詳现を読んでください。

write_volatileずwrite_volatile毎回曞くこずは十分に悲しいですう぀病によっお匕き起こされる迷惑な゚ラヌに぀ながる可胜性があるずいう事実に加えお。 幞いなこずに、Rustは私たちの生掻をより簡単で安党にする機䌚を提䟛しおくれたす。 䞀方では、単玔にvolatileラッパヌを䜜成し玠敵なCのvolatileキヌワヌドにほずんど䌌おいたす、すべおの読み取り/曞き蟌みがコヌド内に残るようにしたす。 ボヌナスずしお、読み取り専甚たたは曞き蟌み専甚のラッパヌを定矩できたすラッパヌはありたせん。必芁に応じおトランクずスピンを提䟛したす。


Volatile 、 ReadVolatile 、 WriteVolatileおよびUniqueVolatile


volatile/ディレクトリ内のvolatile 誰が考えたでしょうかこれら4぀のタむプを実装したす。これらは、その名前から明らかなこずを行いたす。 詳现はドキュメントをご芧ください。 このドキュメントを䟿利な圢匏で実際に読むには、 volatile/ディレクトリで盎接cargo doc --open呌び出しおください。


UniqueVolatileがあるのはなぜですか [ナニヌク揮発性]

VolatileずUniqueVolatile䜿甚するず、揮発性メモリアクセスをUniqueVolatileできたす。 ドキュメントに基づいお、2぀のタむプの違いは䜕ですか

src/lib.rs 。 自分のスキルの粟神でコヌドを読んでください。 その埌コヌドを読んで、次の2぀の質問に答えたす。 終了方法-次のサブフェヌズに進むこずができたす。


読み曞きの制限はどのように敎理されおいたすか [匷制]

WriteVolatileずWriteVolatileは、それぞれポむンタヌの読み取りず曞き蟌みを䞍可胜にしたす。 これはどのように行われたすか

通垞の方法の代わりに特性を䜿甚する利点は䜕ですか [特性]

泚意深く調べるず、各タむプが独自のnewメ゜ッドを1぀だけ実装しおいるこずを眮き換えるこずができたす。 他のすべおのメ゜ッドは、 Writeable方法でReadable 、 WriteableおよびReadableWriteable実装に関連しおいたす。 このすべおの利益は䜕ですか このアプロヌチの少なくずも2぀の利点を説明しおください。

readずwrite安党でnew安党でないのはなぜですか [安党]

readずwriteが安党であるず芋なされるように、 newに関しお䜕が真実である必芁がありたすか 察照的に、 readずwrite安党writeはありたせんwrite代わりにnewを安党ずマヌクするのは安党でしょうか
ヒントこれらすべおのメ゜ッドのドキュメントを読んでください。

なぜnewの䜿甚を匷制するのですか [pub-constructor]


タむプVolatileが次のように宣蚀された堎合


 struct Volatile<T>(pub *mut T); 

次に、 newを呌び出す代わりにVolatile(ptr)を䜿甚しおVolatile(ptr)型の倀を䜜成できたす。 静的呌び出しnewラッパヌを䜜成する䜿甚法は䜕ですか


ヒント䞡方のオプションの安党性ステヌトメントの意味を考慮しおください。




マクロは䜕をしたすか [マクロ]

readable!マクロは䜕をしたすかreadable! writeable! そしおreadable_writeable! 

サブフェヌズC xmodem


このサブフェヌズでは、XMODEMファむル転送プロトコル xmodem/サブディレクトリを実装したす。 䞻な䜜業はxmodem/src/lib.rs 。


XMODEMは、1977幎に開発された単玔なファむル転送プロトコルです。 パケットチェックサム、送信キャンセル、および゚ラヌが発生した堎合に送信を自動的に再詊行する機胜がありたす。 UARTなどのシリアルむンタヌフェむスを介しお情報を送信するために広く䜿甚されおいたす。 プロトコルの䞻芁な機胜はシンプルです。 wikiで詳现を読んでください XMODEM 誰でも蚘事をロシア語に翻蚳できたす。


プロトコル


プロトコル自䜓に぀いおは、テキストファむル「X-Modem File Transfer Protocolの理解」で詳现に説明されおいたす。 ここでいく぀かの説明を繰り返したす。


りィキペディアからの説明に基づいお実装を行わないでください

教育孊からの説明は高レベルで有甚ですが、倚くの詳现はここで実装するものずは異なりたす。 教育孊はプロトコルの抂芁ずしおのみ䜿甚しおください。

XMODEMは非垞にバむナリプロトコルです。生のバむトが送受信されたす。 さらに、プロトコルは半二重です。送信者たたは受信者はい぀でもデヌタを送信したすが、䞡方を同時に送信するこずはありたせん。 最埌に、これはパケットプロトコルです。デヌタは128バむトのブロックパケットに分割されたす。 プロトコルは、どのバむトを送信するか、い぀送信するか、䜕を瀺すか、そしお埌でそれらを読み取る方法を決定したす。


たず、いく぀かの定数を定矩したしょう。


 const SOH: u8 = 0x01; const EOT: u8 = 0x04; const ACK: u8 = 0x06; const NAK: u8 = 0x15; const CAN: u8 = 0x18; 

, NAK , NAK . , NAK , . NAK , .


, , . 1. (.. 255), 0.



, :


  1. SOH
  2. ( 255 - $_ )

    • 256
  3. :
    • NAK , ( 10 )
    • ACK ,

, :


  1. SOH EOT
    • ,
    • EOT —

    • —

    • ,
  2. (128 )

    • ぀たり 256

    • , NAK
    • , ACK

, , , CAN . CAN — .


, :


  1. EOT
  2. NAK ( — )
  3. EOT
  4. ACK ( — )

, ( EOT ):


  1. NAK
  2. EOT ( , )
  3. ACK

XMODEM


XMODEM . , . expect_byte , expect_byte_or_cancel , read_packet write_packet src/lib.rs . Xmodem : packet started . , .


expect_byte expect_byte_or_cancel . ( read_byte write_byte ) read_packet write_packet . , , transmit receive . / . , . cargo test . , — .


std.

std::io . std .

:
{read, write}_packet 33 .

io::Read io::Write (, , ).

? 。

, .

D: ttywrite


ttywrite . XMODEM. xmodem . ttywrite/src/main.rs . test.sh . - socat .


?

, . . , . UART, .

TTY?
TTY — (TeltTYpe writer). , . ( ) . /dev/ , tty.


ttywrite - . structopt , clap . , , Cargo.toml . structopt . , , structopt .


, , --help . , cargo run -- . : cargo run -- --help . . main.rs . Opt . .


, ? [invalid]

. -f idk . structopt , ?

, . . , .



main serial::open . open serial , . open TTYPort , / / ( io::Read io::Write ). ( SerialDevice ).



ttywrite . , , opt main . , stdin . . . -r , . , xmodem . ( ).


XMODEM Xmodem::transfer Xmodem::transmit_with_progress . transmit_with_progress . :


 fn progress_fn(progress: Progress) { println!("Progress: {:?}", progress); } Xmodem::transmit_with_progress(data, to, progress_fn) 

test.sh ttywrite . :


 Opening PTYs... Running test 1/10. wrote 333 bytes to input ... Running test 10/10. wrote 232 bytes to input SUCCESS 



stdin io::stdin() .

io::copy() .

main() 35 .

TTYPort .



test.sh -r ? [bad-test]

-r . XMODEM. , ? XMODEM ? ?



UPD . . .

Source: https://habr.com/ru/post/J351082/


All Articles