2019年4月

Big News

被删除的 Facebook 账户依然会收集你的个人信息:根据 CNET 的最新报道,即使你已经 deactivate 了你的账号, Facebook 依然会追踪你的信息。

Facebook 表示,删除帐户,只会删除你的所有数据,但会继续收集你的信息,以防你改变主意并希望找回你的个人资料

在大数据的时代,我们为了便利所拱手让出去的个人隐私,将吞噬我们的生活。再想拿回,几乎再无可能。如何将公司的欲望关进笼子里,我们需要和苹果学一学。

信息来源:【CNET】

Quick News

  • Microsoft Edge 浏览器将有可能进入 Linux:根据微软员工 Kyle Pflug 在 Twitter 上的回应,Microsoft Edge 浏览器将有可能进入 Linux 系统。【Twitter】
在 Linux 下也可以跑 IE 了!
  • Redhat 公司寻求推出基于 ARM 的 Linux 系统:Redhat 正在研究如何将 Fedora 操作系统移植到 ARM 芯片的设备上。不同于 Android 仅仅基于 Linux 内核,此项目旨在移植整个桌面环境。【Twitter】
手机越做越大,电脑却越做越小。莫非终极就是 Pad?
  • Slack 支持 Office 365 工具的接入:Slack 是大家常用的协作工具,Office 365 的接入将为其效率工作提供更强大的助力。【Techcrunch】
Slack 越来越好用了,就是国内访问不太好

学习在你的系统中创建一个文件系统,并且长期或者非长期地挂载它。

 title=

在计算技术中,文件系统控制如何存储和检索数据,并且帮助组织存储媒介中的文件。如果没有文件系统,信息将被存储为一个大数据块,而且你无法知道一条信息在哪结束,下一条信息在哪开始。文件系统通过为存储数据的文件提供名称,并且在文件系统中的磁盘上维护文件和目录表以及它们的开始和结束位置、总的大小等来帮助管理所有的这些信息。

在 Linux 中,当你创建一个硬盘分区或者逻辑卷之后,接下来通常是通过格式化这个分区或逻辑卷来创建文件系统。这个操作方法假设你已经知道如何创建分区或逻辑卷,并且你希望将它格式化为包含有文件系统,并且挂载它。

创建文件系统

假设你为你的系统添加了一块新的硬盘并且在它上面创建了一个叫 /dev/sda1 的分区。

1、为了验证 Linux 内核已经发现这个分区,你可以 cat 出 /proc/partitions 的内容,就像这样:

[root@localhost ~]# cat /proc/partitions
major minor  #blocks  name

 253            0   10485760 vda
 253            1       8192000 vda1
  11            0       1048575 sr0
  11            1       374 sr1
   8            0   10485760 sda
   8            1   10484736 sda1
 252            0       3145728 dm-0
 252            1       2097152 dm-1
 252            2       1048576 dm-2
   8    16      1048576 sdb

2、决定你想要去创建的文件系统种类,比如 ext4、XFS,或者其他的一些。这里是一些可选项:

[root@localhost ~]# mkfs.<tab><tab>
mkfs.btrfs mkfs.cramfs mkfs.ext2 mkfs.ext3 mkfs.ext4 mkfs.minix mkfs.xfs

3、为了这次练习的目的,选择 ext4。(我喜欢 ext4,因为如果你需要的话,它可以允许你去压缩文件系统,这对于 XFS 并不简单。)这里是完成它的方法(输出可能会因设备名称或者大小而不同):

[root@localhost ~]# mkfs.ext4 /dev/sda1
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=8191 blocks
194688 inodes, 778241 blocks
38912 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=799014912
24 block groups
32768 blocks per group, 32768 fragments per group
8112 inodes per group
Superblock backups stored on blocks:
     32768, 98304, 163840, 229376, 294912

Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done

4、在上一步中,如果你想去创建不同的文件系统,请使用不同变种的 mkfs 命令。

挂载文件系统

当你创建好文件系统后,你可以在你的操作系统中挂载它。

1、首先,识别出新文件系统的 UUID 编码。使用 blkid 命令列出所有可识别的块存储设备并且在输出信息中查找 sda1:

[root@localhost ~]# blkid
/dev/vda1: UUID="716e713d-4e91-4186-81fd-c6cfa1b0974d" TYPE="xfs"
/dev/sr1: UUID="2019-03-08-16-17-02-00" LABEL="config-2" TYPE="iso9660"
/dev/sda1: UUID="wow9N8-dX2d-ETN4-zK09-Gr1k-qCVF-eCerbF" TYPE="LVM2_member"
/dev/mapper/test-test1: PTTYPE="dos"
/dev/sda1: UUID="ac96b366-0cdd-4e4c-9493-bb93531be644" TYPE="ext4"
[root@localhost ~]#

2、运行下面的命令挂载 /dev/sd1 设备:

[root@localhost ~]# mkdir /mnt/mount_point_for_dev_sda1
[root@localhost ~]# ls /mnt/
mount_point_for_dev_sda1
[root@localhost ~]# mount -t ext4 /dev/sda1 /mnt/mount_point_for_dev_sda1/
[root@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 7.9G 920M 7.0G 12% /
devtmpfs 443M 0 443M 0% /dev
tmpfs 463M 0 463M 0% /dev/shm
tmpfs 463M 30M 434M 7% /run
tmpfs 463M 0 463M 0% /sys/fs/cgroup
tmpfs 93M 0 93M 0% /run/user/0
/dev/sda1 2.9G 9.0M 2.7G 1% /mnt/mount_point_for_dev_sda1
[root@localhost ~]#

命令 df -h 显示了每个文件系统被挂载的挂载点。查找 /dev/sd1。上面的挂载命令使用的设备名称是 /dev/sda1。用 blkid 命令中的 UUID 编码替换它。注意,在 /mnt 下一个被新创建的目录挂载了 /dev/sda1。

3、直接在命令行下使用挂载命令(就像上一步一样)会有一个问题,那就是挂载不会在设备重启后存在。为使永久性地挂载文件系统,编辑 /etc/fstab 文件去包含你的挂载信息:

UUID=ac96b366-0cdd-4e4c-9493-bb93531be644 /mnt/mount_point_for_dev_sda1/ ext4 defaults 0 0

4、编辑完 /etc/fstab 文件后,你可以 umount /mnt/mount_point_for_fev_sda1 并且运行 mount -a 命令去挂载被列在 /etc/fstab 文件中的所有设备文件。如果一切顺利的话,你可以使用 df -h 列出并且查看你挂载的文件系统:

root@localhost ~]# umount /mnt/mount_point_for_dev_sda1/
[root@localhost ~]# mount -a
[root@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 7.9G 920M 7.0G 12% /
devtmpfs 443M 0 443M 0% /dev
tmpfs 463M 0 463M 0% /dev/shm
tmpfs 463M 30M 434M 7% /run
tmpfs 463M 0 463M 0% /sys/fs/cgroup
tmpfs 93M 0 93M 0% /run/user/0
/dev/sda1 2.9G 9.0M 2.7G 1% /mnt/mount_point_for_dev_sda1

5、你也可以检测文件系统是否被挂载:

[root@localhost ~]# mount | grep ^/dev/sd
/dev/sda1 on /mnt/mount_point_for_dev_sda1 type ext4 (rw,relatime,seclabel,stripe=8191,data=ordered)

现在你已经知道如何去创建文件系统并且长期或者非长期的挂载在你的系统中。


via: https://opensource.com/article/19/4/create-filesystem-linux-partition

作者:Kedar Vijay Kulkarni (Red Hat) 选题:lujun9972 译者:liujing97 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Big News

微软释放出其基于 Chromium 的 Edge 浏览器:微软为了改进浏览器的兼容性以及减少前端领域的碎片化,主动发起改革,将 Edge 浏览器的内核由自家的 EdgeHTML 变为 Chromium 提供的 WebKit 内核。

对于前端来说,还真的是一个大的利好消息,当 Edge 也开始使用 Chromium 内核以后,前端开发者以后只需要兼容两种渲染引擎了,分别是 Firefox 使用的 Gecko 和 Chromium 使用的 Webkit。这当然算是一件好事情。 不过,反过来想一想,如果渲染引擎一家独大的话,那未来, HTML 标准的定制是否也需要看浏览器内核厂商的脸色呢?

信息来源:【MicrosoftEdgeInsider】

Quick News

  • 共享单车迎来涨价潮:近日,北京地区的共享单车开始实行新的收费价格表。摩拜单车新版骑行15分钟以内收费1元,超出部分每15分钟收费0.5元,骑行一小时费用为2.5元。小蓝单车则是起步价由每30分钟1元更改为每15分钟1元,超出时长后每15分钟0.5元,骑行1小时同样为2.5元。【虎嗅】
  • Windows Embedded POSReady 2009 停止服务: Windows Embedded POSReady 2009 是微软基于 Windows XP SP3 定制的为服务点(POS)设计的嵌入式操作系统,广泛适用于收银机、服务亭、电子标牌、ATM机、加油机等设备。【快科技】
  • 虚拟货币“挖矿”活动被列为淘汰产业:近日国家发改委发布的关于就《产业结构调整指导目录(2019年本,征求意见稿)》中将虚拟货币“挖矿”活动列入淘汰类产业之中。【每日经济新闻】

Git 为软件开发所带来的巨大影响是其它工具难以企及的。

在 Linus Torvalds 开发 Git 后的十四年间,它为软件开发所带来的影响是其它工具难以企及的:在 StackOverflow 的 2018 年开发者调查 中,87% 的受访者都表示他们使用 Git 来作为他们项目的版本控制工具。显然,没有其它工具能撼动 Git 版本控制管理工具(SCM)之王的地位。

为了在 4 月 7 日 Git 的十四周年这一天向 Git 表示敬意,我问了一些爱好者他们最喜欢 Git 的哪一点。以下便是他们所告诉我的:

(为了便于理解,部分回答已经进行了小幅修改)

“我无法忍受 Git。无论是难以理解的术语还是它的分布式。使用 Gerrit 这样的插件才能使它像 Subversion 或 Perforce 这样的集中式仓库管理器使用的工具的一半好用。不过既然这次的问题是‘你喜欢 Git 的什么?’,我还是希望回答:Git 使得对复杂的源代码树操作成为可能,并且它的回滚功能使得实现一个要 20 次修改才能更正的问题变得简单起来。”

— Sweet Tea Dorminy

“我喜欢 Git 是因为它不会强制我执行特定的工作流程,并且开发团队可以自由地以适合自己的方式来进行团队开发,无论是拉取请求、以电子邮件递送差异文件或是给予所有人推送的权限。”

— Andy Price

“我从 2006、2007 年的样子就开始使用 Git 了。我喜欢 Git 是因为,它既适用于那种从未离开过我电脑的小项目,也适用于大型的团队合作的分布式项目。Git 使你可以从(几乎)所有的错误提交中回滚到先前版本,这个功能显著地减轻了我在软件版本管理方面的压力。”

— Jonathan S. Katz

“我很欣赏 Git 那种 底层命令和高层命令 的理念。用户可以使用 Git 有效率地分享任何形式的信息,而不需要知道其内部工作原理。而好奇的人可以透过其表层的命令,而发现其为许多代码分享平台提供了支持的可以定位内容的文件系统。”

— Matthew Broberg

“我喜欢 Git 是因为浏览、开发、构建、测试和向我的 Git 仓库中提交代码的工作几乎都能用它来完成。它经常会调动起我参与开源项目的积极性。”

— Daniel Oh

“Git 是我用过的首个版本控制工具。数年间,它从一个可怕的工具变成了一个友好的工具。我喜欢它使你在修改代码的时候更加自信,因为它能保证你主分支的安全(除非你强制提交了一段考虑不周的代码到主分支)。你可以检出先前的提交来撤销更改,这一点也是很棒的。”

— Kedar Vijay Kulkarni

“我之所以喜欢 Git 是因为它淘汰了一些其它的版本控制工具。没人使用 VSS,而 Subversion 可以和 git-svn 一起使用(如果必要),BitKeeper 则和 Monotone 一样只为老一辈所知。当然,我们还有 Mercurial,不过在我几年之前用它来为 Firefox 添加 AArch64 支持时,我觉得它仍是那种还未完善的工具。部分人可能还会提到 Perforce、SourceSafe 或是其它企业级的解决方案,我只想说它们在开源世界里并不流行。”

— Marcin Juszkiewicz

“我喜欢内置的 SHA1 化对象模型(commit → tree → blob)的简易性。我也喜欢它的高层命令。同时我也将它作为对 JBoss/Red Hat Fuse 的补丁机制。并且这种机制确实有效。我还喜欢 Git 的 三棵树的故事。”

— Grzegorz Grzybek

“我喜欢 自动生成的 Git 说明页(这个页面虽然听起来是有关 Git 的,但是事实上这是一个没有实际意义的页面,不过它总是会给人一种像是真的 Git 页面的感觉…),这使得我对 Git 的敬意油然而生。”

— Marko Myllynen

“Git 改变了我作为开发者的生活。它使得 SCM 问题从世界上消失得无影无踪。”

— Joel Takvorian

看完这十个爱好者的回答之后,就轮到你了:你最欣赏 Git 的什么?请在评论区分享你的看法!


via: https://opensource.com/article/19/4/what-do-you-love-about-git

作者:Jen Wike Huger 选题:lujun9972 译者:zhs852 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

课程输入 02 是以课程输入 01 为基础讲解的,通过一个简单的命令行实现用户的命令输入和计算机的处理和显示。本文假设你已经具备 课程11:输入01 的操作系统代码基础。

1、终端

几乎所有的操作系统都是以字符终端显示启动的。经典的黑底白字,通过键盘输入计算机要执行的命令,然后会提示你拼写错误,或者恰好得到你想要的执行结果。这种方法有两个主要优点:键盘和显示器可以提供简易、健壮的计算机交互机制,几乎所有的计算机系统都采用这个机制,这个也广泛被系统管理员应用。

早期的计算一般是在一栋楼里的一个巨型计算机系统,它有很多可以输命令的'终端'。计算机依次执行不同来源的命令。

让我们分析下真正想要哪些信息:

  1. 计算机打开后,显示欢迎信息
  2. 计算机启动后可以接受输入标志
  3. 用户从键盘输入带参数的命令
  4. 用户输入回车键或提交按钮
  5. 计算机解析命令后执行可用的命令
  6. 计算机显示命令的执行结果,过程信息
  7. 循环跳转到步骤 2

这样的终端被定义为标准的输入输出设备。用于(显示)输入的屏幕和打印输出内容的屏幕是同一个(LCTT 译注:最早期的输出打印真是“打印”到打印机/电传机的,而用于输入的终端只是键盘,除非做了回显,否则输出终端是不会显示输入的字符的)。也就是说终端是对字符显示的一个抽象。字符显示中,单个字符是最小的单元,而不是像素。屏幕被划分成固定数量不同颜色的字符。我们可以在现有的屏幕代码基础上,先存储字符和对应的颜色,然后再用方法 DrawCharacter 把其推送到屏幕上。一旦我们需要字符显示,就只需要在屏幕上画出一行字符串。

新建文件名为 terminal.s,如下:

.section .data
.align 4
terminalStart:
.int terminalBuffer
terminalStop:
.int terminalBuffer
terminalView:
.int terminalBuffer
terminalColour:
.byte 0xf
.align 8
terminalBuffer:
.rept 128*128
.byte 0x7f
.byte 0x0
.endr
terminalScreen:
.rept 1024/8 core.md Dict.md lctt2014.md lctt2016.md lctt2018.md LICENSE published README.md scripts sources translated 768/16
.byte 0x7f
.byte 0x0
.endr

这是文件终端的配置数据文件。我们有两个主要的存储变量:terminalBuffer 和 terminalScreen。terminalBuffer 保存所有显示过的字符。它保存 128 行字符文本(1 行包含 128 个字符)。每个字符有一个 ASCII 字符和颜色单元组成,初始值为 0x7f(ASCII 的删除字符)和 0(前景色和背景色为黑)。terminalScreen 保存当前屏幕显示的字符。它保存 128x48 个字符,与 terminalBuffer 初始化值一样。你可能会觉得我仅需要 terminalScreen 就够了,为什么还要terminalBuffer,其实有两个好处:

  1. 我们可以很容易看到字符串的变化,只需画出有变化的字符。
  2. 我们可以回滚终端显示的历史字符,也就是缓冲的字符(有限制)

这种独特的技巧在低功耗系统里很常见。画屏是很耗时的操作,因此我们仅在不得已的时候才去执行这个操作。在这个系统里,我们可以任意改变 terminalBuffer,然后调用一个仅拷贝屏幕上字节变化的方法。也就是说我们不需要持续画出每个字符,这样可以节省一大段跨行文本的操作时间。

你总是需要尝试去设计一个高效的系统,如果在很少变化的情况下这个系统会运行的更快。

其他在 .data 段的值得含义如下:

  • terminalStart 写入到 terminalBuffer 的第一个字符
  • terminalStop 写入到 terminalBuffer 的最后一个字符
  • terminalView 表示当前屏幕的第一个字符,这样我们可以控制滚动屏幕
  • temrinalColour 即将被描画的字符颜色

terminalStart 需要保存起来的原因是 termainlBuffer 是一个环状缓冲区。意思是当缓冲区变满时,末尾地方会回滚覆盖开始位置,这样最后一个字符变成了第一个字符。因此我们需要将 terminalStart 往前推进,这样我们知道我们已经占满它了。如何实现缓冲区检测:如果索引越界到缓冲区的末尾,就将索引指向缓冲区的开始位置。环状缓冲区是一个比较常见的存储大量数据的高明方法,往往这些数据的最近部分比较重要。它允许无限制的写入,只保证最近一些特定数据有效。这个常常用于信号处理和数据压缩算法。这样的情况,可以允许我们存储 128 行终端记录,超过128行也不会有问题。如果不是这样,当超过第 128 行时,我们需要把 127 行分别向前拷贝一次,这样很浪费时间。

显示 Hellow world 插入到大小为5的循环缓冲区的示意图。

环状缓冲区是数据结构一个例子。这是一个组织数据的思路,有时我们通过软件实现这种思路。

之前已经提到过 terminalColour 几次了。你可以根据你的想法实现终端颜色,但这个文本终端有 16 个前景色和 16 个背景色(这里相当于有 16 2 = 256 种组合)。CGA终端的颜色定义如下:

表格 1.1 - CGA 颜色编码

序号颜色 (R, G, B)
0黑 (0, 0, 0)
1蓝 (0, 0, ⅔)
2绿 (0, ⅔, 0)
3青色 (0, ⅔, ⅔)
4红色 (⅔, 0, 0)
5品红 (⅔, 0, ⅔)
6棕色 (⅔, ⅓, 0)
7浅灰色 (⅔, ⅔, ⅔)
8灰色 (⅓, ⅓, ⅓)
9淡蓝色 (⅓, ⅓, 1)
10淡绿色 (⅓, 1, ⅓)
11淡青色 (⅓, 1, 1)
12淡红色 (1, ⅓, ⅓)
13浅品红 (1, ⅓, 1)
14黄色 (1, 1, ⅓)
15白色 (1, 1, 1)

我们将前景色保存到颜色的低字节,背景色保存到颜色高字节。除了棕色,其他这些颜色遵循一种模式如二进制的高位比特代表增加 ⅓ 到每个组件,其他比特代表增加 ⅔ 到各自组件。这样很容易进行 RGB 颜色转换。

棕色作为替代色(黑黄色)既不吸引人也没有什么用处。

我们需要一个方法从 TerminalColour 读取颜色编码的四个比特,然后用 16 比特等效参数调用 SetForeColour。尝试你自己实现。如果你感觉麻烦或者还没有完成屏幕系列课程,我们的实现如下:

.section .text
TerminalColour:
teq r0,#6
ldreq r0,=0x02B5
beq SetForeColour

tst r0,#0b1000
ldrne r1,=0x52AA
moveq r1,#0
tst r0,#0b0100
addne r1,#0x15
tst r0,#0b0010
addne r1,#0x540
tst r0,#0b0001
addne r1,#0xA800
mov r0,r1
b SetForeColour

2、文本显示

我们的终端第一个真正需要的方法是 TerminalDisplay,它用来把当前的数据从 terminalBuffer拷贝到 terminalScreen 和实际的屏幕。如上所述,这个方法必须是最小开销的操作,因为我们需要频繁调用它。它主要比较 terminalBuffer 与 terminalDisplay 的文本,然后只拷贝有差异的字节。请记住 terminalBuffer 是以环状缓冲区运行的,这种情况,就是从 terminalView 到 terminalStop,或者 128*48 个字符,要看哪个来的最快。如果我们遇到 terminalStop,我们将会假定在这之后的所有字符是 7f 16 (ASCII 删除字符),颜色为 0(黑色前景色和背景色)。

让我们看看必须要做的事情:

  1. 加载 terminalView、terminalStop 和 terminalDisplay 的地址。
  2. 对于每一行:

    1. 对于每一列:

      1. 如果 terminalView 不等于 terminalStop,根据 terminalView 加载当前字符和颜色
      2. 否则加载 0x7f 和颜色 0
      3. 从 terminalDisplay 加载当前的字符
      4. 如果字符和颜色相同,直接跳转到第 10 步
      5. 存储字符和颜色到 terminalDisplay
      6. 用 r0 作为背景色参数调用 TerminalColour
      7. 用 r0 = 0x7f(ASCII 删除字符,一个块)、 r1 = x、r2 = y 调用 DrawCharacter
      8. 用 r0 作为前景色参数调用 TerminalColour
      9. 用 r0 = 字符、r1 = x、r2 = y 调用 DrawCharacter
      10. 对位置参数 terminalDisplay 累加 2
      11. 如果 terminalView 不等于 terminalStop,terminalView 位置参数累加 2
      12. 如果 terminalView 位置已经是文件缓冲器的末尾,将它设置为缓冲区的开始位置
      13. x 坐标增加 8
    2. y 坐标增加 16

尝试去自己实现吧。如果你遇到问题,我们的方案下面给出来了:

1、我这里的变量有点乱。为了方便起见,我用 taddr 存储 textBuffer 的末尾位置。

.globl TerminalDisplay
TerminalDisplay:
push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
x .req r4
y .req r5
char .req r6
col .req r7
screen .req r8
taddr .req r9
view .req r10
stop .req r11

ldr taddr,=terminalStart
ldr view,[taddr,#terminalView - terminalStart]
ldr stop,[taddr,#terminalStop - terminalStart]
add taddr,#terminalBuffer - terminalStart
add taddr,#128*128*2
mov screen,taddr

2、从 yLoop 开始运行。

mov y,#0
yLoop$:

2.1、

mov x,#0
xLoop$:

从 xLoop 开始运行。

2.1.1、为了方便起见,我把字符和颜色同时加载到 char 变量了

teq view,stop
ldrneh char,[view]

2.1.2、这行是对上面一行的补充说明:读取黑色的删除字符

moveq char,#0x7f

2.1.3、为了简便我把字符和颜色同时加载到 col 里。

ldrh col,[screen]

2.1.4、 现在我用 teq 指令检查是否有数据变化

teq col,char
beq xLoopContinue$

2.1.5、我可以容易的保存当前值

strh char,[screen]

2.1.6、我用比特偏移指令 lsr 和 and 指令从切分 char 变量,将颜色放到 col 变量,字符放到 char 变量,然后再用比特偏移指令 lsr 获取背景色后调用 TerminalColour 。

lsr col,char,#8
and char,#0x7f
lsr r0,col,#4
bl TerminalColour

2.1.7、写入一个彩色的删除字符

mov r0,#0x7f
mov r1,x
mov r2,y
bl DrawCharacter

2.1.8、用 and 指令获取 col 变量的低半字节,然后调用 TerminalColour

and r0,col,#0xf
bl TerminalColour

2.1.9、写入我们需要的字符

mov r0,char
mov r1,x
mov r2,y
bl DrawCharacter

2.1.10、自增屏幕指针

xLoopContinue$:
add screen,#2

2.1.11、如果可能自增 view 指针

teq view,stop
addne view,#2

2.1.12、很容易检测 view 指针是否越界到缓冲区的末尾,因为缓冲区的地址保存在 taddr 变量里

teq view,taddr
subeq view,#128*128*2

2.1.13、 如果还有字符需要显示,我们就需要自增 x 变量然后到 xLoop 循环执行

add x,#8
teq x,#1024
bne xLoop$

2.2、 如果还有更多的字符显示我们就需要自增 y 变量,然后到 yLoop 循环执行

add y,#16
teq y,#768
bne yLoop$

3、不要忘记最后清除变量

pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
.unreq x
.unreq y
.unreq char
.unreq col
.unreq screen
.unreq taddr
.unreq view
.unreq stop

3、行打印

现在我有了自己 TerminalDisplay 方法,它可以自动显示 terminalBuffer 内容到 terminalScreen,因此理论上我们可以画出文本。但是实际上我们没有任何基于字符显示的例程。 首先快速容易上手的方法便是 TerminalClear, 它可以彻底清除终端。这个方法不用循环也很容易实现。可以尝试分析下面的方法应该不难:

.globl TerminalClear
TerminalClear:
ldr r0,=terminalStart
add r1,r0,#terminalBuffer-terminalStart
str r1,[r0]
str r1,[r0,#terminalStop-terminalStart]
str r1,[r0,#terminalView-terminalStart]
mov pc,lr

现在我们需要构造一个字符显示的基础方法:Print 函数。它将保存在 r0 的字符串和保存在 r1 的字符串长度简单的写到屏幕上。有一些特定字符需要特别的注意,这些特定的操作是确保 terminalView 是最新的。我们来分析一下需要做什么:

  1. 检查字符串的长度是否为 0,如果是就直接返回
  2. 加载 terminalStop 和 terminalView
  3. 计算出 terminalStop 的 x 坐标
  4. 对每一个字符的操作:

    1. 检查字符是否为新起一行
    2. 如果是的话,自增 bufferStop 到行末,同时写入黑色删除字符
    3. 否则拷贝当前 terminalColour 的字符
    4. 检查是否在行末
    5. 如果是,检查从 terminalView 到 terminalStop 之间的字符数是否大于一屏
    6. 如果是,terminalView 自增一行
    7. 检查 terminalView 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
    8. 检查 terminalStop 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
    9. 检查 terminalStop 是否等于 terminalStart, 如果是的话 terminalStart 自增一行。
    10. 检查 terminalStart 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
  5. 存取 terminalStop 和 terminalView

试一下自己去实现。我们的方案提供如下:

1、这个是 Print 函数开始快速检查字符串为0的代码

.globl Print
Print:
teq r1,#0
moveq pc,lr

2、这里我做了很多配置。 bufferStart 代表 terminalStart, bufferStop 代表terminalStop, view 代表 terminalView,taddr 代表 terminalBuffer 的末尾地址。

push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
bufferStart .req r4
taddr .req r5
x .req r6
string .req r7
length .req r8
char .req r9
bufferStop .req r10
view .req r11

mov string,r0
mov length,r1

ldr taddr,=terminalStart
ldr bufferStop,[taddr,#terminalStop-terminalStart]
ldr view,[taddr,#terminalView-terminalStart]
ldr bufferStart,[taddr]
add taddr,#terminalBuffer-terminalStart
add taddr,#128*128*2

3、和通常一样,巧妙的对齐技巧让许多事情更容易。由于需要对齐 terminalBuffer,每个字符的 x 坐标需要 8 位要除以 2。

and x,bufferStop,#0xfe
lsr x,#1

4.1、我们需要检查新行

charLoop$:
ldrb char,[string]
and char,#0x7f
teq char,#'\n'
bne charNormal$

4.2、循环执行值到行末写入 0x7f;黑色删除字符

mov r0,#0x7f
clearLine$:
strh r0,[bufferStop]
add bufferStop,#2
add x,#1
teq x,#128 blt clearLine$
    
b charLoopContinue$

4.3、存储字符串的当前字符和 terminalBuffer 末尾的 terminalColour 然后将它和 x 变量自增

charNormal$:
strb char,[bufferStop]
ldr r0,=terminalColour
ldrb r0,[r0]
strb r0,[bufferStop,#1]
add bufferStop,#2
add x,#1

4.4、检查 x 是否为行末;128

charLoopContinue$:
cmp x,#128
blt noScroll$

4.5、设置 x 为 0 然后检查我们是否已经显示超过 1 屏。请记住,我们是用的循环缓冲区,因此如果 bufferStop 和 view 之前的差是负值,我们实际上是环绕了缓冲区。

mov x,#0
subs r0,bufferStop,view
addlt r0,#128*128*2
cmp r0,#128*(768/16)*2

4.6、增加一行字节到 view 的地址

addge view,#128*2

4.7、 如果 view 地址是缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

teq view,taddr
subeq view,taddr,#128*128*2

4.8、如果 stop 的地址在缓冲区末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

noScroll$:
teq bufferStop,taddr
subeq bufferStop,taddr,#128*128*2

4.9、检查 bufferStop 是否等于 bufferStart。 如果等于增加一行到 bufferStart。

teq bufferStop,bufferStart
addeq bufferStart,#128*2

4.10、如果 start 的地址在缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

teq bufferStart,taddr
subeq bufferStart,taddr,#128*128*2

循环执行知道字符串结束

subs length,#1
add string,#1
bgt charLoop$

5、保存变量然后返回

charLoopBreak$:
sub taddr,#128*128*2
sub taddr,#terminalBuffer-terminalStart
str bufferStop,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]
str bufferStart,[taddr]

pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
.unreq bufferStart
.unreq taddr
.unreq x
.unreq string
.unreq length
.unreq char
.unreq bufferStop
.unreq view

这个方法允许我们打印任意字符到屏幕。然而我们用了颜色变量,但实际上没有设置它。一般终端用特性的组合字符去行修改颜色。如 ASCII 转义(1b 16)后面跟着一个 0 - f 的 16 进制的数,就可以设置前景色为 CGA 颜色号。如果你自己想尝试实现;在下载页面有一个我的详细的例子。

4、标志输入

现在我们有一个可以打印和显示文本的输出终端。这仅仅是说对了一半,我们需要输入。我们想实现一个方法:ReadLine,可以保存文件的一行文本,文本位置由 r0 给出,最大的长度由 r1 给出,返回 r0 里面的字符串长度。棘手的是用户输出字符的时候要回显功能,同时想要退格键的删除功能和命令回车执行功能。它们还需要一个闪烁的下划线代表计算机需要输入。这些完全合理的要求让构造这个方法更具有挑战性。有一个方法完成这些需求就是存储用户输入的文本和文件大小到内存的某个地方。然后当调用 ReadLine 的时候,移动 terminalStop 的地址到它开始的地方然后调用 Print。也就是说我们只需要确保在内存维护一个字符串,然后构造一个我们自己的打印函数。

按照惯例,许多编程语言中,任意程序可以访问 stdin 和 stdin,它们可以连接到终端的输入和输出流。在图形程序其实也可以进行同样操作,但实际几乎不用。

让我们看看 ReadLine 做了哪些事情:

  1. 如果字符串可保存的最大长度为 0,直接返回
  2. 检索 terminalStop 和 terminalStop 的当前值
  3. 如果字符串的最大长度大约缓冲区的一半,就设置大小为缓冲区的一半
  4. 从最大长度里面减去 1 来确保输入的闪烁字符或结束符
  5. 向字符串写入一个下划线
  6. 写入一个 terminalView 和 terminalStop 的地址到内存
  7. 调用 Print 打印当前字符串
  8. 调用 TerminalDisplay
  9. 调用 KeyboardUpdate
  10. 调用 KeyboardGetChar
  11. 如果是一个新行直接跳转到第 16 步
  12. 如果是一个退格键,将字符串长度减 1(如果其大于 0)
  13. 如果是一个普通字符,将它写入字符串(字符串大小确保小于最大值)
  14. 如果字符串是以下划线结束,写入一个空格,否则写入下划线
  15. 跳转到第 6 步
  16. 字符串的末尾写入一个新行字符
  17. 调用 Print 和 TerminalDisplay
  18. 用结束符替换新行
  19. 返回字符串的长度

为了方便读者理解,然后然后自己去实现,我们的实现提供如下:

  1. 快速处理长度为 0 的情况
.globl ReadLine
ReadLine:
teq r1,#0
moveq r0,#0
moveq pc,lr

2、考虑到常见的场景,我们初期做了很多初始化动作。input 代表 terminalStop 的值,view 代表 terminalView。Length 默认为 0。

string .req r4
maxLength .req r5
input .req r6
taddr .req r7
length .req r8
view .req r9

push {r4,r5,r6,r7,r8,r9,lr}

mov string,r0
mov maxLength,r1
ldr taddr,=terminalStart
ldr input,[taddr,#terminalStop-terminalStart]
ldr view,[taddr,#terminalView-terminalStart]
mov length,#0

3、我们必须检查异常大的读操作,我们不能处理超过 terminalBuffer 大小的输入(理论上可行,但是 terminalStart 移动越过存储的 terminalStop`,会有很多问题)。

cmp maxLength,#128*64
movhi maxLength,#128*64

4、由于用户需要一个闪烁的光标,我们需要一个备用字符在理想状况在这个字符串后面放一个结束符。

sub maxLength,#1

5、写入一个下划线让用户知道我们可以输入了。

mov r0,#'_'
strb r0,[string,length]

6、保存 terminalStop 和 terminalView。这个对重置一个终端很重要,它会修改这些变量。严格讲也可以修改 terminalStart,但是不可逆。

readLoop$:
str input,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]

7、写入当前的输入。由于下划线因此字符串长度加 1

mov r0,string
mov r1,length
add r1,#1
bl Print

8、拷贝下一个文本到屏幕

bl TerminalDisplay

9、获取最近一次键盘输入

bl KeyboardUpdate

10、检索键盘输入键值

bl KeyboardGetChar

11、如果我们有一个回车键,循环中断。如果有结束符和一个退格键也会同样跳出循环。

teq r0,#'\n'
beq readLoopBreak$
teq r0,#0
beq cursor$
teq r0,#'\b'
bne standard$

12、从 length 里面删除一个字符

delete$:
cmp length,#0
subgt length,#1
b cursor$

13、写回一个普通字符

standard$:
cmp length,maxLength
bge cursor$
strb r0,[string,length]
add length,#1

14、加载最近的一个字符,如果不是下划线则修改为下换线,如果是则修改为空格

cursor$:
ldrb r0,[string,length]
teq r0,#'_'
moveq r0,#' '
movne r0,#'_'
strb r0,[string,length]

15、循环执行值到用户输入按下

b readLoop$
readLoopBreak$:

16、在字符串的结尾处存入一个新行字符

mov r0,#'\n'
strb r0,[string,length]

17、重置 terminalView 和 terminalStop 然后调用 Print 和 TerminalDisplay 显示最终的输入

str input,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]
mov r0,string
mov r1,length
add r1,#1
bl Print
bl TerminalDisplay

18、写入一个结束符

mov r0,#0
strb r0,[string,length]

19、返回长度

mov r0,length
pop {r4,r5,r6,r7,r8,r9,pc}
.unreq string
.unreq maxLength
.unreq input
.unreq taddr
.unreq length
.unreq view

5、终端:机器进化

现在我们理论用终端和用户可以交互了。最显而易见的事情就是拿去测试了!删除 main.s 里 bl UsbInitialise 后面的代码后如下:

reset$:
  mov sp,#0x8000
  bl TerminalClear
  
  ldr r0,=welcome
  mov r1,#welcomeEnd-welcome
  bl Print

loop$:
  ldr r0,=prompt
  mov r1,#promptEnd-prompt
  bl Print
  
  ldr r0,=command
  mov r1,#commandEnd-command
  bl ReadLine
  
  teq r0,#0
  beq loopContinue$
  
  mov r4,r0
  
  ldr r5,=command
  ldr r6,=commandTable
  
  ldr r7,[r6,#0]
  ldr r9,[r6,#4]
  commandLoop$:
    ldr r8,[r6,#8]
    sub r1,r8,r7
    
    cmp r1,r4
    bgt commandLoopContinue$
    
    mov r0,#0
    commandName$:
      ldrb r2,[r5,r0]
      ldrb r3,[r7,r0]
      teq r2,r3
      bne commandLoopContinue$
      add r0,#1
      teq r0,r1
      bne commandName$
    
    ldrb r2,[r5,r0]
    teq r2,#0
    teqne r2,#' '
    bne commandLoopContinue$
    
    mov r0,r5
    mov r1,r4
    mov lr,pc
    mov pc,r9
    b loopContinue$
  
  commandLoopContinue$:
    add r6,#8
    mov r7,r8
    ldr r9,[r6,#4]
    teq r9,#0
    bne commandLoop$
  
  ldr r0,=commandUnknown
  mov r1,#commandUnknownEnd-commandUnknown
  ldr r2,=formatBuffer
  ldr r3,=command
  bl FormatString
  
  mov r1,r0
  ldr r0,=formatBuffer
  bl Print

loopContinue$:
  bl TerminalDisplay
  b loop$

echo:
  cmp r1,#5
  movle pc,lr

  add r0,#5
  sub r1,#5
  b Print

ok:
  teq r1,#5
  beq okOn$
  teq r1,#6
  beq okOff$
  mov pc,lr
  
  okOn$:
    ldrb r2,[r0,#3]
    teq r2,#'o'
    ldreqb r2,[r0,#4]
    teqeq r2,#'n'
    movne pc,lr
    mov r1,#0
    b okAct$
  
  okOff$:
    ldrb r2,[r0,#3]
    teq r2,#'o'
    ldreqb r2,[r0,#4]
    teqeq r2,#'f'
    ldreqb r2,[r0,#5]
    teqeq r2,#'f'
    movne pc,lr
    mov r1,#1
  
  okAct$:
  
    mov r0,#16
    b SetGpio

.section .data
.align 2
welcome: .ascii "Welcome to Alex's OS - Everyone's favourite OS"
welcomeEnd:
.align 2
prompt: .ascii "\n> "
promptEnd:
.align 2
command:
  .rept 128
    .byte 0
  .endr
commandEnd:
.byte 0
.align 2
commandUnknown: .ascii "Command `%s' was not recognised.\n"
commandUnknownEnd:
.align 2
formatBuffer:
  .rept 256
    .byte 0
  .endr
formatEnd:

.align 2
commandStringEcho: .ascii "echo"
commandStringReset: .ascii "reset"
commandStringOk: .ascii "ok"
commandStringCls: .ascii "cls"
commandStringEnd:

.align 2
commandTable:
.int commandStringEcho, echo
.int commandStringReset, reset$
.int commandStringOk, ok
.int commandStringCls, TerminalClear
.int commandStringEnd, 0

这块代码集成了一个简易的命令行操作系统。支持命令:echo、reset、ok 和 cls。echo 拷贝任意文本到终端,reset 命令会在系统出现问题的是复位操作系统,ok 有两个功能:设置 OK 灯亮灭,最后 cls 调用 TerminalClear 清空终端。

试试树莓派的代码吧。如果遇到问题,请参照问题集锦页面吧。

如果运行正常,祝贺你完成了一个操作系统基本终端和输入系列的课程。很遗憾这个教程先讲到这里,但是我希望将来能制作更多教程。有问题请反馈至 [email protected]。

你已经在建立了一个简易的终端操作系统。我们的代码在 commandTable 构造了一个可用的命令表格。每个表格的入口是一个整型数字,用来表示字符串的地址,和一个整型数字表格代码的执行入口。 最后一个入口是 为 0 的 commandStringEnd。尝试实现你自己的命令,可以参照已有的函数,建立一个新的。函数的参数 r0 是用户输入的命令地址,r1 是其长度。你可以用这个传递你输入值到你的命令。也许你有一个计算器程序,或许是一个绘图程序或国际象棋。不管你的什么点子,让它跑起来!


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input02.html

作者:Alex Chadwick 选题:lujun9972 译者:guevaraya 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

程序员都是凡人,但数学则是不朽的。通过让编程变得更数学化,计算机科学家希望能消除向黑客敞开大门的编程错误。研究人员在 GitHub 上发布了加密工具 EverCrypt,向这个目标迈出了一大步。

就像证明毕达哥拉斯定理那样,他们能证明 EverCrypt 可完全避开多种黑客攻击。

EverCrypt 没有采用常见的编程方法编写,而是利用了形式化验证。他们首先明确代码能做什么,然后证明只能这么做,排除了代码在特殊情况下偏离的可能性。

EverCrypt 始于 2016 年,是微软研究院项目 Project Everest 的一部分,当时加密库是许多软件的薄弱环节,存在大量 bug。

来源:solidot.org

更多资讯

Google Chrome 等浏览器不再允许关闭点击跟踪

Chrome、Safari、Opera 和 Microsoft Edge 的新版本将不再允许用户关闭“ 链接审计 ( hyperlink auditing ) ”的功能。链接审计是一项 HTML 标准,被用于跟踪网站链接的点击。它通过创建特定网页的 POST 请求,用户检查请求头文件就可以了解点击的源地址。

来源: solidot.org
详情: http://t.cn/E6MkXbD

4 月编程语言排行榜:C++ 重回前三 PHP 呈下降势头

TIOBE 公布了 2019 年 4 月编程语言排行榜,总体排名变化不大,排名前十的分别是:Java、C、C++、Python、Visual Basic .NET、C#、JavaScript、SQL、PHP 和 汇编语言。不过与上期相比,依然有值得关注的亮点。

来源: cnBeta.COM
详情: http://t.cn/E6MkRBv

英国收紧社交媒体审查 向仇恨言论等网络安全问题说不

英国政府在网络安全方面将继续采取强硬立场,近期将会成立全球首家专门负责社交媒体公司的独立监管机构。对于没有达到要求的公司不仅要面临巨额的罚款,而且公司的高管负责人因工作疏忽需要承担个人责任。

来源: 开源中国
详情: http://t.cn/E6Mk1jH

研究人员发现中国企业简历信息泄露:涉 5.9 亿份简历

据美国科技媒体ZDNet报道,有研究人员发现,中国企业今年前3个月出现数起简历信息泄漏事故,涉及5.9亿份简历。大多数简历之所以泄露,主要是因为MongoDB和ElasticSearch服务器安全措施不到位,不需要密码就能在网上看到信息,或者是因为防火墙出现错误导致。

来源: 新浪科技
详情: http://t.cn/E6MksYr

(信息来源于网络,安华金和搜集整理)