Browsed by
Category: C

Kernel Driver btusb Overview

Kernel Driver btusb Overview

Function btusb_probe btusb_probe is use for hot plug-in for bluetooth usb generic controller, here will explain the function in detail. First is an interface check mechanism This special condition is used for supporting apple Macbook 12,8 (2015 early). According to the normal specification, the main interface for USB is 0, and audio (isochronous) is 1, but apple made a change on it, changing the main interface to 2 and audio to 3. The “bInterfaceNumber !=2 ” is for checking hardware…

Read More Read More

[Linux 0.11] Draft 5 虚拟内存管理(mm/memory.c)

[Linux 0.11] Draft 5 虚拟内存管理(mm/memory.c)

Overview 本文介绍 32 位保护模式下的内存分页, 以及 linux0.11 对物理内存的管理。 意义 既然要使用内存分页,那么就一定有他的优势所在。我们首先来探讨一下使用内存分页的意义, 分页在于为进程提供了虚拟地址空间,通过提供的这个虚拟地址空间,我们可以做到下面的这些: 精细的权限控制粒度: 内存页大小以 4KB 为一页单位(也可以是4MB, 这里不讨论这种情况), 可以针对每一个内存页设置该4K空间的访问权限。相比分段的粗粒度精细了很多,目前的分段功能只是一个兼容性考虑,分段都是将整个0 – 最大内存空间直接映射为一个段; 可以使得进程独享地址空间: 通过切换CR3寄存器的内容,可以实现多个进程占用同一个虚拟地址空间。 有效的解决了进程对大块连续内存的请求: 这里用一个例子来说明一下。 例子是这样的: 如果我们有16MB的物理内存,现在有进程A B C分别占用5MB, 2MB, 3MB内存, 且不共享内存。然后现在进程B退出了,我们还剩余8MB内存,可是如果不使用分页的话,内存连续分配, 我们现在没有办法分配出一个连续的8MB的空间了,只能分配最多最多6MB连续的内存空间, 如下图所示。 而现在存在分页,虚拟地址,我们完全可以分配连续的8MB的虚拟地址空间,其中2MB映射到物理内存的中间那个2MB空隙,其余6MB映射到最后剩余的6MB。 由此可见,分页是十分必要的,那么下面就来介绍一下如何实现分页&虚拟内存管理 地址转换过程 我们先来看一下虚拟地址是如何转换为物理地址的 完整的转换过程为 虚拟地址 –> (GDT) –> 线性地址 –> (Page Table) –> 物理地址 关于VirtualAddr -> LinearAddr 的过程我在之前的文章中有过介绍,这里就不做说明,想要跳过那个文章的读者可以简单的理解为目前的虚拟地址和线性地址值是相同的,因而我们直接从线性地址出发。首先来看下图   (图片来源:Intel® 64 and IA-32 Architectures Software Developer’s Manual) 线性地址为32位的地址, 其中高十位为 Page Directory,中间十位为 Page Table,最后十二位是 Offset。过程如下: 根据 CR3 寄存器(忘记了寄存器的功能的话戳这里)找到了页目录表的地址。 根据 Linear Address 的高十位与页表目录地址相加,找到了对应的页目录项(PDE)。 页目录项内存有该页目录的起始地址,将此地址与 Linear Address 21 – 12 位(即中间十位)相加,找到对应的页表项(PTE)…

Read More Read More

[Linux 0.11] Draft 4 GCC Assembly

[Linux 0.11] Draft 4 GCC Assembly

全文参考 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm 阅读文档永远比阅读博客能获得更多的信息哦~ 本文对 GCC Assembly 进行总结和介绍,也是个人的笔记,欢迎各位指正,内容供参考 * Basic Asm — 基本不能用的 assembly * Extended Asm 功能强大的可扩展的ASM

Eudyptula Challenge 1 — 8 总结

Eudyptula Challenge 1 — 8 总结

TL;DR (PS: 昨天竟然在一个非计算机领域的朋友口中听到TLNR好神奇) 从开始做eudyptula-challenge已经有一个多月了,也从原来的连第一关都会卡关好久到现在第八关只用了不到四十分钟的时间就写好了(虽然第八关的coding要求很简单,主要是要练习git send-mail的使用方法)随着Challenge的进行,之前关卡学到的一些东西难免会遗忘,因此在继续进行之前,现将前面学到的知识进行总结。注意: 本文不是Eudyptula Challenge的攻略,Eudyptula Challenge明确禁止了对答案代码的公布和分享,个人也赞同这种做法,毕竟是Challenge,需要你自己研究,而不是直接上网就能搜到答案(尽管现在的确能搜到答案了,比如某章鱼猫(( Intro What is Eudyptula Challenge? 这里就引用官网的介绍了 The Eudyptula Challenge is a series of programming exercises for the Linux kernel, that start from a very basic “Hello world” kernel module, moving on up in complexity to getting patches accepted into the main Linux kernel source tree. How does it work? 官网上也给了相应的介绍,不过窝认为从一个例子来介绍更为形象: Eudyptula-Challenge的评判系统是由”A set of convoluted shell scripts that are slow to anger and impossible to debug.”(摘自官网)来进行的,也就是全部自动评测(不过有的时候它的只能程度让我猜想后面有人在操作*****(大雾 以一个Task为例, 当你注册成功Eudyptula Challenge之后,会收到一封说明邮件以及你的第一个任务,之后你所有的任务提交都将通过在第一个任务里给你分配的ID以plain-text mail的形式进行。 当你收到一个Task的时候,根据相应的知识完成任务要求的代码之后,你需要通过纯文本邮件客户端(如mutt)将proof运行结果的输出作为正文,将写好的代码作为附件(这里不能用gmail的plain-text模式,因为它会把邮件附件转为base64格式)通过客户端发送给[email protected],之后你会收到一封通知邮件,表示系统已经成功收到你的提交(有可能收不到,因为脚本也许会卡住,这时候你如果等了一天还没收到,那你可以再次发送一封,不要频繁重发,小企鹅会生气的(不要问我怎么知道的Orz)) 通知邮件的格式是这样的 blabla,…

Read More Read More

IO 多路复用 — select 和 poll

IO 多路复用 — select 和 poll

本文为 高性能网络编程学习 系列文章的第2篇 下面我们使用select, poll, epoll来进行IO multiplexing 本文我们演示 select 和 poll做IO多路复用 select的用法查看man page就可以得到,这里只列出遇到的问题 nfds参数,表明要watch的最大fd的数字 举例说明,如果你要watch的文件描述符为24 — 31,那么你应该将nfds设置为32 为了防止SIGPIPE信号终止程序运行,要讲SIGPIPE信号忽略掉 代码如下 /************************************************************************* > File Name: server.c > Author: VOID_133 > Mail: ################### > Created Time: Wed 21 Dec 2016 04:03:25 PM HKT ************************************************************************/ #define _GNU_SOURCE #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<pthread.h> #include<arpa/inet.h> #include<sys/socket.h> #include<sys/select.h> #include<string.h> #include<sys/errno.h> #define MAX_BUF_SIZE 1000 void usage(char *proc_name) { printf(“%s [port]\n”, proc_name); exit(1); } void setnonblock(int fd) { int old_flag = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, old_flag | O_NONBLOCK); return ; }…

Read More Read More

ULK Chapter2 总结

ULK Chapter2 总结

本章的知识结构如下 地址转换过程 –Logical Address–> [Segment Unit] –Linear Address–> [Paging Unit] –Physical Address–> 谈到内存地址,具体来讲有三种不同类型的地址,逻辑地址,线性地址,物理地址。 逻辑地址对应内存的分段 线性地址对应分页 物理地址对应到硬件芯片上的内存单元的地址 MMU通过Segment Unit与Paging Unit两个硬件电路将一个逻辑地址转为物理地址, 具体转换过程如上代码段所示 下面对整个转换过程进行概述 段选择符 15 0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +T+ R + + index +I+ P + + + + L + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ [0-1]RPL: 请求者特权级 [2]TI: Table Indicator, 指明是从GDT还是LDT中取出段描述符(Segment Descriptor) [3-15]index:用来指定从GDT中第index项取出Segment Descriptor 段描述符 对段描述符的解释参考 [不是科普向?] RE: 从零开始的操作系统开发 第二集 中相应内容即可 Logical Addr ===> Linear Addr 逻辑地址的高16位为段选择符(Segment Selector)其余32位(或者64位)为偏移量(Offset) 流程如下 检查TI确定是从GDT(TI=0)还是从LDT(TI =1)中选择段描述符 从Segment Selector的index字段计算出段描述符的地址,计算方法 index * 8 (一个Segment Descriptor大小为8) 并与gdtr/ldtr中的内容相加得到Segment Descriptor 把逻辑地址的offset字段与Segment Descriptor中的Base字段相加,得到Linear Address   而Linux中的分段只是一个兼容性考虑,分段和分页的作用是重复的,分页能以更精细的粒度对内存进行管理,因而在Linux中分页是主要的手段,Linux分段中的用户代码段,数据段,内核代码段,数据段,都是以Base = 0…

Read More Read More

将内核编译到自定义的目录下

将内核编译到自定义的目录下

参考wiki: https://wiki.archlinux.org/index.php/Kernels/Traditional_compilation 使用ArchLinux作为构建Linux的环境 方法如下 假设我们的customized directory为kernel-build 我们必须在kernel-tree目录结构下对内核进行编译,假设kernel-tree目录名为linux-kernel 下面是具体的操作: make menuconfig # Change the local version in General Settings make -j8 make modules -j8 sudo make modules_install 在 make menuconfig 的时候,最好对内核版本进行修改,使之不会在make modules_install的时候覆盖掉现有内核的modules 修改途径为General Setup里的Local Version项 这样执行之后,应该在arch/ARCH/boot/下面存在bzImage内核镜像,并且modules应该被安装在了/lib/modules/<linux-version>-<localversion> 下 下一步操作, 修改linux.preset文件,并创建initrd文件 ## Change to kernel-build directory cp ../arch/<arch>/boot/bzImage [image-name] cp /etc/mkinitcpio.d/linux.preset . 修改linux.preset文件, 修改完毕后的内容类似下面 # mkinitcpio preset file for the ‘linux’ package ALL_config=”/etc/mkinitcpio.conf” ALL_kver=”/home/void001/linux-kernel/kernel-build/vmlinuz” PRESETS=(‘default’ ‘fallback’) #default_config=”/etc/mkinitcpio.conf” default_image=”/home/void001/linux-kernel/kernel-build/initramfs-linux.img” #default_options=”” #fallback_config=”/etc/mkinitcpio.conf” fallback_image=”/home/void001/linux-kernel/kernel-build/initramfs-linux-fallback.img” fallback_options=”-S autodetect” 我们需要修改ALL_kver, default_image, fallback_image三个选项,使其将image保存到指定的目录下 然后使用 mkinitcpio -p ./linux.preset 创建initrd, initrd-fallback,目前kernel-build目录应该有如下文件: ╰─➤ ls…

Read More Read More

多进程&多线程 echo server实现

多进程&多线程 echo server实现

本文为 高性能网络编程学习 系列文章的第1篇   多进程版本 本文承接上文的单进程 echo server 建立一个多进程的echo server。代码的改动不多,下面贴一下完整的代码 /************************************************************************* > File Name: server.c > Author: VOID_133 > A very simple tcp echo server illustrate use of socket > Ver1 only accept single connection, no multiple connection allowed > Mail: ################### > Created Time: Wed 21 Dec 2016 04:03:25 PM HKT ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<string.h> #include<sys/errno.h> #define MAX_BUF_SIZE 1000 void usage(char *proc_name) { printf(“%s [port]\n”, proc_name); exit(1); } int main(int argc, char** argv) { int sockfd, clifd; //sockaddr_in…

Read More Read More