关于翘课玩魔兽

Facebook: Dong Hao Twitter: donh_ weibo: 翘课玩魔兽

Win8 VPN 720 ERROR FIX

I got my Windows 8.1 updated on Lenovo T440s Laptop the other days, and found my personal VPN unsuccessfully connected. What’s weired is my Android and IOS devices connected normally. So I reinstalled my PPTP and L2TP based on IP-SEC, and it turned out that the same issue with me. What’s going on?

First of all, I double checked that all different devices had been able to connect my VPN server, so it’s not about my VPS. Secondly, I updated win8 which may be quite the cause of abnormity. Thirdly, it verified that my Ubuntu client connected successfully.

So the anwer is clear, it has nothing to do with my VPS, but about the win8. Actually, (the following solution came from the internet) Microsoft has errors with the newest WAN MINI port drivers since Jan. 2013 which I found it  in a forum, and MS shouldn’t solve it! So the solutions are as follows:
1) Uninstall the drivers related to WAN Miniport (IP), WAN Miniport (IPv6) and WAN Miniport (Network Monitor).
2) Start -> Run ->  Regedit -> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4d36e972-e325-11ce-bfc1-08002be10318} -> Export
3) Edit the exported regist file and locate the above three subkey and deleted them all, double check you don’t delete the wrong part. Those subkeys has a “DriverDesc” which matches your broken miniports.
4) Go back to Device Manager, and now you are able to update the WAN MINI PORT drivers with errors. Right click the WAN MINI PORT IP (4 eg) -> Update Driver Software -> Browse My Computer -> Let me pick driver from a list -> uncheck “Show compatible hardware” and wait for the drivers listing generation. Then choose the first “Microsoft” drivers listed and pull the polling row to the top and then choose the first [BlueTooth Personal], and ignore warnings. Then the driver will become a fake blue tooth driver and you can delete it now.
5) Repeat step 4 for the remaining  WAN MINIport IPv6 and  WAN MINIport (Network Monitor)
6) Reboot, then all the right drivers will be installed automatically.

Linux系统学习之内存初始化

接下来的一段时间准备系统学习一下Linux的源代码,能顺利回答下列问题,Linux的i386内存寻址部分就算过关了。(题目出自陈香兰老师授课讲稿)

在32位pc中,结合Linux2.6.26/arch/x86/kernel/head_32.S中228-251行相关代码,关于临时2级页表的初始化过程,假设pg0所在的物理地址是0x567000,回答下列问题(以下涉及到数值的地方,请用16进制表示):
填写在swapper_pg_dir中第0x0项的内容是什么,有什么含义?
若填写了swapper_pg_dir中第0x1项,则此内容是什么?
填写在pg0的第0x0项、第0x1项和第0x3FF项的内容是多少,有什么含义?
根据swapper_pg_dir的第0x0项和pg0的内容,这个临时页表所代表的地址空间中,0~4MB-1的空间被映射的物理地址空间范围是什么?
若内核地址空间从3G开始,那么填写在swapper_pd_dir中第0x300项和0x301项的内容是什么,与上述第0项和第1项有什么关系,有什么含义?

唠叨两句,线性地址和物理地址经过硬件转化,所以看到奇奇怪怪的物理地址也不用担心,这跟逻辑地址没什么直接联系,另外,读代码之前要先明白这段代码是做swapper_pg_dir初始化用的,带着目的读会提高效率. 回顾x86的内存寻址过程,大概是CR3寄存器配合PDT,然后找到PTE的某项后加Page Offset找到所要的内容。不过这里是临时页表的初始化,NO PAE,OK,继续!

/arch/x86/kernel/head_32.S 页目录初始化代码节选
/* Physical address */
#define pa(X) ((X) – __PAGE_OFFSET)
page_pde_offset = (__PAGE_OFFSET >> 20);
/*__PAGE_OFFSET是0xc0000000,低于这个地址的被划分为用户空间,因此page_pde_offset是0xc00,页目录偏移,也就是整个页目录的大小,看不懂没关系,稍后会用到*/
  • movl $pa(__brk_base), %edi
    /*__brk_base由内核编译时指定,表示初始时堆的开始地址,注意kernel将所有的初始化好的页表都放在堆的开始处,这里所说的地址都是指运行时的虚拟地址VA,具体这里应该是pg0对应的物理地址,存入edi,也就是第一个page所在的地址,swapper_pg_dir的第一项*/
  • movl $pa(initial_page_table), %edx
    /*initial_page_table在paging_init()初始化,将swapper_pg_dir(存放页全局目录PGD的地址)送入edx*/
  • movl $PTE_IDENT_ATTR, %eax
    /*
    x86/include/asm/pgtable_types.h(#define PTE_IDENT_ATTR 0x003) PTE的属性是0x003,即PRESENT+RW,另外还有 #define PDE_IDENT_ATTR   0x067      /* PRESENT+RW+USER+DIRTY+ACCESSED */  #define PGD_IDENT_ATTR   0x001      /* PRESENT (no other attributes) */
    */

10:

  • leal PDE_IDENT_ATTR(%edi),%ecx /* Create PDE entry */
    补充说明:leal(加载有效地址)是取寄存器的地址赋值到右边,
    leal     S,D 结果:&S->D
    movel S,D 结果:S->D
    movel (S), D 结果:&S->D
    leal (S), D 结果:S->D
    ecx=edi+PDE_INDENT_ATTR
    /*把edi的值即pg0所在物理地址加0x067(PDE的属性)放入ecx,构建一个页目录项*/
    /*第二次循环,edi寄存器指向pg0+1024×4,即pg1的物理地址不用再赋值,下同*/
  • movl %ecx,(%edx) /* Store identity PDE entry */
    /*然后把ecx(pg0及属性)送入swapper_pg_dir的第零项,注意edx存放的是swapper_pg_dir的物理地址,因此该行代码把pg0及属性写入swapper_pg_dir第一项*/
  • movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */
    /*再把ecx送到swapper_pg_dir的第768项,page_pde_offset为0xc00,swapper_pg_dir每项为4字节,因此为768项,回顾1024个页表项,前768为用户空间,后256为内核空间,这里叫kernel PDE entry是这个意思*/
    /*第二轮循环,edx已经自加了4,下同*/
  • addl $4,%edx
    /*本段代码循环执行,edx的增量为4,即swapper_pg_dir每项的大小,先往后看*/
  • movl $1024, %ecx
    /*准备初始化1024个表项,这个是和loop配合使用的,记得否?*/
    /*tag 10做的工作就是创建一个PDE entry并放入ecx,然后加两个属性标志位存在swapper_pg_dir里*/
11:
  • stosl/*eax(0x003)的内容放入edi指向的物理地址(pg0),然后edi+4,*/
  • addl $0x1000,%eax
    /*eax: 0x1003, 0x2003, 0x3003 …, 0x3ff003*/
    /*提示:pg0页有4K,按照edi+4依次递增放入eax的值,换句话说,pg0的第零项是0x0003,第一项0x1003…, 第1023项,0x3ff003*/
    /*第二轮循环,eax每轮循环增长4K*1024=4M,最终会超过ebp的值,对应swapp_pg_dir每个PDE,下同*/
  • loop 11b
    /*循环执行前两行代码,初始化了pg0的全部1024个页表项,每个4B,这个时候,swapper_pg_dir的第一项,pg0已经全部初始化完毕(真累),再补充说明下,这个pg0其实就对应了物理地址前4MB了。
  • /*
  • * End condition: we must map up to the end + MAPPING_BEYOND_END.
  • */
  • movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
    /*ebp指向指向的物理地址+MAPPING_BEYOND_END+0x003*/
    /*需要映射到end+MAPPING_BEYOND_END,将内核最终地址保存到这里,当eax<ebp则重复初始化过程,ebp推算过程如下:

    • Enough space to fit pagetables for the low memory linear map */
    • #define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
      #define PTRS_PER_PGD 1024
      #define PAGE_SHIFT 12
      PAGE_TABLE_SIZE(0X40000000>>12) <<12
    • MAPPING_BEYOND_END = \
      PAGE_TABLE_SIZE(((1<<32) – __PAGE_OFFSET) >> PAGE_SHIFT)  <<  \ PAGE_SHIFT
    • PAGE_OFFSET 以外的地址包括0x100000000-0xc0000000=0x40000000,共0x40000页,算得配套页表大小 PAGE_TABLE_SIZE为0x40000/1024=0x100(256个) MAPPING_BEYOND_END为0x100>>PAGE_SHIFT = 0x100000,即256KB
  • cmpl %ebp,%eax
    /*eax=0x3ff03*/
    /*第二轮 eax = 0x7ff03 …. */
  • jb 10b
    /*至此,执行完毕,swapper_pg_dir所指向的PDE已初始化完毕,*/
  • addl $__PAGE_OFFSET, %edi
  • movl %edi, pa(_brk_end)
  • shrl $12, %eax
  • movl %eax, pa(max_pfn_mapped)
  • /* Do early initialization of the fixmap area */
  • movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
  • movl %eax,pa(initial_page_table+0xffc)
至此,回到刚才的问题:
填写在swapper_pg_dir中第0x0项的内容是什么,有什么含义?
swapper_pg_dir第0项内容是pg0的物理地址+PDE_INDENT_ATTR,也就是0x567067, 表示该页表是用户页表,可读写,可访问..(PRESENT+RW+USER+DIRTY+ACCESSED)
若填写了swapper_pg_dir中第0x1项,则此内容是什么?
0x568067
填写在pg0的第0x0项、第0x1项和第0x3FF项的内容是多少,有什么含义?
(回想stosl,即 movl eax, edi; addl $4, edi)pg0的第0项表示第一页的物理地址,内容是0x003, 第二页物理地址是0x1003 … 下同. 它们对应物理地址前4MB.
根据swapper_pg_dir的第0x0项和pg0的内容,这个临时页表所代表的地址空间中,0~4MB-1的空间被映射的物理地址空间范围是什么?
显然是物理地址0~4MB-1
若内核地址空间从3G开始,那么填写在swapper_pd_dir中第0x300项和0x301项的内容是什么,与上述第0项和第1项有什么关系,有什么含义?
第0x300项(768项)与0x301项(769项)分别和0x000项与0x001相同,分别为0x567067和0x568067,这是为了实模式到保护模式的平稳过度,在启用分页后可以继续执行.
swapper_pg_dir包含的1024个页目录项,前768指向用户空间,后256指向内核空间

 

 

怀北滑雪记

周末,翘课玩魔兽同学有幸去了怀柔滑雪场,分享下.

由于是第一次滑雪,去之前翘课做了大量的准备工作:带足了巧克力,红牛,黑卡一类功能性食物和饮料,并多带了一双袜子(网上教的,不知道为什么,带上先).上午九点半准时入场,拿兑换券领到一卡通,开始换取租赁的滑雪服,滑雪鞋和双板滑雪板.换好以后,一切收拾妥当,冲进雪里. 准备尝试第一个赛道: 儿童道! 长200米,坡度为6度.
被升降机带到坡顶, 我小心翼翼的握紧滑雪杖,回想起google告知的片段:下蹲,降低重心,握住金属杖用力向后撑,一下,两下,动了!加速了! 欣喜之余继续重复着新学的动作,随着速度越来越快,我突然想到一个问题: “怎么减速呢?!没学?!” 卧槽!这下囧了, 就在我思考的几秒钟内,速度越来愈快, 大脑一片空白,最后选择了一个比较帅的姿势跳起来向后转身,然后趴在雪坡上向前滑行三米的刹车方式,一时间有个工作人员冲过来,帮我捡起被KO后掉落的物品: 登山杖. 看见我一副很犀(chuo)利(bi)的样子,语重心长的对我说:”下次你要倒的时候记得提前跟被撞的人说一声.”
我默:”OK, 没问题!但是我应该怎么减速呢?”
“内八字就行”
“好,谢谢!” 我拿起手杖重新排队进入升降机.
第二次进入儿童道, 告诉自己:感受一下,雪. 下蹲,走你! 这次比第一次更加小心, 加速,内八字, 速度果然没起来, 而不幸的是,一个妹子似乎重走了我第一次的覆辙, 更不幸的是,她笔直的冲向我. 于是我再次紧张的无法用言语形容, 然后身体僵硬的倒了下去….

又经过两轮的练习, 初步掌握了几点要领:另外,内八字的减速滑法只有在初级道才管用, 因为速度快到一定程度的话唯一的减速方法是走”S”型路线. 继续在儿童道实验了下,加速,向左转弯,减速,再加速,再向右转弯,再减速. 成功了! 正当我欣喜的时候,旁边缓缓的冲下去一个妹子,全身红色衣服,另加一个红色头盔,这分明是电影里的恐龙特急克塞号的人间大炮啊! 不过你这前仰后合双手撑雪的机器舞姿势实在让我接受不能啊,对不起,我没忍住, 于是我又以一个自认为比较帅的姿势,跳起来,转身, 趴下…..原谅我笑点太低.

几次的下坡经历让我获得了一些自信,我深深赶脚已经不能再沉沦与儿童赛道了!于是颠颠地跑去挑战中级赛道,11度的坡度,长300米左右,赛道跟儿童级赛道是相连的,也就是说中级赛道的底端是儿童赛道的最高点.
再来!我又一次冲下雪道,可是我万万没想到,加速快的让人难以想象,我在两秒钟内达到了极快的速度,然后努力的转弯试图减速.然后我发现转不动,是的,转不动,大脑再次空白了,身体僵硬,还在加速,怎么办? 老子摔! 于是我这再次…. 算了不说了, 这次的滑行距离大约有10米. 不过摔的很爽!穿着滑雪服,在有意识的摔倒的情况下一般是不会痛的. 这在我接下来下坡的几次摔倒经历中得到了论证, 而最后一次我终于以S型走位终于刹住车了,再次欣喜若狂,但是左看右看,发现我已经滑到儿童道上去了….

至此整个上午我仅仅说过三句话:
1. 让一下让一下!
2. 啊……
3. 对不起!

扯淡结束, 如果你想去滑雪的话, 只需要额外带一双厚袜子就可以了,因为滑完鞋子会湿到里面.其他没有.对了,可以带一只杯子,滑雪场一般有热水.

番外:极品的是又一次我在悠然自得的S型路线上驰骋,然后直通通的装上了一个原地休息的兄弟,放眼望去,整条道上就我们俩.holy shit! 我真是奇葩….

KVM源代码阅读笔记

暂时以x86为例子,下同,KVM在X86下表现为一个驱动. 这里主要讨论AMD的svm,驱动代码主要位于arch/x86/kvm/svm.c. 英特尔的vmx也会顺带提及.不多说,直接上干货!

加载驱动模块svm.ko -> module_init(svm_init) (svm.c)加粗括号内为函数所在文件名或路径,下同.

svm_init(kvm_init)
     调用kvm_init(kvm_x86_ops,sizeof (struct vcpu_svm))(virt/kvm/kvm_main.c)
开始初始化,参数为kvm_x86_ops(x86.h)
intel的vmx.c中的初始化函数同样会调用kvm_init(),只是参数kvm_x86_ops, sizeof struct vcpu_svm/vcpu_vmx不同.

至此OS得到:
1. kvm_x86_ops(svm.c)中预定义的N多函数.
2. vcpu_svm(kvm_svm.h)我们需要用到它的大小(size)作为参数
3. 调用kvm_init(kvm_main.c)

继续,kvm_init()首先调用了kvm_init_debug(),它:
创建了一些debug entry, kvm_stats_debugfs_item结构体在x86.c中初始化,之后kvm_init()开始调用kvm_arch_init(opaque)(x86.c),

  • 使用传入的kvm_x86_ops参数,留心下会发现这个东西是通过一个void *类型的指针opaque传入的(svm.c).
  • 进入kvm_arch_init(opaque),首先它检测当前的OS是否支持kvm并初始化 kvm_x86_ops全局指针,然后调用kvm_mmu_module_init()(mmu.c)
    • 这个函数初始化了三个暂存的cache,然后调用kvm_init_msr_list()(msr的全称为machine specific registers)它通过rdmr_safe()把msr保存到全局变量msrs_to_save[]数组.
  • 回到kvm_arch_init()(x86.c),调用kvm_mmu_set_mask_ptes()(mmu.c)
    至此,kvm_arch_init()结束返回.

之后返回到kvm_init().调用kvm_arch_hardware_setup()(x86.c),实际上调用的是 kvm_x86_ops->hardware_setup(),仍以svm为例,假设我们使用svm.c中的kvm_x86_ops连接了参数结构 体,则需要跳至svm.c中的svm_hardware_setup()函数(intel的vmx则是vmx.c中的 hardware_setup())

  • 进入svm_hardware_setup()分配两个内存页,然后两页全部填充1,之后再init_msrpm_offsets()申请一个全局内存页变量,同样全部填充1,注意第二次申请页时调用了set_msr_interception()对可以拦截的MSR进行设置标记.
  • 然后通过宏对每一个虚拟cpu调用svm_cpu_init()(for_each_possible_cpu(cpu))
    • svm_cpu_init()
      1. 为传入的cpu分配一个svm_cpu_data结构体sd
      2. 为sd的cpu字段初始化
      3. 为sd的saved_data变量分配一个页面

 

  • per_cpu(svm_data, cpu) = svm_data (include/asm-generic/percpu.h)展开宏定义
    • per_cpu(var, cpu) => (*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu))) => #define SHIFT_PERCPU_PTR(__p, __offset)
      ({ __verify_pcpu_ptr((__p));
      RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
      })
      最终调用了RELOC_HIDE(include/linux/compiler-gcc.h) 猜想可能是一个隐藏重定位用的
  • svm.c文件的起始位置有行代码static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);(include/linux/percpu-defs.h)会在运行时在栈空间创建名与svm_data相关的几个系统变量.
  • 我们的目标是应该可以通过调用per_cpu(svm_data,cpu)可以获取当前cpu变量(描述结构体),而为了cpu值则可以通过调用get_cpu_var()(include/asm-generic/percpu.h)获取.为了达到这一目的,我们需要对每一个虚拟cpu做如下操作
    per_cpu(svm_data, cpu) = svm_data
  • 这时每个虚拟cpu均被初始化,进而保证以后每当调用per_cpu()的时候能找到当时存在这里的svm_cpu_data和svm_data->save_data. (貌似说太多了,其实就是初始化)
    为了以后可以这么用
    int me = raw_smp_processor_id();
    sd = per_cpu(svm_data, me);

再次返回kvm_init()(kvm_main.c)对每一个online的cpu调用smp_call_function_single(cpu,kvm_arch_check_processor_compat,&r,1);

  • 先看kvm_arch_check_processor_compat,它返回 kvm_x86_ops->check_processor_compatibility.进入svm.c看这个void函数发现它仅仅强制参数指针指向的值转换为0,所以还是关心smp_call_function_single()(kernel/smp.c)好了,它让第一个参数指定的cpu运行第二个参数传入的回调函数,即刚刚提到的check_processor_compatibility, smp_ops.smp_call_function_mask(mask, func, info, wait)

之后再次回到kvm_init()(kvm_main.c),调用register_cpu_notifier(&kvm_cpu_notifier)注册cpu状态变化的通知函数

  • 注册kvm_cpu_notifier回调函数.notifier_call = kvm_cpu_hotplug,
  • kvm_cpu_hotplug
    • 分别处理CPU_DYING, CPU_UP_CANCELED 与 CPU_ONLINE三种通知,并使能或禁止cpu虚拟化特性
    • hardware_enable
      • hardware_enable_nolock()
        • kvm_arch_hardware_enable()
    • hardware_disable

然后注册重启通知函数,原理同上.留着重启的时候运行.

通过kmem_cache_create()(mm/slab_common.c)创建sizeof(vcpu_size)大小的内存,猜测这个函数可以满足内存的对齐要求.

然后把早先传给kvm_init()的参数THIS_MODULE,也就是svm的模块名分别赋值给三个file operation结构体变量:
    kvm_chardev_ops.owner = module;
    kvm_vm_fops.owner = module;
    kvm_vcpu_fops.owner = module;
这三个变量都是file_operation结构体被部分初始化的全局变量,分别用户处理对不同介质的设备读写(一切皆是文件).被部分初始化的函数入口地址分别指向
kvm_dev_ioctl,kvm_vm_release,noop_llseek等函数(kvm_main.c)熟悉设备驱动的同学们应该不会感到陌生.

之后,调用misc_register()(drivers/char/misc.c)注册一个主设备号为10,次设备号为232的misc设备.随后把kvm的一些比较核心的函数注册到

  • syscore_ops结构体,包括resume,suspend,
  • preempt_ops结构体,包括kvm_sched_in,kvm_sched_out

后者(preempt_ops)是结构体kvm_preempt_ops的变量,从命名方式看,这两个函数可以申请调度器对任务的换入换出进行通知.

最后调用kvm_init_debug(),忘了说,kvm模块的加载依赖debugfs,所以在加载之前要手动挂载之,好在目前流行的发行版几乎都会开启了debugfs支持.这个函数建立了debugfs目录下的kvm目录,然后建立了一系列复杂的tracepoint,这里就不展开讲了.

至此,初始化完成.

参考资料:

  1. KVM : SMALL LOOK-INSIDE
  2. Linux内核源代码kvm树, 下载点这里

dell E6430 修复记

事先声明,这篇没有任何干货,是全凭windows经验进行修复的流水账.

公司发了戴尔的高配latitude E6430,配置了第三代的i7, 8G内存, 500GB硬盘和1G显存的NV显卡(这个对于Linux简直是灾难,后面会谈), 外部报价1w1左右. 可惜不能连外网. holy shit!! 这尼玛是严重的资源浪费! 安全软件是赛门铁克和趋势科技哼哈二将.撇开自娱自乐的趋势科技不谈,赛门铁克真是在windows防火墙上下足了功夫,流行的各种安全软件都不能干掉它几个相互关联的守护进程,卸载退出需要密码,而且给用户仅仅enable了一个客户端,nac(network access control)更是没戏.我做了试着在注册表里删掉了symantec的退出验证, 运行smc -stop,欣喜的是赛门铁克关了成功连接了家里的wifi,蛋疼的是依旧上不了网,不停的有数据包送到,但就是发不出去.之后我修改赛门铁克的策略,这个实属下策了,因为策略文件长的让人发指,要研究透了它可不容易.操作如下,导出策略文件xxx.policy,打开,把本来应该丢弃的ip段访问从丢弃改为通过.导入之,开始运行,好么,是不报错了,但是赛门铁克直接提示无法提供完全保护.担心这段日志被上报,于是赶紧把之前的策略导回来.这个方案让我看到了曙光,但需要进一步改进.

最终方案: 双系统.这个是最先应该想倒的,也是最先做的.一个月前就装了ubuntu,但是前几天系统总出现各种奇葩问题:

1. 安装virtualbox后每次启动都会提示一个模块无法初始化,需要手动启动.
2. 显卡驱动(NV5200)3D特效莫名其妙消失了,出于蛋疼,去官网更新了NV驱动,3D特效回来,心想果然闭源的驱动还是不靠谱,
3. 没过两天,系统不能关机了.表现为开机后alt+ctrl+f1显示黑屏(有一个cursor在屏幕左上角闪),而alt+ctrl+f2正常进入控制台.虽然不影响使用,但是关机时系统hang住(偶尔,很偶尔关机会表现为注销),这时alt+ctrl+del热启动有效.忽视之.又没过几天热启动无效,每次关机都需要长按电源键.在持续了近一个星期的这种关机方式之后,我顿时觉得这是对IT从业人员的一种侮辱.
于是尝试进行修复:
1. 第一个问题很常见,virtualbox(以下简称VB)在软件源里更新不及时,添加官方源后重新安装即可,但是之前VB所建立的数据似乎向下兼容性问题很大,表现为新版本VB打开之前的虚拟机镜像后Guest OS的CPU usage几乎稳定在90%以上.换了几个模拟方式,问题依旧,期间还蓝屏好几次.于是只好放弃之前的旧数据,重新安装了新的image.正暗自庆幸问题解决,没过两天老问题又出现了,这让我一口老血喷了一墙.放弃治疗.
2. 显卡驱动重新安装后运行良好,但是安装期间的一行日志引起了我的注意,就是NV重新编译了内核,好让NV显卡替代之前的板载显卡,其实就是dkms把NV的一个驱动模块设置为了开机启动启动,可是VB的核心模块同样需要dkms开机自动启动,更何况我每次启动VB的时候做的就是这个操作,于是怀疑NV显卡和VB冲突.选择卸载NV驱动,安装开源驱动.
3. 不能关机的问题我实在摸不着北,试着在启动参数里加了acpi=off, 仍未解决,怀疑前两个问题导致,卸载NV驱动后仍然不能关机,聊以慰藉的是系统关机hang住的时候按电源键时可以被OS捕获,也就是说可以正常关机了.
目前状态: VB问题依旧, NV显卡驱动被卸载后系统无特效, 关机不正常.
我擦, 折腾了半天一个问题都没解决.
重新安装NV闭源驱动,安装完成后发现仍然没有3D特效, 艹! 放弃治疗,do-release-update!重启后发现出现了键盘偶尔连击,没错,按一个钮,比如a,屏幕出现一排a.果断不能忍.重装系统!

手上有三张iso,一个是Ubuntu 12.04 lts,两个是Ubuntu 11.10 alternate release,后者提供了更多的功能,比如硬盘加密,LVM等,于是选择安装后者,当然主要原因还是在于之前那个糟心的系统是12.04(心理阴影). 备份数据后,安装过程无任何异常,但是重启进入新系统后,擦,黑屏! 第一反应是我的iso有问题, 于是换了另一张11.10重装,重启进入新系统,依旧黑屏!!无奈了,换12.04装吧,没想到这个iso在初始化界面就直接悲剧了.
考虑到之前报废的系统也是用这个iso装的(也许是我打开的方式不对),试着把它烧到U盘里安装,问题依旧.猜想可能是dell BIOS的问题,因为我上个月进行过一次升级.可这么大的bug戴尔不能任由它作死吧?给戴尔客服打电话,语音提示今天是周六,非工作日,人家不上班,好吧,还得靠自己搞定.
又用上述介质试了一遍,问题依旧,经验告诉我,需要翻出内核启动参数列表了,仍然是12.04,在初始化的时候加入了acpi=off和noapic两个参数,哎,竟然启动了.安装好,重启进系统,黑屏依旧!!!
目前的情况是,11.10安装后黑屏,12.04后启动时黑屏,但是通过禁止电源管理和禁止中断的内核参数可以启动,安装后同样黑屏.那索性启动内核的时候同样加这两个参数好了,进入grub列表,编辑,顺利启动,终于能上网了,第一时间查看了戴尔官网,发现果然有BIOS升级包了.亏你还在笔记本上贴了Ubuntu的logo,坑啊.

后记,这次NV果断选择了源里的驱动,虽然旧点,虽然依旧没有3D特效,但是总比这么折腾强.虚拟机选择virsh了,虽然翘课之前是做KVM的,总用Oracle的东西似乎不太合适(VB确实好用). 安装完firefox的flash-plugin后,发现3D回来了.人品爆发!!撒花!!!

一切的一切,是为了双十一啊, 有了外网我才能抢宝贝啊!!!!购物车已经塞满了啊!!!!

11月11日下午五点半.

合用路由器(续)

路由器(这里说的是无线路由,下同)的工作模式分为两种:路由模式,AP模式;
路由模式你肯定不陌生,家里ISP提供的那根网线就是通过路由模式拨号上网的。这个流程是 ISP -> MODEM -> ROUTER -> PC;当然还有3G路由模式,也属于这一类。
AP模式稍微复杂些,它又分为:
1. AP模式(废话),简单说来,就是给有线网加无线信号覆盖,典型场景是酒店。以我的TP-LINK WR720N为例(下同),默认情况下AP模式不开启DHCP服务,没有密码,而且即插即用,不多说。
2. 客户端模式,这个也比较简单,Client模式相当于无线网卡,用网线和PC连接好即可,下面才是重头戏。
3. 中继模式
4. 桥接模式
这两个模式需要放在一起说了。按字面意思理解,中继就是两个设备之间信号强度不够的时候加一个中继信号放大器,增强信号质量,方便远距离传输。而桥接模式是指两个设备之间彼此绑定MAC地址后直接建立连接,可以点对点也可以点对多点。如果学过计算机网络,你会知道,专业一点的解释,桥接是局域网到局域网的桥接,是不穿越网络层的传输,另外,中继连接的是同种网络传输协议,桥接则相反。

补充:提到这两个模式不得不提的就是WDS了,通过中继或者桥接模式组网形成的无线网络架构,目前市面上的路由器几乎大都支持,当然不同厂家不同型号的路由器建立WDS可能会悲剧。需要注意的是:所有WDS接入的路由设备都必须使用相同的信道,加密方式,密码(如果有的话)。基于桥接的WDS需要设定相同的SSID以及相同的无线信道,中继WDS的缺点在我上一篇博客也提到过,就是带宽减半,因为要同时桥接和接受无线客户端数据。

具体的设置方法请看这里