自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

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

作為用戶也可以通過敲擊鍵盤,或調(diào)用諸如 printf 這樣的庫函數(shù),在屏幕上輸出信息,同時支持換行和滾屏等友好設(shè)計,這些都是 tty_init 初始化,以及其對外封裝的小功能函數(shù),來實(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)是怎么獲取到當(dāng)前時間的呢?

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

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

打開這個函數(shù)后我又是很開心,因?yàn)楹芏?,且沒有更深入的方法調(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 與外設(shè)交互的一個基本玩法,CPU 與外設(shè)打交道基本是通過端口,往某些端口寫值來表示要這個外設(shè)干嘛,然后從另一些端口讀值來接受外設(shè)的反饋。

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

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

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

 


 

端口


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
驅(qū)動器/磁頭或 LBA 塊地址 24~27 驅(qū)動器/磁頭或 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 最底層是如何與外設(shè)打交道有點(diǎn)感覺了?是不是也不難?就是按照人家的操作手冊,然后無腦按照要求讀寫端口就行了。

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

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

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

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

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

那我們的代碼,其實(shí)就是與它打交道,獲取它的一些數(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 手冊要求的讀寫指定端口就行了,我們就不展開了。

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

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

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

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

想研究可以仔細(xì)看看這段代碼,不過我覺得這種細(xì)節(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; 

就這。

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

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

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

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

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

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

 

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

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-04-15 14:40:26

Unix操作系統(tǒng)

2010-02-26 14:13:51

Linux操作系統(tǒng)

2010-04-28 18:59:59

Unix操作系統(tǒng)

2010-03-04 14:34:50

Linux操作系統(tǒng)

2010-04-30 16:02:45

Unix操作系統(tǒng)

2009-12-25 17:05:50

Linux操作系統(tǒng)

2015-04-30 08:00:05

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

2021-04-19 11:23:29

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

2009-12-09 17:25:19

Linux操作系統(tǒng)

2009-07-23 18:43:25

操作系統(tǒng)LinuxWindows

2021-04-19 05:42:51

Mmap文件系統(tǒng)

2023-05-07 23:22:24

golang

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時間格式化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號