你的中文说的很好了,谢谢你的解答

2015-10-27 Thread guodemone via Digitalmars-d-announce

非常感谢,希望DLang可以进入中国的大学,那样Dlang会更有前途,我在为这个目标努力着。



I need D to do (asm+D)bootloader.

2015-10-26 Thread guodemone via Digitalmars-d-announce

sorry,My english is poot.

file asm.h

/*
是bootasm.S汇编文件所需要的头文件,主要是一些与X86保护模式的段访问方式相关的宏定义
*/

#ifndef __BOOT_ASM_H__
#define __BOOT_ASM_H__

/* Assembler macros to create x86 segments */

/* Normal segment */
#define SEG_NULLASM 
\
.word 0, 0; 
\
.byte 0, 0, 0, 0

#define SEG_ASM(type,base,lim)  
\
.word (((lim) >> 12) & 0x), ((base) & 0x);  
  \
.byte (((base) >> 16) & 0xff), (0x90 | (type)), 
  \
(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)


/* Application segment type bits */
#define STA_X   0x8 // 可执行
#define STA_E   0x4 // 向下扩展段(非可执行段)
#define STA_C   0x4 // 一致性代码段(只执行)
#define STA_W   0x2 // 段可写(非可执行段)
#define STA_R   0x2 // 段可读 (可执行段)
#define STA_A   0x1 // 可访问

#endif /* !__BOOT_ASM_H__ */

**
file bootasm.S

# 定义并实现了bootloader最先执行的函数start,此函数进行了一定的初始化,完成了
# 从实模式到保护模式的转换,并调用bootmain.c中的bootmain函数

#include 

# Start the CPU: switch to 32-bit protected mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk 
into
# memory at physical address 0x7c00 and starts executing in real 
mode

# with %cs=0 %ip=7c00.

# gdt 全局描述符表内的数组索引
.set PROT_MODE_CSEG,0x8 
# kernel code segment selector
.set PROT_MODE_DSEG,0x10# 
kernel data segment selector
.set CR0_PE_ON, 0x1 
# protected mode enable flag

.globl start
start:
.code16 
# Assemble for 16-bit mode
cli 
# 禁用中断
cld 
# 字符串操作设定为递增 si++ di++ ,cld的作用是将direct flag标志位清零

# Set up the important data segment registers (DS, ES, SS).
xorw %ax, %ax   
# Segment number zero
movw %ax, %ds  
 # -> Data Segment
movw %ax, %es  
 # -> Extra Segment
movw %ax, %ss  
 # -> Stack Segment

# A20地址线控制打开工作
# Enable A20:
# 为了向后兼容早期的PC机,让物理地址线20接低电平
# 如果A20是关闭的,16bit的寻址范围2^20是1M,如果是打开的,那么就是2^21次方,
# 但是寻址还是h:h=0h+h=10FFEFh=1M+64K-16Bytes
seta20.1:
inb $0x64, %al  
# Wait for not busy
testb $0x2, %al
jnz seta20.1  #测试 bit 1 是不是为0,如果不是跳回去继续执行

# 对于键盘的8042控制芯片 0x64是命令端口 0xd1 代表写命令
movb $0xd1, %al
 # 0xd1 -> port 0x64
outb %al, $0x64

seta20.2:
inb $0x64, %al  
# Wait for not busy
testb $0x2, %al
jnz seta20.2

# 设置写命令后 给0x60端口 发送命令数据0xdf就是打开A20地址线,0xdd就是关闭
movb $0xdf, %al
 # 0xdf -> port 0x60
outb %al, $0x60

# 转入保护模式,这里需要指定一个临时的GDT,来翻译逻辑地址。
# 这里使用的GDT通过gdtdesc段定义,它翻译得到的物理地址和虚拟地址相同,
# 所以转换过程中内存映射不会改变
lgdt gdtdesc
# 启动保护模式前建立好的段描述符合段描述符表

# 打开保护模式标志位,相当于按下了保护模式的开关。
# cr0寄存器的第0位就是这个开关,通过CR0_PE_ON或cr0寄存器,将第0位置1
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0

# 由于上面的代码已经打开了保护模式了,所以这里要使用逻辑地址,
# 而不是之前实模式的地址了。这里用到了PROT_MODE_CSEG,
# 他的值是0x8。根据段选择子的格式定义,0x8就翻译成:
  #  INDEX TI CPL
  #     1  00  0
# INDEX代表GDT中的索引,TI代表使用GDTR中的GDT, CPL代表处于特权级。
# PROT_MODE_CSEG选择子选择了GDT中的第1个段描述符。
# 这里使用的gdt就是变量gdt,下面可以看到gdt的第1个段描述符的基地址是0x,
	# 所以经过映射后和转换前的内存映射的物理地址一样。:7C00=0x7C00 :protcseg 
都是相对于物理内存基址的

ljmp $PROT_MODE_CSEG, $protcseg

.code32 
# Assemble for 32-bit mode
protcseg:
# 重新初始化各个段寄存器。也就是采用平坦式内存方式,
# 代码段同其它段都采用一个内存空间
movw $PROT_MODE_DSEG, %ax   
# 自定义数据段选择子,因为段选择子是16位的