Professional Documents
Culture Documents
1) Asmhead.asm
; haribote-os
; 有关 BOOT_INFO
CYLS EQU 0x0ff0 ; 设置启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率 X
SCRNY EQU 0x0ff6 ; 分辨率 Y
VRAM EQU 0x0ff8 ; 图像缓冲区的起始位置
[BITS 16]
entry:
; 设置屏幕模式
MOV AL, 0x13 ; VGA 显卡,320x200x8 bit
MOV AH, 0x00
INT 0x10
CLI
; 切换到保护模式
LGDT [GDTR0] ; 设置临时 GDT
MOV EAX, CR0
AND EAX, 0x7fffffff ; 禁用分页
OR EAX, 0x00000001 ; 开启保护模式
MOV CR0, EAX
JMP pipelineflush
pipelineflush:
MOV AX, 1*8 ; 写 32bit 段
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
; bootpack 传递
MOV ESI, bootpack ; 源
MOV EDI, BOTPAK ; 目标
MOV ECX, 512*1024/4
CALL memcpy
; 传输磁盘数据
; 从引导区开始
; 剩余的全部
MOV ESI, DSKCAC0+512 ; 源
MOV EDI, DSKCAC+512 ; 目标
MOV ECX, 0
MOV CL, BYTE [CYLS]
IMUL ECX, 512*18*2/4 ; 除以 4 得到字节数
SUB ECX, 512/4 ; IPL 偏移量
CALL memcpy
skip:
MOV ESP, 0xffff
JMP DWORD 2*8:0x00000000
waitkbdout:
IN AL, 0x64
AND AL, 0x02
JNZ waitkbdout ; AND 结果不为 0 跳转至 waitkbdout
RET
memcpy:
MOV EAX, [ESI]
ADD ESI, 4
MOV [EDI], EAX
ADD EDI, 4
SUB ECX, 1
JNZ memcpy ; 结果不为 0 跳转至 memcpy
RET
; memcpy 地址前缀大小
ALIGN 16
GDT0:
RESB 8 ; 初始值
DW 0xffff, 0x0000, 0x9200, 0x00cf ; 可写的 32 位段寄存器
DW 0xffff, 0x0000, 0x9a28, 0x0047 ; 可执行的文件的 32 位寄存器
DW 0
GDTR0:
DW 8*3-1
DD GDT0
ALIGN 16
bootpack:
2) Bootpack.c
#include <stdio.h>
#include "io.h"
#include "pm.h"
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void box_fill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0,
int x1, int y1);
void init_screen(unsigned char *vram, int x, int y);
void put_font8(unsigned char *vram, int xsize, int x, int y, char c,
char *font);
void put_fonts8_asc(unsigned char *vram, int xsize, int x, int y, char c,
char *s);
void init_mouse_cursor8(char *mouse, char bc);
void put_block8_8(unsigned char *vram, int vxsize, int pxsize, int pysize,
int px0, int py0, char *buf, int bxsize);
#define COL8_000000 0
#define COL8_FF0000 1
#define COL8_00FF00 2
#define COL8_FFFF00 3
#define COL8_0000FF 4
#define COL8_FF00FF 5
#define COL8_00FFFF 6
#define COL8_FFFFFF 7
#define COL8_C6C6C6 8
#define COL8_840000 9
#define COL8_008400 10
#define COL8_848400 11
#define COL8_000084 12
#define COL8_840084 13
#define COL8_008484 14
#define COL8_848484 15
struct BootInfo {
char cyls, leds, vmode, reserve;
short scrnx, scrny;
unsigned char *vram;
};
struct SegmentDescriptor {
short limit_low, base_low;
char base_mid, access_right;
char limit_high, base_high;
};
struct GateDescriptor {
short offset_low, selector;
char dw_count, access_right;
short offset_high;
};
void init_gdtidt(void);
void set_segmdesc(struct SegmentDescriptor *sd, unsigned int limit, int base,
int ar);
void set_gatedesc(struct GateDescriptor *gd, int offset, int selector, int ar);
int main(void) {
struct BootInfo *binfo = (struct BootInfo *)0x0ff0;
char s[40], mcursor[256];
init_gdtidt();
init_palette();
for (;;) {
io_hlt();
}
return 0;
}
void init_palette(void) {
static unsigned char table_rgb[16 * 3] = {
0x00, 0x00, 0x00, // 黑色
0xff, 0x00, 0x00, // 亮红色
0x00, 0xff, 0x00, // 亮绿色
0xff, 0xff, 0x00, // 亮黄色
0x00, 0x00, 0xff, // 亮蓝色
0xff, 0x00, 0xff, // 亮紫色
0x00, 0xff, 0xff, // 浅亮蓝色
0xff, 0xff, 0xff, // 白色
0xc6, 0xc6, 0xc6, // 亮灰色
0x84, 0x00, 0x00, // 暗红色
0x00, 0x84, 0x00, // 暗绿色
0x84, 0x84, 0x00, // 暗黄色
0x00, 0x00, 0x84, // 暗蓝色
0x84, 0x00, 0x84, // 暗紫色
0x00, 0x84, 0x84, // 浅暗蓝色
0x84, 0x84, 0x84 // 暗灰色
};
io_cli(); // 禁止中断
io_out8(0x03c8, start);
for (int i = start; i <= end; i++) {
io_out8(0x03c9, rgb[0] / 4);
io_out8(0x03c9, rgb[1] / 4);
io_out8(0x03c9, rgb[2] / 4);
rgb += 3;
}
io_store_eflags(eflags);
}
void box_fill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0,
int x1, int y1) {
for (int y = y0; y <= y1; y++) {
for (int x = x0; x <= x1; x++) {
vram[y * xsize + x] = c;
}
}
}
if (cursor[y][x] == 'O') {
mouse[y * 16 + x] = COL8_FFFFFF;
}
if (cursor[y][x] == '.') {
mouse[y * 16 + x] = bc;
}
}
}
}
void put_block8_8(unsigned char *vram, int vxsize, int pxsize, int pysize,
int px0, int py0, char *buf, int bxsize) {
for (int y = 0; y < pysize; y++) {
for (int x = 0; x < pxsize; x++) {
vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
}
}
}
void init_gdtidt(void) {
struct SegmentDescriptor *gdt = (struct SegmentDescriptor *)0x00270000;
struct GateDescriptor *idt = (struct GateDescriptor *)0x0026f800;
void set_gatedesc(struct GateDescriptor *gd, int offset, int selector, int ar) {
gd->offset_low = offset & 0xffff;
gd->selector = selector;
gd->dw_count = (ar >> 8) & 0xff;
gd->access_right = ar & 0xff;
gd->offset_high = (offset >> 16) & 0xffff;
}
3) io.asm
[BITS 32]
; 程序中包含函数名
GLOBAL io_hlt, io_cli, io_sti, io_stihlt
GLOBAL io_in8, io_in16, io_in32
GLOBAL io_out8, io_out16, io_out32
GLOBAL io_load_eflags, io_store_eflags
[SECTION .text]
io_hlt: ; void io_hlt(void);
HLT
RET
4) io.h
#ifndef _IO_H_
#define _IO_H_
void io_hlt(void);
void io_cli(void);
void io_sti(void);
void io_stihlt(void);
int io_load_eflags(void);
void io_store_eflags(int eflags);
#endif // _IO_H_
5) ipl.asm
; hello-os
; 程序核心
entry:
MOV AX, 0 ; 初始化寄存器
MOV SS, AX
MOV SP, 0x7c00
MOV DS, AX
; 读取硬盘
MOV AX, 0x0820
MOV ES, AX
MOV CH, 0 ; 柱面 0
MOV DH, 0 ; 磁头 0
MOV CL, 2 ; 扇区 2
readloop:
MOV SI, 0 ; 记录失败次数的寄存器
retry:
MOV AH, 0x02 ; AH=0x02:读盘
MOV AL, 1 ; 1 个扇区
MOV BX, 0
MOV DL, 0x00 ; A 驱动器
INT 0x13 ; 调用磁盘 BIOS
JNC next ; 没出错跳转到 next
next:
MOV AX, ES ; 把内存地址后移 0x200
ADD AX, 0x0020
MOV ES, AX ; 实现 ES += 0x0020 的目的
; 扇区范围 1~18
ADD CL, 1 ; 扇区加 1
CMP CL, 18 ; 扇区是否达到 18
JBE readloop ; 小于等于 18 扇区则跳转到 readloop
MOV DH, 0
; 柱面范围 0 ~ 79
ADD CH, 1
CMP CH, CYLS
JB readloop ; 读取指定数量的柱面,未达到 CYLS 则跳转 readloop
; 读取完毕,跳转到 haribote.sys 执行
MOV [0x0ff0], CH ; 记下 IPL 读了多远(谷歌翻译自 IPL がどこまで読ん
だのかをメモ)
JMP 0xc200
fin:
HLT ; CPU 停止,等待指令
JMP fin ; 无限循环
error:
MOV SI, msg
putloop:
MOV AL, [SI]
ADD SI, 1 ; SI 加 1
CMP AL, 0
JE fin
MOV AH, 0x0e ; 显示一个文字
MOV BX, 15 ; 指定字符颜色
INT 0x10 ; 调用显卡 BIOS
JMP putloop
msg:
DB 0x0a, 0x0a ; 两个换行
DB "load error"
DB 0x0a ; 换行
DB 0
ENTRY( main )
MEMORY
{
rom : ORIGIN = 0x000000, LENGTH = 0x280000
ram : ORIGIN = 0x280000, LENGTH = 0x020000
}
SECTIONS
{
. = 0x0000;
.text :
{
*(.text.main);
*(.text);
} > rom AT > ram
.rodata :
{
*(.rodata)
} > ram
.data :
{
*(.data)
} > ram
.bss :
{
*(.bss)
} > ram
}
7) Makefile
ifndef GCCPREFIX
GCCPREFIX :=
endif
AS := nasm
CC := $(GCCPREFIX)gcc
LD := $(GCCPREFIX)ld
OBJCOPY := $(GCCPREFIX)objcopy
QEMU := qemu-system-i386
# C Library Objects
L_OBJS := libc/stdio/stdio.bin
# Kernel Objects
K_OBJS := bootpack.bin io.bin pm.bin hankaku.bin
SYS := haribote.sys
IMG := haribote.img
ifdef DEBUG
QEMU_FLAGS += -gdb tcp::1234 -S
CFLAGS += -g
endif
ipl.bin:
$(AS) -f bin ipl.asm -o ipl.bin -l ipl.lst
asmhead.bin:
$(AS) -f bin asmhead.asm -o asmhead.bin -l asmhead.lst
hankaku.bin: ../hankaku/hankaku.asm
$(AS) -f elf $< -o $@
%.bin: %.asm
$(AS) -f elf $< -o $@ -l $(subst .asm,.lst,$<)
%.bin: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf *.bin
rm -rf *.sys
rm -rf *.obj
rm -rf *.lst
rm -rf $(IMG)
rm -rf **/**/*.bin
.PHONY:
all
8) pm.asm
[BITS 32]
[SECTION .text]
load_gdtr: ; void load_gdt(int limit, int addr);
MOV AX, [ESP+4] ; limit
MOV [ESP+6], AX
LGDT [ESP+6]
RET
9) pm.h
#ifndef _PM_H_
#define _PM_H_
#endif // _PM_H_
Libc
1) include
a) stdarg.h
#ifndef _STDARG_H
#define _STDARG_H
b) stdio.h
#ifndef _STDIO_H
#define _STDIO_H
#include <stdarg.h>
#ifndef NULL
#define NULL ((void *)0)
#endif // NULL
#endif // _STDIO_H
Libc
2) stdio.c
#include <stdarg.h>
#include <stdio.h>
struct SprintBuf {
char *buf;
int count;
};
void printnum(void (*fputch)(char, void *), void *data, unsigned long num,
int base) {
if (num >= base) {
printnum(fputch, data, num / base, base);
}
void vprintfmt(void (*fputch)(char, void *), void *data, const char *fmt,
va_list ap) {
int ch;
unsigned long long num;
char *str;
while (1) {
while ((ch = *fmt++) != '%') {
fputch(ch, data);
if (ch == '\0') {
return;
}
}
num = 0;
switch (ch = *fmt++) {
case 'c':
fputch(va_arg(ap, int), data);
break;
case 'd':
num = va_arg(ap, int);
if ((long long)num < 0) {
fputch('-', data);
num = -(long long)num;
}
printnum(fputch, data, num, 10);
break;
case 'p':
fputch('0', data);
fputch('x', data);
num = (unsigned long)va_arg(ap, void *);
printnum(fputch, data, num, 16);
break;
case 's':
str = va_arg(ap, char *);
if (str == NULL) {
str = "<null>";
}
while (*str != '\0') {
fputch(*str, data);
str++;
}
break;
case '%':
fputch('%', data);
break;
default:
break;
}
}
}
return buf.count;
}
int sprintf(char *s, const char *format, ...) {
va_list ap;
int ret;
va_start(ap, format);
ret = vsprintf(s, format, ap);
va_end(ap);
return ret;
}