第十五章 终章 呈现系统交互界面(中)

本文最后更新于:1 年前

第十五章 终章 呈现系统交互界面(中)

写在前面

这一中章全都是书上实现shell这一部分,为了呈现方便,直接采用了最终的代码,没有一步步按照书上的代码去展示。

实现shell

shell/shell.h创建

1
2
3
4
5
6
7
8
9
10
11
#ifndef __SHELL_SHELL_H
#define __SHELL_SHELL_H

#include "stdint.h"

void print_prompt(void);
static void readline(char* buf,int32_t count);
void my_shell(void);
static int32_t cmd_parse(char* cmd_str,char** argv,char token);

#endif

shell/shell.c创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "shell.h"
#include "global.h"
#include "stdint.h"
#include "string.h"
#include "syscall.h"
#include "stdio.h"
#include "../fs/file.h"
#include "../kernel/debug.h"
#include "buildin_cmd.h"


#define MAX_ARG_NR 16 // 加上命令名外,最多支持15个参数
#define cmd_len 128 //最大支持键入128个字符的命令行输入

/* 存储输入的命令 */
static char cmd_line[cmd_len] = {0};
char final_path[MAX_PATH_LEN] = {0}; // 用于洗路径时的缓冲

/* 用来记录当前目录,是当前目录的缓存,每次执行cd命令时会更新此内容 */
char cwd_cache[64] = {0};
char* argv[MAX_ARG_NR] = {NULL};
int32_t argc = -1;

/* 输出提示符 */
void print_prompt(void) {
printf("[rabbit@localhost %s]$ ", cwd_cache);
}

/* 从键盘缓冲区中最多读入count个字节到buf。*/
static void readline(char* buf, int32_t count) {
ASSERT(buf != NULL && count > 0);
char* pos = buf;

while (read(stdin_no, pos, 1) != -1 && (pos - buf) < count) { // 在不出错情况下,直到找到回车符才返回
switch (*pos) {
/* 找到回车或换行符后认为键入的命令结束,直接返回 */
case '\n':
case '\r':
*pos = 0; // 添加cmd_line的终止字符0
putchar('\n');
return;
case '\b':
if (buf[0] != '\b') { // 阻止删除非本次输入的信息
--pos; // 退回到缓冲区cmd_line中上一个字符
putchar('\b');
}
break;
/* ctrl+l 清屏 */
case 'l' - 'a':
/* 1 先将当前的字符'l'-'a'置为0 */
*pos = 0;
/* 2 再将屏幕清空 */
clear();
/* 3 打印提示符 */
print_prompt();
/* 4 将之前键入的内容再次打印 */
printf("%s", buf);
break;

/* ctrl+u 清掉输入 */
case 'u' - 'a':
while (buf != pos) {
putchar('\b');
*(pos--) = 0;
}
break;
/* 非控制键则输出字符 */
default:
putchar(*pos);
pos++;
}
}
printf("readline: can`t find enter_key in the cmd_line, max num of char is 128\n");
}

/* 分析字符串cmd_str中以token为分隔符的单词,将各单词的指针存入argv数组 */
static int32_t cmd_parse(char* cmd_str, char** argv, char token) {
ASSERT(cmd_str != NULL);
int32_t arg_idx = 0;
while(arg_idx < MAX_ARG_NR) {
argv[arg_idx] = NULL;
arg_idx++;
}
char* next = cmd_str;
int32_t argc = 0;
/* 外层循环处理整个命令行 */
while(*next) {
/* 去除命令字或参数之间的空格 */
while(*next == token) {
next++;
}
/* 处理最后一个参数后接空格的情况,如"ls dir2 " */
if (*next == 0) {
break;
}
argv[argc] = next;

/* 内层循环处理命令行中的每个命令字及参数 */
while (*next && *next != token) { // 在字符串结束前找单词分隔符
next++;
}

/* 如果未结束(是token字符),使tocken变成0 */
if (*next) {
*next++ = 0; // 将token字符替换为字符串结束符0,做为一个单词的结束,并将字符指针next指向下一个字符
}

/* 避免argv数组访问越界,参数过多则返回0 */
if (argc > MAX_ARG_NR) {
return -1;
}
argc++;
}
return argc;
}

/* 简单的shell */
void my_shell(void) {
cwd_cache[0] = '/';
while (1) {
print_prompt();
memset(final_path, 0, MAX_PATH_LEN);
memset(cmd_line, 0, cmd_len);
readline(cmd_line, cmd_len);

if (cmd_line[0] == 0) { // 若只键入了一个回车
continue;
}

argc = -1;
argc = cmd_parse(cmd_line, argv, ' ');
if (argc == -1) {
printf("num of arguments exceed %d\n", MAX_ARG_NR);
continue;
}

if (!strcmp("ls", argv[0])) {
buildin_ls(argc, argv);
} else if (!strcmp("cd", argv[0])) {
if (buildin_cd(argc, argv) != NULL) {
memset(cwd_cache, 0, MAX_PATH_LEN);
strcpy(cwd_cache, final_path);
}
} else if (!strcmp("pwd", argv[0])) {
buildin_pwd(argc, argv);
} else if (!strcmp("ps", argv[0])) {
buildin_ps(argc, argv);
} else if (!strcmp("clear", argv[0])) {
buildin_clear(argc, argv);
} else if (!strcmp("mkdir", argv[0])){
buildin_mkdir(argc, argv);
} else if (!strcmp("rmdir", argv[0])){
buildin_rmdir(argc, argv);
} else if (!strcmp("rm", argv[0])) {
buildin_rm(argc, argv);
}
}
panic("my_shell: should not be here");
}

device/keyboard.c修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include "keyboard.h"
#include "print.h"
#include "io.h"
#include "interrupt.h"
#include "global.h"
#include "stdint.h"
#include "ioqueue.h"

#define KBD_BUF_PORT 0X60

#define KBD_BUF_PORT 0X60

#define esc '\033' //esc 和 delete都没有
#define delete '\0177'
#define enter '\r'
#define tab '\t'
#define backspace '\b'

#define char_invisible 0 //功能性 不可见字符均设置为0
#define ctrl_l_char char_invisible
#define ctrl_r_char char_invisible
#define shift_l_char char_invisible
#define shift_r_char char_invisible
#define alt_l_char char_invisible
#define alt_r_char char_invisible
#define caps_lock_char char_invisible

#define shift_l_make 0x2a
#define shift_r_make 0x36
#define alt_l_make 0x38
#define alt_r_make 0xe038
#define alt_r_break 0xe0b8
#define ctrl_l_make 0x1d
#define ctrl_r_make 0xe01d
#define ctrl_r_break 0xe09d
#define caps_lock_make 0x3a

struct ioqueue kbd_buf; // 定义键盘缓冲区

bool ctrl_status = false,shift_status = false,alt_status = false,caps_lock_status = false,ext_scancode = false;


char keymap[][2] = {
/* 0x00 */ {0, 0},
/* 0x01 */ {esc, esc},
/* 0x02 */ {'1', '!'},
/* 0x03 */ {'2', '@'},
/* 0x04 */ {'3', '#'},
/* 0x05 */ {'4', '$'},
/* 0x06 */ {'5', '%'},
/* 0x07 */ {'6', '^'},
/* 0x08 */ {'7', '&'},
/* 0x09 */ {'8', '*'},
/* 0x0A */ {'9', '('},
/* 0x0B */ {'0', ')'},
/* 0x0C */ {'-', '_'},
/* 0x0D */ {'=', '+'},
/* 0x0E */ {backspace, backspace},
/* 0x0F */ {tab, tab},
/* 0x10 */ {'q', 'Q'},
/* 0x11 */ {'w', 'W'},
/* 0x12 */ {'e', 'E'},
/* 0x13 */ {'r', 'R'},
/* 0x14 */ {'t', 'T'},
/* 0x15 */ {'y', 'Y'},
/* 0x16 */ {'u', 'U'},
/* 0x17 */ {'i', 'I'},
/* 0x18 */ {'o', 'O'},
/* 0x19 */ {'p', 'P'},
/* 0x1A */ {'[', '{'},
/* 0x1B */ {']', '}'},
/* 0x1C */ {enter, enter},
/* 0x1D */ {ctrl_l_char, ctrl_l_char},
/* 0x1E */ {'a', 'A'},
/* 0x1F */ {'s', 'S'},
/* 0x20 */ {'d', 'D'},
/* 0x21 */ {'f', 'F'},
/* 0x22 */ {'g', 'G'},
/* 0x23 */ {'h', 'H'},
/* 0x24 */ {'j', 'J'},
/* 0x25 */ {'k', 'K'},
/* 0x26 */ {'l', 'L'},
/* 0x27 */ {';', ':'},
/* 0x28 */ {'\'', '"'},
/* 0x29 */ {'`', '~'},
/* 0x2A */ {shift_l_char, shift_l_char},
/* 0x2B */ {'\\', '|'},
/* 0x2C */ {'z', 'Z'},
/* 0x2D */ {'x', 'X'},
/* 0x2E */ {'c', 'C'},
/* 0x2F */ {'v', 'V'},
/* 0x30 */ {'b', 'B'},
/* 0x31 */ {'n', 'N'},
/* 0x32 */ {'m', 'M'},
/* 0x33 */ {',', '<'},
/* 0x34 */ {'.', '>'},
/* 0x35 */ {'/', '?'},
/* 0x36 */ {shift_r_char, shift_r_char},
/* 0x37 */ {'*', '*'},
/* 0x38 */ {alt_l_char, alt_l_char},
/* 0x39 */ {' ', ' '},
/* 0x3A */ {caps_lock_char, caps_lock_char}
};

/* 键盘初始化 */
void keyboard_init()
{
put_str("keyboard init start\n");
ioqueue_init(&kbd_buf);
register_handler(0x21, intr_keyboard_handler);
put_str("keyboard init done\n");
}

void intr_keyboard_handler(void)
{
bool ctrl_down_last = ctrl_status;
bool shift_down_last = shift_status;
bool caps_lock_last = caps_lock_status;

bool break_code;
uint16_t scancode = inb(KBD_BUF_PORT);

if(scancode == 0xe0) //多字节处理
{
ext_scancode = true;
return;
}

break_code = ((scancode & 0x0080) != 0); //断码 = 通码 + 0x80 通码最小比0x80小 则只有断码才可以有

if(break_code)
{
uint16_t make_code = (scancode &= 0xff7f); //多字节不处理
if(make_code == ctrl_l_make || make_code == ctrl_r_make) ctrl_status = false;
else if(make_code == shift_l_make || make_code == shift_r_make) shift_status = false;
else if(make_code == alt_l_make || make_code == alt_r_make) alt_status = false;
return;
}
else if((scancode > 0x00 && scancode < 0x3b) || (scancode == alt_r_make) || (scancode == ctrl_r_make))
{
bool shift = false; //先默认设置成false
if((scancode < 0x0e) || (scancode == 0x29) || (scancode == 0x1a) || \
(scancode == 0x1b) || (scancode == 0x2b) || (scancode == 0x27) || \
(scancode == 0x28) || (scancode == 0x33) || (scancode == 0x34) || \
(scancode == 0x35))
{
if(shift_down_last) shift = true;
}
else
{
if(shift_down_last && caps_lock_last) shift = false; //效果确实是这样子的 我试了一下
else if(shift_down_last || caps_lock_last) shift = true; //其中任意一个都是大写的作用
else shift = false;
}

uint8_t index = (scancode & 0x00ff);
char cur_char = keymap[index][shift];

if((ctrl_down_last && cur_char == 'l') || (ctrl_down_last && cur_char == 'u'))
cur_char -= 'a';

if(cur_char)
{
if(!ioq_full(&kbd_buf))
ioq_putchar(&kbd_buf,cur_char);
//put_char(cur_char);
return;
}

if(scancode == ctrl_l_make || scancode == ctrl_r_make)
ctrl_status = true;
else if(scancode == shift_l_make || scancode == shift_r_make)
shift_status = true;
else if(scancode == alt_l_make || scancode == alt_r_make)
alt_status = true;
else if(scancode == caps_lock_make)
caps_lock_status = !caps_lock_status;
else put_str("unknown key\n");
}

return;
}

lib/user/syscall.h修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef __LIB_USER_SYSCALL_H
#define __LIB_USER_SYSCALL_H
#include "stdint.h"


enum SYSCALL_NR {
SYS_GETPID,
SYS_WRITE,
SYS_MALLOC,
SYS_FREE,
SYS_FORK,
SYS_READ,
SYS_PUTCHAR,
SYS_CLEAR,
SYS_GETCWD,
SYS_OPEN,
SYS_CLOSE,
SYS_LSEEK,
SYS_UNLINK,
SYS_MKDIR,
SYS_OPENDIR,
SYS_CLOSEDIR,
SYS_CHDIR,
SYS_RMDIR,
SYS_READDIR,
SYS_REWINDDIR,
SYS_STAT,
SYS_PS
};

uint32_t getpid(void);
uint32_t write(int32_t fd, const void* buf, uint32_t count);
void* malloc(uint32_t size);
void free(void* ptr);
int32_t fork(void);
#endif

lib/user/syscall.c修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "syscall.h"

/* 无参数的系统调用 */
#define _syscall0(NUMBER) ({ \
int retval; \
asm volatile ( \
"int $0x80" \
: "=a" (retval) \
: "a" (NUMBER) \
: "memory" \
); \
retval; \
})


/* 一个参数的系统调用 */
#define _syscall1(NUMBER, ARG1) ({ \
int retval; \
asm volatile ( \
"int $0x80" \
: "=a" (retval) \
: "a" (NUMBER), "b" (ARG1) \
: "memory" \
); \
retval; \
})

/* 两个参数的系统调用 */
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
int retval; \
asm volatile ( \
"int $0x80" \
: "=a" (retval) \
: "a" (NUMBER), "b" (ARG1), "c" (ARG2) \
: "memory" \
); \
retval; \
})

/* 三个参数的系统调用 */
#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
int retval; \
asm volatile ( \
"int $0x80" \
: "=a" (retval) \
: "a" (NUMBER), "b" (ARG1), "c" (ARG2), "d" (ARG3) \
: "memory" \
); \
retval; \
})

/* 返回当前任务pid */
uint32_t getpid()
{
return _syscall0(SYS_GETPID);
}

/* 把buf中count个字符写入文件描述符fd */
uint32_t write(int32_t fd, const void* buf, uint32_t count) {
return _syscall3(SYS_WRITE, fd, buf, count);
}

void* malloc(uint32_t size)
{
return (void*)_syscall1(SYS_MALLOC, size);
}

void free(void* ptr)
{
_syscall1(SYS_FREE, ptr);
}

int32_t fork(void)
{
return _syscall0(SYS_FORK);
}

/* 从文件描述符fd中读取count个字节到buf */
int32_t read(int32_t fd, void* buf, uint32_t count) {
return _syscall3(SYS_READ, fd, buf, count);
}

/* 输出一个字符 */
void putchar(char char_asci) {
_syscall1(SYS_PUTCHAR, char_asci);
}

/* 清空屏幕 */
void clear(void) {
_syscall0(SYS_CLEAR);
}

/* 获取当前工作目录 */
char* getcwd(char* buf, uint32_t size) {
return (char*)_syscall2(SYS_GETCWD, buf, size);
}

/* 以flag方式打开文件pathname */
int32_t open(char* pathname, uint8_t flag) {
return _syscall2(SYS_OPEN, pathname, flag);
}

/* 关闭文件fd */
int32_t close(int32_t fd) {
return _syscall1(SYS_CLOSE, fd);
}

/* 设置文件偏移量 */
int32_t lseek(int32_t fd, int32_t offset, uint8_t whence) {
return _syscall3(SYS_LSEEK, fd, offset, whence);
}

/* 删除文件pathname */
int32_t unlink(const char* pathname) {
return _syscall1(SYS_UNLINK, pathname);
}

/* 创建目录pathname */
int32_t mkdir(const char* pathname) {
return _syscall1(SYS_MKDIR, pathname);
}

/* 打开目录name */
struct dir* opendir(const char* name) {
return (struct dir*)_syscall1(SYS_OPENDIR, name);
}

/* 关闭目录dir */
int32_t closedir(struct dir* dir) {
return _syscall1(SYS_CLOSEDIR, dir);
}

/* 删除目录pathname */
int32_t rmdir(const char* pathname) {
return _syscall1(SYS_RMDIR, pathname);
}

/* 读取目录dir */
struct dir_entry* readdir(struct dir* dir) {
return (struct dir_entry*)_syscall1(SYS_READDIR, dir);
}

/* 回归目录指针 */
void rewinddir(struct dir* dir) {
_syscall1(SYS_REWINDDIR, dir);
}

/* 获取path属性到buf中 */
int32_t stat(const char* path, struct stat* buf) {
return _syscall2(SYS_STAT, path, buf);
}

/* 改变工作目录为path */
int32_t chdir(const char* path) {
return _syscall1(SYS_CHDIR, path);
}

/* 显示任务列表 */
void ps(void) {
_syscall0(SYS_PS);
}

userprog/syscall-init.c修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "syscall-init.h"
#include "../lib/user/syscall.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"
#include "../thread/thread.h"
#include "../kernel/memory.h"
#include "../fs/fs.h"
#include "fork.h"
#include "../device/console.h"

#define syscall_nr 32
typedef void* syscall;
syscall syscall_table[syscall_nr];

/* 返回当前任务的pid */
uint32_t sys_getpid(void)
{
return running_thread()->pid;
}


/* 初始化系统调用 */
void syscall_init(void) {
put_str("syscall_init start\n");
syscall_table[SYS_GETPID] = sys_getpid;
syscall_table[SYS_WRITE] = sys_write;
syscall_table[SYS_MALLOC] = sys_malloc;
syscall_table[SYS_FREE] = sys_free;
syscall_table[SYS_FORK] = sys_fork;
syscall_table[SYS_READ] = sys_read;
syscall_table[SYS_PUTCHAR] = console_put_char;
syscall_table[SYS_CLEAR] = cls_screen;
syscall_table[SYS_GETCWD] = sys_getcwd;
syscall_table[SYS_OPEN] = sys_open;
syscall_table[SYS_CLOSE] = sys_close;
syscall_table[SYS_LSEEK] = sys_lseek;
syscall_table[SYS_UNLINK] = sys_unlink;
syscall_table[SYS_MKDIR] = sys_mkdir;
syscall_table[SYS_OPENDIR] = sys_opendir;
syscall_table[SYS_CLOSEDIR] = sys_closedir;
syscall_table[SYS_CHDIR] = sys_chdir;
syscall_table[SYS_RMDIR] = sys_rmdir;
syscall_table[SYS_READDIR] = sys_readdir;
syscall_table[SYS_REWINDDIR] = sys_rewinddir;
syscall_table[SYS_STAT] = sys_stat;
syscall_table[SYS_PS] = sys_ps;

put_str("syscall_init done\n");
}

thread/thread.c新增

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
void pad_print(char* buf,int32_t buf_len,void* ptr,char format)
{
memset(buf,0,buf_len);
uint8_t out_pad_0idx = 0;
switch(format)
{
case 's':
out_pad_0idx = sprintf(buf,"%s",ptr);
break;
case 'd':
out_pad_0idx = sprintf(buf,"%d",*((int16_t*)ptr));
break;
case 'x':
out_pad_0idx = sprintf(buf,"%x",*((uint32_t*)ptr));
}
while(out_pad_0idx < buf_len)
{
buf[out_pad_0idx] = ' ';
out_pad_0idx++;
}
sys_write(stdout_no,buf,buf_len-1);
}


bool elem2thread_info(struct list_elem* pelem,int arg)
{
struct task_struct* pthread = elem2entry(struct task_struct,all_list_tag,pelem);
char out_pad[16] = {0};
pad_print(out_pad,16,&pthread->pid,'d');

if(pthread->parent_pid == -1)
pad_print(out_pad,16,"NULL",'s');
else
pad_print(out_pad,16,&pthread->parent_pid,'d');

switch(pthread->status)
{
case 0:
pad_print(out_pad,16,"RUNNING",'s');
break;
case 1:
pad_print(out_pad,16,"READY",'s');
break;
case 2:
pad_print(out_pad,16,"BLOCKED",'s');
break;
case 3:
pad_print(out_pad,16,"WAITING",'s');
break;
case 4:
pad_print(out_pad,16,"HANGING",'s');
break;
case 5:
pad_print(out_pad,16,"DIED",'s');
break;
}
pad_print(out_pad,16,&pthread->elapsed_ticks,'x');

memset(out_pad,0,16);
ASSERT(strlen(pthread->name) < 17);
memcpy(out_pad,pthread->name,strlen(pthread->name));
strcat(out_pad,"\n");
sys_write(stdout_no,out_pad,strlen(out_pad));
return false;
}


//打印任务列表
void sys_ps(void)
{
char* ps_title = "PID PPID STAT TICKS COMMAND\n";
sys_write(stdout_no,ps_title,strlen(ps_title));
list_traversal(&thread_all_list,elem2thread_info,0);
}

shell/buildin_cmd.h创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef __SHELL_BUILDIN_CMD_H
#define __SHELL_BUILDIN_CMD_H
#include "stdint.h"

static void wash_path(char* old_abs_path,char* new_abs_path);
void make_clear_abs_path(char* path,char* final_path);
void buildin_pwd(uint32_t argc,char** argv);
char* buildin_cd(uint32_t argc,char** argv);
void buildin_ls(uint32_t argc,char** argv);
void buildin_ps(uint32_t argc,char** argv);
void buildin_clear(uint32_t argc,char** argv);
int32_t buildin_mkdir(uint32_t argc,char** argv);
int32_t buildin_rmdir(uint32_t argc,char** argv);
int32_t buildin_rm(uint32_t argc,char** argv);

#endif

shell/buildin_cmd.c创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#include "buildin_cmd.h"
#include "../fs/file.h"
#include "../fs/fs.h"
#include "debug.h"
#include "string.h"
#include "syscall.h"
#include "stdio-kernel.h"
#include "../fs/dir.h"
#include "../fs/fs.h"
#include "stdio.h"
#include "shell.h"

extern char final_path[160];

//在用户态就把路径给解析出来
void wash_path(char* old_abs_path,char* new_abs_path)
{
ASSERT(old_abs_path[0] == '/');
char name[MAX_FILE_NAME_LEN] = {0};
char* sub_path = old_abs_path;
sub_path = path_parse(sub_path,name);

//如果直接就是根目录 直接返回即可
if(name[0] == 0)
{
new_abs_path[0] = '/';
new_abs_path[1] = 0;
return;
}
new_abs_path[0] = 0;
strcat(new_abs_path,"/");
while(name[0])
{
if(!strcmp("..",name)) //返回上级
{
char* slash_ptr = strrchr(new_abs_path,'/'); //等于移动到最偏右的/位置去
if(slash_ptr != new_abs_path) //如果为 /aaa 那么移动之后就到/的位置了 如果是/aaa/bbb 那么就会回到/aaa/
*slash_ptr = 0; // 把/变成0
else
*(slash_ptr+1) = 0; // 如果是 / 或者 /aaa 那么都回到/ 则把最右边+1置零位即可
}
else if(strcmp(".",name)) //如果不是到. 增加到后米纳即可 .等于没有作用 继续遍历即可
{
if(strcmp(new_abs_path,"/")) //不是 / 防止出现// 的情况
strcat(new_abs_path,"/");
strcat(new_abs_path,name);
}

memset(name,0,MAX_FILE_NAME_LEN);
if(sub_path)
sub_path = path_parse(sub_path,name);
}
}

//把path处理 . ..去掉 储存在final_path getcwd得到当前工作目录 + 相对路径 即绝对路径
void make_clear_abs_path(char* path,char* final_path)
{
char abs_path[MAX_PATH_LEN] = {0};
if(path[0] != '/') //如果不是绝对路径就弄成绝对路径
{
memset(abs_path,0,MAX_PATH_LEN);
if(getcwd(abs_path,MAX_PATH_LEN) != NULL)
{
if(!((abs_path[0] == '/') && abs_path[1] == 0))
strcat(abs_path,"/");
}
}
//把path 加到工作目录的头上
strcat(abs_path,path);
wash_path(abs_path,final_path);
}

// pwd命令中的内建函数 得到当前工作目录
void buildin_pwd(uint32_t argc,char** argv)
{
//没有参数才可以
if(argc != 1)
printf("pwd: no argument support!\n");
else
{
if(getcwd(final_path,MAX_PATH_LEN) != NULL)
printf("%s\n",final_path);
else
printf("pwd: get current work directory failed\n");
}
}

// 支持一个参数 改变当前工作目录
char* buildin_cd(uint32_t argc,char** argv)
{
if(argc > 2)
{
printf("cd: only support 1 argument!\n");
return NULL;
}
if(argc == 1)
{
final_path[0] = '/';
final_path[1] = 0;
}
else make_clear_abs_path(argv[1],final_path);

if(chdir(final_path) == -1)
{
printf("cd: no such directory %s\n",final_path);
return NULL;
}
return final_path;
}

// ls内建函数 仅支持-l -h -h等于不支持 哈哈
void buildin_ls(uint32_t argc,char** argv)
{
char* pathname = NULL;
struct stat file_stat;
memset(&file_stat,0,sizeof(struct stat));
bool long_info = false;
uint32_t arg_path_nr = 0;
uint32_t arg_idx = 1; //第一个字符串是 ls 跳过
while(arg_idx < argc) //仅仅支持 ls 或者 ls -l 或者 ls -l path的形式
{
if(argv[arg_idx][0] == '-')
{
if(!strcmp("-l",argv[arg_idx]))
long_info = true;
else if(!strcmp("-h",argv[arg_idx]))
{
printf("usage: -l list all all information about the file.\nnot support -h now sry - -\n");
return;
}
else
{
printf("ls: invaild option %s\nTry 'ls -l' u can get what u want\n",argv[arg_idx]);
return;
}
}
else
{
if(arg_path_nr == 0)
{
pathname = argv[arg_idx];
arg_path_nr = 1;
}
else
{
printf("ls: only support one path\n");
return;
}
}
++arg_idx;
}

if(pathname == NULL) //ls 或者 ls -l
{
//得到工作目录
if(getcwd(final_path,MAX_PATH_LEN) != NULL)
pathname = final_path;
else
{
printf("ls: getcwd for default path failed\n");
return;
}
}
else
{
make_clear_abs_path(pathname,final_path);
pathname = final_path;
}

//目录下的文件
if(stat(pathname,&file_stat) == -1)
{
printf("ls: cannot access %s: No such file or directory\n",pathname);
return;
}

if(file_stat.st_filetype == FT_DIRECTORY) //得到目录文件才继续
{
struct dir* dir = opendir(pathname); //得到目录指针
struct dir_entry* dir_e = NULL;
char sub_pathname[MAX_PATH_LEN] = {0};
uint32_t pathname_len = strlen(pathname);
uint32_t last_char_idx = pathname_len - 1;
memcpy(sub_pathname,pathname,pathname_len);

//方便后面得到当前目录下的文件stat信息
//加个/ 之后每个文件加文件名stat即可
if(sub_pathname[last_char_idx] != '/')
{
sub_pathname[pathname_len] = '/';
++pathname_len;
}

rewinddir(dir); //目录指针指向0 方便readdir遍历目录项
if(long_info) // ls -l 这里是目录的ls
{
char ftype;
printf("total: %d\n",file_stat.st_size);
while((dir_e = readdir(dir))) //通过readdir来遍历目录项 我还专门回去看了看这个函数
{
ftype = 'd';
if(dir_e->f_type == FT_REGULAR)
ftype = '-';
sub_pathname[pathname_len] = 0; //把字符串末尾设0 方便strcat函数
strcat(sub_pathname,dir_e->filename);
memset(&file_stat,0,sizeof(struct stat));
if(stat(sub_pathname,&file_stat) == -1)
{
printf("ls: cannot access %s:No such file or directory\n",dir_e->filename);
return;
}
printf("%c %d %d %s\n",ftype,dir_e->i_no,file_stat.st_size,dir_e->filename);
}
}
else //仅仅是ls 把文件名写出来即可
{
while((dir_e = readdir(dir)))
printf("%s ",dir_e->filename);
printf("\n");
}
closedir(dir);
}
else
{
if(long_info)
printf("- %d %d %s\n",file_stat.st_ino,file_stat.st_size,pathname);
else
printf("%s\n",pathname);
}
}

void buildin_ps(uint32_t argc,char** argv)
{
//不应该有参数
if(argc != 1)
{
printf("ps: no argument support!\n");
return;
}
ps();
}

void buildin_clear(uint32_t argc,char** argv)
{
if(argc != 1)
{
printf("clear: no argument support!\n");
return;
}
clear();
}

int32_t buildin_mkdir(uint32_t argc,char** argv)
{
//必须要有一个 安装路径参数
int32_t ret = -1;
if(argc != 2)
printf("mkdir: only support 1 argument!\n");
else
{
make_clear_abs_path(argv[1],final_path);
if(strcmp("/",final_path)) //不是根目录 根目录一直都在
{
if(mkdir(final_path) == 0)
ret = 0;
else
printf("mkdir: create directory %s failed.\n",argv[1]);
}
}
return ret;
}

int32_t buildin_rmdir(uint32_t argc,char** argv)
{
int32_t ret = -1;
if(argc != 2)
printf("rmdir: only support 1 argument!\n");
else
{
make_clear_abs_path(argv[1],final_path);
if(strcmp("/",final_path)) // 不能删除根目录
{
if(rmdir(final_path) == 0)
ret = 0;
else printf("rmdir: remove %s failed\n");
}
}
return ret;
}

int32_t buildin_rm(uint32_t argc,char** argv)
{
int32_t ret = -1;
if(argc != 2)
printf("rm: only support 1 argument!\n");
else
{
make_clear_abs_path(argv[1],final_path);
if(strcmp("/",final_path))
{
if(unlink(final_path) == 0)
ret = 0;
else printf("rm: delete %s failed\n",argv[1]);
}
}
return ret;
}

lib/user/assert.h创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef __LIB_USER_ASSERT_H
#define __LIB_USER_ASSERT_H

#define NULL ((void*)0)

void user_spin(char* filename, int line, const char* func, const char* condition);
#define panic(...) user_spin(__FILE__, __LINE__, __func__, __VA_ARGS__)

#ifdef NDEBUG
#define assert(CONDITION) ((void)0)
#else
#define assert(CONDITION) \
if (!(CONDITION)) { \
panic(#CONDITION); \
}

#endif/*NDEBUG*/

#endif/*__LIB_USER_ASSERT_H*/

lib/user/assert.c创建

1
2
3
4
5
6
#include "assert.h"
#include "stdio.h"
void user_spin(char* filename, int line, const char* func, const char* condition) {
printf("\n\n\n\nfilename %s\nline %d\nfunction %s\ncondition %s\n", filename, line, func, condition);
while(1);
}

kernel/main.c修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"
#include "../lib/kernel/stdio-kernel.h"
#include "../fs/fs.h"
#include "../fs/file.h"
#include "../shell/shell.h"

int main(void) {
put_str("I am kernel\n");
init_all();
intr_enable();
cls_screen();
console_put_str("[rabbit@localhost /]$ ");
while(1);
return 0;
}

/* init进程 */
void init(void) {
uint32_t ret_pid = fork();
if(ret_pid) { // 父进程
while(1);
} else { // 子进程
my_shell();
}
PANIC("init: should not be here");
}

makefile修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS = -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
$(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
$(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
$(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
$(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \
$(BUILD_DIR)/ioqueue.o $(BUILD_DIR)/tss.o $(BUILD_DIR)/process.o \
$(BUILD_DIR)/syscall-init.o $(BUILD_DIR)/syscall.o $(BUILD_DIR)/stdio.o \
$(BUILD_DIR)/stdio-kernel.o $(BUILD_DIR)/ide.o $(BUILD_DIR)/fs.o $(BUILD_DIR)/inode.o \
$(BUILD_DIR)/file.o $(BUILD_DIR)/dir.o $(BUILD_DIR)/fork.o $(BUILD_DIR)/shell.o \
$(BUILD_DIR)/buildin_cmd.o

############## c代码编译 ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
thread/thread.h kernel/interrupt.h device/console.h \
device/keyboard.h device/ioqueue.h userprog/process.h \
lib/user/syscall.h userprog/syscall-init.h lib/stdio.h \
lib/kernel/stdio-kernel.h fs/file.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
thread/thread.h device/console.h device/keyboard.h userprog/tss.h \
userprog/syscall-init.h device/ide.h fs/fs.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h \
kernel/kernel.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
kernel/interrupt.h thread/thread.h kernel/debug.h kernel/global.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
lib/kernel/print.h lib/stdint.h kernel/interrupt.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
kernel/debug.h kernel/global.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h kernel/global.h \
thread/sync.h thread/thread.h lib/kernel/list.h kernel/interrupt.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
kernel/debug.h kernel/interrupt.h lib/kernel/print.h \
userprog/process.h thread/sync.h lib/user/syscall.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
kernel/interrupt.h lib/stdint.h kernel/debug.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/console.o: device/console.c device/console.h \
lib/kernel/print.h thread/sync.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
kernel/global.h lib/stdint.h device/ioqueue.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \
kernel/interrupt.h kernel/global.h kernel/debug.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/tss.o: userprog/tss.c userprog/tss.h \
kernel/global.h thread/thread.h lib/kernel/print.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/process.o: userprog/process.c userprog/process.h \
lib/string.h kernel/global.h kernel/memory.h lib/kernel/print.h \
thread/thread.h kernel/interrupt.h kernel/debug.h device/console.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/syscall-init.o: userprog/syscall-init.c userprog/syscall-init.h \
lib/user/syscall.h lib/stdint.h lib/kernel/print.h kernel/interrupt.h thread/thread.h \
kernel/memory.h fs/file.h userprog/fork.h lib/kernel/stdio-kernel.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.h fs/file.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/stdio.o: lib/stdio.c lib/stdio.h lib/stdint.h lib/string.h lib/user/syscall.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/stdio-kernel.o: lib/kernel/stdio-kernel.c lib/kernel/stdio-kernel.h \
lib/stdio.h device/console.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/ide.o: device/ide.c device/ide.h lib/stdint.h kernel/debug.h \
lib/kernel/stdio-kernel.h lib/stdio.h kernel/global.h thread/sync.h \
lib/kernel/io.h device/timer.h kernel/interrupt.h lib/kernel/list.h fs/fs.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/fs.o: fs/fs.c fs/fs.h lib/stdint.h kernel/global.h device/ide.h fs/inode.h fs/dir.h \
fs/super_block.h lib/kernel/stdio-kernel.h lib/string.h kernel/debug.h lib/kernel/list.h \
fs/file.h thread/thread.h device/ioqueue.h device/keyboard.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/inode.o: fs/inode.c fs/inode.h device/ide.h kernel/debug.h thread/thread.h \
kernel/memory.h lib/string.h lib/kernel/list.h kernel/interrupt.h lib/kernel/bitmap.h \
fs/file.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/file.o: fs/file.c fs/file.h lib/kernel/stdio-kernel.h thread/thread.h device/ide.h \
fs/file.h kernel/global.h kernel/interrupt.h device/console.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/dir.o: fs/dir.c fs/dir.h device/ide.h fs/fs.h fs/inode.h kernel/memory.h lib/string.h lib/stdint.h \
lib/kernel/stdio-kernel.h kernel/debug.h fs/file.h kernel/memory.h lib/string.h kernel/debug.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/fork.o: userprog/fork.c userprog/fork.h kernel/global.h lib/stdint.h lib/string.h \
kernel/memory.h kernel/interrupt.h thread/sync.h thread/thread.h kernel/debug.h userprog/process.h \
lib/kernel/stdio-kernel.h fs/file.h lib/kernel/list.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/shell.o: shell/shell.c shell/shell.h kernel/global.h lib/stdint.h lib/string.h \
lib/user/syscall.h lib/stdio.h fs/file.h kernel/debug.h shell/buildin_cmd.h fs/fs.h
$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/buildin_cmd.o: shell/buildin_cmd.c shell/buildin_cmd.h fs/file.h fs/fs.h kernel/debug.h \
lib/string.h lib/user/syscall.h fs/dir.h fs/fs.h lib/stdio.h shell/shell.h
$(CC) $(CFLAGS) $< -o $@

############## 汇编代码编译 ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
$(AS) $(ASFLAGS) $< -o $@

############## 链接所有目标文件 #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
dd if=$(BUILD_DIR)/kernel.bin \
of=/home/podest/bochs/hd60M.img \
bs=512 count=200 seek=9 conv=notrunc

clean:
cd $(BUILD_DIR) && rm -f ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

运行结果

图为bochs运行界面
图为bochs运行界面
图为bochs运行界面
图为bochs运行界面