论文部分内容阅读
摘 要: 首先对嵌入式Linux操作系统内核和S3C2410处理器进行了简单介绍,在此基础上,对 系统引导程序進行了设计,重点介绍了将Linux移植到S3C2410处理器的步骤和方法,并对移 植过程的关键部分进行了详细阐述。编译生成的内核在嵌入式系统中运行稳定,结果证明方 法可行,对于开发其它嵌入式系统具有参考意义。
关键词:嵌入式操作系统;移植;Linux;S3C2410
中图分类号: TP368.1 文献标识码:A 文章编号:1672-1098(2008)03-0073-04
1 Linux内核和实验系统简介
嵌入式操作系统作为大多数嵌入式应用系统的软件平台,它管理着系统的资源,为应用 软件提供各种必要的服务。在嵌入式应用系统中使用嵌入式操作系统,已是大势所趋。目前 嵌入式操作系统的种类繁多,但Linux以其源代码开放和可移植性强等特点,被广泛使用。 本文将介绍如何将内核版本为2.4.18的Linux移植到基于ARM920T的S3C2410处理器上。
1.1 Linux操作系统内核
Linux操作系统主要由内核、shell、文件结构组成,其中内核是灵魂,负责整个系统的 内存管理、进程调度和文件管理。Linux内核与大部分UNIX内核一样是单内核体系结构的, 能够根据需要定制内核映像的尺寸,具有很大灵活性,不需要重新编译内核和引导就能检验 新的内核组件,这个特性对于嵌入式而言是非常有好处的,方便用户构筑自己的个人内核。 Linux内核有五个主要的子系统组成:进程调度、内存管理、虚拟文件系统、网络接口和进 程间通信。
本文将对内核版本为2.4.18的Linux进行移植,其内核代码分布如图1所示。
(1) /arch目录包含了目前Linux支持的硬件结构——如i386、alpha、arm等的内核代码;
(2) /drives目录包含了内核中所有的设备驱动程序;
(3) /fs目录包含了所有的文件系统的代码;
(4) /include目录包含了建立内核代码所需要的大部分库文件,这个模块利用其它模块重建 内核;
(5) /init目录包含了内核的初始化代码,内核从此处运行;
(6) /ipc目录包含了进程间通信代码;
(7) /kernel子目录包含了主内核代码;
(8) /mm目录包含所有独立于CPU体系结构的内存管理代码;
(9) /net目录包含了和网络相关的代码,如ipv4、ipv6等。
一般在每个目录下都有一个.depend文件和一个Makefile文件,这两个文件都是编译时使用 的辅助文件。
1.2 S3C2410处理器
S3C2410是SAMSUNG公司基于ARM920T处理器内核开发的一款16/32位嵌入式处理器,运行 频率高达200多MHz,具有MMU和高速缓存等丰富片上资源,可以广泛用于PDA、internet设备 和手持式设备。其片上集成的功能主要包括以下几个方面:
(1) 1.8V ARM 内核,3.3V存储器,3.3V外部I/O, 具有16kB指令缓存/16kB数据缓存和MMU 的微处理器;
(2) 外部存储控制器(SDRAM 控制和片选逻辑);
(3) LCD控制器(支持上到4k色的STN和256k色的TFT), I通道LCD专 用DMA;
(4) 具有外部请求引脚的4通道DMA;
(5) 3通道UART, 2通道SPI;
(6) 1通道IIC总线控制器,1通道US总线控制器;
(7) 1.0版本的SD主机接口和兼容的2-11版本的Multi-Media卡协议;
(8) 2端口 USB 主机,1端口 USB 设备(USB1.1);
(9) 4通道PWM定时器,1通道内部定时器;
(10) 看门狗电路;
(11) 117个通用I/O口,24通道外部中断源;
(12) 电源控制:常规、缓慢、空闲和断电模式;
(13) 8通道10位ADC和触摸屏接口;
(14) 具有日历功能的实时时钟RTC;
(15) 具有锁相环的片上时钟发生器。
2 将Linux移植到S3C2410
2.1 移植思路
首先要为Linux设计一个BootLoader,通过BootLoader来初始化硬件,引导Linux运行。 Bootloader设计可以在ads中实现。然后,针对硬件环境和设计的 BootLoader修改Linux内 核。接下来,在Linux操作系统下建立交叉编译环境。最后,配置、编译、连接Linu x,下 载编译得到的映像文件到Flash,通过BootLoader 来启动嵌入式操作系统Linux。
2.2 Boot Loader的设计
引导加载程序通常称为Boot Loader,就是在操作系统内核运行之前运行的一段小程序 。通过这段小程序,初始化硬件设备、建立内存空间的映射图,从而建立适当的系统软硬件 环境,为调用操作系统内核做好准备。
本系统Boot Loader的第一阶段主要完成基本的硬件初始化,用汇编语言实现:①关闭w atchdog,屏蔽所有中断;②设置处理器时钟和工作频率,CPU工作频率为200 M Hz;③初始化外部寄存器;④初始化堆栈指针SP;⑤拷贝Boot Loader的第二阶段到RAM空间 中,使用一个 跳转语句跳转到第二阶段的main入口函数。在完成以上操作后就为main函数的运行建立起了 一个基本的环境。
第二阶段用C语言完成:①通用I/O口的设置;②完成内存映射初始化和内存管理单元初 始化:men_map_init(); mmu_init(); 这两个函数在/arch/s3c2410/mmu.c中;③初 始化mtd设备:mtd_dev_init();这个函数在/drivers/mtd/maps/s3c2410_flash.c中 ;④拷贝flash中的kernel映像和根文件系统映像到RAM空间中;⑤跳转到内核的第 一条指令 处。跳转时需要满足下列条件:R0为0;R1为机器类型ID;禁止中断(IRQ和FIQ);C PU设置 为SVC模式(SVC是供操作系统使用的一种保护模式);关闭MMU;关闭数据Cache。至此Boot Loader的任务结束。
2.3 Linux内核的修改
假定内核代码放在/usr/src/Linux-2.4.18目录下
(1) 打开根目录下的Makefile文件 此文件用来指定编译规则,例如哪些需要编译,哪些 需要先编译。
指定目标平台:Arch=arm;
指定交叉编译器:添加CROSS_COMPILE=arm-linux-。
(2) 打开/arch/arm目录下的Makefile文件 启动代码的产生需要通过此文件,由于2.4内 核还没有对S3C2410的支持,在此添加如下代码:
ifeq((CONFIG_ARCH_S3C2410),y)
TEXTADDR=0xC0008000
MACHINE=s3c2410
Endif
TEXTADDR是内核的最终运行地址,该位置一般在RAM区起始地址偏移0x8000处(RAM起始地址 到偏移0x8000之间的32KB空间中存放一些全局数据结构如启动参数、内存页表等信息)。
(3) 打开/arch/arm/boot目录下的Makefile文件 ZTEXTADDR是解压前image.rom的位置, ZRELADDR是内核解压并最终执行的位置。ZRELADDR与TEXTADDR之间符合如下映射关系:_v irt_to_phys(TEXTADDR)==ZRELADDR.
ifeq((CONFIG_ARCH_s3c2410),y)
ZTEXTADDR=0XC0008000
ZRELADDR=0X30008000
endif
(4) 打开/arch/arm/boot/compressed目录下的Makefile文件,添加ifeq(“$(CONFIG_A RCH_S3C2410),y)
OBJS+=head-s3c2410.o
endif
(5) 打开/arch/arm/config.in 此文件是配置文件,决定了在配置菜单中看到的内容。添 加$CONFIG_ARCH_S3C2410子选项
If[“$ CONFIG_ARCH_S3C2410” = “y”];then
Comment ‘Archimedes/A5000 Implementations’
Dep_bool ‘SMDK (MERI TECH BOARD)’
CONFIG_S3C2410_SMDK//
$CONFIG_ARCH_S3C2410
//其他
fi
在if[“$CONFIG_FOOTBRIDGE_HOST ”=“y”-o
……
“$CONFIG_ARCH_SA1100”=“y”];then
define_bool CONFIG_ISA y
else
define_bool CONFIG_ISA n
fi
中依樣添加“$CONFIG_ARCH_s3c2410”=“y”-o \。
(6) 打开/arch/arm/boot/compressed/head-s3c2410.s 此处需要添加内核解压前处 理器初始化文件head-s3c2410.s,示例代码如下:
.section #“.start”,“ax”
_S3C2410_start:
bic r2,pc,#0x1f @清除pc相关位,放于r2
add r3,r2,#0x4000
l:
ldr r0,[r2],#32
teq r2,r3
bne 1b
mcr p15,0,r0,c7,c10,4 @写回Write Buffer
mcr p15,0,r0,c7,c7,0 @刷新I&D caches
#if 0
@禁用MMU,caches
……
#endif
mov r0,#0x00200000
l:
subs r0,r0,#1
bne 1b
依次将$(CONFIG_ARCH_2410)加入
(7) 打开/arch/arm/kernel/Makefile
no-irq-arch:=$(CONFIG_ARCH_INTEGRATOR)$(CONFIG_ARCH_CLPS711X)
……
$(CONFIG_ARCH_AT91RM9200
并添加 obj-$(CONFIG_MIZI)+=ecard.o
obj-$(CONFIG_ARCH_APM)+=apm2.o
(8) 打开/arch/arm/kernel/entry-arm v.s 此文件主要定义CPU初始化时中断处理部分 ,可参考处理器使用手册,按处理器使用要求配置。
(9) 打开/arch/arm/kernel/debug-arm v.s 此文件用于最基本的串口调试功能,包括 调试串口的地址初始化、发送、等待、忙状态定义等。使用此文件可以在启动过程中打印出 相关信息。
(10) 打开/arch/arm/kernel/setup.c 此文件中要根据使用的板子设置几个变量。nr_b a nks指定了内存块的数量,bank指定了每块内存块的范围,PAGE_OFFSET是内存起始地址, MEM_SIZE是内存的大小,PAGE_OFFSET和MEM_SIZE要在/include/asm-arm/arch-s3c 2410中定义。
(11) 打开/arch/arm/mm/mm-arm v.c 此文件用于与硬件相关的内存管理,如初始化内 存页表内存映射等。将init_maps->bufferable=0;改为init_maps->bufferable=1。
(12) 打开/arch/arm/mach-s3c2410 建立相应目录并按照处理器使用要求编写irq.c、m m.c 、time.c、arch.c、Makefile,分别实现中断控制器的初始化,地址的虚实映射关系,时钟 中断和实时时钟处理以及有关Ramdisk使用参数等的设置。
(13) 打开/include/asm-arm/arch-s3c2410 此目录下定义用到的头文件。
2.4 编译Linux内核
在完成上述工作后,再进行如下编译,即可得到我们需要的映像文件。
(1) make clean:该命令清除以前构造内核时生成的所有目标文件、模块和临时文件。
(2) make dep:该命令搜索Linux输出与源代码之间的依赖关系,并以此生成依赖文件。
(3) make menuconfig:该命令是用来调用菜单式配制内核界面。
(4) make zImage:该命令用来编译内核,生成压缩的Linux内核目标代码zImage文件。
(5) make modules:该命令编译模块驱动程序
2.5 文件系统的生成——创建JFFS2文件系统
文件系统是Linux系统必备的一个部分,本系统使用mkfs.jffs2工具来创建JFFS2文件系 统。首先建立上述的/bin、/sbin等目录,然后拷贝命令工具到/bin文件夹,拷贝系统控制 程序到/sbin目录下,拷贝应用程序运行时所需要的库到/lib文件夹,库文件可以从pc机上 的交叉编译根据安装目录下拷贝,如libc-2.2.2.so、libcrypt-2.2.2.so、libm-2.2.2 .so等。这些准备完成后键入命令:
mkfs.jffs2 #-d jffs2 #-o root.jffs2
生成JFFS2根文件系统。
上述工作完成后,将Boot Loader、Linux内核、文件系统烧写到目标机的FLASH中,目 标机就能运行Linux系统了。
3 结束语
本文作者创新点:版本2.4的Linux并没有包含进对S3C2410的支持,本文详尽分析了将L inux-2.4移植到S3C2410上的主要技术,在移植过程中重点阐述的移植思路和方法对将Linux 嵌入式操作系统移植到其他处理器为核心的硬件平台也有借鉴作用。
参考文献:
[1] 毛德操,胡希明.Linux内核源代码情景分析[M].杭州:浙江大学出版社,20 01.
[2] 邹思轶.嵌入式Linux设计与应用[M].北京:清华大学出版社,2002.
[3] 白伟平,包启亮.基于ARM的嵌入式Boot Loader浅析[J].微计算机信息,2 006,22(11):99-100.
[4] 吴娴.嵌入式Linux文件系统的设计与实现[J].计算机工程与应用,2005,4 1(9):111-112.
(责任编辑:李 丽)
关键词:嵌入式操作系统;移植;Linux;S3C2410
中图分类号: TP368.1 文献标识码:A 文章编号:1672-1098(2008)03-0073-04
1 Linux内核和实验系统简介
嵌入式操作系统作为大多数嵌入式应用系统的软件平台,它管理着系统的资源,为应用 软件提供各种必要的服务。在嵌入式应用系统中使用嵌入式操作系统,已是大势所趋。目前 嵌入式操作系统的种类繁多,但Linux以其源代码开放和可移植性强等特点,被广泛使用。 本文将介绍如何将内核版本为2.4.18的Linux移植到基于ARM920T的S3C2410处理器上。
1.1 Linux操作系统内核
Linux操作系统主要由内核、shell、文件结构组成,其中内核是灵魂,负责整个系统的 内存管理、进程调度和文件管理。Linux内核与大部分UNIX内核一样是单内核体系结构的, 能够根据需要定制内核映像的尺寸,具有很大灵活性,不需要重新编译内核和引导就能检验 新的内核组件,这个特性对于嵌入式而言是非常有好处的,方便用户构筑自己的个人内核。 Linux内核有五个主要的子系统组成:进程调度、内存管理、虚拟文件系统、网络接口和进 程间通信。
本文将对内核版本为2.4.18的Linux进行移植,其内核代码分布如图1所示。
(1) /arch目录包含了目前Linux支持的硬件结构——如i386、alpha、arm等的内核代码;
(2) /drives目录包含了内核中所有的设备驱动程序;
(3) /fs目录包含了所有的文件系统的代码;
(4) /include目录包含了建立内核代码所需要的大部分库文件,这个模块利用其它模块重建 内核;
(5) /init目录包含了内核的初始化代码,内核从此处运行;
(6) /ipc目录包含了进程间通信代码;
(7) /kernel子目录包含了主内核代码;
(8) /mm目录包含所有独立于CPU体系结构的内存管理代码;
(9) /net目录包含了和网络相关的代码,如ipv4、ipv6等。
一般在每个目录下都有一个.depend文件和一个Makefile文件,这两个文件都是编译时使用 的辅助文件。
1.2 S3C2410处理器
S3C2410是SAMSUNG公司基于ARM920T处理器内核开发的一款16/32位嵌入式处理器,运行 频率高达200多MHz,具有MMU和高速缓存等丰富片上资源,可以广泛用于PDA、internet设备 和手持式设备。其片上集成的功能主要包括以下几个方面:
(1) 1.8V ARM 内核,3.3V存储器,3.3V外部I/O, 具有16kB指令缓存/16kB数据缓存和MMU 的微处理器;
(2) 外部存储控制器(SDRAM 控制和片选逻辑);
(3) LCD控制器(支持上到4k色的STN和256k色的TFT), I通道LCD专 用DMA;
(4) 具有外部请求引脚的4通道DMA;
(5) 3通道UART, 2通道SPI;
(6) 1通道IIC总线控制器,1通道US总线控制器;
(7) 1.0版本的SD主机接口和兼容的2-11版本的Multi-Media卡协议;
(8) 2端口 USB 主机,1端口 USB 设备(USB1.1);
(9) 4通道PWM定时器,1通道内部定时器;
(10) 看门狗电路;
(11) 117个通用I/O口,24通道外部中断源;
(12) 电源控制:常规、缓慢、空闲和断电模式;
(13) 8通道10位ADC和触摸屏接口;
(14) 具有日历功能的实时时钟RTC;
(15) 具有锁相环的片上时钟发生器。
2 将Linux移植到S3C2410
2.1 移植思路
首先要为Linux设计一个BootLoader,通过BootLoader来初始化硬件,引导Linux运行。 Bootloader设计可以在ads中实现。然后,针对硬件环境和设计的 BootLoader修改Linux内 核。接下来,在Linux操作系统下建立交叉编译环境。最后,配置、编译、连接Linu x,下 载编译得到的映像文件到Flash,通过BootLoader 来启动嵌入式操作系统Linux。
2.2 Boot Loader的设计
引导加载程序通常称为Boot Loader,就是在操作系统内核运行之前运行的一段小程序 。通过这段小程序,初始化硬件设备、建立内存空间的映射图,从而建立适当的系统软硬件 环境,为调用操作系统内核做好准备。
本系统Boot Loader的第一阶段主要完成基本的硬件初始化,用汇编语言实现:①关闭w atchdog,屏蔽所有中断;②设置处理器时钟和工作频率,CPU工作频率为200 M Hz;③初始化外部寄存器;④初始化堆栈指针SP;⑤拷贝Boot Loader的第二阶段到RAM空间 中,使用一个 跳转语句跳转到第二阶段的main入口函数。在完成以上操作后就为main函数的运行建立起了 一个基本的环境。
第二阶段用C语言完成:①通用I/O口的设置;②完成内存映射初始化和内存管理单元初 始化:men_map_init(); mmu_init(); 这两个函数在/arch/s3c2410/mmu.c中;③初 始化mtd设备:mtd_dev_init();这个函数在/drivers/mtd/maps/s3c2410_flash.c中 ;④拷贝flash中的kernel映像和根文件系统映像到RAM空间中;⑤跳转到内核的第 一条指令 处。跳转时需要满足下列条件:R0为0;R1为机器类型ID;禁止中断(IRQ和FIQ);C PU设置 为SVC模式(SVC是供操作系统使用的一种保护模式);关闭MMU;关闭数据Cache。至此Boot Loader的任务结束。
2.3 Linux内核的修改
假定内核代码放在/usr/src/Linux-2.4.18目录下
(1) 打开根目录下的Makefile文件 此文件用来指定编译规则,例如哪些需要编译,哪些 需要先编译。
指定目标平台:Arch=arm;
指定交叉编译器:添加CROSS_COMPILE=arm-linux-。
(2) 打开/arch/arm目录下的Makefile文件 启动代码的产生需要通过此文件,由于2.4内 核还没有对S3C2410的支持,在此添加如下代码:
ifeq((CONFIG_ARCH_S3C2410),y)
TEXTADDR=0xC0008000
MACHINE=s3c2410
Endif
TEXTADDR是内核的最终运行地址,该位置一般在RAM区起始地址偏移0x8000处(RAM起始地址 到偏移0x8000之间的32KB空间中存放一些全局数据结构如启动参数、内存页表等信息)。
(3) 打开/arch/arm/boot目录下的Makefile文件 ZTEXTADDR是解压前image.rom的位置, ZRELADDR是内核解压并最终执行的位置。ZRELADDR与TEXTADDR之间符合如下映射关系:_v irt_to_phys(TEXTADDR)==ZRELADDR.
ifeq((CONFIG_ARCH_s3c2410),y)
ZTEXTADDR=0XC0008000
ZRELADDR=0X30008000
endif
(4) 打开/arch/arm/boot/compressed目录下的Makefile文件,添加ifeq(“$(CONFIG_A RCH_S3C2410),y)
OBJS+=head-s3c2410.o
endif
(5) 打开/arch/arm/config.in 此文件是配置文件,决定了在配置菜单中看到的内容。添 加$CONFIG_ARCH_S3C2410子选项
If[“$ CONFIG_ARCH_S3C2410” = “y”];then
Comment ‘Archimedes/A5000 Implementations’
Dep_bool ‘SMDK (MERI TECH BOARD)’
CONFIG_S3C2410_SMDK//
$CONFIG_ARCH_S3C2410
//其他
fi
在if[“$CONFIG_FOOTBRIDGE_HOST ”=“y”-o
……
“$CONFIG_ARCH_SA1100”=“y”];then
define_bool CONFIG_ISA y
else
define_bool CONFIG_ISA n
fi
中依樣添加“$CONFIG_ARCH_s3c2410”=“y”-o \。
(6) 打开/arch/arm/boot/compressed/head-s3c2410.s 此处需要添加内核解压前处 理器初始化文件head-s3c2410.s,示例代码如下:
.section #“.start”,“ax”
_S3C2410_start:
bic r2,pc,#0x1f @清除pc相关位,放于r2
add r3,r2,#0x4000
l:
ldr r0,[r2],#32
teq r2,r3
bne 1b
mcr p15,0,r0,c7,c10,4 @写回Write Buffer
mcr p15,0,r0,c7,c7,0 @刷新I&D caches
#if 0
@禁用MMU,caches
……
#endif
mov r0,#0x00200000
l:
subs r0,r0,#1
bne 1b
依次将$(CONFIG_ARCH_2410)加入
(7) 打开/arch/arm/kernel/Makefile
no-irq-arch:=$(CONFIG_ARCH_INTEGRATOR)$(CONFIG_ARCH_CLPS711X)
……
$(CONFIG_ARCH_AT91RM9200
并添加 obj-$(CONFIG_MIZI)+=ecard.o
obj-$(CONFIG_ARCH_APM)+=apm2.o
(8) 打开/arch/arm/kernel/entry-arm v.s 此文件主要定义CPU初始化时中断处理部分 ,可参考处理器使用手册,按处理器使用要求配置。
(9) 打开/arch/arm/kernel/debug-arm v.s 此文件用于最基本的串口调试功能,包括 调试串口的地址初始化、发送、等待、忙状态定义等。使用此文件可以在启动过程中打印出 相关信息。
(10) 打开/arch/arm/kernel/setup.c 此文件中要根据使用的板子设置几个变量。nr_b a nks指定了内存块的数量,bank指定了每块内存块的范围,PAGE_OFFSET是内存起始地址, MEM_SIZE是内存的大小,PAGE_OFFSET和MEM_SIZE要在/include/asm-arm/arch-s3c 2410中定义。
(11) 打开/arch/arm/mm/mm-arm v.c 此文件用于与硬件相关的内存管理,如初始化内 存页表内存映射等。将init_maps->bufferable=0;改为init_maps->bufferable=1。
(12) 打开/arch/arm/mach-s3c2410 建立相应目录并按照处理器使用要求编写irq.c、m m.c 、time.c、arch.c、Makefile,分别实现中断控制器的初始化,地址的虚实映射关系,时钟 中断和实时时钟处理以及有关Ramdisk使用参数等的设置。
(13) 打开/include/asm-arm/arch-s3c2410 此目录下定义用到的头文件。
2.4 编译Linux内核
在完成上述工作后,再进行如下编译,即可得到我们需要的映像文件。
(1) make clean:该命令清除以前构造内核时生成的所有目标文件、模块和临时文件。
(2) make dep:该命令搜索Linux输出与源代码之间的依赖关系,并以此生成依赖文件。
(3) make menuconfig:该命令是用来调用菜单式配制内核界面。
(4) make zImage:该命令用来编译内核,生成压缩的Linux内核目标代码zImage文件。
(5) make modules:该命令编译模块驱动程序
2.5 文件系统的生成——创建JFFS2文件系统
文件系统是Linux系统必备的一个部分,本系统使用mkfs.jffs2工具来创建JFFS2文件系 统。首先建立上述的/bin、/sbin等目录,然后拷贝命令工具到/bin文件夹,拷贝系统控制 程序到/sbin目录下,拷贝应用程序运行时所需要的库到/lib文件夹,库文件可以从pc机上 的交叉编译根据安装目录下拷贝,如libc-2.2.2.so、libcrypt-2.2.2.so、libm-2.2.2 .so等。这些准备完成后键入命令:
mkfs.jffs2 #-d jffs2 #-o root.jffs2
生成JFFS2根文件系统。
上述工作完成后,将Boot Loader、Linux内核、文件系统烧写到目标机的FLASH中,目 标机就能运行Linux系统了。
3 结束语
本文作者创新点:版本2.4的Linux并没有包含进对S3C2410的支持,本文详尽分析了将L inux-2.4移植到S3C2410上的主要技术,在移植过程中重点阐述的移植思路和方法对将Linux 嵌入式操作系统移植到其他处理器为核心的硬件平台也有借鉴作用。
参考文献:
[1] 毛德操,胡希明.Linux内核源代码情景分析[M].杭州:浙江大学出版社,20 01.
[2] 邹思轶.嵌入式Linux设计与应用[M].北京:清华大学出版社,2002.
[3] 白伟平,包启亮.基于ARM的嵌入式Boot Loader浅析[J].微计算机信息,2 006,22(11):99-100.
[4] 吴娴.嵌入式Linux文件系统的设计与实现[J].计算机工程与应用,2005,4 1(9):111-112.
(责任编辑:李 丽)