当前位置: 首页 > 编程日记 > 正文

《LINUX3.0内核源代码分析》第一章:内存寻址

https://blog.csdn.net/ekenlinbing/article/details/7613334
摘要:本章主要介绍了LINUX3.0内存寻址方面的内容,重点对follow_page函数进行注释,以帮助读者大致了解ARM A9的页表组织。 读者需要理解一些基本概念:虚拟地址、物理地址、MPU、MMU、ARM中的二级页表、cache、TLB。

法律声明:《LINUX3.0内核源代码分析》系列文章由谢宝友(scxby@163.com)发表于http://xiebaoyou.blog.chinaunix.net,文章中的LINUX3.0源代码遵循GPL协议。除此以外,文档中的其他内容由作者保留所有版权。谢绝转载。

本连载文章并不是为了形成一本适合出版的书籍,而是为了向有一定内核基本的读者提供一些linux3.0源码分析。因此,请读者结合《深入理解LINUX内核》第三版阅读本连载。

本系列文章分析ARM A9的linux3.0代码实现。因此,需要读者有一定的ARM体系硬件知识。推荐阅读《ARM嵌入式系统开发-软件设计与优化》。另外,读者最好对内核有所了解,推荐阅读《深入理解LINUX内核》第三版。

读者需要理解一些基本概念:虚拟地址、物理地址、MPU、MMU、ARM中的二级页表、cache、TLB。

1.1 基本函数
Linux3.0将分页抽象为四级:

名称数据结构备注
页全局目录Pgd_t
页上级目录Pud_tA9未用
页中间目录Pmd_tA9未用
页表Pte_t
/*** 对A9来说,只支持4K大小的页,因此PAGE_SHIFT定义为12.它表示一个虚拟地址的页内偏移量的位数。* 根据它计算出来的页大小PAGE_SIZE为4K,PAGE_MASK为0xffff000。*/#define PAGE_SHIFT           12#define PAGE_SIZE              (_AC(1,UL) << PAGE_SHIFT)#define PAGE_MASK           (~(PAGE_SIZE-1))/*** 对A9来说,没有PMD和PUD,因此,PMD_SHIFT和PUD_SHIFT的值与PGDIR_SHIFT是一样的,都是21.* 21表示一个页全局目录项代表了2^20即1M的地址空间。*/#define PMD_SHIFT            21#define PGDIR_SHIFT                  21/*** 分别代表一个页表、页中间目录、页全局目录表中表项的个数。*/#define PTRS_PER_PTE               512#define PTRS_PER_PMD             1#define PTRS_PER_PGD              2048/*** 将pte\pmd\pud\pgd\pgprot转换为整型值*/#define pte_val(x)      (x)#define pmd_val(x)      (x)#define pgd_val(x)      ((x)[0])#define pgprot_val(x)   (x)/*** 将整型值转换为pte\pmd\pud\pgd\pgprot*/#define __pte(x)        (x)#define __pmd(x)        (x)#define __pgprot(x)     (x)

1.1.1 判断页表项标志的函数

/*** 页表项是否为0*/#define pte_none(pte)                 (!pte_val(pte))/*** 页表项是否可用。当页在内存中但是不可读写时置此标志。典型的用途是写时复制。*/#define pte_present(pte)  (pte_val(pte) & L_PTE_PRESENT)/*** 页表项是否有可写标志*/#define pte_write(pte)                (!(pte_val(pte) & L_PTE_RDONLY))/*** 页表项是否为脏*/#define pte_dirty(pte)                 (pte_val(pte) & L_PTE_DIRTY)/*** 页表项是否表示最近没有被访问过*/#define pte_young(pte)               (pte_val(pte) & L_PTE_YOUNG)/*** 页表项是否有可执行标志*/#define pte_exec(pte)                 (!(pte_val(pte) & L_PTE_XN))#define pte_special(pte)    (0)/*** 清除页表项的值。*/#define pte_clear(mm,addr,ptep)     set_pte_ext(ptep, __pte(0), 0)/*** 向一个页表项中写入指定的值。*/#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)/*** 判断两个页表项是否指向相同的页并且有相同的访问权限*/static inline int pte_same(pte_t pte_a, pte_t pte_b){return pte_val(pte_a) == pte_val(pte_b);}/*** 检查页中间目录项是否指向不可用的页表。*/#define pmd_bad(pmd)               (pmd_val(pmd) & 2)/*** 页表项是否可用。当页在内存中但是不可读写时置此标志。典型的用途是写时复制。*/#define pte_present(pte)  (pte_val(pte) & L_PTE_PRESENT)

1.1.2 页表项操作函数

/*** 虚拟地址在页全局目录中索引*/#define pgd_index(addr)             ((addr) >> PGDIR_SHIFT)/*** 计算一个进程用户态地址对应的页全局目录项地址。* 计算内核态地址的页全局目录项地址应当使用pgd_offset_k*/#define pgd_offset(mm, addr)  ((mm)->pgd + pgd_index(addr))/* to find an entry in a kernel page-table-directory *//*** 计算一个内核态地址的页全局目录项地址。*/#define pgd_offset_k(addr)        pgd_offset(&init_mm, addr)/*** 获得页全局目录项所指向的页面。对A9来说,就是pmd_page*/#define pgd_page(pgd)                                  (pud_page((pud_t){ pgd }))/*** 获得页全局目录项的虚拟地址。*/#define pgd_page_vaddr(pgd)                     (pud_page_vaddr((pud_t){ pgd }))/*** 在页全局目录表中,查找一个虚拟地址对应的页上级目录位置。* 对二级页表来说,页上级目录就是页全局目录,因此直接返回页全局目录。*/#define pud_offset(pgd, start)           (pgd)/*** 获得页上级目录页面。*/#define pud_page(pud)                         pgd_page(pud)/*** 获得页上级目录页面的虚拟地址。*/#define pud_page_vaddr(pud)            pgd_page_vaddr(pud)/*** 获得一个虚拟地址的页中间目录中的地址。对二级页表来说,没有pmd,直接返回页全局目录地址即可。*/#define pmd_offset(dir, addr)    ((pmd_t *)(dir))/*** 获得页中间目录指向的页表页面。*/#define pmd_page(pmd)             pfn_to_page(__phys_to_pfn(pmd_val(pmd)))/*** 获得一个线性地址对应的页表项在页表中的索引*/#define pte_index(addr)              (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))/*** 在主内核页表中定位内核地址对应的页表项的虚拟地址。*/#define pte_offset_kernel(pmd,addr)        (pmd_page_vaddr(*(pmd)) + pte_index(addr))/*** 在进程页表中定位线性地址对应的页表项的地址。如果页表保存在高端内存中,那么还为页表建立一个临时内核映射。*/#define pte_offset_map(pmd,addr)  (__pte_map(pmd) + pte_index(addr))/*** 如果页表在高端内存中,不解除由pte_offset_map建立的临时内核映射。*/#define pte_unmap(pte)                      __pte_unmap(pte)/*** 获取页表项中的页帧号。*/#define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)/*** 根据页帧号和页面属性,合成页表项。*/#define pfn_pte(pfn,prot)  __pte(__pfn_to_phys(pfn) | pgprot_val(prot))/*** 从页表项中提取页帧号,并定位该页帧号对应的页框。*/#define pte_page(pte)                 pfn_to_page(pte_pfn(pte))/*** 根据页框和页面属性,合成页表项。*/#define mk_pte(page,prot)        pfn_pte(page_to_pfn(page), prot)/*** 当页表项映射到文件,并且没有装载进内存时,从页表项中提取文件页号。*/#define pte_to_pgoff(x)              (pte_val(x) >> 3)/*** 将页面映射的页号存放到页表项中*/#define pgoff_to_pte(x)              __pte(((x) << 3) | L_PTE_FILE)

1.1.3 页表分配相关的函数

/*** 为页全局目录分配内存*/pgd_t *pgd_alloc(struct mm_struct *mm)/*** 释放页全局目录项*/void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)/*** 分配页上级目录,在二级页表中,此函数什么也不做。*/#define pud_alloc(mm, pgd, address)        (pgd)/*** 释放页上级目录,在二级页表中,这个函数什么也不做*/#define pud_free(mm, x)                               do { } while (0)Pmd_alloc、pmd_free、pte_alloc_map、pte_free等宏或函数与此类似。

1.2 刷新cache和TLB
Cache是CPU与内存之间的缓存,而TLB是CPU与MMU之间缓存。

当外部硬件通过DMA修改了内存中的数据时,需要使cache中的数据失效,强制CPU从内存中装载数据。当CPU向缓存中写入数据后,为了通过DMA将数据传送到外部硬件,则需要将缓存中的数据强制写入内存。

当页表项映射的页面发生变化后,也需要将页面缓存的内容写入内存。

同理,当修改了页表项后,为了避免TLB中缓存的项进行错误的MMU转换,也需要使TLB中缓存的项失效。

1.3 follow_page函数
follow_page函数是从进程的页表中搜索特定地址对应的页面对象。这个函数对于理解LINUX内核页表管理有帮助。

struct page *follow_page(struct vm_area_struct *vma, unsigned long address,unsigned int flags){pgd_t *pgd;pud_t *pud;pmd_t *pmd;pte_t *ptep, pte;spinlock_t *ptl;struct page *page;struct mm_struct *mm = vma->vm_mm;/*** 对ARM A9来说,没有配置巨页功能,follow_huge_addr实际上是空处理。*/page = follow_huge_addr(mm, address, flags & FOLL_WRITE);if (!IS_ERR(page)) {BUG_ON(flags & FOLL_GET);goto out;}page = NULL;/*** 在一级目录项中,查找地址对应的一级目录索引项。*/pgd = pgd_offset(mm, address);/*** 该地址对应的一级目录项无效。对ARM来说,pgd_none总返回0,真正的判断是在pmd_none。*/if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))goto no_page_table;/*** 查找地址对应的页上级目录项。这对4级目录的分组体系来说才有效。ARM不存在页上级目录和页中间目录。* pud总是返回pgd。*/pud = pud_offset(pgd, address);/*** pud_none总是返回0,因此下面的判断是无用。真正有用的判断在后面的pmd_none*/if (pud_none(*pud))goto no_page_table;if (pud_huge(*pud) && vma->vm_flags & VM_HUGETLB) {BUG_ON(flags & FOLL_GET);page = follow_huge_pud(mm, address, pud, flags & FOLL_WRITE);goto out;}if (unlikely(pud_bad(*pud)))goto no_page_table;/*** 取页中间目录,对ARM来说,pmd直接返回pud,即pgd。*/pmd = pmd_offset(pud, address);/*** 判断pmd是否为0,即ARM一级目录是否有效。对pgd,pud的判断都是无用的,真正的判断在这里。*/if (pmd_none(*pmd))goto no_page_table;/*** 判断pmd是否是一个巨页,以及用户虚拟地址空间段是否是一个巨页段,略过。*/if (pmd_huge(*pmd) && vma->vm_flags & VM_HUGETLB) {BUG_ON(flags & FOLL_GET);/*** 查找巨页地址映射的物理页面。*/page = follow_huge_pmd(mm, address, pmd, flags & FOLL_WRITE);goto out;}/*** 透明巨页处理,对某些体系结构,如mips来说,这个功能是有效的。但是虽然ARM硬件支持巨页(1M页)* 目前的内核还不支持ARM巨页,略过。*/if (pmd_trans_huge(*pmd)) {if (flags & FOLL_SPLIT) {split_huge_page_pmd(mm, pmd);goto split_fallthrough;}spin_lock(&mm->page_table_lock);if (likely(pmd_trans_huge(*pmd))) {if (unlikely(pmd_trans_splitting(*pmd))) {spin_unlock(&mm->page_table_lock);wait_split_huge_page(vma->anon_vma, pmd);} else {page = follow_trans_huge_pmd(mm, address,pmd, flags);spin_unlock(&mm->page_table_lock);goto out;}} elsespin_unlock(&mm->page_table_lock);/* fall through */}split_fallthrough:/*** 判断pmd是否有效。*/if (unlikely(pmd_bad(*pmd)))goto no_page_table;/*** 在二级页表中找到地址对应的pte。并将pte指针返回。* 注意,这里获取了进程的内存页表锁。以防止内核其他路径修改进程页表,使得ptep指向的pte产生变化。* ptl是内存页表锁。* 如果内核支持将pte表放到高端内存,那么还需要调用kmap_atomic将页表到内核地址空间中。*/ptep = pte_offset_map_lock(mm, pmd, address, &ptl);pte = *ptep;/*** 这里判断页表项是否有效。* 有时,页面在内存中,但是不允许访问。比如写时复制。* 当页完全不在内存中时,页表项也没有效。*/if (!pte_present(pte))goto no_page;/*** 希望搜索一个可写的页面,但是页表项没有写权限。*/if ((flags & FOLL_WRITE) && !pte_write(pte))goto unlock;/*** 根据pte中保存的页帧号,找到该页帧号对应的page结构。*/page = vm_normal_page(vma, address, pte);if (unlikely(!page)) {/* 根据页帧号无法找到page结构,可能是一些特殊情况。如驱动自行管理的pte出了问题。 */if ((flags & FOLL_DUMP) || /* 不允许返回0页 */!is_zero_pfn(pte_pfn(pte))) /* 不是0页 */goto bad_page;page = pte_page(pte);/* 向上层返回0页 */}/*** 调用者要求获取页面引用,则增加页面引用计数。*/if (flags & FOLL_GET)get_page(page);if (flags & FOLL_TOUCH) {/* 调用者希望设置访问标志,可能是随后会写页面 */if ((flags & FOLL_WRITE) &&/* 获取写引用 */!pte_dirty(pte) && !PageDirty(page))/* 页面和pte的脏标志都还没有设置,则强制设置脏标志 */set_page_dirty(page);/** pte_mkyoung() would be more correct here, but atomic care* is needed to avoid losing the dirty bit: it is easier to use* mark_page_accessed().*//*** 标记页面访问标志。*/mark_page_accessed(page);}/*** 调用者想将页面锁在内存中。*/if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) {/** The preliminary mapping check is mainly to avoid the* pointless overhead of lock_page on the ZERO_PAGE* which might bounce very badly if there is contention.** If the page is already locked, we don't need to* handle it now - vmscan will handle it later if and* when it attempts to reclaim the page.*/if (page->mapping && trylock_page(page)) {/* 锁住页面,不交换到外部存储器中 */lru_add_drain();  /* push cached pages to LRU *//** Because we lock page here and migration is* blocked by the pte's page reference, we need* only check for file-cache page truncation.*/if (page->mapping)mlock_vma_page(page);unlock_page(page);}}unlock:/*** 释放进程页面锁,同时,如果支持将页表放到高端内存,就解除对页表的映射。*/pte_unmap_unlock(ptep, ptl);out:return page;bad_page:pte_unmap_unlock(ptep, ptl);return ERR_PTR(-EFAULT);no_page:pte_unmap_unlock(ptep, ptl);if (!pte_none(pte))return page;no_page_table:/** When core dumping an enormous anonymous area that nobody* has touched so far, we don't want to allocate unnecessary pages or* page tables.  Return error instead of NULL to skip handle_mm_fault,* then get_dump_page() will return NULL to leave a hole in the dump.* But we can only make this optimization where a hole would surely* be zero-filled if handle_mm_fault() actually did handle it.*/if ((flags & FOLL_DUMP) &&(!vma->vm_ops || !vma->vm_ops->fault))return ERR_PTR(-EFAULT);return page;

相关文章:

java integer int 比较_java Integer和int之间的比较问题是什么?

展开全部java Integer和int之间e68a84e8a2ad3231313335323631343130323136353331333365633864的比较问题。求解释public static void main(String[] args) { // TODO Auto-generated method stub Integer a new Integer(1); Integer b new Integer(1); int c1; Integer e 1;…

Oracle 12C -- 基于sequence的列的默认值

12C支持先创建一个sequence&#xff0c;然后再将该sequence指定为某个列的值的默认表达式。 和"identity column"具有以下不同点&#xff1a; 对列的个数没有限制 sequence必须在列定义之前定义 如果删除了sequence&#xff0c;会导致后面的insert报错 表的owner&…

Python的XML-RPC学习

编写客户端提交数据到服务器处理是程序员最常碰到的几个问题之一。各种不同的语言对此都有相应的解决方案。比如Unix下&#xff0c;C程序员们可以用SUNRPC&#xff0c;Java程序员则使用RMI来处理。大多数语言还都可以使用Web Service或者ICE。它们的使用方法类似&#xff0c;编…

Anaconda安装,jupyter notebook 使用说明

conda install pandas---安装pandas包 conda remove package_names conda update package_names conda list ---列出该环境下安装的package conda install nb_conda --------安装nb_conda用于notebook自动关联nb_conda的环境 conda create -n env_name package_name -------…

ARM32页表-虚拟地址到物理地址的转换

ARM32的页表 页表就是用于将虚拟地址转换为物理地址的转换关系表。访问虚拟地址时&#xff0c;计算机通过页表找到对应的实际物理地址访问。 我们在上一节介绍了内存管理模块概图, 怎么完成从pgd 到 page的转化呢&#xff1f; linux 内核code是通过follow_page来完成的…

java 重载 参数子类_java - Java中带有子类参数的函数重载 - 堆栈内存溢出

这个问题已经在这里有了答案&#xff1a;我有一个扩展了另一个类的类(在这种情况下&#xff0c;这是一个例外)&#xff1a;public class NewTypeException extends Exception {private String exceptionField;public String getExceptionField() {return exceptionField;}publi…

Caused by: java.sql.BatchUpdateException

Caused by: java.sql.BatchUpdateException: Table (%s) has been dropped, altered or renamed.解决方法重启项目转载于:https://www.cnblogs.com/mySummer/p/4723561.html

do{ ...}while(0)应用技巧

辅助定义复杂的宏example: #define A(args) do { a(args); b() } while(0);如果定义#define A(args) a(args);b();if(i > 0) A(i) if(i > 0 )do { a(2);b();} while(0) 或者while(1)a(args);b(); 这不是我们想要的&#xff0c;因为第二个b();不会被执行。代替g…

Idea--使用Idea调试设置

参考 https://blog.csdn.net/yyjava/article/details/81453748 关闭一些Idea默认设置&#xff0c;否则懵逼到爆炸.. 1.关闭集合类视图 2.关闭watch视窗默认调用toString&#xff08;真的很懵逼&#xff01;&#xff01;&#xff09; 转载于:https://www.cnblogs.com/microcat/p…

基于i2c子系统的驱动分析

https://blog.csdn.net/qq_28992301/article/details/52467766

creo JAVA_Creo 4.0二次开发工具框架搭建

一、新建MFC DLL工程二、配置项目属性附加依赖项中输入&#xff1a;netapi32.lib;psapi.lib;mpr.lib;wsock32.lib;protk_dll_NU.lib;protk_dllmd_NU.lib;protkmd_NU.lib;protoolkit_NU.lib;pt_asynchronous.lib;ptasyncmd.lib;ucore.lib;udata.lib;尝试编译工程&#xff0c;如果…

html5 FileReader初识

使用html5的FileReader可以实现多媒体文件的预览功能&#xff0c;代码如下&#xff1a; <html> <head> <script type"text/javascript"> var fileReader new FileReader(); fileReader.onload function(event) {document.getElementById(image).…

puppet aix之自动化用户管理

一、 用户组的管理 (一) Puppet组管理特性 1. manages_aix_lam用来管理AIX的LAM(Loadable Authentication Module)系统。 2. manages_members对于目录服务是组属性成员&#xff0c;而不是用户。 3. system_groups用来允许你创建比较小GID的系统组&#xff0c;一般小…

C# 文件操作

C# 文件操作文件操作: 检查 创建 读取 写入 修改 删除目录操作: 检查 创建 读取 写入 修改 删除文件操作 若要执行此操作...请参阅本主题中的示例...创建文本文件向文件写入文本写入文本文件向文件写入文本读取文本文件从文件读取文本向文件中追加文本File.AppendText FileInfo…

一种内存池管理技术

本文介绍一种内存池管理技术。 在m公司工作了4年多&#xff0c;一直负责内存池模块问题的处理&#xff0c;比如内存越界&#xff0c;data abort 系统异常的处理&#xff0c;本文加以总结&#xff0c;以便后续参考。 读本文之前&#xff0c;先有个约定&#xff0c;本文中提到的p…

企业支付宝账号开发接口实现

转载自&#xff1a;http://my.oschina.net/xshuai/blog/313809 关于即时到账的开发。审核通过。简单测试如下。 希望看的可以收藏或者赞一下哦。 1:拥有自己的支付宝企业账号。去产品商店选择适合自己的方案。并签约合同。 2:选择合适的商家收款产品并去签约。填写相应的信息 3…

Fastadmin管理Mysql_FastAdmin-CMS模版制作(6)-正式部署

一、工具信息介绍(1)服务器系统&#xff1a;CentOS7.2 64位系统&#xff1b;(2)服务器面板&#xff1a;宝塔&#xff0c;官网地址&#xff1a;https://www.bt.cn/&#xff1b;(3)PHP7.2&#xff1b;(4)mysql5.6&#xff1b;(5)Nginx&#xff1b;二、运行环境安装(1)进入宝塔官网…

使用微软提供的Office Online实现Office文档的在线查看,编辑等功能

使用微软提供的Office Online平台只需要一个网址即可在线查看Xls,doc,PPT等文档http://view.officeapps.live.com/op/view.aspx?src要查看的文档地址在线编辑需要登录live.com并从onedrive中打开或新建文档也可以来自在线模板(下面的Excel来自Excel Online模板&#xff0c;编辑…

HDU(1847)Good Luck in CET-4 Everybody!

利用PN分析求解此题。递推下去会发现3和3的倍数都是P点。 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <set> using namespace std; int main() {int n;while(~scanf("%d",&n)){i…

uboot引导kernel - 1 - Flash的分区

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题1&#xff1a;Flash的分区相关问题 在 上述步骤1/2/4 中都提到了从启动介质(iNand/SD)中读取uboot/kernel到SRAM/DDR中&#xff0c;那么具体从启动介质的什么位置分别读取呢&#xff1f;  上述步骤1中&#xff0c;iROM的…

fedora mysql默认密码忘记_Linux fedora 24 忘记密码图形化界面修改root密码的方法

方法及其简单&#xff0c;只需要两步即可&#xff1a;1、第一步&#xff1a;打开终端&#xff0c;输入sudo su命令。–此处的密码为普通用户的密码&#xff0c;也就是开机时输入的密码。2、第二步&#xff1a;直接sudo passwd root就重置了roor密码了。此时输入新的密码即可&am…

Java Web项目结构

Java Web项目结构&#xff08;一般&#xff09; 1、Java src 2、JRE System Library 3、Java EE 6 Libraries 4、Web App Libraries 5、WebRoot 版权声明&#xff1a;本文博客原创文章&#xff0c;博客&#xff0c;未经同意&#xff0c;不得转载。转载于:https://www.cnblogs.c…

WTForms 小计1 forms

2019独角兽企业重金招聘Python工程师标准>>> 定义 from wtforms import Form, StringField, validators class MyForm(Form):first_name StringField(uFirst Name, validators[validators.input_required()])last_name StringField(uLast Name, validators[vali…

day32-1 事件Event

事件Event-线程 每一个线程都是独立运行且状态不可预测。你把一个任务丢到子线程中&#xff0c;这个任务将异步执行&#xff0c;如何获取到这个任务的执行状态&#xff1f;使用threading库中的Event对象。对象包含一个可由线程设置的信号标志&#xff0c;线程直到等到该标志为真…

uboot引导kernel - 2- uboot/kernel需要放在DDR什么位置的问题

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题2&#xff1a; uboot阶段DDR的分区的问题 上述步骤2和步骤4中&#xff0c;有将uboot/kernel拷贝纸DDR的步骤&#xff0c;具体要拷贝到DDR的什么位置呢&#xff1f; 分清楚这两个概念&#xff1a; 链接地址&#xff1a;链接…

java ftp pasv_Ftp主动模式和被动模式以及java连接ftp模式设置

FTP的主动模式与被动模式FTP服务器使用20和21两个网络端口与FTP客户端进行通信。FTP服务器的21端口用于传输FTP的控制命令&#xff0c;20端口用于传输文件数据。FTP主动模式&#xff1a;FTP客户端向服务器的FTP控制端口(默认是21)发送连接请求&#xff0c;服务器接受连接&#…

Python2.7 安装numpy报错解决方法

Windows 10下用pip安装numpy包报错&#xff1a; Microsoft Visual C 9.0 is required Unable to find vcvarsall.bat Get it from http://aka.ms/vcpython27 通过报错提示信息&#xff0c;打开http://aka.ms/vcpython27会跳转到Microsoft Visual C Compiler for Python 2.7的下…

异常The Struts dispatcher cannot be found. This is

2019独角兽企业重金招聘Python工程师标准>>> 原因&#xff1a;struts2的过滤器映射路径写错 解决方案&#xff1a;在web.xml中配置struts2的过滤器如下&#xff1a; <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*&…

UNDO表空间损坏,爆满,ORA-600[4194]/[4193]错误解决

模拟手工删除UNDO表空间 在ORADATA 中把UNDOTBS01.DBF 删除模拟启库SQL> STARUP;*第 1 行出现错误:ORA-01157: 无法标识/锁定数据文件 2 - 请参阅 DBWR 跟踪文件ORA-01110: 数据文件 2: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\UNDOTBS01.DBF利用系统本身的默认手动管理 MAN…

uboot引导kernel - 3 -uboot给内核传参详解

uboot中执行theKernel函数后&#xff0c;kernel正式启动。如下函数&#xff0c;我们发现有3个参数。 1. 参数 0&#xff1b; 2. 参数machid; 如下code 中获取machid, gd是个全局变量. 2.1 bi_arch_number是board_info中的一个元素&#xff0c;含义是&#xff1a;开发板的机器…