一份古老的C代码
chdir/usr/sys/ken# cat main.c
#
#include "../param.h"
#include "../user.h"
#include "../systm.h"
#include "../proc.h"
#include "../text.h"
#include "../inode.h"
#include "../seg.h"
#define CLOCK10177546
#define CLOCK20172540
/*
* Icode is the octal bootstrap
* program executed in user mode
* to bring up the system.
*/
int icode[]
{
0104413, /* sys exec; init; initp */
0000014,
0000010,
0000777, /* br . */
0000014, /* initp: init; 0 */
0000000,
0062457, /* init: </etc/init\0> */
0061564,
0064457,
0064556,
0000164,
};
/*
* Initialization code.
* Called from m40.s or m45.s as
* soon as a stack and segmentation
* have been established.
* Functions:
* clear and free user core
* find which clock is configured
* hand craft 0th process
* call all initialization routines
* fork - process 0 to schedule
* - process 1 execute bootstrap
*
* panic: no clock -- neither clock responds
* loop at loc 6 in user mode -- /etc/init
* cannot be executed.
*/
main()
{
extern schar;
register i, *p;
/*
* zero and free all of core
*/
updlock = 0;
i = *ka6 + USIZE;
UISD->r = 077406;
for(;;) {
UISA->r = i;
if(fuibyte(0) < 0)
break;
clearseg(i);
maxmem++;
mfree(coremap, 1, i);
i++;
}
if(cputype == 70)
for(i=0; i<62; i=+2) {
UBMAP->r = i<<12;
UBMAP->r = 0;
}
printf("mem = %l\n", maxmem*5/16);
printf("RESTRICTED RIGHTS\n\n");
printf("Use, duplication or disclosure is subject to\n");
printf("restrictions stated in Contract with Western\n");
printf("Electric Company, Inc.\n");
maxmem = min(maxmem, MAXMEM);
mfree(swapmap, nswap, swplo);
/*
* determine clock
*/
UISA->r = ka6; /* io segment */
UISD->r = 077406;
lks = CLOCK1;
if(fuiword(lks) == -1) {
lks = CLOCK2;
if(fuiword(lks) == -1)
panic("no clock");
}
/*
* set up system process
*/
proc.p_addr = *ka6;
proc.p_size = USIZE;
proc.p_stat = SRUN;
proc.p_flag =| SLOAD|SSYS;
u.u_procp = &proc;
/*
* set up 'known' i-nodes
*/
*lks = 0115;
cinit();
binit();
iinit();
rootdir = iget(rootdev, ROOTINO);
rootdir->i_flag =& ~ILOCK;
u.u_cdir = iget(rootdev, ROOTINO);
u.u_cdir->i_flag =& ~ILOCK;
/*
* make init process
* enter scheduling loop
* with system process
*/
if(newproc()) {
expand(USIZE+1);
estabur(0, 1, 0, 0);
copyout(icode, 0, sizeof icode);
/*
* Return goes to loc. 0 of user init
* code just copied out.
*/
return;
}
sched();
}
/*
* Load the user hardware segmentation
* registers from the software prototype.
* The software registers must have
* been setup prior by estabur.
*/
sureg()
{
register *up, *rp, a;
a = u.u_procp->p_addr;
up = &u.u_uisa;
rp = &UISA->r;
if(cputype == 40) {
up =- 8;
rp =- 8;
}
while(rp > &UISA->r)
*--rp = *--up + a;
if((up=u.u_procp->p_textp) != NULL)
a =- up->x_caddr;
up = &u.u_uisd;
rp = &UISD->r;
if(cputype == 40) {
up =- 8;
rp =- 8;
}
while(rp > &UISD->r) {
*--rp = *--up;
if((*rp & WO) == 0)
rp[(UISA-UISD)/2] =- a;
}
}
/*
* Set up software prototype segmentation
* registers to implement the 3 pseudo
* text,data,stack segment sizes passed
* as arguments.
* The argument sep specifies if the
* text and data+stack segments are to
* be separated.
*/
estabur(nt, nd, ns, sep)
{
register a, *ap, *dp;
if(sep) {
if(cputype == 40)
goto err;
if(nseg(nt) > 8 || nseg(nd)+nseg(ns) > 8)
goto err;
} else
if(nseg(nt)+nseg(nd)+nseg(ns) > 8)
goto err;
if(nt+nd+ns+USIZE > maxmem)
goto err;
a = 0;
ap = &u.u_uisa;
dp = &u.u_uisd;
while(nt >= 128) {
*dp++ = (127<<8) | RO;
*ap++ = a;
a =+ 128;
nt =- 128;
}
if(nt) {
*dp++ = ((nt-1)<<8) | RO;
*ap++ = a;
}
if(sep)
while(ap < &u.u_uisa) {
*ap++ = 0;
*dp++ = 0;
}
a = USIZE;
while(nd >= 128) {
*dp++ = (127<<8) | RW;
*ap++ = a;
a =+ 128;
nd =- 128;
}
if(nd) {
*dp++ = ((nd-1)<<8) | RW;
*ap++ = a;
a =+ nd;
}
while(ap < &u.u_uisa) {
*dp++ = 0;
*ap++ = 0;
}
if(sep)
while(ap < &u.u_uisa) {
*dp++ = 0;
*ap++ = 0;
}
a =+ ns;
while(ns >= 128) {
a =- 128;
ns =- 128;
*--dp = (127<<8) | RW;
*--ap = a;
}
if(ns) {
*--dp = ((128-ns)<<8) | RW | ED;
*--ap = a-128;
}
if(!sep) {
ap = &u.u_uisa;
dp = &u.u_uisa;
while(ap < &u.u_uisa)
*dp++ = *ap++;
ap = &u.u_uisd;
dp = &u.u_uisd;
while(ap < &u.u_uisd)
*dp++ = *ap++;
}
sureg();
return(0);
err:
u.u_error = ENOMEM;
return(-1);
}
/*
* Return the arg/128 rounded up.
*/
nseg(n)
{
return((n+127)>>7);
}
# 这是一份非常经典的 Unix V6 内核(大约 1975 年)的 main.c 文件,来自贝尔实验室。它负责计算机启动后 第一个用户态进程的创建 和系统初始化。下面用通俗的方式解释核心逻辑:
[*]清除用户核心:循环扫描所有未被内核占用的内存页,用 clearseg 清零,并调用 mfree 归还给空闲内存管理表(coremap)。
[*]检测时钟:检查两个可能的时钟地址(CLOCK1 和 CLOCK2),如果都失败则调用 panic("no clock")。
[*]建立 0 号进程(系统进程):手动设置 proc 结构,赋予 SRUN(就绪)状态和 SSYS(系统进程)标志。
[*]初始化文件系统:调用 cinit()(字符设备)、binit()(块设备)、iinit()(i 节点缓存),然后通过 iget 获取根目录(rootdir)。
[*]创建 init 进程(1 号进程):调用 newproc() 复制进程,如果成功(返回非零),则扩展用户空间、设置用户段寄存器、将 icode 引导程序复制到进程地址 0 处,然后 return 会跳转到该引导程序,最终执行 /etc/init。
[*]调度循环:如果创建失败,则父进程(0 号进程)进入 sched() 循环,作为系统调度器永远运行。
int icode { ... } 是一个硬编码的引导代码(八进制),它执行 exec("/etc/init") 来启动用户态的管理进程。整个流程就是操作系统从硬件启动到多任务运行的 关键桥梁。
如果你对其中某个细节(如内存分段、时钟检测)有疑问,欢迎继续提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]