您的位置:首页 > 其它

给出一个printk函数的实现版本(用于早期调试用)

2010-04-25 18:44 423 查看
它有三部分组成。vsprintf,printk,debug.s中mywrite函数。其中vsprintf函数是linux实现我调试后拿来使用,对这个函数的调试可用

gdb来调。呵呵,mywrite则是我自己写的。呵呵,改了很多次了。我把所有原件不加修改的发上来,以期可以看到系统开发的真实过程吧。

/*文件名:followking/include/stdarg.h
*本文件改写linux-0.11/inclde/stdarg.h,目的是为了体验整个系统构建的过程。
*作者:hk0625
*开始时间: 2010年03月27号星期六 14:17
*完成时间: 2010年03月27号星期六 未完成
*最后修改时间: 2010年04月08日星期四 09:35
*地点:北京化工大学郁夫图书馆文法阅览室小圆桌
*Email:shaohua20051231@163.com
*下面let's try!
*/
#ifndef _STDARG_H
#define _STDARG_H
/*
typedef char * va_list;

#define __va_rounded_size(TYPE) /
(((sizeof (TYPE) + sizeof (int) -1 ) / sizeof (int)) * sizeof (int))

#ifndef __sparc__
#define va_start(AP, LASTARG) /
(AP = ((char *) &(LASTARG) + __va_rounded_size(LASTARG)))
#else
#define va_start(AP, LASTARG) /
(__builtin_saverages(), /
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif
*/
//void va_end(va_list); /*在gnulib中定义*/

//#define va_end(AP) //在这里理解起来有点困难。呵呵
/*
#define va_arg(AP, TYPE) /
(AP += __va_rounded_size (TYPE), /
*((TYPE *)(AP - __va_rounded_size (TYPE))))
*/
/********************************************************
* 提供另一种实现方式,理由是为了排除在这里出错的可能性 *
* 2010年03月30号星期二 13:31 *
********************************************************/

typedef char * va_list;

#define va_start(ap, v) /
((void)(ap = (va_list)&v + sizeof(v)))
#define va_arg(ap, type) (*((type *)(ap))++)
#define va_end(ap) ((void) (ap=0))

#endif /*_STDARG_H */

/*文件名:followking/include/debug.h
*作者:hk0625
*开始时间: 2010年03月30号星期二 15:27
*完成时间: 2010年04月13日星期二 16:24(完成)
*最后修改时间: 2010年04月13日星期二 16:24
*地点:北京化工大学郁夫图书馆文法阅览室小圆桌
*Email: shaohua20051231@163.com
*下面let's try!
*/
//本头文件用于调试。呵呵,打印整数吧。
#include <fkix/sched.h>
//int printf(const char *fmt, ...);
#define ONLY_TASK 0
#define TASK_TSS 1
#define ALL 2

int mywrite(int line, char * str, int len);
void clear();
void my_tty_write(char *str, int len);
void print_task_struct(struct task_struct *p, int type);
void print_tss_struct(struct tss_struct *p);
void print_desc_struct(struct desc_struct *p, int n);
void print_buffer_head(struct buffer_head * bh);

void test_memory_c(void);
void test_fork_c(void);
void test_sched_c(void);
void test_exit_c(void);
void test_hd_c(void);
void test_buffer_c(void);

/*文件名:followking/kernel/vsprintf.c
*本文件改写linux-0.11/kernel/vsprintf.c,目的是为了体验整个系统构建的过程。
*作者:hk0625
*开始时间: 2010年03月27号星期六 15:08
*完成时间: 2010年04月06日星期二 16:52(完成)
*最后修改时间: 2010年04月08日星期四 11:35
*地点:北京化工大学郁夫图书馆文法阅览室小圆桌&北化1#宿舍楼426
*Email: shaohua20051231@163.com
*下面let's try!
*/

#include <stdarg.h>
#include <string.h> //目前还不知道那里用到它。呵呵
//现在知道了。呵呵 2010年03月28号星期天 16:06
//这里用到了一个strlen()。现在就去实现它吧。
#include <debug.h>
#include <fkix/kernel.h>
#define ZEROPAD 1 /* 填充0 */
#define SIGN 2 /* 无符号或是有符号长整数 */
#define PLUS 4 /* 显示加 */
#define SPACE 8 /* 如果是加号,则置空格 */
#define LEFT 16 /* 左调 */
#define SPECIAL 32 /* 0x */
#define SMALL 64 /* 使用小写字母 */

#define is_digit(c) ((c) >= '0' && (c) <= '9')

static int skip_atoi(const char **s);
static char * number(char * str, int num, int base, int size,
int precision, int type);

int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
int i;
char * str;
char *s;
int *ip;
int flags; /* number()使用的标志*/
int field_width; /* width of output field */
int precision; /*min.整数数字个数;max.字符串的个数*/
int qualifier; /* 'h', 'l',或'L'用于整数字段。*/

for (str=buf; *fmt; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
/* 处理标志域 */
flags = 0;
repeat:
++fmt;
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}

/* 获取域宽度 */
field_width = -1;

if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}

/* 获取精度 */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}

/* 获取长度修饰符,并存入qualifer */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
//下面进行转换分析。
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
break;
case 's':
s = va_arg(args, char *);
len = strlen(s);
if (precision < 0)
precision = len;
else if (len > precision)
len = precision;
if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i=0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
break;

case 'o':
flags |= SPECIAL;
str = number(str, va_arg(args, unsigned long), 8,
field_width, precision, flags);
break;
case 'p':
if (field_width == -1) {
field_width = 8;
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
break;
case 'x':
flags |=SMALL;
case 'X':
flags |= SPECIAL;
str = number(str, va_arg(args, unsigned long), 16,
field_width, precision, flags);
break;

case 'd':
case 'i':
flags |= SIGN;
case 'u':
str = number(str, va_arg(args, unsigned long), 10,
field_width, precision, flags);
break;

case 'n':
ip = va_arg(args, int *);
*ip = (str - buf);
break;

default:
if (*fmt != '%')
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
break;

}//switch

}//for()
*str = '/0';
return str-buf;
}//vsprintf()

/************************************************************
* vsprintf()中用到number()和skip_atoi(),接下来我们实现它。*
* 2010年03月27号星期六 16:04 *
* **********************************************************/

//将字符串转换成整数。
static int skip_atoi(const char **s)
{
int i=0;

while (is_digit(**s))

i = i*10 + *((*s)++) - '0';
return i;
}

#define do_div(n, base) ({ /
int __res; /
__asm__("divl %4":"=a" (n), "=d"(__res):"0"(n), "1"(0), "r"(base)); /
__res;})
/**********************************************
* 周六了,晚上图书馆不开门。在宿舍编吧。呵呵 *
* 2010年03月27号星期六 21:44 *
* ********************************************/
//整数进制转换。
static char * number(char * str, int num, int base, int size,
int precision, int type)
{
char c, sign, tmp[36];
const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;

if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
if (type&LEFT) type &= ~ZEROPAD;
if (base<2 || base>36)
return 0;
c = (type & ZEROPAD)? '0':' ';
if (type&SIGN && num<0) {
sign = '-';
num = -num;
} else
sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ': 0);
if (sign) size--;
if (type&SPECIAL) {
if (base==16) size -= 2;
else if (base==8) size--;
}

i=0;
if (num==0)
tmp[i++]='0';
else while (num!=0)
tmp[i++]=digits[do_div(num,base)];
tmp[i] = '/0';

if (i>precision) precision=i;
size -= precision;

if (!(type&(ZEROPAD+LEFT)))
while (size-- > 0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type&SPECIAL) {
if (base==8)
*str++ = '0';
else if (base == 16) {
*str++ = '0';
*str++ = digits[33];
}
}
if (!(type&LEFT))
while (size-- >0)
*str++ = c;
while (i < precision--)
*str++ = '0';
while (i-->0)
*str++ = tmp[i];

while (size-->0)
*str++ = tmp[i];
while (size-- >0)
*str++ = ' ';

return str;
}
/***********************************************************************
* 为了调试方便,接下来我想实现有关打印的其它函数,有了这个函数作为基础*
* 我想我可以实现printf函数了,呵呵。printf(init/main.c) *
* 2010年03月27号星期六 22:13 *
***********************************************************************/

/*文件名:followking/kernel/printk.c
*本文件改写linux-0.11/kernel/printk.c,目的是为了体验整个系统构建的过程。
*作者:hk0625
*开始时间: 2010年03月27号星期六 13:45
*完成时间: 2010年03月27号星期六 22:25
*最后修改时间: 2010年04月05日星期一 19:14
*地点:北京化工大学郁夫图书馆文法阅览室小圆桌
*Email:shaohua20051231@163.com
*下面let's try!
*/
//当处于内核模式的时候,我们没法使用printf(),因为寄存器fs指向的对方不对。
//为此而外编写printf并在使用前保存fs。呵呵

#include <stdarg.h>
#include <stddef.h>
#include <fkix/kernel.h>
#include <debug.h>
#include <unistd.h>

static char buf[1024];

extern int vsprintf(char *buf, const char *fmt, va_list args);

int printk(const char *fmt, ...)
{
va_list args;
int i;

va_start(args, fmt);
i=vsprintf(buf, fmt, args);
// mywrite(0, buf, i);
va_end(args);

__asm__ __volatile__(
"push %%fs/n/t"
"push %%ds/n/t"
"popl %%fs/n/t"
"pushl %0/n/t"
"pushl $buf/n/t"
"pushl $0/n/t"
// "call mywrite/n/t"
// "call write/n/t"
// "call sys_tty_write/n/t"
"call tty_write/n/t"
"addl $8, %%esp/n/t"
"popl %0/n/t"
"popl %%fs"
::"a"(i));

// write(0, buf, i);
return i;
}
/*************************************************************
* 原先的想法有点错误,呵呵,vsprintf才应该是打印函数的原型。*
* 其实写到这里,我个人觉得,其实第一个应该实现的函数应该是 *
* vsprintf()。呵呵,下面我们把在这文件遇到的函数及宏定义都 *
* 实现吧。看来还挺多的。先把三个头文件中相关的宏定义及函数 *
* 声明先实现,然后去实现vsprintf(kernel/vsprintf.c)最后 *
* 实现tty_write(kernel/chr_drv/tty_io.c) *
* 2010年03月27号星期六 14:14 *
* *****************************************/

;文件名:followking/init/debug.s
;作者:hk0625
;开始时间: 2010年03月26号星期五 18:47
;完成时间: 2010年03月26号星期五 18:47
;最后修改时间: 2010年04月13日星期二 17:09
;地点: 北京化工大学郁夫图书馆文法阅览室小圆桌
;Email:shaohua20051231@163.com
;下面let's try
global clear, mywrite, my_tty_write
extern buf, ;line, col
line: dd 0
col: dd 0
clear:
push eax
push ebx
push ecx

mov ebx, 0xb8000
mov eax, 0x0700
mov cx, 0x4000
clear_s:
mov [ebx], ax
add ebx, 2
loop clear_s

pop ecx
pop ebx
pop eax
ret
mywrite:
push ebp
mov ebp, esp
sub esp, 0x18
push eax
push ebx
push ecx
push esi
;第一个参数,行数
mov eax, [line]
mov bl, 160
mul bl
mov ebx, eax
add ebx, 0xb8000
mov eax, [col]
add ebx, eax
;第二个参数,字符串地址。
mov esi, [ebp+12]
;第三个参数,字符串长度。
mov ecx, [ebp+16]

.s mov al, [fs:esi]
cmp al, 0x09
je .tab
cmp al, 0x0a
je .cr
cmp al, 0x0d
je .next
mov ah, 0x07
mov [ebx], ax
add ebx, 2
add word [col], 2
cmp word [col], 160
jae .cr
jmp .next
.tab:
and ebx, 0xfffffff0
add ebx, 16
and word[col], 0xfff0
add word[col], 16
cmp word[col], 160
jae .cr
jmp .next
.cr:
call cr
.next: inc esi
loop .s

pop esi
pop ecx
pop ebx
pop eax

leave
ret

my_tty_write:
push ebp
mov ebp, esp
sub esp, 0x18

push eax
push ebx
push ecx
push esi

mov eax, [line]
mov bl, 160
mul bl
mov ebx, eax
add ebx, 0xb8000
mov eax, [col]
add ebx, eax
;第一个参数,字符串地址。
mov esi, [ebp+8]
;第二个参数,字符串长度。
mov ecx, [ebp+12]

.s mov al, [esi]
cmp al, 0x09
je .tab
cmp al, 0x0a
je .cr
cmp al, 0x0d
je .next
mov ah, 0x07
mov [ebx], ax
add ebx, 2
add word [col], 2
cmp word [col], 160
jae .cr
jmp .next
.tab:
and ebx, 0xfffffff0
add ebx, 16
and word[col], 0xfff0
add word[col], 16
cmp word[col], 160
jae .cr
jmp .next
.cr:
call cr
.next: inc esi
loop .s

pop esi
pop ecx
pop ebx
pop eax

leave
ret

cr:
;换行,目前还没有想到更好的算法,这个先用吧。呵呵
inc word [line]
mov word [col], 0
mov eax, [line]
cmp al, 24
jbe .next2
call up_one_line
dec word[line]
mov eax, [line]

.next2 mov bl, 160
mul bl
mov ebx, eax
add ebx, 0xb8000
mov eax, [col]
add ebx, eax
ret
;2010年04月08日星期四 20:33
;将整个屏幕的内容向上移动一行。
up_one_line:
push eax
push ebx
push ecx

mov ebx, 0xb8000
mov cx, 0x2000 - 160
.s
mov eax, [ebx+160]
mov [ebx], eax
add ebx, 4
loop .s

mov ax, 0x0700
mov cx, 160
.s1
mov ax, [ebx]
add ebx, 2
loop .s1

pop ecx
pop ebx
pop eax
ret
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐