编者按: 德里克·安德森(Derek Anderson) 是Startup Grind展会活动的创始人 ,该展会在15个国家35个城市进行一系列的创业公司活动,不仅指导帮助创业者,而且还为他们提供相互交流的机会。 此外,安德森还创立了Commonred,并曾在美国艺电娱乐软件公司任职。
大约九年前,我在犹他州普罗沃市(Provo,Utah)的一所大学公寓里遇到了瑞安·史密斯(Ryan Smith)。当时,我们都还待在学校里,我问他最近在忙些什么工作,他说,“我和我父亲正在着手成立一家在线调查公司,叫Qualtrics”,九年过去了,现在的Qualtrics拥有5000个客户,并获得了7000万美元的融资。而且,Qualtrics去年拒绝了一笔高达5亿美元的收购,该公司雄心勃勃,拟向建立一个价值10亿美元的公司勇敢前进。
去年,Qualtrics公司广受业界好评,红杉资本(Sequoia Capital)合伙人布瑞恩·施瑞埃尔(Bryan Schreier)甚至称他们是“世界上最大最低调的软件公司”。风云变幻的如此之快。Qualtrics是由Ryan和他的父亲共同创立的一家公司,他们通过调研学生或客户,帮助学校和企业收集反馈信息和相关数据。他们有5000名客户,其中包括联邦快递,惠普,捷蓝航空,微软,百事可乐公司,还有Zappos。笔者最近在犹他州的Startup Grind大会上对Ryan进行了采访,了解了这一切是如何发生的。
2001年的夏天,Ryan还在惠普公司做一名实习生,他的父亲斯科特(Scott)电话告诉Ryan,他得了咽喉癌,需要立即手术。Ryan因此不得不回到家中,并休学了一学期。在家中,Ryan发现他的父亲已经几近完成了Qualtrics的雏形。每天,当斯科特完成化疗以后,父子二人就开始在Qualtrics上下功夫。当斯科特的身体有所好转的时候,Ryan已经拓展了20家客户,于是,他们决定招聘一支小团队共同开发这款产品。
Qualtrics产品的第一个客户,来自学术界。Ryan意识到,它可以很容易的在网上找到一些关键决策者的联系信息,如果这对一个客户有用的话,那么这些信息自然而然的也一定会对其他客户有用。他的第一个客户是来自凯洛格管理学院(Kellogg School of Management)的教授。十年后,Qualtrics首批合作的十个客户仍然还在。
这一切,都发生在2002年和2003年Ryan父母位于犹他州普罗沃市房子的地下室里。Ryan第一个招聘的员工,是他的一个朋友,他说服这位朋友拒绝了原来能拿到6万美元的工作,而在当时,Qualtrics支付的薪水只有8000美元。但很快------第二年,他的这位朋友就拿到了1.2万美元。到了2004年,他们的公司已经扩大到了20人,小区街边停满了公司员工的汽车,周围邻居还抱怨从地下室传来的吵杂声音,甚至小区的垃圾车都无法装满Qualtrics公司的垃圾。事实上,当时Ryan一个月的收入就有10万美元。在公司创立五年之后,他们每月的收入超过一百万美元。
Qualtrics公司的产品始终始终专注于最初的设想和客户。Ryan经常和他在谷歌任职的弟弟贾里德(Jared)交流想法,还讨论公司可能的发展方向。而贾里德也竭尽全力的帮助Ryan。“除了250所高校覆盖项目,其他的什么都不要谈。”为了扩大产品用量,Qualtrics公司运用病毒式的市场营销方法,全身心的投入到将其产品推广到250所高校的项目之中。他们面临的第一个压力,就是发生在九个月前的故事,当时他们刚刚宣布获得了融资,但是,他们决定拒绝参加Inc.Magazine高成长企业排行榜评选,事实上,他们已经连续六年没有参加过诸如此类的评选了。“低调的赚钱有什么错吗?事实上,低调有很多好处。”
随着团队和业务的发展,Ryan管理和构建的工程技术团队的能力已经达到了极限。“我扪心自问,'我知道最好的工程师是谁吗?”实际上,如上文介绍的,Ryan的弟弟贾里德是世界上为数不多的业界精英,他从2004年开始,就在谷歌任职,并负责创建了180人的工程产品管理团队。贾里德·史密斯是这些硅谷测试工程师精英中的一份子,像他这样的人,每一个企业创始人都希望让他们加入公司,但是在内心深处,他们知道也许他们只有1%的可能会加入创业公司。但是,Ryan做到了,贾里德加入了Qualtrics公司,而且取得了令人激动不已的成绩。Ryan是这样评价贾里德的工程技术的,和同样的团队相比,贾里德的生产力是他们的七倍,同时带来的客户和收益也绝对遥遥领先。
在2008年,第一家风险投资公司强势的致电Qualtrics公司,但是,Qualtrics团队礼貌的拒绝了风投的介入,并继续埋头发展。到了2010年,公司规模已经扩大到100名员工,而且每天都能收到三家投资收购的咨询。正如笔者提到过的,至少有6家著名的风险投资公司被Qualtrics婉言拒绝了。我想,这些风投公司也许从来没有经历过被拒绝这种事情吧。
终于,在去年5月,Qualtrics,这家从未融过一美元资金的公司,宣布Accel Partners和Sequoia Capital向该公司投资7000万美元。事实上Accel Partners为了能够投资Qualtrics已经苦苦等待了三年。Ryan说:“一加一必须要等于五,如果一加一不等于五,那么这轮融资根本没有意义。我们要众志成城的实现我们的目标,因此,我们希望Sequoia和Accel共同参与进来。”
Qualtrics现在拥有300名员工,地下室显然已经不足以容纳他们了。如今,在犹他州他们有了一个“不惜重金”打造的公司总部。该企业的文化,氛围,以及创造性的设计,任何一点都不亚于硅谷。99designs公司总裁兼首席执行官Patrick Lkewellyn最近走访了Qualtrics的新办公地点,他感慨道:“史密斯父子终于在普罗沃市创立了这家公司,他们对企业的业绩无比专注,正是因为完全的透明,才造就了这样的企业文化。”
无论对自己的未来,还是对Qualtrics的未来,Ryan都表现出令人吃惊的前瞻水平。由于本轮7000万美元的融资,随之而来的压力的期望将会被推的更高。Ryan说:“任何一家企业,都很少能拥有实现十亿美元的业绩的机会。因此,我们的未来将十分宏大,我本人,也将会比以往任何时候都要努力。”
Android系统的内核要加载并运行,其实是经历了千辛万苦的,因为万事开头难。在一个系统刚开始时,并没有什么资源可以使用,CPU只认得0x00000000地址,并从那里运行第一条指令,并且这段代码有大小限制,不可以很大。因此需要开发一个引导程序放在那里运行,在这里的培训课程里,主要使用是S3C6410开发板,并且使用UBoot作为引导程序(Bootloader)。UBoot是一个很通用的引导程序,并且在嵌入式系统的应用里非常广泛,功能也相当强大,设计的架构相当灵活,很方便移植到不同的嵌入式设备里。
从前面知道ARM的CPU是固定从0x00000000开始运行的,那么UBoot的编译出来的大小,是放不到0x00000000的内存空间的,那么UBoot又是怎么样获得控制权呢?其实在S3C6410里可以通过CPU的管脚设置不同的电平,可以选择运行CPU内部的程序,然后让这段小程序加载UBoot到合适地址运行。那么接着下来的问题就是UBoot放到那里才是合适的地址?要理解这个合适地址,就需要看S3C6410的手册了,通过阅读这个手册,就会发现CPU的内存是固定在两个地址空间,如下:
0x50000000--0x5FFFFFFF大小为256M
0x60000000--0x6FFFFFFF大小为256M
由此可知,所有内存RAM都必须放到这段地址空间,也就是物理地址空间,因此UBoot就必须加载到这段内存空间里才可以运行,那么UBoot在编译时是否需要知道在那里运行呢?答案是需要的。UBoot运行时,有很多数据是需要找到对内存地址寻址。在UBoot编译时,就作出如下指定:
TEXT_BASE= 0xc7e00000
哗,这里的地址为什么是0xc7e00000的呢?难道是写错了吗?其实这里是大有文章的,与其相关的内容就是MMU了,所谓的MMU就是一个内存映射的硬件,主要作用就是把无限的虚拟内存地址空间映射到有限的物理内存地址空间,作用就是复用物理内存,方便编译所有软件。由此可知,UBoot是编译到虚拟地址0xc7e00000运行,在未有开启MMU之前,它的物理地址是0x57e00000,其实在物理地址上来看来是同一个地方。
从前面的可以知道UBoot真实运行的物理地址是0x57e00000,相对应的虚拟地址是0xc7e00000,这段地址相对于256内存来说是一个高端地址,为什么要放到这个地址运行,而不放到0x50000000的物理地址(虚拟机地址0xC0000000)运行呢?其实这是为了后面的内核linux运行做好准备,否则就会相互打架,整个系统运行就出错。从UBoot编译后的内存映像文件可以看到相关信息:
c7e00000T _start
c7e00020t _undefined_instruction
c7e00024t _software_interrupt
c7e00028t _prefetch_abort
c7e0002ct _data_abort
c7e00030t _not_used
c7e00034t _irq
c7e00038t _fiq
c7e0003ct _pad
c7e00040T _end_vect
c7e00040t _TEXT_BASE
c7e00044t _TEXT_PHY_BASE
c7e00048T _armboot_start
c7e0004cT _bss_start
c7e00050T _bss_end
c7e00054t reset
这段映像文件就说明所有开始代码都是相对0xc7e00000开始的,包括所有数据访问。在UBoot的MMU配置里,用下面的代码来把物理地址0x50000000映射到虚拟地址0xc0000000,如下:
//128MB for SDRAM 0xC0000000 -> 0x50000000
.set__base, 0x500
.rept0xD00 - 0xC00
FL_SECTION_ENTRY__base,3,0,1,1
.set__base,__base+1
.endr
引导程序加载运行,做好充分准备之后就可以加载内核运行了。它加载内核地址也是有讲究的,一般linux内核需要加载在0x50008000的物理地址开始,因此虚拟地址就是0xc0008000了,这样就可以把内核加载在低端运行,高端地址就可以给所有应用程序运行了。
总结一下,CPU从0x00000000开始运行Flash的程序,然后把UBoot重定位到物理地址0x57e00000(虚拟地址0xc7e00000)运行,然后打开MMU,就对应在虚拟地址0xc7e00000运行,然后加载内核到虚拟地址0xc0008000(物理地址0x50008000),然后再跳到这个地址里运行,因此UBoot要指定虚拟地址0xc7e00000作来连接程序的基地址。
Config.mk有下面一段话:
# SMDK6410 has a 128 MB SDR SDRAM
#
# 5000'0000 to 5800'0000
#
#
# Linux-Kernel is expected to be at 5000'8000, entry 5000'8000
# optionally with a ramdisk at 5080'0000
#
# we load ourself to 57e0'0000 without MMU
# with MMU, load address is changed to 0xc7e0_0000
#
# download area is 5000'0000
#
ifndef TEXT_BASE
TEXT_BASE = 0xc7e00000
endif
S3C6410datasheet地址如下:
DRAM Controller of the Memory Port1 :
Address Size(MB)
0x5000_0000 0x5FFF_FFFF 256MB
0x6000_0000 0x6FFF_FFFF 256MB