Liệu kernel có hàm main () không? [đóng cửa]


52

Tôi đang học trình điều khiển thiết bị và lập trình Kernel. Theo cuốn sách của Jonathan Corbet, không có main()chức năng nào trong trình điều khiển thiết bị.

Vì vậy, tôi hai câu hỏi:

  • Tại sao chúng ta không cần một main()chức năng trong trình điều khiển thiết bị?
  • Liệu hạt nhân có một main()chức năng?

Ai đó có thể giải thích điều này với tôi?


1
Cũng được hỏi bởi cùng một người dùng ở đây: stackoverflow.com/q/18266063/827263
Keith Thompson

@KeithThndry ... Vâng ... Chỉ vì tôi không nhận được câu trả lời mình muốn nên tôi đã hỏi nó ở đây.
ai đó

@Shadur ... dù sao thì bây giờ nó cũng sắp đóng cửa ... Và tôi không có quyền di cư mà ...
ai đó

Điều này đáng lẽ phải được đóng lại theo cách khác, cái này có nhiều lượt xem hơn :-)
Ciro Santilli 改造 心 心 事件

Câu trả lời:


82

Trong các chương trình không gian người dùng, main()là điểm vào chương trình được gọi bởi mã khởi tạo libc khi nhị phân được thực thi. Mã hạt nhân không có sự sang trọng để dựa vào libc, vì chính libc dựa vào giao diện tòa nhà nhân để phân bổ bộ nhớ, I / O, quản lý quy trình, v.v.

Điều đó nói rằng, tương đương với main()mã hạt nhân start_kernel(), được gọi bởi bộ tải khởi động sau khi đã tải hình ảnh hạt nhân, giải nén nó vào bộ nhớ và thiết lập phân trang phần cứng và bộ nhớ thiết yếu. start_kernel()thực hiện phần lớn thiết lập hệ thống và cuối cùng sinh ra quá trình init.

Điểm vào các mô-đun hạt nhân Linux là một hàm init được đăng ký với kernel bằng cách gọi module_init()macro. Hàm init mô-đun đã đăng ký sau đó được gọi bởi mã kernel thông qua do_initcalls()chức năng trong khi khởi động kernel.


11
Cảm ơn bạn đã nhận ra mục đích thực sự của mainphương thức trong C. (Đây là một quan niệm sai lầm quá phổ biến mà HĐH thực hiện cuộc gọi trực tiếp main, không phải là trường hợp và thậm chí còn ít hơn trong trường hợp C ++.) Tôi ' d cung cấp cho bạn một upvote khác nếu tôi có thể chỉ cho điều đó.
một CVn

1
@Thomas ... Cảm ơn câu trả lời tuyệt vời này ....
ai đó

17

Nhân không có mainchức năng. mainlà một khái niệm của ngôn ngữ C. Nhân được viết bằng C và lắp ráp. Mã nhập của kernel được viết bởi assembly.

Trình tự khởi động được tổ chức như sau:

  1. BIOS thường tải bộ tải khởi động từ thiết bị khối khởi động. Một bộ tải khởi động phổ biến ngay bây giờ là grub.
  2. Grub tải một hình ảnh hạt nhân vào ram, có thể với một thiết bị gốc ban đầu ( initrd). Sau đó, mã tại một số địa chỉ được thực thi.
  3. Hình ảnh hạt nhân có một số mô-đun hạt nhân, ví dụ: mô-đun hệ thống tập tin, trình điều khiển thiết bị. Hình ảnh hạt nhân sử dụng mô-đun hệ thống tập tin để gắn kết hệ thống tập tin gốc. Bây giờ kernel có thể tải và chạy tất cả các mô-đun kernel từ đĩa.
  4. Nhân chạy các tác vụ khởi tạo. Ví dụ: đi qua bus PCI và tìm tất cả các thiết bị PCI, khởi tạo tất cả các trình điều khiển thiết bị.
  5. Cuối cùng, kernel tạo tiến trình 0 và tiến trình 1 ( inittiến trình), chuyển ngữ cảnh của CPU từ vòng 0 sang vòng 3 và bắt đầu quá trình init (id tiến trình là 1). Bây giờ khởi động kernel đã xong!
  6. Các initchương trình chạy tất cả các init script. Tất cả các dịch vụ được bắt đầu. Vỏ được gọi là. Người dùng có thể đăng nhập.

Các mainchức năng là một hàm C. Trên thực tế phương pháp chính không phải là điểm vào của các chương trình C. Thời gian chạy C gọi nhiều chức năng trước đó main. GCC có một tính năng mở rộng: các nhà xây dựng. Các hàm được khai báo "constructor" được gọi trước main.

Ví dụ:

/* This should not be used directly. Use block_init etc. instead. */ 
#define module_init(function, type) \
    static void _attribute__((constructor)) do_qemu_init ## function(void) { \
    register_module_init(function, type); \
} 

Macro này là từ dự án qemu.


Phương thức chính là phương thức ac. Phương thức chính không phải là mục nhập của chương trình c. Thời gian chạy đã gọi nhiều phương thức trước phương thức chính.
Edward Shen

tốt, bios thường tải một bộ tải khởi động và bộ tải khởi động đó tải một hình ảnh hạt nhân (và có thể là một initrd). Mã của kernel nằm trong hình ảnh kernel, không phải initrd
Stéphane Chazelas

GCC có một tính năng mở rộng: constructor. Khai báo phương thức "constructor" được gọi trước phương thức chính. Ví dụ: / * Điều này không nên được sử dụng trực tiếp. Sử dụng block_init, vv thay vào đó. * / #define module_init (hàm, loại) \ static void _attribution __ ((constructor)) do_qemu_init ## function (void) {\ register_module_init (function, type); \}
Edward Shen

1
initrd.img KHÔNG phải là hình ảnh hạt nhân. Đó là một tập hợp các mô-đun được nạp bởi kernel khi khởi động. Hình ảnh hạt nhân thường có tên bắt đầu bằng "vmlinuz" nhưng khác với distro đến distro.
goldilocks

3
Câu trả lời này chứa đầy "tất cả mọi thứ là PC / Linux / i86" và nó khởi động theo cách đó và hạt nhân là như vậy ... Tại sao mọi người nghĩ đó là cách khả thi duy nhất trên thế giới?
Jens

9

Ví dụ, có một hàm main () trong arch / x86 / boot / main.c để chuẩn bị hệ thống chuyển từ chế độ thực sang chế độ được bảo vệ nhưng các kiến ​​trúc khác không có mã như vậy. Có một tổng quan đẹp về cách khởi động Linux kernel 2.6.x trên nền tảng x86 hoạt động. Nó thực sự đáng đọc nó.

Theo tài liệu HOWTO làm phát triển nhân Linux , nhân Linux là

một môi trường C độc lập, không phụ thuộc vào thư viện C tiêu chuẩn, do đó một số phần của tiêu chuẩn C không được hỗ trợ.

Điều gì theo BTW tiêu chuẩn C có nghĩa là

Nó được định nghĩa theo triển khai cho dù một chương trình trong môi trường tự do được yêu cầu để xác định chức năng 'chính'.

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.