5.OP-TEE+qemu的启动过程分析--run-only目标执行

   

OP-TEE+qemu的启动过程分析--run-only目标执行

使用qemu模拟运行OP-TEE的时候,是通过在在build目录中执行make run-only来实现的。

1.run-only目标内容

在Makefile(qemu.mk)文件中关于run-only目标的定义如下:

.PHONY: run-only                                                                                                
run-only:                                                                                                       
    $(call check-terminal)                                                                                      
    $(call run-help)                                                                                            
    $(call launch-terminal,54320,"Normal World")                                                                
    $(call launch-terminal,54321,"Secure World")                                                                
    $(call wait-for-ports,54320,54321)                                                                          
    $(QEMU_PATH)/arm-softmmu/qemu-system-arm \                                                                  
        -nographic \                                                                                            
        -serial tcp:localhost:54320 -serial tcp:localhost:54321 \                                               
        -s -S -machine virt -machine secure=on -cpu cortex-a15 \                                                
        -m 1057 \                                                                                               
        -bios $(ROOT)/out/bios-qemu/bios.bin \                                                                  
        $(QEMU_EXTRA_ARGS)

run-only目标中执行的相关函数都会在build对应的文件中进行定义,下面大致介绍以下上述函数的功能:

$(call check-terminal):check-terminal在qemu的工程中不会被定义,该语句不会被执行,但是在其他工程中会被定义,具体请查看build/common.mk文件

$(call run-help):run-help函数定义在build/commom.mk文件中,主要用来打印出相关的启动帮助信息

$(call launch-terminal,54320,"Normal World"):执行 launch-terminal,54320,"Normal World",其中launch-terminal在build/common.mk文件中被定义

$(call launch-terminal,54321,"Secure World"):执行功能同上,只是重定向时将端口换成了54321,且启动的terminal名字为Secure World

$(call wait-for-ports,54320,54321):调用wait-for-prots函数,该函数定义在build/common.mk文件中,主要功能是检查上面启动的两个terminal的通过socket通信是否正常

$(QEMU_PATH)/arm-softmmu/qemu-system-arm :该指令就是调用qemu-system-arm指令并设定好qemu启动的各种参数,然后开始启动linux跟OP-TEE,该指令被完全展开之后如下:

/home/icyshuai/devel/optee/build/../qemu/arm-softmmu/qemu-system-arm \
	-nographic \
	-serial tcp:localhost:54320 -serial tcp:localhost:54321 \
	-s -S -machine virt -machine secure=on -cpu cortex-a15 \
	-m 1057 \
	-bios /home/icyshuai/devel/optee/build/../out/bios-qemu/bios.bin \

-nographic :不显示图形界面

-serial:将串口重定向到后面的参数部分

-S:使用C来控制启动(在qemu的console界面输入C之后才会正式启动系统)

-m:设定虚拟的内存大小

-bios:指定BIOS的文件(该image中会包含OP-TEE,linux,rootfs的镜像)

执行完成之后,然后在qemu的console端输入字母c,然后回车就开始正式的启动linux+OP-TEE

2.launch-terminal函数

launch-term函数的主要功能是用来启动terminal,该函数定义在build/common.mk文件中。具体内容如下:

define launch-terminal
   @nc -z  127.0.0.1 $(1) || \
   $(gnome-terminal) -t "$(2)" -x $(SOC_TERM_PATH)/soc_term $(1) &
endef

$(gnome-terminal)的定义也在common.mk文件中,定义如下:

gnome-terminal := $(shell command -v gnome-terminal 2>/dev/null)

所以当调用$(call launch-terminal, 54320, "Normal World")等价于

gnome-terminal -t "Normal World" -x $(SOC_TERM_PATH)/soc_term 54320

该函数的调用的作用是启动一个名字为Normal World的terminal,并且在terminal中执行"soc_term 54320",而soc_term就是在soc_term目录中编译出来的可执行文件。执行soc_term 54320命令的主要作用是将该terminal的输入和输出通过54320端口重新定向标准输入和输出端。

3.soc_term可执行文件

soc_term可执行文件是用来实现normal world和secure world两个terminal输入和输出重定向到标准输入输出端口,该可执行文件的source code存放在soc_term目录中。soc_term.c文件中的main函数定义如下:

int main(int argc, char *argv[])
{
	int listen_fd;
	char *port;
	bool have_handle_telnet_option = false;

	switch (argc) {
	case 2:
		port = argv[1];
		break;
	case 3:
		if (strcmp(argv[1], "-t") != 0)
			usage();
		have_handle_telnet_option = true;
		port = argv[2];
		break;
	default:
		usage();
	}

	save_current_termios();//获取当前的terminal的信息(标准输入输出的terminal配置)

	listen_fd = get_listen_fd(port);//建立socket机制,并监听输入的端口号

	printf("listening on port %s\n", port);
	if (have_handle_telnet_option)	//判定是否使用telent
		printf("Handling telnet commands\n");

/* 进入loop循环,完成端口监听和输入输出的重定向 */
	while (true) {
		int fd = accept_fd(listen_fd);	//开始接收建立的监听端口的信息

		handle_telnet = have_handle_telnet_option;
		handle_telnet_codes(-1, NULL, NULL); /* Reset internal state *///为使用telent时不起作用

		warnx("accepted fd %d", fd);
		set_tty_noncanonical();	//拷贝当前terminal的信息,并配置其他参数,然后条用tcsetattr函数来设定当前启动的terminal的信息

		serve_fd(fd);	//开始处理监听收到的数据,并根据对应的revent进行重定向操作,server_fd函数的注释见后续章节。

 /* 处理完成之后,fd */
		if (close(fd))
			err(1, "close");
		fd = -1;

/* 保存当前terminos的配置 */
		restore_termios();
	}
}

server_fd函数主要完成接收到的监控端口的数据,并执行重定向操作。代码内容和解释如下:

static void serve_fd(int fd)
{
	uint8_t buf[512];
	struct pollfd pfds[2];

/* 设定pollfd参数,用于实现重定向操作 */
	memset(pfds, 0, sizeof(pfds));
	pfds[0].fd = STDIN_FILENO;
	pfds[0].events = POLLIN;
	pfds[1].fd = fd;
	pfds[1].events = POLLIN;

	while (true) {
		size_t n;

/* 获取监听事件的pfds[0]和pfds[1]中定义的事件 */
		if (poll(pfds, 2, -1) == -1)
			err(1, "poll");

/* 如果pfds[0]中的POLLIN时间触发(在该terminal的标准输入有输入操作),则进行读取操作 */
		if (pfds[0].revents & POLLIN) {
			n = read(STDIN_FILENO, buf, sizeof(buf)); //从该terminal的标准输入端口中读取输入的数据
			if (n == -1)
				err(1, "read stdin");
			if (n == 0)
				errx(1, "read stdin EOF");

			/* TODO handle case when this write blocks */
/* 将读取到的数据写入到重定向的port捆绑的socket */
			if (!write_buf(fd, buf, n)) {
				warn("write_buf fd");
				break;
			}
		}

/* 如果pfds[1]中的POLLIN时间触发(监测到该terminal的port捆绑的socket有输入流操作),则读取监测的port对应的socket句柄中的数据 */
		if (pfds[1].revents & POLLIN) {
			n = read(fd, buf, sizeof(buf));	//读取与port捆绑的socket的句柄中的数据
			if (n == -1) {
				warn("read fd");
				break;
			}
			if (n == 0) {
				warnx("read fd EOF");
				break;
			}
			handle_telnet_codes(fd, buf, &n);

/* 将读取到的数据写入到该terminal的标准输出 */
			if (!write_buf(STDOUT_FILENO, buf, n))
				err(1, "write_buf stdout");
		}
	}
}


 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值