即刻启程
0昨天到科创中心走完了离职的最后流程。2008.3.24怀揣着500块提着箱子开始实习。五年后忘了挥衣袖,带走了一床薄被,一个杯子。
加入时公司200人,离开时已经到1300多人,在金融基地前台墙上,已经很难再从容的挂上新的公司全家福。在我职业生涯的第五个年头,也是在Sangfor的第五个年头,我走下了这趟快速行驶的列车,踏上新的旅程。是离别就需要拿出勇气去告别旧的朋友、稳定的环境、还有一段旧的时光。也就必然有着反复而漫长的反省和思考,关于昨天、当下和未来。结果是在离职原因写上:
在踏入婚姻坟墓的之前,是时候作出一些改变,换另一种方式继续提升自己。磨剑五年,带着所学开始出去闯荡。
准备创业了!
这不是一时热血的鲁莽。毕业当年,指点前程,信誓旦旦,大有不创伟业誓不还的气势,借用毛的诗:
孩儿立志出乡关,不取功名誓不还. 埋骨何须桑梓树,人生无处不青山.
毕业视频上放言,四十岁之前赚到一千万!如今看来虽有偏颇之处,但创业的念头疾风中之劲草,当时间越逼近当年计划的五年沉积之末时,愈发强烈。万事俱备之时难侯,韶华之期易逝。与其空等水到渠成,不如现在开始吧。
临别前,我作了一次尝试:
——一次机会
何老大:
2008.3.24进入深信服,如今已五载,是时候作一个总结。在发这封邮件之前,我已经提交了离职信,如离职原因所言,“在进入稳定的婚姻坟墓前,是时候作出一些改变,换另一种方式继续提升自己”。五年磨剑,我准备带着从深信服学到的东西开始出去闯荡。一般讲来,一个良好运转的普通员工离职不会起太多波澜,更不至于惊动到您,您将继续领导深信服前行,而我将面对真实的创业环境,野蛮生长。但过往的经历让我知道,努力尝试加上缘分,可能会产生意外。
我想做一次冒昧的尝试:请老板吃一次饭。饭是普通的饭,但将赤诚以对,知无不言,对我来说将是一次非凡的经历,希望对您也会有一些帮助。我愿意谈谈我自己和在深信服的这些年,谈谈对未来的看法。少数杰出的员工可以带领公司前行,这个群体是公司关注较多的。但多数像我这样普通的员工是公司前进的划桨者,公司虽偶有员工访谈,但我相信有一些肺腑之言还留在了心里。您也可以谈谈你自己,谈谈在深信服的这些年,谈谈作为一个创业者是如何成长起来的,这些将成为我人生中不可多得的指导经验,照耀我的奋斗之路。 这是一次机会。
您事务繁多,我能接受任何答复。不管如何,在此表达一位创业新手对一位老将的崇敬之情!廖伟强
2013.4.28
当然得到的答复不出意料
——Re:一次机会
很抱歉没有及时回复你的邮件,也非常遗憾深信服无法为你提供进一步发展的机会。
同时也祝福你创业路上取得大的成就。每一个深信服的同事取得人生的成功(不管是不是在深信服取得的),都是令我感到骄傲的事情。吃饭就免了,你可以随时来找我聊一聊,也可以书面和我沟通,我也愿意倾听你对深信服过去和未来的一些看法,包括分享一些自己的经历。
新的办公室已经租好,24平方丈之地将是另一场奋斗的起点,外包(www.etopshine.com)起步练手,即刻启程!
PHP REST框架开源项目prest
0源代码托管地址:https://github.com/hellolwq/prest
作者:顶烁科技
特性描述:
本API目前测试的是Linux+Apache+Mysql+PHP环境,其它环境暂时没有测试。
1、api与类方法一一对应,方便快速添加。
2、支持api类方法参数检查。
3、支持权限检查。
4、支持ticket生成、校验,可防止被中间人盗用。
5、支持API自定义缓存时间。
6、继承restdb可使用默认数据库方法。
一、配置Apache支持.htaccess文件
AllowOverride All
Options FollowSymLinks
二、配置rest/inc/config.php
三、使用rest.sql建立数据库
1、登录帐号http://host/rest/user/login?uname=test&passwd=test
2、测试其它接口http://host/rest/user/add?uname=test&passwd=test
四、添加接口
在rest/handlers目录添加对应类文件和静态方法即可。
比如,需要添加http://host/rest/foo/test?arg1=xxx&arg2=xxx&xxx接口。
参数目前可以通过querystring或是post方式传入。
添加foo.php文件
类
class foo{
public function test($arg1,$arg2...)
{
auth::check_permission(ROLE_ADMIN);/*检查该方法要求的权限*/
#logic about $obj
....
return new response(array('body'=>$obj,’cache’=>’5′));
}
}
目前返回对象支持:
body:返回正文对象,可以是任何的变量,将转换成json格式返回。
cache:缓存秒数,默认为无缓存。
header:自定义头部对象,里面是key=>value对的数组。
code:返回的http状态码。
五、自定义路径映射
修改config.php变量,加入映射关系。
$g_maps = array(
…,
‘/abc/test’=>array(
‘class’=>’foo’,
‘method’=>’test’
)
)
TODO LIST
1、按http规范,对有副作用影响接口强制要求使用POST/DELETE/PUT 等方法。
2、补充功能函数,目前只添加了对mysql数据库的基本操作。
一道正则表达式题
0Elance.com的PHP水平测试,其中有一个题目是这样的:
Write a function declared as function ReformatPhoneNumber($number), whose argument will contain string data representing some phone number data (entered by the user). A valid phone number may consist of
between 7 and 12 digits (0..9). Assume that in between some adjacent digits there may optionally appear either a single space, or a single hyphen (-). Any other phone number should be considered invalid.
If the phone number is valid, the return value of your function should contain a string containing between 7 and 12 digits, representing the same phone number after removing all hyphens and spaces. If the
phone number is invalid, throw a standard PHP5 Exception initialized with the text “Invalid phone number”.
The first and the last character of the string should be a number.
For example, after calling ReformatPhoneNumber(’012-345 69′) the return value should be ’01234569′. Calling the function with any of these values: ’012345′, ‘-012345 678′, ’01203- 34566′, ’123456678875432′,
’1234×567′ should result in an exception.
该题的关键部分是效验用户输入的电话号码是否合法,因可能因为有意或无意的原因,得到的结果可能是不正确的,不能信任用户、前端的任何输入。因此这里要根据下面的规则判断输入是否为合法的电话号码:
- 电话号码由7-12位数字组成,每位数据是0-9.
- 数字中间可以由-或是空格作分隔符,但是数字只间只能有一个分隔符号,不能出现a b,a–b,a- b这种多个分隔符的情况。
- 开始和结尾只能是数字。
分享下解题思路:
- 因为这里的判断条件较多,直接使用字符操作可能较复杂,首选正则表达式。
- 字符串的规律是数字开始,后面-、空格和数字组合的重复,在正则表达式里面可以*,+,{a,b},?等限定。
- 为了避免有多个分隔符,要求分隔符后立即接数字,因此该组合应该是[- ]\d,事实上分隔符号不是必须的,因此修改为[- ]?\d。结合推理项2,在不考虑长度的情况下,即为^\d([- ]?\d)*,这个表达式有个。该正则表达式,正好还满足了结尾必定是数字。
- 最后,考虑电话号码数长度为7-12的情况,因为这个正则表达式是一个数字和数字、分隔符号组合重复(事实上该组合只包含一个数字),那么只要限制组合的个数就可以限定数字的总长度了。于是正则表达式的最终值为:
^\d([- ]?\d){6,11}$
function ReformatPhoneNumber($phone)
{
if(!preg_match('/^\d([- ]?\d){6,11}$/', $phone))
throw new Exception('input valid!');
return preg_replace('/[ |-]/','',$phone);
}
echo ReformatPhoneNumber("1-234678");
老师托梦
0昨日与DH、WSC夜游南山后,骑车、拍照 ,玩的尽兴、累得扎实,十一点半才归来,洗澡完倒头便睡了。
本该是一个酣畅淋漓的大觉,却因为一个梦,终于煎熬不住,早上七点前便醒来,再无睡意。
回想梦中之事,唏嘘不以,推推旁边的linger,迫不及待的想要与她分享。无奈死猪一只,只得独自己品尝。
数学课堂上,胡忌老师在分发作业本。因为往日作业批改完只看各项是否完成,打一勾了事。这回却是逐题修改评分。喊一个名字,报一下分数,气氛有些紧张。我的作业是胡乱填写的,一直相安无事,混过了好些日子。此刻,我像个做错事的孩子,等待着即将到来的惩罚。当着全班的丢尽总不是件体面的事,却又不知除了这般,又会是怎么的结果,种种揣测下,惶恐不安。一番胆颤心惊后终于轮到我,先生翻阅作业,一脸凝重,厉声道:22分,全班最低分!请注意:这不是鼓励,是耻辱!
一个战栗,瞬间从梦中惊醒,背后阵阵凉意。
胡老师是我小学恩师,得其帮助,我曾迷途知返。十多年后,当我再次迷茫,居然于梦中再次受此当头棒喝,冥冥之中似有天意。回想当下的碌碌无为,大概是我的作业本上交的都是混日子的胡填乱写。真正的答案,在蹉跎中一次次擦肩而过,我玩乐中醉生梦死中,视而不见。
QEMU的HACKING文件
0qemu工程根目录下的HACKING文件,不仅适用于修改开源项目,写所有程序的时候都应该保持同样的良好习惯。
1. Preprocessor
For variadic macros, stick with this C99-like syntax:
#define DPRINTF(fmt, …) \
do { printf(“IRQ: ” fmt, ## __VA_ARGS__); } while (0)2. C types
It should be common sense to use the right type, but we have collected
a few useful guidelines here.2.1. Scalars
If you’re using “int” or “long”, odds are good that there’s a better type.
If a variable is counting something, it should be declared with an
unsigned type.If it’s host memory-size related, size_t should be a good choice (use
ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
but only for RAM, it may not cover whole guest address space.If it’s file-size related, use off_t.
If it’s file-offset related (i.e., signed), use off_t.
If it’s just counting small numbers use “unsigned int”;
(on all but oddball embedded systems, you can assume that that
type is at least four bytes wide).In the event that you require a specific width, use a standard type
like int32_t, uint32_t, uint64_t, etc. The specific types are
mandatory for VMState fields.Don’t use Linux kernel internal types like u32, __u32 or __le32.
Use target_phys_addr_t for guest physical addresses except pcibus_t
for PCI addresses. In addition, ram_addr_t is a QEMU internal address
space that maps guest RAM physical addresses into an intermediate
address space that can map to host virtual address spaces. Generally
speaking, the size of guest memory can always fit into ram_addr_t but
it would not be correct to store an actual guest physical address in a
ram_addr_t.Use target_ulong (or abi_ulong) for CPU virtual addresses, however
devices should not need to use target_ulong.Of course, take all of the above with a grain of salt. If you’re about
to use some system interface that requires a type like size_t, pid_t or
off_t, use matching types for any corresponding variables.Also, if you try to use e.g., “unsigned int” as a type, and that
conflicts with the signedness of a related variable, sometimes
it’s best just to use the *wrong* type, if “pulling the thread”
and fixing all related variables would be too invasive.Finally, while using descriptive types is important, be careful not to
go overboard. If whatever you’re doing causes warnings, or requires
casts, then reconsider or ask for help.2.2. Pointers
Ensure that all of your pointers are “const-correct”.
Unless a pointer is used to modify the pointed-to storage,
give it the “const” attribute. That way, the reader knows
up-front that this is a read-only pointer. Perhaps more
importantly, if we’re diligent about this, when you see a non-const
pointer, you’re guaranteed that it is used to modify the storage
it points to, or it is aliased to another pointer that is.2.3. Typedefs
Typedefs are used to eliminate the redundant ‘struct’ keyword.2.4. Reserved namespaces in C and POSIX
Underscore capital, double underscore, and underscore ‘t’ suffixes should be
avoided.3. Low level memory management
Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
APIs is not allowed in the QEMU codebase. Instead of these routines,
use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
g_new0/g_realloc/g_free or QEMU’s qemu_vmalloc/qemu_memalign/qemu_vfree
APIs.Please note that g_malloc will exit on allocation failure, so there
is no need to test for failure (as you would have to with malloc).
Calling g_malloc with a zero size is valid and will return NULL.Memory allocated by qemu_vmalloc or qemu_memalign must be freed with
qemu_vfree, since breaking this will cause problems on Win32 and user
emulators.4. String manipulation
Do not use the strncpy function. According to the man page, it does
*not* guarantee a NULL-terminated buffer, which makes it extremely dangerous
to use. Instead, use functionally equivalent function:
void pstrcpy(char *buf, int buf_size, const char *str)Don’t use strcat because it can’t check for buffer overflows, but:
char *pstrcat(char *buf, int buf_size, const char *s)The same limitation exists with sprintf and vsprintf, so use snprintf and
vsnprintf.QEMU provides other useful string functions:
int strstart(const char *str, const char *val, const char **ptr)
int stristart(const char *str, const char *val, const char **ptr)
int qemu_strnlen(const char *s, int max_len)There are also replacement character processing macros for isxyz and toxyz,
so instead of e.g. isalnum you should use qemu_isalnum.Because of the memory management rules, you must use g_strdup/g_strndup
instead of plain strdup/strndup.5. Printf-style functions
Whenever you add a new printf-style function, i.e., one with a format
string argument and following “…” in its prototype, be sure to use
gcc’s printf attribute directive in the prototype.This makes it so gcc’s -Wformat and -Wformat-security options can do
their jobs and cross-check format strings with the number and types
of arguments.
使用QEMU Trace
0QEMU提供了trace机制跟踪关键内部关键步骤执行流程,用于性能问题排查、了解内部执行流程。详细的使用方法在qemu的文档目录:
qemu-kvm-1.2.0-rc2\docs\tracing.txt
实际使用的过程中有有几点需要作修改方能正常使用:
- 需要在qemu-kvm命令行里面加trace参数,我们一般用的是libvirt提供的virsh命令,解析虚拟机配置文件后间接操作qemu-kvm,无法加入额外的参数,可以使用命令行的方式执行qemu-kvm,参数参考虚拟机正常运行时ps -aux | grep qemu获取的结果,注意要把-S去掉,不然虚拟机会在启动之前阻塞住。
- 使用libvirt时,生成的trace文件一般在/var/lib/libvirt/images/下,实在没找到可以使用find / -name trace*pid*命令查找。trace文件一般是已经trace-pid的命令方式存在,文件中的日志信息以二进制格式存在,不能直接查看。
- 执行./simpletrace.py ../trace-events /var/lib/libvirt/images/trace-16601可以输出可读的跟踪信息。注意:“../trace-events” 指的是“/usr/lwq/soft/kvm/qemu-kvm-1.2.0/trace-events” 而非/tmp/events文件。
tracing.txt原文如下:
= Tracing =
== Introduction ==
This document describes the tracing infrastructure in QEMU and how to use it
for debugging, profiling, and observing execution.== Quickstart ==
1. Build with the ‘simple’ trace backend:
./configure –enable-trace-backend=simple
make2. Create a file with the events you want to trace:
echo bdrv_aio_readv > /tmp/events
echo bdrv_aio_writev >> /tmp/events3. Run the virtual machine to produce a trace file:
qemu -trace events=/tmp/events … # your normal QEMU invocation
4. Pretty-print the binary trace file:
./simpletrace.py trace-events trace-*
== Trace events ==
There is a set of static trace events declared in the “trace-events” source
file. Each trace event declaration names the event, its arguments, and the
format string which can be used for pretty-printing:qemu_vmalloc(size_t size, void *ptr) “size %zu ptr %p”
qemu_vfree(void *ptr) “ptr %p”The “trace-events” file is processed by the “tracetool” script during build to
generate code for the trace events. Trace events are invoked directly from
source code like this:#include “trace.h” /* needed for trace event prototype */
void *qemu_vmalloc(size_t size)
{
void *ptr;
size_t align = QEMU_VMALLOC_ALIGN;if (size < align) {
align = getpagesize();
}
ptr = qemu_memalign(align, size);
trace_qemu_vmalloc(size, ptr);
return ptr;
}=== Declaring trace events ===
The “tracetool” script produces the trace.h header file which is included by
every source file that uses trace events. Since many source files include
trace.h, it uses a minimum of types and other header files included to keep the
namespace clean and compile times and dependencies down.Trace events should use types as follows:
* Use stdint.h types for fixed-size types. Most offsets and guest memory
addresses are best represented with uint32_t or uint64_t. Use fixed-size
types over primitive types whose size may change depending on the host
(32-bit versus 64-bit) so trace events don’t truncate values or break
the build.* Use void * for pointers to structs or for arrays. The trace.h header
cannot include all user-defined struct declarations and it is therefore
necessary to use void * for pointers to structs.* For everything else, use primitive scalar types (char, int, long) with the
appropriate signedness.Format strings should reflect the types defined in the trace event. Take
special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
respectively. This ensures portability between 32- and 64-bit platforms.=== Hints for adding new trace events ===
1. Trace state changes in the code. Interesting points in the code usually
involve a state change like starting, stopping, allocating, freeing. State
changes are good trace events because they can be used to understand the
execution of the system.2. Trace guest operations. Guest I/O accesses like reading device registers
are good trace events because they can be used to understand guest
interactions.3. Use correlator fields so the context of an individual line of trace output
can be understood. For example, trace the pointer returned by malloc and
used as an argument to free. This way mallocs and frees can be matched up.
Trace events with no context are not very useful.4. Name trace events after their function. If there are multiple trace events
in one function, append a unique distinguisher at the end of the name.== Generic interface and monitor commands ==
You can programmatically query and control the dynamic state of trace events
through a backend-agnostic interface:* trace_print_events
* trace_event_set_state
Enables or disables trace events at runtime inside QEMU.
The function returns “true” if the state of the event has been successfully
changed, or “false” otherwise:#include “trace/control.h”
trace_event_set_state(“virtio_irq”, true); /* enable */
[...]
trace_event_set_state(“virtio_irq”, false); /* disable */Note that some of the backends do not provide an implementation for this
interface, in which case QEMU will just print a warning.This functionality is also provided through monitor commands:
* info trace-events
View available trace events and their state. State 1 means enabled, state 0
means disabled.* trace-event NAME on|off
Enable/disable a given trace event or a group of events having common prefix
through wildcard.The “-trace events=” command line argument can be used to enable the
events listed in from the very beginning of the program. This file must
contain one event name per line.A basic wildcard matching is supported in both the monitor command “trace
-event” and the events list file. That means you can enable/disable the events
having a common prefix in a batch. For example, virtio-blk trace events could
be enabled using:
trace-event virtio_blk_* on== Trace backends ==
The “tracetool” script automates tedious trace event code generation and also
keeps the trace event declarations independent of the trace backend. The trace
events are not tightly coupled to a specific trace backend, such as LTTng or
SystemTap. Support for trace backends can be added by extending the “tracetool”
script.The trace backend is chosen at configure time and only one trace backend can
be built into the binary:./configure –trace-backend=simple
For a list of supported trace backends, try ./configure –help or see below.
The following subsections describe the supported trace backends.
=== Nop ===
The “nop” backend generates empty trace event functions so that the compiler
can optimize out trace events completely. This is the default and imposes no
performance penalty.Note that regardless of the selected trace backend, events with the “disable”
property will be generated with the “nop” backend.=== Stderr ===
The “stderr” backend sends trace events directly to standard error. This
effectively turns trace events into debug printfs.This is the simplest backend and can be used together with existing code that
uses DPRINTF().=== Simpletrace ===
The “simple” backend supports common use cases and comes as part of the QEMU
source tree. It may not be as powerful as platform-specific or third-party
trace backends but it is portable. This is the recommended trace backend
unless you have specific needs for more advanced backends.The “simple” backend currently does not capture string arguments, it simply
records the char* pointer value instead of the string that is pointed to.==== Monitor commands ====
* info trace
Display the contents of trace buffer. This command dumps the trace buffer
with simple formatting. For full pretty-printing, use the simpletrace.py
script on a binary trace file.The trace buffer is written into until full. The full trace buffer is
flushed and emptied. This means the ‘info trace’ will display few or no
entries if the buffer has just been flushed.* trace-file on|off|flush|setEnable/disable/flush the trace file or set the trace file name.
==== Analyzing trace files ====
The “simple” backend produces binary trace files that can be formatted with the
simpletrace.py script. The script takes the “trace-events” file and the binary
trace:./simpletrace.py trace-events trace-12345
You must ensure that the same “trace-events” file was used to build QEMU,
otherwise trace event declarations may have changed and output will not be
consistent.=== LTTng Userspace Tracer ===
The “ust” backend uses the LTTng Userspace Tracer library. There are no
monitor commands built into QEMU, instead UST utilities should be used to list,
enable/disable, and dump traces.=== SystemTap ===
The “dtrace” backend uses DTrace sdt probes but has only been tested with
SystemTap. When SystemTap support is detected a .stp file with wrapper probes
is generated to make use in scripts more convenient. This step can also be
performed manually after a build in order to change the binary name in the .stp
probes:scripts/tracetool –dtrace –stap \
–binary path/to/qemu-binary \
–target-type system \
–target-arch x86_64 \
<trace-events >qemu.stp== Trace event properties ==
Each event in the “trace-events” file can be prefixed with a space-separated
list of zero or more of the following event properties.=== “disable” ===
If a specific trace event is going to be invoked a huge number of times, this
might have a noticeable performance impact even when the event is
programmatically disabled.In this case you should declare such event with the “disable” property. This
will effectively disable the event at compile time (by using the “nop” backend),
thus having no performance impact at all on regular builds (i.e., unless you
edit the “trace-events” file).In addition, there might be cases where relatively complex computations must be
performed to generate values that are only used as arguments for a trace
function. In these cases you can use the macro ‘TRACE_${EVENT_NAME}_ENABLED’ to
guard such computations and avoid its compilation when the event is disabled:#include “trace.h” /* needed for trace event prototype */
void *qemu_vmalloc(size_t size)
{
void *ptr;
size_t align = QEMU_VMALLOC_ALIGN;if (size < align) {
align = getpagesize();
}
ptr = qemu_memalign(align, size);
if (TRACE_QEMU_VMALLOC_ENABLED) { /* preprocessor macro */
void *complex;
/* some complex computations to produce the ‘complex’ value */
trace_qemu_vmalloc(size, ptr, complex);
}
return ptr;
}
重用.config文件编译3.5.4内核
0内核编译会使用make menuconfig(或是xmenuconfig等替代方式)生式.config文件,用于配置内核需要编译的组件。因此在重新编译或是编译新的内核时可以使用该文件配置快速配置,同时保持原有的编译配置。.config文件在源编译目录下,或者为/boot/config-`uname -r`
假设该文件在/boot目录下,当前编译目录为/usr/src/new_kernel/。
完成内核编译前工具准备,内核源代码下载等工作,见:http://wiki.centos.org/HowTos/Custom_Kernel
使用如下步骤,使用原配置文件编译新内核:
- cp /boot/config-`uname -r` /usr/src/new_kernel/
- make oldconfig /*使用旧.config文件,配置新内核增加的特性*/
- make menuconfig /*检查下需要更改部分*/
- make && make install && make modules_install /*编译、安装内核*/
如果安装完重启后,出现下列错误:
modprobe FATAL could not load modules.dep
说明可能文件系统加载出错了,尝试把ata驱动加载到initrd.img里边,我这里从CentOS6.3的默认2.6.32-279.el6.x86_64内核升级到3.5.4:
mkinitrd -f –with=sd_mod –with=libata /boot/initrd-3.5.4.img 3.5.4
并更新/boot/menu.lst相应配置,然后重启。
内核启动进程初始化
0内核启动,进入保护模式后在位于sched.c的main->sched_init初始化启动进程,是系统的第一个进程。
static union task_union init_task = {INIT_TASK,};
…
struct task_struct *current = &(init_task.task), *last_task_used_math = NULL;
这里使用了INIT_TASK宏对启动进程进行赋值,
#define INIT_TASK \
/* state etc */ { 0,15,15, \
/* signals */ 0,NULL,{(fn_ptr) 0,}, \
/* ec,brk... */ 0,0,0,0,0, \
/* pid etc.. */ 0,-1,0,0,0, \
/* uid etc */ 0,0,0,0,0,0, \
/* alarm */ 0,0,0,0,0,0, \
/* math */ 0, \
/* fs info */ -1,0133,NULL,NULL,0, \
/* filp */ {NULL,}, \
{ \
{0,0}, \
/* ldt */ {0x9f,0xc0fa00}, \
{0x9f,0xc0f200}, \
}, \
/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
0,0,0,0,0,0,0,0, \
0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
_LDT(0),0x80000000, \
{} \
}, \
}
虽然linus在宏上给了一些标记来,但是我们还是通过对比task_struct 结构体来看一下,这个进程是如何初始化的。
struct task_struct {
/* these are hardcoded - don't touch */
long state; /* -1 unrunnable, 0 runnable, >0 stopped */
long counter;
long priority;
long signal;
fn_ptr sig_restorer;
fn_ptr sig_fn[32];
/* various fields */
int exit_code;
unsigned long end_code,end_data,brk,start_stack;
long pid,father,pgrp,session,leader;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
long alarm;
long utime,stime,cutime,cstime,start_time;
unsigned short used_math;
/* file system info */
int tty; /* -1 if no tty, so it must be signed */
unsigned short umask;
struct m_inode * pwd;
struct m_inode * root;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
struct desc_struct ldt[3];
/* tss for this task */
struct tss_struct tss;
}
通过结构体定义,基本可以看出初初始结构体的各状态。这里对初始化的数组结构ldt和tss进行解析。ldt是局部描述符表(local description table),用来描述进程内部的段信息,一般只有数据段和代码段。而tss则是任务段描述符号,描述当前任务信息,用于CPU在任务切换时使用。32位下段描述符使用8字节,Intel手册上对各位的描述的如下:
因此,对于LDT中描述的的数据段和代码段5-8字节相同,都是0x9F。
00000000 0000000000000000 10011111 0x9f 而1-4字节,只有limit部分是不相同的,即数据段和代码码的权限、基址等信息都是相同的。事实上,因为基础相同,两段其实是重合在一起。X86CPU虽然引入了分段形式,但是Linux,包括当前的Windows,在分段时都将数据段和代码段设成相同的起始地址,使得线性地址和逻辑地址一致,而仅使用了分页机制来实现了与物理地址的映射。当然据我的同事球哥描述,分段机制是X86CPU上面的鸡肋,我暂时未能明白,不知道是否因为实际上没有操作系统用到而显无用。
0000000011000000 1111101000000000 0xc0fa00
0000000011000000 1111001000000000 0xc0f200
对于TSS,我们也先从它的结构体tss_struct 看起:
struct tss_struct {
long back_link; /* 16 high bits zero */
long esp0;
long ss0; /* 16 high bits zero */
long esp1;
long ss1; /* 16 high bits zero */
long esp2;
long ss2; /* 16 high bits zero */
long cr3;
long eip;
long eflags;
long eax,ecx,edx,ebx;
long esp;
long ebp;
long esi;
long edi;
long es; /* 16 high bits zero */
long cs; /* 16 high bits zero */
long ss; /* 16 high bits zero */
long ds; /* 16 high bits zero */
long fs; /* 16 high bits zero */
long gs; /* 16 high bits zero */
long ldt; /* 16 high bits zero */
long trace_bitmap; /* bits: trace 0, bitmap 16-31 */
struct i387_struct i387;
};
这里共有四对espN,ssN,对应的是CPU的四个ring权限级别的堆栈指针和栈选择符。实际的操作系统中只用到了ring0和ring3,其它未用到,因此赋0值。
内核栈的esp被赋值为PAGE_SIZE+(long)&init_task,我们也注意到,下面这个联合:
union task_union {
struct task_struct task;
char stack[PAGE_SIZE];
};
这里,内核栈与进程结构体task_struct共用4K,一个物理页,因为栈是从高位向低位开始使用,因此栈指针,初始化时指向的是进程结构体所在页的最尾端。这里也暗示,内核栈大小为:4K-sizeof(task_struct)。栈溢出会把覆盖掉进行结构体,造成内核崩溃。
各通用寄存器都初始化为0,段寄存器均初始化为0×17=10111b,我们对一下Intel手册上的描述:

,翻译一下,也就是指身边ring3(RPL=11b),LDT(TI=1)的2(Index=10b)号段描述符号,也就是数据段了。
我这里有个疑问,cs段寄存器应指向代码段0xF,为啥也指向数据段寄存器0×17了呢?
Linux的串口硬盘、网卡驱动问题
0使用PC安装Linux经常会遇到驱动的问题,尤其是像red hat9之类比较老版本,处理串口硬盘、网卡时,自带的驱动支持有限。一旦遇上,就得抓破头皮想解决办法。最近安装Cent OS5.4、RedHat9时遇到了俩问题:
- 网卡无法驱动,使用的是Realtek的8101芯片。
- vmWare映射串口物理硬盘安装的Red Hat9,安装完后grub无法引导。
编译网卡驱动
此时因网卡无法驱动,需要使用其它能上网的机器或操作系统下载完后拷备到Linux环境,如果是后者,本机上的其它操作系统上下载的代码可以用Ext2Fsd从Windows中写入内容到Linux盘。从Realtek下载对应的驱动,编译安装,8101芯片下载地址为:
这里有个问题,r8101的驱动程序在2.4.X下面生成r8101.o,我使用64位生成r8101.ko文件,2.4.x的Makefie文件没有处理该项不同,是个bug。编译完成后需要手动
insmod r8101.o
串口硬盘兼容模式
串口硬盘的无法引导的问题,可以在BIOS下面找到IDE相关选项,修改为兼容模式。
我使用的BIOS配置路径为:
Chipset->South Bridge Config->IDE Config->ATA/IDE Config
将其值修改成:
[Compatible]
同时Legacy IDE Channels 修改为:
[PATA Pri,SATA Sec]
串口硬盘即会工作在并口的兼容模式下。因为兼容模式无法发挥SATA的优势,进入系统后可以下载对应驱动,编译安装,关闭该兼容模式。



最新评论