跳到主要內容

擴充核心-切換堆疊和GDT

接續「重新放置核心-整理記憶體中的核心並將控制權交給它」。

esp, GDT 等內容目前還在 Loader中,為了方便控制,我們預計將它們放進核心中。

再者,目前已經可以採用 C 語言了,因此我們將盡量避免用編譯。在此,我們透過 C 語言將 Loader 中的原 GDT 全部複製給新的 GDT,並將 gdt_ptr 中的內容換成新的 GDT 的基底位址和界限。

程式碼

kernel.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                               kernel.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                     Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; ----------------------------------------------------------------------
; 編譯連接方法:
; $ rm -f kernel.bin
; $ nasm -f elf -o kernel.o kernel.asm
; $ nasm -f elf -o string.o string.asm
; $ nasm -f elf -o klib.o klib.asm
; $ gcc -c -o start.o start.c
; $ ld -s -Ttext 0x30400 -o kernel.bin kernel.o string.o start.o klib.o
; $ rm -f kernel.o string.o start.o
; $
; ----------------------------------------------------------------------

SELECTOR_KERNEL_CS equ 8

; 導入函數
extern cstart

; 導入全局變量
extern gdt_ptr

[SECTION .bss]
StackSpace  resb 2 * 1024
StackTop:  ; 堆疊頂

[section .text] ; 程式碼在此

global _start ; 導出 _start

_start:
 ; 此時記憶體看上去是這樣的(更詳細的記憶體情況在 LOADER.ASM 中有說明):
 ;              ┃                                    ┃
 ;              ┃                 ...                ┃
 ;              ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃■■■■■■Page  Tables■■■■■■┃
 ;              ┃■■■■■(大小由LOADER決定)■■■■┃ PageTblBase
 ;    00101000h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃■■■■Page Directory Table■■■■┃ PageDirBase = 1M
 ;    00100000h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃□□□□ Hardware  Reserved □□□□┃ B8000h ← gs
 ;       9FC00h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp
 ;       90000h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃■■■■■■■KERNEL.BIN■■■■■■┃
 ;       80000h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
 ;       30000h ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┋                 ...                ┋
 ;              ┋                                    ┋
 ;           0h ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
 ;
 ;
 ; GDT 以及相應的描述符是這樣的:
 ;
 ;                Descriptors               Selectors
 ;              ┏━━━━━━━━━━━━━━━━━━┓
 ;              ┃         Dummy Descriptor           ┃
 ;              ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃         DESC_FLAT_C    (0~4G)     ┃   8h = cs
 ;              ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃         DESC_FLAT_RW   (0~4G)     ┃  10h = ds, es, fs, ss
 ;              ┣━━━━━━━━━━━━━━━━━━┫
 ;              ┃         DESC_VIDEO                 ┃  1Bh = gs
 ;              ┗━━━━━━━━━━━━━━━━━━┛
 ;
 ; 注意! 在使用 C 程式碼的時候一定要保證 ds, es, ss 這幾個段寄存器的值是一樣的
 ; 因為編譯器有可能編譯出使用它們的程式碼, 而編譯器默認它們是一樣的. 比如串拷貝操作會用到 ds 和 es.
 ;
 ;


 ; 把 esp 從 LOADER 挪到 KERNEL
 mov esp, StackTop ; 堆疊在 bss 段中

 sgdt [gdt_ptr] ; cstart() 中將會用到 gdt_ptr
 call cstart  ; 在此函數中改變了gdt_ptr,讓它指向新的GDT
 lgdt [gdt_ptr] ; 使用新的GDT

 ;lidt [idt_ptr]

 jmp SELECTOR_KERNEL_CS:csinit
csinit:  ; “這個跳轉指令強制使用剛剛初始化的結構”——<<OS:D&I 2nd>> P90.

 push 0
 popfd ; Pop top of stack into EFLAGS

 hlt

kliba.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                              klib.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                       Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


[SECTION .data]
disp_pos dd 0

[SECTION .text]

; 導出函數
global disp_str

; ========================================================================
;                  void disp_str(char * info);
; ========================================================================
disp_str:
 push ebp
 mov ebp, esp

 mov esi, [ebp + 8] ; pszInfo
 mov edi, [disp_pos]
 mov ah, 0Fh
.1:
 lodsb
 test al, al
 jz .2
 cmp al, 0Ah ; 是ENTER嗎?
 jnz .3
 push eax
 mov eax, edi
 mov bl, 160
 div bl
 and eax, 0FFh
 inc eax
 mov bl, 160
 mul bl
 mov edi, eax
 pop eax
 jmp .1
.3:
 mov [gs:edi], ax
 add edi, 2
 jmp .1

.2:
 mov [disp_pos], edi

 pop ebp
 ret

string.asm

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                              string.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                       Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[SECTION .text]

; 導出函數
global memcpy


; ------------------------------------------------------------------------
; void* memcpy(void* es:pDest, void* ds:pSrc, int iSize);
; ------------------------------------------------------------------------
memcpy:
 push ebp
 mov ebp, esp

 push esi
 push edi
 push ecx

 mov edi, [ebp + 8] ; Destination
 mov esi, [ebp + 12] ; Source
 mov ecx, [ebp + 16] ; Counter
.1:
 cmp ecx, 0  ; 判斷計數器
 jz .2  ; 計數器為零時跳出

 mov al, [ds:esi]  ; ┓
 inc esi   ; ┃
     ; ┣ 逐字元移動
 mov byte [es:edi], al ; ┃
 inc edi   ; ┛

 dec ecx  ; 計數器減一
 jmp .1  ; 循環
.2:
 mov eax, [ebp + 8] ; 返回值

 pop ecx
 pop edi
 pop esi
 mov esp, ebp
 pop ebp

 ret   ; 函數結束,返回
; memcpy 結束-------------------------------------------------------------

start.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            start.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"

PUBLIC void* memcpy(void* pDst, void* pSrc, int iSize);

PUBLIC void disp_str(char * pszInfo);

PUBLIC u8  gdt_ptr[6]; /* 0~15:Limit  16~47:Base */
PUBLIC DESCRIPTOR gdt[GDT_SIZE];

PUBLIC void cstart()
{

 disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
   "-----\"cstart\" begins-----\n");

 /* 將 LOADER 中的 GDT 複製到新的 GDT 中 */
 memcpy(&gdt,       /* New GDT */
        (void*)(*((u32*)(&gdt_ptr[2]))),    /* Base  of Old GDT */
        *((u16*)(&gdt_ptr[0])) + 1    /* Limit of Old GDT */
  );
 /* gdt_ptr[6] 共 6 個字節:0~15:Limit  16~47:Base。用作 sgdt/lgdt 的參數。*/
 u16* p_gdt_limit = (u16*)(&gdt_ptr[0]);
 u32* p_gdt_base  = (u32*)(&gdt_ptr[2]);
 *p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
 *p_gdt_base  = (u32)&gdt;
}

const.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_


/* 函数类型 */
#define PUBLIC  /* PUBLIC is the opposite of PRIVATE */
#define PRIVATE static /* PRIVATE x limits the scope of x */

/* GDT 和 IDT 中描述符的个数 */
#define GDT_SIZE 128


#endif /* _ORANGES_CONST_H_ */

type.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_TYPE_H_
#define _ORANGES_TYPE_H_

typedef unsigned int  u32;
typedef unsigned short  u16;
typedef unsigned char  u8;

#endif /* _ORANGES_TYPE_H_ */

protect.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            protect.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_PROTECT_H_
#define _ORANGES_PROTECT_H_

/* 存儲段描述符/系統段描述符 */
typedef struct s_descriptor  /* 共 8 個字節 */
{
 u16 limit_low;  /* Limit */
 u16 base_low;  /* Base */
 u8 base_mid;  /* Base */
 u8 attr1;   /* P(1) DPL(2) DT(1) TYPE(4) */
 u8 limit_high_attr2; /* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
 u8 base_high;  /* Base */
}DESCRIPTOR;

#endif /* _ORANGES_PROTECT_H_ */

loader.asm

將原 loader.asm 的 356~357 行註解掉。因為我們已經卻任何新順利載入,是故可省略此測試用的資訊了。

boot.asm/ fat12hdr.inc, load.inc, pm.inc

與原來的檔案相同。

步驟

  1. 編譯 boot.asm (nasm boot.asm -o boot.bin)
  2. 編譯 loader.asm (nasm loader.asm -o loader.bin)
  3. 編譯 kliba.asm 為 ELF 格式 (nasm -f elf kliba.asm -o kliba.o)
  4. 編譯 string.asm 為 ELF 格式 (nasm -f elf string.asm -o string.o)
  5. 編譯 start.c (gcc -c -fno-builtin -o start.o start.c)
  6. 編譯 kernel.asm 為 ELF 格式,並設定程式入口位址 0x30400
    nasm -f elf kernel.asm -o kernel.o
    ld -s -Ttext 0x30400 kernel.o string.o start.o kliba.o -o kernel.bin
  7. 用 bximage 建立 floppy image,命名為 a.img
  8. 將 boot.bin 寫入 a.img 開機磁區(dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc)
  9. 複製 kernel.bin 與 loader.bin 至 a.img
    mount tmp
    sudo mount -o loop a.img tmp
    sudo cp loader.bin tmp
    sudo cp kernel.bin tmp
    sudo umount tmp
    rmdir tmp
執行結果

留言

這個網誌中的熱門文章

用 C# 批次控制 Word 合併列印

前由 我有全區的電話資料,問題在於我要依不同里別來製作出電話簿。結果如下圖: 單純採用合併列印無法達成我的需求。解決方法係用「功能變數」儲存上一個里別,與現在里別進行比較:若不同,則換頁。不過,這樣功能變數還蠻長的。最後,我還是採用 C# 來解決。 解決方案 用 C# 控制 WORD 中合併列印的「資料來源 Data Source」,給予不同里別的「sqlstatement」。迴圈處理不同的里別即可。但可預見其處理過程會很慢,不過還好,我可以不用在意它,有跑出結果即可。 程式碼 IList<string> areas = new List<string>() { "後壁", "侯伯", "嘉苳", "土溝", "嘉田", "嘉民", "菁豊", "崁頂", "後廍", "墨林", "菁寮", "新嘉", "頂長", "平安", "仕安", "竹新", "新東", "長安", "頂安", "福安", "烏樹" }; string root = @"D:\"; // 根目錄 string data = root + @"\data.docm"; // 資料檔(即資料來源) string template = root + @"\template.docx"; // 已設定好格式與合併欄位的 Word 檔 string output = @"d:\Final"; // 輸出之資料夾 object oMissing = System.Reflection.Missing.Va...

[Symfony+Doctrine] 透過非 Id 來使用 Pessimistic Lock

根據 文件 ,Doctrine 有 Pessimistic Lock,又分為兩種: LockMode::PESSIMISTIC_WRITE:對應至 MySQL 的 Select FOR UPDATE LockMode::PESSIMISTIC_READ:對應至 MySQL 的 Select LOCK IN SHARE MODE 差別在於 LOCK IN SHARE MODE 會將在 row 的資料鎖定(row-level lock),在非同一交易(Transaction)下,不給寫入,其他交易可以讀取, 且可以繼續 Select LOCK IN SHARE MODE 。而 FOR UPDATE 不僅鎖定該資料,在非同一交易下,不給寫入,其它交易可以讀取, 但不能 Select LOCK IN SHARE MODE 。MySQL 文件有更詳細的比較與情境使用的說明,參考 網址 。 現在問題是,我們要完全採用 ORM 來處理資料。Doctrine 的文件提到 EntityManager::find 可以採用 Pessimistic Lock, 但 find 是透過 id 來處理 。而其他 find 系列函數(包括:findAll, findBy, findOneBy)皆不支援 LockMode。 因此,勢必要有方法來「透過非 id 來使用 Pessimistic Lock」。透過查看原始碼,簡單的方法是有的,解法之範例如下: 19 public function depositAction() 20 { 21 22 $em = $this->getDoctrine()->getManager(); 23 24 $em->transactional(function ($em) { 25 $entityName = 'AcmeTrainingBundle:Account'; 26 $lockMode = LockMode::PESSIMISTIC_READ; 27 $orderBy = null; 28 $...

VLC c# 順利編譯

原文網址: http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 原文作者: haibindev 原文標題:c#万能视频播放器 本文的重點在於修正 class VlcPlayer,使其能順利在 VC# Express 2010 .Net Framework 4 下順利編譯。 修正重點在於 CallingConvention = CallingConvention. StdCall 改成 CallingConvention = CallingConvention. Cdecl using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace VlcDotNet { class VlcPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VlcPlayer(string pluginPath) { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); } public ...