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 即可运行
阅读(1170) | 评论(0) | 转发(0) |