Viết HĐH cho Raspberry Pi bằng C


19

Tôi đã tìm thấy các hướng dẫn Baking Pi , nhưng họ chỉ sử dụng ngôn ngữ lắp ráp . Tôi đã làm theo các bài học đầu tiên, nhưng tôi đã tự hỏi làm thế nào để sử dụng C thay thế. Ý tôi là, có một lý do họ đã phát minh ra các ngôn ngữ cấp cao hơn. Tôi đã thử chỉ biên dịch mã C thành .otệp object ( ), biên dịch

.section .init
.globl _start
_start:

bl main

loop$:
b loop$

đến một tệp đối tượng khác và liên kết chúng lại với nhau và do đó có được kernel.img. Sau đó tôi đã thay thế kernel đã có mặt của mình, nhưng nó không thực thi mã C. Mã C tôi đã viết chỉ nên bật đèn LED OK và sau đó quay lại (sau đó đến loop$: b loop$). Nhưng đèn LED OK nhấp nháy ngẫu nhiên một vài lần và sau đó tắt. Đây là mã C của tôi:

int main(int argc, char ** argv) {
    volatile unsigned *gpioAddr = (volatile unsigned *)0x20200000;
    *(gpioAddr + 4) = 1 << 18;
    *(gpioAddr + 40) = 1 << 16;
    return 0;
}

Làm cách nào để sử dụng C để phát triển hệ điều hành trên Raspberry Pi?

Tôi nghi ngờ đó là một lỗi trong mã (mặc dù tôi chỉ là người có sở thích). Tôi biết việc thiết lập C có thể phức tạp, nhưng tôi không phải là người đầu tiên làm việc này. AFAIK, tất cả các hệ điều hành hiện đang chiếm ưu thế chủ yếu được viết bằng C, vì vậy phải có một bài viết giải thích quy trình. Tôi cũng sẽ rất hài lòng với một danh sách các bước, vì vậy tôi có thể google cho các bước đó và có thể hỏi một câu hỏi ít rộng hơn một chút.

Lưu ý: lắp ráp ARM tương đương với mã C ở trên hoạt động tốt. Nó bật đèn LED (sau một chút nhấp nháy). Tôi nghĩ (hy vọng) điều đó cho thấy Raspberry Pi của tôi vẫn ổn.


C được thiết kế để trở thành ngôn ngữ lắp ráp di động cho Unix. Linux được viết bằng C, bạn có thể tiết kiệm khá nhiều thời gian bằng cách xem cách nó được thực hiện.
Thorbjørn Ravn Andersen

1
@ ThorbjørnRavnAndersen Tôi nghĩ rằng tôi không đọc được nguồn Linux. Linux phức tạp hơn nhiều so với những gì tôi muốn biết, do đó che khuất những phần thú vị đối với tôi.
11684

1
Ừm, 'lên dây' một vài đèn LED.
11684

1
Cảm ơn bạn, nhưng tôi muốn làm hầu hết mọi thứ bản thân mình. Đó là một dự án học tập.
11684

1
Tôi phải thừa nhận rằng tôi chưa bao giờ thấy một câu hỏi nào trước đây về cách viết một hệ điều hành. Và có một số câu trả lời thú vị. Thật là điên rồ ...
Piotr Kula

Câu trả lời:


14

Tôi đã viết một kernel rất đơn giản cách đây nhiều năm và chạy nó trên một chiếc 386. Tôi đã không thực hiện lập trình kim loại trần trong nhiều năm, nhưng theo nghĩa rộng, bạn cần phải viết một số mã trình biên dịch sẽ:

  • vô hiệu hóa các ngắt trong quá trình khởi động
  • nếu Pi có bộ điều khiển bộ nhớ, bạn sẽ cần thiết lập nó
  • thiết lập một dấu thời gian
  • cấu hình bộ điều khiển ngắt
  • thiết lập một ngăn xếp để bạn có thể thực thi mã C

Thiết lập ngăn xếp rất dễ dàng - tìm một số bộ nhớ không được sử dụng và tải địa chỉ mà đăng ký từng được sử dụng làm con trỏ ngăn xếp.

Trong mã C của bạn, bạn cần khởi tạo các cấu trúc dữ liệu hệ điều hành như nhóm bộ nhớ và bảng luồng. Bạn sẽ không thể sử dụng các chức năng của thư viện C - bạn sẽ cần phải tự viết những thứ đó.

Nếu bạn muốn viết một os đa nhiệm đơn giản, bạn sẽ cần viết một số thói quen của trình biên dịch để lưu các thanh ghi CPU trên ngăn xếp và tải một tập các giá trị thanh ghi khác từ ngăn xếp của luồng khác. Và bạn sẽ cần phải viết một API để tạo các chủ đề khác nhau.


1
Thật khó để lựa chọn giữa câu trả lời này và của Georges Dupéron. Tôi chấp nhận cái này và đưa cái kia lên.
11684

13

Tôi đã không nhìn sâu vào mã của bạn, nhưng dường như với tôi bạn đang đi đúng hướng. Đảm bảo rằng:

  • Các _startbiểu tượng thực sự là một trong những sử dụng khi dịch và liên kết tập tin lắp ráp và tập tin C của bạn (và main()không được sử dụng thay)
  • Khi gọi main(), bạn cần sử dụng quy ước gọi C:
    • ấn vào ngăn xếp địa chỉ của lệnh theo lệnh gọi của bạn (địa chỉ trả về, sẽ được sử dụng bởi returncâu lệnh trong C)
    • đẩy các đối số cho hàm. Trong trường hợp của bạn, bạn có thể đẩy hai giá trị 32 bit (tổng cộng 8 byte), nhưng để làm cho mọi thứ đơn giản hơn, bạn cũng có thể xóa các đối số và chỉ cần cóint main() { ... }
    • có thể dành một số không gian trên ngăn xếp cho giá trị trả về
    • Tôi không thể nhớ theo thứ tự những thứ này nên được đẩy
    • Để biết chính xác hàm C mong đợi điều gì, hãy tháo rời nó ( objdump -S main.o) và xem cách nó thao tác ngăn xếp.
  • Nếu bạn không tôn trọng quy ước gọi, thì mã lắp ráp được tạo bởi trình biên dịch C có thể làm xáo trộn địa chỉ trả về trên ngăn xếp và trong trường hợp của bạn, bạn thậm chí không đẩy địa chỉ trả về, vì vậy lệnh trả về sẽ nhảy ở đâu đó ngẫu nhiên, thay vì đi đến loop$.

Các wiki OSDev sẽ là một ressource rất hữu ích - nó chủ yếu liên quan đến việc phát triển x86 nhưng hầu hết thông tin là vẫn áp dụng đối với pi mâm xôi.

Một số tài nguyên cụ thể khác của raspberry-pi osdev:


Thật khó để lựa chọn giữa câu trả lời này và Steve's. Tôi đã cho bạn một upvote và chấp nhận người khác. Tôi rất tiếc sự khác biệt 5 rep.
11684

OSDev wiki là tốt - và thậm chí có một số cụ thể RasPi thứ
Wally

2

Vấn đề chính bạn có thể gặp phải là các thư viện C và mã prologue. Nó bắt đầu trước khi mã của riêng bạn bắt đầu thực thi và thiết lập ngăn xếp, heap và thực hiện nhiều điều hữu ích khác. Tuy nhiên, khi bạn đang cố gắng lập trình cho kim loại trần, bạn không có bất kỳ HĐH nào chạy bên dưới bạn và tốt hơn hết là tránh gọi các chức năng này. Để làm được điều đó, bạn cần các phiên bản sửa đổi của thư viện C và / hoặc một số biểu tượng toàn cầu được xác định hoặc thay thế bằng thư viện của riêng bạn. Quá trình này có một chút liên quan, đó là lý do tại sao mọi người 'Baking Pi' chọn sử dụng lắp ráp cho hướng dẫn của họ.


Cảm ơn bạn đã trả lời câu hỏi của tôi (và xin lỗi vì đã trả lời quá muộn). Nhưng (thật bất ngờ!) Tôi đã mua pi của mình để tìm hiểu về điều đó, bit liên quan đến các quy trình cấp thấp (tôi không muốn làm điều đó trên một máy tính để bàn đắt tiền có nguy cơ phá hủy các tệp / thư / ảnh cá nhân). Bạn có thể vui lòng thêm cách tôi thiết lập ngăn xếp, hoặc một bài viết / hướng dẫn / một số tài nguyên giải thích điều đó? (Và những gì khác tôi có thể cần để chạy C).
11684

2

Hãy thử điều này thay thế:

http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/

Ngoài ra, trải nghiệm x86 có một chút khác biệt. Nó có thể được áp dụng cho lập trình hệ điều hành kim loại trần ARM nói chung. Nhưng đối với Pi, xin lỗi, đó là gpu khởi động trước và thiết lập khá nhiều trước mã OS (?) Của bạn.


1
Một chi tiết nhỏ hơn sẽ là tuyệt vời, điều gì xảy ra nếu liên kết trong câu trả lời của bạn bị phá vỡ?
Darth Vader

Nó vẫn ở đó nhưng tôi nghĩ đối với những người đến đây, có thể google "van kim loại trần" và tốt hơn nên thử loạt OSDEV (để vượt qua nhà phát triển chéo khi tôi vật lộn, đọc diễn đàn; Tôi đăng bài bạn có thể thử google "OSDEV diễn đàn sáu tháng qua ")
Dennis Ng

Tôi biết đây là một câu trả lời cũ cho một câu hỏi thậm chí cũ hơn, nhưng trang này nằm trên web.archive.org trong trường hợp nó bị sập.
nặc danh

1

s-matyukevich/raspberry-pi-os

https://github.com/s-matyukevich/raspberry-pi-os

Repo tuyệt vời này thực hiện cả C bootstraping, và đi vào các chủ đề khá phức tạp.

Hơn nữa, nó xem xét cách nhân Linux làm mọi việc và chú thích mã nhân Linux.

Hãy xem hướng dẫn đầu tiên để thiết lập tối giản: https://github.com/s-matyukevich/raspberry-pi-os/tree/43f682d406c8fc08736ca3edd08a1c8e477c72b0/src/lesson01/src

Tôi khuyên bạn nên nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.