Chinaunix首页 | 论坛 | 博客
  • 博客访问: 467093
  • 博文数量: 164
  • 博客积分: 4024
  • 博客等级: 上校
  • 技术积分: 1580
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-10 16:27
文章分类

全部博文(164)

文章存档

2011年(1)

2010年(108)

2009年(55)

我的朋友

分类:

2010-06-28 15:34:56

esp,GDT等内容目前还在loader中,为了方便控制我们得把他们放到内核比较好。
 
下面我们:
 
切换堆栈和GDT
 


; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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


gdt_ptr和cstart分别是一个全局变量和全局函数,他们定义在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;
}

函数cstart首先把位于loader中的原GDT全部复制给新的GDT,然后把gdt_ptr中的内容换成新的GDT的基地址和界限。

memcpy在string.asm中

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_ */


好了 编译连接

nasm -f -elf -o kernel.o kernel.asm

nasm -f elf -o string.o string.asm

gcc -c -o start.o start.c

ld -s -Ttext 0x30400 -o kernel.bin kernel.o string.o start.c

好了 可以运行试试了

 

然后添加显示字符串的代码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    ; 是回车吗?
    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

在start.c中调用disp_str("\n\n\n\n\n""--------\""cstart\"" begins-----\n");

 编译运行:

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 -fno-builtin start.o start.c

ld -s -Ttext 0x30400 -o kernel.bin kernel.o string.o start.o klib.o

 

整理目录:

---a.img

--bochsrc

--MyOSboot

    --MyOSboot.asm

    --include

       --fat12hdr.inc

       --load.inc

       --pm.inc

   --loader.asm

--include

  --const.h

  --protect.h

  --type.h

--kernel

 --kernel.asm

 --start.c

--lib

 --klib.asm

 --string.asm

 

 

 

Makefile:

 


 

#####################
# Makefile for Tinix #
######################


# Entry point of Tinix
# It must be as same as 'KernelEntryPointPhyAddr' in load.
ENTRYPOINT    = 0x30400

# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET    = 0x400


# Programs, flags, etc.
ASM        = nasm
DASM        = ndisasm
CC        = gcc
LD        = ld
ASMBFLAGS    = -I boot/include
ASMKFLAGS    = -I include -f elf
CFLAGS        = -I include -c -fno-builtin
LDFLAGS        = -s -Ttext $(ENTRYPOINT)
DASMFLAGS    = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

# This Program
TINIXBOOT    = boot/boot.bin boot/loader.bin
TINIXKERNEL    = kernel.bin
OBJS        = kernel/kernel.o kernel/start.o lib/klib.o lib/string.o
DASMOUTPUT    = kernel.bin.asm

# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg

# Default starting position
everything : $(TINIXBOOT) $(TINIXKERNEL)

all : realclean everything

final : all clean

image : final buildimg

clean :
    rm -f $(OBJS)

realclean :
    rm -f $(OBJS) $(TINIXBOOT) $(TINIXKERNEL)

disasm :
    $(DASM) $(DASMFLAGS) $(TINIXKERNEL) > $(DASMOUTPUT)

# Write "boot.bin" & "loader.bin" into floppy image "TINIX.IMG"
# We assume that "TINIX.IMG" exists in current folder
buildimg :
    mount TINIX.IMG /mnt/floppy -o loop
    cp -f boot/loader.bin /mnt/floppy/
    cp -f kernel.bin /mnt/floppy
    umount /mnt/floppy

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
    $(ASM) $(ASMBFLAGS) -o $@ $<

boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc
    $(ASM) $(ASMBFLAGS) -o $@ $<

$(TINIXKERNEL) : $(OBJS)
    $(LD) $(LDFLAGS) -o $(TINIXKERNEL) $(OBJS)

kernel/kernel.o : kernel/kernel.asm
    $(ASM) $(ASMKFLAGS) -o $@ $<

kernel/start.o : kernel/start.c ./include/type.h ./include/const.h ./include/protect.h
    $(CC) $(CFLAGS) -o $@ $<

lib/klib.o : lib/klib.asm
    $(ASM) $(ASMKFLAGS) -o $@ $<

lib/string.o : lib/string.asm
    $(ASM) $(ASMKFLAGS) -o $@ $<

直接 make image 即可运行
阅读(1092) | 评论(0) | 转发(0) |
0

上一篇:保护模式编程十二

下一篇:intel汇编指令

给主人留下些什么吧!~~