现在的位置: 首页 > 综合 > 正文

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

2013年03月11日 ⁄ 综合 ⁄ 共 10058字 ⁄ 字号 评论关闭

它有三部分组成。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

 

 

抱歉!评论已关闭.