成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

原來操作系統(tǒng)獲取時間的方式也這么 low

系統(tǒng)
書接上回,上回書咱們說到,通過初始化控制臺的 tty_init 操作,內(nèi)核代碼可以很方便地在控制臺輸出字符啦!

書接上回,上回書咱們說到,通過初始化控制臺的 tty_init 操作,內(nèi)核代碼可以很方便地在控制臺輸出字符啦!

作為用戶也可以通過敲擊鍵盤,或調(diào)用諸如 printf 這樣的庫函數(shù),在屏幕上輸出信息,同時支持換行和滾屏等友好設計,這些都是 tty_init 初始化,以及其對外封裝的小功能函數(shù),來實現(xiàn)的。

我們繼續(xù)往下看下一個初始化的倒霉鬼,time_init。

  1. void main(void) { 
  2.     ... 
  3.     mem_init(main_memory_start,memory_end); 
  4.     trap_init(); 
  5.     blk_dev_init(); 
  6.     chr_dev_init(); 
  7.     tty_init(); 
  8.     time_init(); 
  9.     sched_init(); 
  10.     buffer_init(buffer_memory_end); 
  11.     hd_init(); 
  12.     floppy_init(); 
  13.      
  14.     sti(); 
  15.     move_to_user_mode(); 
  16.     if (!fork()) {init();} 
  17.     for(;;) pause(); 

曾經(jīng)我很好奇,操作系統(tǒng)是怎么獲取到當前時間的呢?

當然,現(xiàn)在都聯(lián)網(wǎng)了,可以從網(wǎng)絡上實時同步。那當沒有網(wǎng)絡時,為什么操作系統(tǒng)在啟動之后,可以顯示出當前時間呢?難道操作系統(tǒng)在電腦關機后,依然不停地在某處運行著,勤勤懇懇數(shù)著秒表么?

當然不是,那我們今天就打開這個 time_init 函數(shù)一探究竟。

打開這個函數(shù)后我又是很開心,因為很短,且沒有更深入的方法調(diào)用。

  1. #define CMOS_READ(addr) ({ \ 
  2.     outb_p(0x80|addr,0x70); \ 
  3.     inb_p(0x71); \ 
  4. }) 
  5.  
  6. #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) 
  7.  
  8. static void time_init(void) { 
  9.     struct tm time
  10.     do { 
  11.         time.tm_sec = CMOS_READ(0); 
  12.         time.tm_min = CMOS_READ(2); 
  13.         time.tm_hour = CMOS_READ(4); 
  14.         time.tm_mday = CMOS_READ(7); 
  15.         time.tm_mon = CMOS_READ(8); 
  16.         time.tm_year = CMOS_READ(9); 
  17.     } while (time.tm_sec != CMOS_READ(0)); 
  18.     BCD_TO_BIN(time.tm_sec); 
  19.     BCD_TO_BIN(time.tm_min); 
  20.     BCD_TO_BIN(time.tm_hour); 
  21.     BCD_TO_BIN(time.tm_mday); 
  22.     BCD_TO_BIN(time.tm_mon); 
  23.     BCD_TO_BIN(time.tm_year); 
  24.     time.tm_mon--; 
  25.     startup_time = kernel_mktime(&time); 

夢想的代碼呀!

那主要就是對 CMOS_READ 和 BCD_TO_BIN 都是啥意思展開講一下就明白了了。

首先是 CMOS_READ

  1. #define CMOS_READ(addr) ({ \ 
  2.     outb_p(0x80|addr,0x70); \ 
  3.     inb_p(0x71); \ 
  4. }) 

就是對一個端口先 out 寫一下,再 in 讀一下。

這是 CPU 與外設交互的一個基本玩法,CPU 與外設打交道基本是通過端口,往某些端口寫值來表示要這個外設干嘛,然后從另一些端口讀值來接受外設的反饋。

至于這個外設內(nèi)部是怎么實現(xiàn)的,對使用它的操作系統(tǒng)而言,是個黑盒,無需關心。那對于我們程序員來說,就更不用關心了。

對 CMOS 這個外設的交互講起來可能沒感覺,我們看看與硬盤的交互。

最常見的就是讀硬盤了,我們看硬盤的端口表。

 


 

端口


0x1F0

數(shù)據(jù)寄存器 數(shù)據(jù)寄存器

0x1F1

錯誤寄存器 特征寄存器

0x1F2

扇區(qū)計數(shù)寄存器 扇區(qū)計數(shù)寄存器

0x1F3

扇區(qū)號寄存器或 LBA 塊地址 0~7 扇區(qū)號或 LBA 塊地址 0~7
0x1F4
磁道數(shù)低 8 位或 LBA 塊地址 8~15 磁道數(shù)低 8 位或 LBA 塊地址 8~15
0x1F5
磁道數(shù)高 8 位或 LBA 塊地址 16~23 磁道數(shù)高 8 位或 LBA 塊地址 16~23
0x1F6
驅動器/磁頭或 LBA 塊地址 24~27 驅動器/磁頭或 LBA 塊地址 24~27
0x1F7
命令寄存器或狀態(tài)寄存器 命令寄存器

那讀硬盤就是,往除了第一個以外的后面幾個端口寫數(shù)據(jù),告訴要讀硬盤的哪個扇區(qū),讀多少。然后再從 0x1F0 端口一個字節(jié)一個字節(jié)的讀數(shù)據(jù)。這就完成了一次硬盤讀操作。

如果覺得不夠具體,那來個具體的版本。

  • 在 0x1F2 寫入要讀取的扇區(qū)數(shù)
  • 在 0x1F3 ~ 0x1F6 這四個端口寫入計算好的起始 LBA 地址
  • 在 0x1F7 處寫入讀命令的指令號
  • 不斷檢測 0x1F7 (此時已成為狀態(tài)寄存器的含義)的忙位
  • 如果第四步驟為不忙,則開始不斷從 0x1F0 處讀取數(shù)據(jù)到內(nèi)存指定位置,直到讀完

看,是不是對 CPU 最底層是如何與外設打交道有點感覺了?是不是也不難?就是按照人家的操作手冊,然后無腦按照要求讀寫端口就行了。

當然,讀取硬盤的這個無腦循環(huán),可以 CPU 直接讀取并做寫入內(nèi)存的操作,這樣就會占用 CPU 的計算資源。

也可以交給 DMA 設備去讀,解放 CPU,但和硬盤的交互,通通都是按照硬件手冊上的端口說明,來操作的,實際上也是做了一層封裝。

好了,我們已經(jīng)學會了和一個外設打交道的基本玩法了。

那我們代碼中要打交道的是哪個外設呢?就是 CMOS。

它是主板上的一個可讀寫的 RAM 芯片,你在開機時長按某個鍵就可以進入設置它的頁面。

那我們的代碼,其實就是與它打交道,獲取它的一些數(shù)據(jù)而已。

我們回過頭看代碼。

  1. static void time_init(void) { 
  2.     struct tm time
  3.     do { 
  4.         time.tm_sec = CMOS_READ(0); 
  5.         time.tm_min = CMOS_READ(2); 
  6.         time.tm_hour = CMOS_READ(4); 
  7.         time.tm_mday = CMOS_READ(7); 
  8.         time.tm_mon = CMOS_READ(8); 
  9.         time.tm_year = CMOS_READ(9); 
  10.     } while (time.tm_sec != CMOS_READ(0)); 
  11.     BCD_TO_BIN(time.tm_sec); 
  12.     BCD_TO_BIN(time.tm_min); 
  13.     BCD_TO_BIN(time.tm_hour); 
  14.     BCD_TO_BIN(time.tm_mday); 
  15.     BCD_TO_BIN(time.tm_mon); 
  16.     BCD_TO_BIN(time.tm_year); 
  17.     time.tm_mon--; 
  18.     startup_time = kernel_mktime(&time); 

前面幾個賦值語句 CMOS_READ 就是通過讀寫 CMOS 上的指定端口,依次獲取年月日時分秒等信息。具體咋操作代碼上也寫了,也是按照 CMOS 手冊要求的讀寫指定端口就行了,我們就不展開了。

所以你看,其實操作系統(tǒng)程序,也是要依靠與一個外部設備打交道,來獲取這些信息的,并不是它自己有什么魔力。操作系統(tǒng)最大的魅力,就在于它借力完成了一項偉大的事,借 CPU 的力,借硬盤的力,借內(nèi)存的力,以及現(xiàn)在借 CMOS 的力。

至于 CMOS 又是如何知道時間的,這個就不在我們討論范圍了。

接下來 BCD_TO_BIN 就是 BCD 轉換成 BIN,因為從 CMOS 上獲取的這些年月日都是 BCD 碼值,需要轉換成存儲在我們變量上的二進制數(shù)值,所以需要一個小算法來轉換一下,沒什么意思。

最后一步 kernel_mktime 也很簡單,就是根據(jù)剛剛的那些時分秒數(shù)據(jù),計算從 1970 年 1 月 1 日 0 時起到開機當時經(jīng)過的秒數(shù),作為開機時間,存儲在 startup_time 這個變量里。

想研究可以仔細看看這段代碼,不過我覺得這種細節(jié)不必看。

  1. startup_time = kernel_mktime(&time); 
  2.  
  3. // kernel/mktime.c 
  4. long kernel_mktime(struct tm * tm) 
  5.     long res; 
  6.     int year
  7.     year = tm->tm_year - 70; 
  8.     res = YEAR*year + DAY*((year+1)/4); 
  9.     res += month[tm->tm_mon]; 
  10.     if (tm->tm_mon>1 && ((year+2)%4)) 
  11.         res -= DAY
  12.     res += DAY*(tm->tm_mday-1); 
  13.     res += HOUR*tm->tm_hour; 
  14.     res += MINUTE*tm->tm_min; 
  15.     res += tm->tm_sec; 
  16.     return res; 

就這。

所以今天其實就是,計算出了一個 startup_time 變量而已,至于這個變量今后會被誰用,怎么用,那就是后話了。

相信你逐漸也體會到了,此時操作系統(tǒng)好多地方都是用外設要求的方式去詢問,比如硬盤信息、顯示模式,以及今天的開機時間的獲取等。

所以至少到目前來說,你還不應該感覺操作系統(tǒng)有多么的“高端”,很多時候都是繁瑣地,讀人家的硬件手冊,獲取到想要的的信息,拿來給自己用,或者對其進行各種設置。

但你一定要耐得住寂寞,真正體現(xiàn)操作系統(tǒng)的強大設計之處,還得接著往下讀。

欲知后事如何,且聽下回分解。

本文轉載自微信公眾號「低并發(fā)編程」,可以通過以下二維碼關注。轉載本文請聯(lián)系低并發(fā)編程公眾號。本網(wǎng)站已獲得低并發(fā)編程的授權。

 

責任編輯:武曉燕 來源: 低并發(fā)編程
相關推薦

2010-08-02 13:55:20

2010-04-22 14:18:42

Aix操作系統(tǒng)

2018-08-09 16:12:59

操作系統(tǒng)內(nèi)存分配

2019-03-14 09:29:02

Linux系統(tǒng)內(nèi)存

2010-02-26 14:13:51

Linux操作系統(tǒng)

2010-04-15 14:40:26

Unix操作系統(tǒng)

2010-04-28 18:59:59

Unix操作系統(tǒng)

2010-03-04 14:34:50

Linux操作系統(tǒng)

2009-12-25 17:05:50

Linux操作系統(tǒng)

2010-04-30 16:02:45

Unix操作系統(tǒng)

2009-12-09 17:25:19

Linux操作系統(tǒng)

2021-04-19 05:42:51

Mmap文件系統(tǒng)

2021-04-19 11:23:29

操作系統(tǒng)計算機DOS

2023-05-07 23:22:24

golang

2009-07-23 18:43:25

操作系統(tǒng)LinuxWindows

2015-04-30 08:00:05

數(shù)據(jù)中心多種操作系統(tǒng)

2009-12-02 17:01:05

路由器功能

2021-11-15 06:56:46

操作系統(tǒng)U盤

2012-03-30 14:43:23

2022-01-07 13:34:25

Java時間格式化
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品美女久久久 | 欧美视频区 | av网站免费看 | 亚洲高清在线 | 欧美综合一区二区 | 久久精品国产亚洲一区二区三区 | 国产精品高潮呻吟久久aⅴ码 | 国产精品精品 | 99久久久无码国产精品 | 亚洲大片在线观看 | 91久久| 欧美精品一区二区在线观看 | 九九综合 | 情侣酒店偷拍一区二区在线播放 | 浮生影院免费观看中文版 | 亚洲a一区二区 | 欧美中文字幕在线 | 欧美亚洲国语精品一区二区 | 天天天天操| av在线一区二区三区 | 在线播放中文字幕 | 夜夜草| 亚洲一区二区久久 | 久色视频在线观看 | 一级黄色毛片 | 成人在线免费视频观看 | 99国产精品久久久 | 日本羞羞影院 | www.888www看片 | 天天干天天操天天爽 | 嫩草视频网站 | 天堂国产 | 国产精品污www在线观看 | 一级大黄色片 | 国产精品毛片一区二区在线看 | 中文字幕一区二区三 | av电影手机在线看 | 亚洲精品国产成人 | 国产精品久久久久久久久久妇女 | 久草院线 | 亚洲免费在线视频 |