抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

今日、海を見た。もう怖くない

开始之前先简单介绍一下这次的任务要求:

《操作系统原理》第一次上机实验

一、实验目的

  1. 理解操作系统生成的概念和过程;
  2. 理解操作系统两类用户界面(操作界面,系统调用)概念;

二、实验内容

  1. 在 Ubuntu 或其他 Linux 平台环境下裁剪和编译 Linux
    内核,并启用新的内核。
  2. 在 Ubuntu 或其他 Linux 平台为 Linux 内核增加 1-3 个新
    的系统调用,并启用新的内核,编写一个应用程序测试新增加的系
    统调用是否能正确工作。
  3. 在 Windows 环境下,编写一个批处理程序(算命大
    师.bat),程序运行后,输入:出生年月日(例如 2000-07-31)。系
    统输出相应的属相和星座,例如:你属兔, 狮子座。要求:输入进
    行合法性检查,能循环接收用户的输入,直到输入 q 或 Q 就退出。

Front-matter

由于增加系统调用的部分在之前已经做过了,而且一遍下来耗时很多…… 在家里一台电脑折腾的情况下挺浪费时间的就不做了。想要看上次怎么做的请去看这里

因为Bat年久失修,微软官网上都找不到它的文档,于是考虑写一个Powershell脚本。况且新型Windows的cmd都是可以执行Powershell脚本的,就直接写了;然后因为我实在是不懂星座,当不了星座带师;干脆就把之前大一无聊写的简易野兽先辈论证器的逻辑搞过来整成了Powershell版本的野兽先辈论证器(

事实上后来也有补充一个Bat的简单的版本。算了这篇文章还是文风清新了一点,我重写一篇好了 ==
新文章的地址是:

好的,接下来是实验报告正文:

实验目的

  1. 理解操作系统生成的概念和过程;
  2. 理解操作系统两类用户界面(操作界面,系统调用)概念;

实验内容

  1. 在 Ubuntu 或其他 Linux 平台环境下裁剪和编译 Linux
    内核,并启用新的内核。
  2. 在 Ubuntu 或其他 Linux 平台为 Linux 内核增加 1-3 个新
    的系统调用,并启用新的内核,编写一个应用程序测试新增加的系
    统调用是否能正确工作。
  3. 在 Windows 环境下,编写一个批处理程序(算命大
    师.bat),程序运行后,输入:出生年月日(例如 2000-07-31)。系
    统输出相应的属相和星座,例如:你属兔, 狮子座。要求:输入进
    行合法性检查,能循环接收用户的输入,直到输入 q 或 Q 就退出。

因为裁剪、增加系统调用和应用修改后的内核已经在上一次实验中做过了,这里仅简述实验过程和实验结果。

实验过程

第一个实验包含了编辑内核,生成补丁已经应用内核三个步骤。这里将简要介绍。第二个实验仅包含编码和测试。

编辑内核

在下载的内核使用menuconfig打开图形化的内核裁剪页面,进行必要的调整之后保存为配置文件就可以了。

复制一份下载的纯净内核文件,修改其中的include/uapi/asm-generic/unistd.hinclude/linux/syscalls.h两个头文件来增加系统调用的函数。

进入系统调用注册表的目录arch/x86/entry/syscalls,根据要安装的操作系统位数修改其下的tbl文件,注册增加的系统调用。特别注意不应该与已经存在的系统调用的编号冲突。

使用vim打开系统调用的实现的源文件kernel/sys.c来增加刚才增加的函数的实现。如果要增加的是在内核缓冲区打印消息这种最简单的系统调用,则它可以是下面这样:

1
2
3
4
5
6
asmlinkage void sys_shirohashow(void)
{
printk("Shiroha do your best!");
printk("\n@Edit by Shiroha on 2019-11-15.");
return 0;
}

这样,我们就增加了一个系统调用函数sys_shirohashow的实现。完成之后还要在include/uapi/asm-generic/unistd.h增加宏。

生成补丁并应用内核

将修改过的内核和纯净内核使用diff -Naur生成差异补丁,再使用patch命令应用到纯净内核上。使用make -j6进行多线程编译。

编译成功后执行安装,并将必要的文件复制到特定的地方之后更新grub的引导信息,就完成了内核的应用。

在运行新内核的操作系统上写C程序,调用增加的系统调用,就可以看到我们在内核中编写的程序可以成功运行了。

编写Powershell程序

简要分析实验要求,大概得出这个程序的工作流程:

流程图

因为Powershell支持绝大多数的C语言特性,可以开强类型变量也可以构造函数,并且可以使用 .NET Framework 的一些东西,所以很轻松的就写出来了。

编码环境和工具:

文本编辑器 : Microsoft Visual Studio Code 1.44
操作系统版本 : Windows 10 Pro 1903 18362.720
Powershell版本 : Windows Powershell 5.1

关于输入文字的方式,可以使用Powershell原生的Read-Host,也可以使用框架提供的GUI窗口;甚至还可以使用 Visual Basic 的窗口。这就看个人喜好了,下面的代码是使用了框架的窗口实现的生日数字论证器:

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
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

[int[]] $days = 29,31,28,31,30,31,30,31,31,30,31,30,31
$dayIsIllegal = "The days you input is illegal. try again"
[string[]] $months = 'Feb','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
[string[]] $iiyokoiyo = @(
'1+1+4-5-1^4=0',
'1+1+4-5*1^4=1',
'1+1+4-5+1^4=2',
'1+1-4+5*1^4=3',
'1+1+4-5-1+4=4',
'1+1+4-5+1*4=5',
'1+1+4+5-1-4=6',
'1+1+4+5-1*4=7',
'1+1+4+5+1-4=8',
'1+1*4+5-1^4=9',
'1+1+4+5-1^4=10',
'1+1+4+5*1^4=11',
'1+1+4+5+1^4=12',
'1+1*4+5-1+4=13',
'1+1+4+5-1+4=14',
'1+1+4+5+1*4=15',
'1+1+4+5+1+4=16',
'1+1+4*5-1-4=17',
'1+1+4*5-1*4=18',
'1+1+4*5+1-4=19',
'1+1*4*5-1^4=20',
'1+1+4*5-1^4=21',
'1+1+4*5*1^4=22',
'1+1+4*5+1^4=23',
'1+1*4*5-1+4=24',
'1+1+4*5-1+4=25',
'1+1+4+5*1*4=26',
'1+1+4*5+1+4=27',
'(1+1)*4+5*1*4=28',
'(1+1+4)*5-1^4=29',
'(1+1+4)*5*1^4=30',
'(1+1+4)*5+1^4=31'
)

function isLunar ([int] $y)
{
if($y % 4) {return 'False'}
else {if($y % 400) {return 'True'}
else {if($y % 100) {return 'False'}
else {return 'True'}}}
}

while(1)
{
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Birthday input form'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(65,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Point(160,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Input your Birthday as YYYY-MM-DD'
$form.Controls.Add($label)

$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)

$form.Topmost = $true

$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$x = $textBox.Text
"Your input: "+$x
if($x -eq 'q' -or $x -eq 'Q')
{
"Exting ..."
exit
}
[int[]] $data = $x.Split('-')
if($data.Count -ne 3)
{
Write-Host -ForegroundColor RED "The String you input is not refer to a date."
continue
}
if($data[0] -lt 1)
{
Write-Host -ForegroundColor YELLOW "You cannot born before AC. try again"
continue
}
if($data[1] -lt 1 -or $data[1] -gt 12)
{
Write-Host -ForegroundColor RED "The month is illegal. try again"
continue
}
$lunar = isLunar $data[0]
$month = $data[1]
if ($lunar -eq 'True' -and $data[1] -eq 2) {$month = 0}
if($data[2] -lt 1 -or $data[2] -gt $days[$month])
{
Write-Host -ForegroundColor RED $dayIsIllegal
continue
}

Write-Host -ForegroundColor YELLOW "PROOVE STRAT:"
"You born in "+$months[$data[1]]+", which means "+$data[1]+", and there is "+$iiyokoiyo[$data[1]]
"You born at "+$data[2]+", and there is "+$iiyokoiyo[$data[2]]
Write-Host -ForegroundColor GREEN "Q.E.D. You are HonMono No Yaju Senpai ! "

pause
}
}

代码中的自定义函数isLunar完成对闰年的判断。通过返回字符串作为布尔值代表结果。每次循环都调用框架创建一个包含两个按钮和一个文本框的窗口,用来获得用户的输入。输入之后从文本框组件中获得输入的字符串进行后续处理。

这里使用了Add-Type引入了框架,使用$来定义变量和数组,使用[]来指定强类型限制。对于输入字符串不是YYYY-MM-DD格式的情况,我利用强类型转换的失败自动抛出异常,并继续到下一个循环。关于弹出GUI窗口的操作,具体请参照微软的官方文档

显而易见地,也可以使用控制台直接输入文字而不是弹出一个GUI窗口来获取用户输入。这就需要使用到Read-Host

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
[int[]] $days = 29,31,28,31,30,31,30,31,31,30,31,30,31
$dayIsIllegal = "The days you input is illegal. try again"
[string[]] $months = 'Feb','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'
[string[]] $iiyokoiyo = @(
'1+1+4-5-1^4=0',
'1+1+4-5*1^4=1',
'1+1+4-5+1^4=2',
'1+1-4+5*1^4=3',
'1+1+4-5-1+4=4',
'1+1+4-5+1*4=5',
'1+1+4+5-1-4=6',
'1+1+4+5-1*4=7',
'1+1+4+5+1-4=8',
'1+1*4+5-1^4=9',
'1+1+4+5-1^4=10',
'1+1+4+5*1^4=11',
'1+1+4+5+1^4=12',
'1+1*4+5-1+4=13',
'1+1+4+5-1+4=14',
'1+1+4+5+1*4=15',
'1+1+4+5+1+4=16',
'1+1+4*5-1-4=17',
'1+1+4*5-1*4=18',
'1+1+4*5+1-4=19',
'1+1*4*5-1^4=20',
'1+1+4*5-1^4=21',
'1+1+4*5*1^4=22',
'1+1+4*5+1^4=23',
'1+1*4*5-1+4=24',
'1+1+4*5-1+4=25',
'1+1+4+5*1*4=26',
'1+1+4*5+1+4=27',
'(1+1)*4+5*1*4=28',
'(1+1+4)*5-1^4=29',
'(1+1+4)*5*1^4=30',
'(1+1+4)*5+1^4=31'
)

function isLunar ([int] $y)
{
if($y % 4) {return 'False'}
else {if($y % 400) {return 'True'}
else {if($y % 100) {return 'False'}
else {return 'True'}}}
}

while(1)
{
$x = Read-Host "Please input your birthday as YYYY-MM-DD "
"Your input: "+$x
if($x -eq "") {"You input nothing, try again."}
if($x -eq 'q')
{
"Exting because of 'q'..."
exit
}
[int[]] $data = $x.Split('-')
if($data.Count -ne 3)
{
Write-Host -ForegroundColor RED "The String you input is not refer to a date."
continue
}
if($data[0] -lt 1)
{
Write-Host -ForegroundColor YELLOW "You cannot born before AC. try again"
continue
}
if($data[1] -lt 1 -or $data[1] -gt 12)
{
Write-Host -ForegroundColor RED "The month is illegal. try again"
continue
}
$lunar = isLunar $data[0]
$month = $data[1]
if ($lunar -eq 'True' -and $data[1] -eq 2) {$month = 0}
if($data[2] -lt 1 -or $data[2] -gt $days[$month])
{
Write-Host -ForegroundColor RED $dayIsIllegal
continue
}

Write-Host -ForegroundColor YELLOW "PROOVE STRAT:"
"You born in "+$months[$data[1]]+", which means "+$data[1]+", and there is "+$iiyokoiyo[$data[1]]
"You born at "+$data[2]+", and there is "+$iiyokoiyo[$data[2]]
Write-Host -ForegroundColor GREEN "Q.E.D. You are HonMono No Yaju Senpai ! "

pause
}

和上一个代码不同,因为没有引入框架创建GUI窗口,这个脚本的代码就显的短得多。理论上还可以使用[Microsoft.VisualBasic.interaction].Inputbox(string,string,string)来构建输入的GUI窗口,这里就不尝试了。

当然,文首提到的仓库中也包含了功能并不复杂的简单的 bat 脚本版本。如果你想看那些内容,可以前往这篇文章的重制版的地址:https://shiraha.cn/2020/class-FoDOS-experiment-1/

实验结果

应用新内核

详情请看上一次的实验报告

编写脚本程序

特别要注意的地方是,因为安全原因的考虑,Windows 10 系统自带的Powershell因为安全考虑,默认是禁止通过控制台加载ps1脚本文件的。我们需要进行检查:

使用以下命令检查当前的执行策略;如果值为Restricted,将不允许任何的脚本加载运行。

1
get-executionpolicy

如果是Restricted,我们需要将它变更为RemoteSigned,通过执行以下命令来实现。

1
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

这样,我们就可以通过ps1脚本的相对路径/绝对路径来运行任何的ps1脚本了。以下默认你已经保证你的Powershell允许直接加载脚本。

在某个目录新建一个文件,后缀名叫做ps1;比如我的叫YJSNPI.ps1。将实验过程中的两端代码中的任何一段复制到其中保存;随后右键开始菜单,打开Windows Powershell,使用cd命令到达你现在的目录(或者在Explorer的“文件”选项卡中,在当前的目录下启动Windows Powershell);使用命令.\YJSNPI.ps1执行刚才我们创建的脚本。

如果上述步骤不出现问题,预计就会看到下面的画面:

有窗口版本弹出的GUI输入框:

LMD_7SEUR7_E9V_6_4WF~YB.jpg

输入不合法判定:

PZ__B794716QTC_4_7P_ZTF.jpg

输入正确之后进行后处理输出字符串:

J~__XMFPF__AP19MFI_QD6D.jpg

输入Q之后退出脚本:

~WL_PYFOW4DLB@_LY3H__YC.jpg

无弹出窗口的输入版本的基本操作:

__OWFP_BLXG_A2FQFD_I3ZE.jpg

上述截图足以证明这些操作已经正确的实现。

体会

通过这次实验,我:

  • 熟悉了Linux内核的应用过程,对Linux命令的理解更进一步;
  • 更加生动的理解了系统调用的概念以及Linux操作系统从POST开始之后的启动过程;
  • 熟悉了Powershell简单开发和部分.NET API的使用;

特别的,一般的家用Windows 10的Powershell是不允许直接加载ps1脚本的,需要先行修改运行策略。

后记

编程开始之前查查官方文档基本就差不多了。需要了解的只有运算,输入输出就可以了。因为有了这些东西,无论什么程序都可以写出来——因为它已经“图灵完备”了。如果提供了更多的支持(比如框架),只会降低我们开发的难度。

其实所有的整数都可以被用某些方式计算得到114514

参考资料

评论