【IDT】 windows IDT GDT LDT

article/2025/9/19 3:15:55

IDT:

(Interrupt Descrptor Table)中断描述符表,用来处理中断的。

IDT的获取:

  1. 可以通过SIDT指令,它可以在内存中找到IDT,返回一个IDTR结构的地址。
  2. 也可以通过kpcr结构获取

ISR:

中断服务例程

CPU通过查找在中断服务描述表(IDT)中找到的中断服务例程(ISR),知道如何响应以及对新接收到的中断执行哪些内核例程。

IDT的指针存储在每个物理处理器的IDTR寄存器中,每个处理器都有自己的IDTR寄存器,指向自己的中断描述符表。

IDT位置

可以通过读取IDTR寄存器的值来检查中断服务描述表在内核中的位置:

r  idtr

在这里插入图片描述
IDT 结构:
在这里插入图片描述

实模式和保护模式

CPU复位(reset)或加电(power on)的时候以实模式启动,处理器以实模式工作。
在实模式下,内存寻址方式和8086相同,由16位段寄存器的内容乘以16(10H)当
做段基地址,加上16位偏移地址形成20位的物理地址,最大寻址空间1MB,最大分
段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。在实模式下,所
有的段都是可以读、写和可执行的。
286架构导入保护模式,允许硬件等级的存储器保护。然而要使用这些新的特色,
需要额外先前不需要的软件指令。由于x86微处理机主要的设计规格,是能够完全
地向前兼容于针对先前所有x86芯片所撰写的软件,因此286芯片的开机是处于
’实模式’—也就是关闭新的存储器保护特性的模式,所以可以运行针对旧的微处
理器所设计的软件。到现在为止,即使最新的x86 CPU一开始在电源打开处于实
模式下,也能够运行针对先前任何芯片所撰写的软件.[1]

GDT、LDT与IDT

  1. 在保护模式下,对一个段的描述包括3方面因素:Base Adress, Limit, Access 它们加在一起放在一个64-bit长的数据结构中,被称为段描述符。
    在这里插入图片描述
  2. 段描述符使用数组存储,使用LGDT指令将GDT的入口地址装入GDTr寄存器。
  3. 段选择子,一个16位的数据结构。
    在这里插入图片描述
    三个都是比较重要的系统表
    这三个表都是在内存中由操作系统所建。但并不是固化在那里,所以从理论上是可以被读写的。

这三个表都是描述符表。

GDT: 全局服务描述符表
LDT: 局部描述符表
IDT: 中断服务描述符表

GDT 与IDT表

GDT的理解

    GDT全局服务描述表(Global Descriptor Table)
先理解一下实模式下得编程模型:在实模式下,对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment就是一个段的BaseAdress,一个Segment的最大长度是64kb,这是16bit系统所能表示的最大长度。

而offset是相对于此Segment Base Adress的偏移量。 Base Adress + offset就是一个内存绝对地址。由此,我们可以看出,一个段具备两个因素:Base Address 和 Limit (段的最大长度)
对于一个内存地址访问,需要指出: 使用哪个段,及相对于这个段Base Address 的offset 这个offset应该小于此段的limit。 对于16 bit 系统 ,limit不需要指定,默认最大长度为64k,且16bit的offset永远也不会大于此limit。
在保护模式下,内存的管理模式分为两种: 段模式和页模式,其中页模式也是基于段模式的。段模式是必不可少的。页模式是可选的。
对于段模式来讲,访问一个内存地址仍然使用Segment:offset的方式。 由于保护模式运行在32位系统上,那么segment的两个因素: Base Address 和limit 都是32位的。允许将一个段的地址设为32bit所能表示的任何值,而不像实模式下,一个段的Base Address只能是16的倍数。 保护模式,顾名思义,就是又为段模式提供了保护机制。也就是说一个段的描述符需要规定对自身的访问权限(Access)。
所以,在保护模式下,对一个段的描述则包括3方面的因素:【Base Address, limit , Access】,它们加在一起被放在一个64bit长的数据结构中,被称为段描述符。
在这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段寄存器装入这个段描述符。但为了保持向后兼容,将段寄存器仍然规定为16-bit。(虽然
每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16bit的),那么我们无法通过16-bit的长度的段寄存器来直接引用64-bit的段描述符,怎么办?
解决的方法就是把这些长度为64bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用。这个全局的数组就是GDT。事实上,在GDT中存放的不仅仅是段描述符,还有其他描述符。
GDT可以被存放在内存的任何位置,当通过段寄存器引用一个段描述符时,CPU必须知道GDT的入口,也就是基地址放在哪里。所以Intel设计了一个寄存器GDTR用来存放GDT入口地址。
程序员将GDT设定在内存某个位置之后,可以通过:LGDT指令将GDT的入口地装入此寄存器。从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。

在整个系统中,全局服务描述表GDT只有一张(一个处理器对应一个GDT)
GDT可以被放在内存任何位置
系统用GDTR寄存器存放当前GDT表的基地址。
用LDTR寄存器存放LDT表地址

我们知道,在实模式下,CPU是16位的,意思是 寄存器是16位的,数组总线是16位的,但地址总线是20位的。物理内存计算公式:

                物理地址   =  段地址 * 16 + 偏移量

段地址和偏移量都是16位,能寻址的最大内存地址为1M

2的20次方就是1M

若一个内存地址是20:30 最终的内存地址是: 20 * 16 +30

实模式和保护模式

实模式只有20位地址总线, 寻址空间只有1M ,以及8个16位的通用寄存器。4个16位的段寄存器。为了能够通过16位的寄存器去构成20位的主存地址,采取一种特殊的方法,使用下面的地址:

段基址: 段偏移量

物理地址 = 段地址 << 4 + 段内偏移

保护模式下,CPU的32条地址线全部有效,可寻址4G的字节的物理地址空间。但是为了兼容16位。此时计算机中的通用寄存器都成为32位。

在保护模式下存在一些限制。把这些限制信息放在一个全局服务描述表(GDT)中。

GDT的作用是提供段式存储机制。段寄存器提供段值,即描述符在GDT中的索引。

在进入保护模式前、必须准备好GDT、描述符和描述符选择子。

全局服务描述表:

    包含一个段的基址,界限及属性内容。其中段基地址和16位的系统中的段地址一样。只是在16位系统中段地址必须是16的倍数,但是在32位系统中段地址可以是任意地址。

寻址方式:

段地址(选择子)------在GDT中找到描述符-------
在描述符中找到段地址-----段地址+偏移地址 = 线性地址

IDT结构体:

//idtr指向这个结构体
typedef struct _IDT_INFO{UINT16 uIdtLimit;   // IDT范围UINT16 uLowIdtBase;   // IDT低基址UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, *PIDT_INFO;// IDT表中描述符结构体
//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{// USHORT == UINT16USHORT uOffsetLow;       //0x0,低地址偏移USHORT uSelector;     //0x2,段选择器//USHORT uAccess;      //0x4UINT8 uReserved;     // 保留UINT8 GateType : 4;     // 中断类型UINT8 StorageSegment : 1;   // 为0则是中断门UINT8 DPL : 2;      // 特权级UINT8 Present : 1;      // 如未使用中断可置为0USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;

获取IDTR

__asm sidt stcIDT

遍历IDT:

#include <ntifs.h>
#include <ntddk.h>#define MAKE_LONG(a,b) ((a) + (b<<16))typedef struct _IDT_INFO {UINT16 uIdtLimit;   // IDT范围UINT16 uLowIdtBase;   // IDT低基址UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, * PIDT_INFO;//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{// USHORT == UINT16USHORT uOffsetLow;       //0x0,低地址偏移USHORT uSelector;     //0x2,段选择器//USHORT uAccess;      //0x4UINT8 uReserved;     // 保留UINT8 GateType : 4;     // 中断类型UINT8 StorageSegment : 1;   // 为0则是中断门UINT8 DPL : 2;      // 特权级UINT8 Present : 1;      // 如未使用中断可置为0USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;void OnUnload(DRIVER_OBJECT* pDriver)
{pDriver;
}NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{NTSTATUS status = STATUS_SUCCESS;pRegPath;pDriver->DriverUnload = OnUnload;//KdBreakPoint();IDT_INFO stcIDT = { 0 };PIDTENTRY pIdtEntry = NULL;ULONG uAddr = 0;// IDT table__asm sidt stcIDT;// IDT arraypIdtEntry = (PIDTENTRY)MAKE_LONG(stcIDT.uLowIdtBase, stcIDT.uHighIdtBase);KdPrint(("-------------IDT---------------\n"));KdPrint(("IDT Addr: 0x%p\n", pIdtEntry));for (ULONG i = 0; i < 0x100; ++i){KdPrint(("Interrupted number: %d\n", i));uAddr = MAKE_LONG(pIdtEntry[i].uOffsetLow, pIdtEntry[i].uOffsetHigh);KdPrint(("Interrupted Addr: 0x%p\n", uAddr));KdPrint(("selector: %d\n", pIdtEntry[i].uSelector));KdPrint(("GataType: %d\n", pIdtEntry[i].GateType));KdPrint(("DPL: %d\n\n", pIdtEntry[i].DPL));}return status;
}

获取IDTR

__asm sidt stcIDT

遍历IDT:

#include <ntifs.h>
#include <ntddk.h>#define MAKE_LONG(a,b) ((a) + (b<<16))typedef struct _IDT_INFO {UINT16 uIdtLimit;   // IDT范围UINT16 uLowIdtBase;   // IDT低基址UINT16 uHighIdtBase;   // IDT高基址
}IDT_INFO, * PIDT_INFO;//0x8 bytes (sizeof)
typedef struct _IDTENTRY
{// USHORT == UINT16USHORT uOffsetLow;       //0x0,低地址偏移USHORT uSelector;     //0x2,段选择器//USHORT uAccess;      //0x4UINT8 uReserved;     // 保留UINT8 GateType : 4;     // 中断类型UINT8 StorageSegment : 1;   // 为0则是中断门UINT8 DPL : 2;      // 特权级UINT8 Present : 1;      // 如未使用中断可置为0USHORT uOffsetHigh; //0x6   // 高地址偏移
}IDTENTRY, *PIDTENTRY;void OnUnload(DRIVER_OBJECT* pDriver)
{pDriver;
}NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{NTSTATUS status = STATUS_SUCCESS;pRegPath;pDriver->DriverUnload = OnUnload;//KdBreakPoint();IDT_INFO stcIDT = { 0 };PIDTENTRY pIdtEntry = NULL;ULONG uAddr = 0;// IDT table__asm sidt stcIDT;// IDT arraypIdtEntry = (PIDTENTRY)MAKE_LONG(stcIDT.uLowIdtBase, stcIDT.uHighIdtBase);KdPrint(("-------------IDT---------------\n"));KdPrint(("IDT Addr: 0x%p\n", pIdtEntry));for (ULONG i = 0; i < 0x100; ++i){KdPrint(("Interrupted number: %d\n", i));uAddr = MAKE_LONG(pIdtEntry[i].uOffsetLow, pIdtEntry[i].uOffsetHigh);KdPrint(("Interrupted Addr: 0x%p\n", uAddr));KdPrint(("selector: %d\n", pIdtEntry[i].uSelector));KdPrint(("GataType: %d\n", pIdtEntry[i].GateType));KdPrint(("DPL: %d\n\n", pIdtEntry[i].DPL));}return status;
}

遍历GDT:

#include <ntddk.h>#define MAKE_LONG(a,b) ((LONG)(((UINT16)(((DWORD_PTR)(a)) & 0xffff)) | ((UINT32)((UINT16)(((DWORD_PTR)(b)) & 0xffff))) << 16))typedef struct _GDT_INFO {UINT16 uGdtLimit;UINT16 uLowGdtBase;UINT16 uHighGdtBase;
}GDT_INFO, *PGDT_INFO;//0x8 bytes (sizeof)
typedef struct _GDTENTRY
{USHORT LimitLow;                                                        //0x0USHORT BaseLow;                                                         //0x2union{struct{UCHAR BaseMid;                                                  //0x4UCHAR Flags1;                                                   //0x5UCHAR Flags2;                                                   //0x6UCHAR BaseHi;                                                   //0x7} Bytes;                                                            //0x4struct{ULONG BaseMid : 8;                                           ULONG Type : 4;     ULONG S : 1;ULONG Dpl : 2;                                               ULONG Pres : 1;                                              ULONG LimitHi : 4;                                           ULONG Avl : 1;                                               ULONG Reserved_0 : 1;                                        ULONG D_B : 1;                                       ULONG Granularity : 1;                                       ULONG BaseHi : 8;                                            } Bits;                                                          } HighWord;                                                          
}GDTENTRY, *PGDTENTRY;void OnUnload(DRIVER_OBJECT* pDriver)
{pDriver;
}NTSTATUS DriverEntry(DRIVER_OBJECT* pDriver, UNICODE_STRING* pRegPath)
{NTSTATUS status = STATUS_SUCCESS;pRegPath;pDriver->DriverUnload = OnUnload;//KdBreakPoint();GDT_INFO stcGDT = { 0 };PGDTENTRY pGdtEntry = NULL;unsigned int nGdtEntry = 0;ULONG uData = 0;// IDT table__asm sgdt stcGDT;// IDT arraypGdtEntry = (PGDTENTRY)MAKE_LONG(stcGDT.uLowGdtBase, stcGDT.uHighGdtBase);KdPrint(("-------------GDT---------------\n"));KdPrint(("GDT Addr: 0x%p\n", pGdtEntry));nGdtEntry = stcGDT.uGdtLimit / 8;for (ULONG i = 0; i < nGdtEntry; ++i){if (!(pGdtEntry[i].HighWord.Bits.Pres)) continue;uData = (ULONG)pGdtEntry[i].BaseLow+ ((ULONG)(pGdtEntry[i].HighWord.Bits.BaseMid) << 16)+ ((ULONG)(pGdtEntry[i].HighWord.Bits.BaseHi) << 24);KdPrint(("BaseAddr: 0x%p\n", uData));uData = pGdtEntry[i].LimitLow+ ((ULONG)(pGdtEntry[i].HighWord.Bits.LimitHi) << 16);KdPrint(("Segment Limit: 0x%08X ", uData));(pGdtEntry[i].HighWord.Bits.Granularity)? KdPrint(("pages\n")): KdPrint(("bytes\n"));KdPrint(("DPL: %d\n", pGdtEntry[i].HighWord.Bits.Dpl));if ((pGdtEntry[i].HighWord.Bits.S == 0)){KdPrint(("Type: System segment\t"));switch (pGdtEntry[i].HighWord.Bits.Type){case 12:KdPrint(("Call Gate "));break;case 14:KdPrint(("Interruptting Gate "));break;case 15:KdPrint(("Trap Gate "));break;case 5:KdPrint(("Task Gate "));break;default:KdPrint(("Unknown "));break;}KdPrint(("\n"));}else{if (pGdtEntry[i].HighWord.Bits.Type & 0x8){KdPrint(("Type: Code Segment\n"));KdPrint(("Attr: "));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x4 ? "C" : "-"));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x2 ? "R" : "-"));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x1 ? "A" : "-"));KdPrint(("\n"));}else{KdPrint(("Type: Data Segment\n"));KdPrint(("Attr: "));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x4 ? "E" : "-"));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x2 ? "W" : "-"));KdPrint(("%s", pGdtEntry[i].HighWord.Bits.Type & 0x1 ? "A" : "-"));KdPrint(("\n"));}}KdPrint(("\n"));}return status;
}

REFERENCE

https://www.cnblogs.com/ciyze0101/p/5350613.html windows 下的IDT hook和GDT的学习
https://blog.csdn.net/ggh19/article/details/113705230?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-113705230-blog-50654629.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-113705230-blog-50654629.pc_relevant_default&utm_relevant_index=2 操作系统中的描述符和GDT


http://chatgpt.dhexx.cn/article/NgjcoDhK.shtml

相关文章

GDT 表与段选择子等解析

来源&#xff1a;https://blog.csdn.net/qq_37653144/article/details/82821540 https://blog.csdn.net/yeruby/article/details/39718119 https://blog.csdn.net/lindorx/article/details/89410113 全局描述表(GDT Global Descriptor Table):在保护模式下一个重要的数据结构…

GDT和GDTR

文章目录 GDTR和GDTGDT和GDTR关系GDTR的结构GDT的结构如何在MBR中建立GDT和GDTR? GDTR和GDT GDT和GDTR关系 GDT是global descriptor table&#xff0c;全局描述符表&#xff0c;它是描述符组成的一张描述符表。描述符就是段描述符它用来描述一个段的信息&#xff0c;由8个字节…

GDT,LDT,GDTR,LDTR

GDT,LDT,GDTR,LDTR 前言全局描述符表GDT局部描述符表LDT中断描述符表IDT段选择子任务寄存器TR实例1&#xff1a;访问GDT2&#xff1a;访问LDT 前言 所谓工作模式&#xff0c;是指CPU的寻址方式、寄存器大小、指令用法和内存布局等。 实模式 段基址:段内偏移地址”产生的逻辑地…

GDT和LDT详解

1.GDT 我们回顾一下实际的操作系统的内存关系: ​ 程序/进程 → 映射 段 表 逻辑地址 → segment unit 段 基 址 偏 移 地 址 虚拟地址 → page unit 页 表 物理内存地址 \text{程序/进程}\overset{段表}{\xrightarrow[\text{映射}]{}} \text{逻辑地址}\overset{段基址偏移…

GDT(全局描述符表)和LDT(局部描述符表)

Home > GDT&#xff08;全局描述符表&#xff09;和LDT&#xff08;局部描述符表&#xff09; 每个程序都有自己的LDT&#xff0c;但是同一台计算机上的所有程序共享一个GDT。LDT描述局部于每个程序的段&#xff0c;包括其代码、数据、堆栈等。GDT描述系统段&#xff0c…

什么是数据可视化?

到底什么是数据可视化&#xff1f;带你一窥究竟&#xff5e; 技术人最不该忽视可视化数据分析&#xff01; 导读&#xff1a;在这个“人人都是数据分析师”的时代&#xff0c;大企业的同学几乎都在参与数据的采集、加工与消费。数据可视化作为连接“加工——消费”的重要一环…

当下最火的中台到底是个什么鬼,看完这一篇最通俗易懂的文章后,你就会彻底明白了!...

公众号关注 「奇妙的 Linux 世界」 设为「星标」&#xff0c;每天带你提升技术视野&#xff01; 背景 自从阿里巴巴现任CEO逍遥子在2015年提出”大中台&#xff0c;小前台”战略以来&#xff0c;关于”什么是中台”&#xff0c;可谓是一石激起千层浪&#xff0c;大量文章在描述…

STD::是什么?

【&#xff23;&#xff0b;&#xff0b;】std&#xff1a;&#xff1a;是什么&#xff1f; 引例&#xff1a; #include<iostream> int main() {std::cout<<"我喜欢C";//输出一句话std::cout<<std::endl;//换行return 0; } 1.std是什么&#xff1…

C语言中 1%3,算术什么意思啊 算数什么意思

算术什么意思啊 算数什么意思以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 算术是什么意思 数学 什么是算术和 算术和是正数的和,即绝对值的和,例如2+13.5+7,Ge个数值皆为正且相加。  主要区别于代数和,…

matlab语句temp,maxtemp什么意思 will什么意思

maxtemp什么意思 will什么意思以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Min Temp 和 Max Temp 是什么意思 最小的Temp和最大Temp Temp: Chang用的办公软件和其他应用程序通常会临时保Cun用户的工作结果,…

html 玫瑰花

简易html 代码玫瑰花 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>玫瑰</title><style type"text/css"> #shusheng { position: absolute; width: 100%; height: 100%; text-align: center; } &…

计算并输出所有的玫瑰花数

如果一个n位正整数等于它的n个数字的n次方和&#xff0c;则称该数为n位自方幂数。四位自方幂数称为玫瑰花数。编程计算并输出所有的玫瑰花数。 #include <stdio.h> #include <math.h>int main() {for (int i 1000; i < 10000; i){if (i pow(i%10, 4) pow((i/…

C语言代码:玫瑰花

前文 在古希腊神话中&#xff0c;玫瑰花集爱与美于一身&#xff0c;既是美神的化身&#xff0c;又溶进了爱神的血液&#xff0c;所以它所代表的含义是爱情。 我们应该用玫瑰花来表达我们的爱意&#xff0c;但是好多的恋人都是因为异地而没有办法去买一束新鲜的玫瑰去送给自己的…

七夕玫瑰花合集

图片来源&#xff1a;百度动图 一年一度的七夕又快到了&#xff0c;用Python画一朵玫瑰花送给你的那个TA吧图片。更多表白代码可以到”阿黎逸阳的代码“公众号中翻看表白合集中的文章。 一、绘制结果 1. 玫瑰花1 2. 玫瑰花2 二、画玫瑰花代码 1. 用turtle库画一朵玫瑰花版本1 #…

C++玫瑰花源码

#include "stdafx.h" #include <graphics.h> #include <conio.h> #include <math.h> // 定义全局变量 int rosesize 500; int h -250; // 定义结构体 struct DOT { double x; double y; double z; double red; // 红…

Python玫瑰花

用Python画一朵玫瑰花&#xff08;附带源码&#xff09; 需要的模块包 turtle(内置包) 源码部分 import turtle# 设置初始位置 turtle.penup() turtle.left(90) turtle.fd(200) turtle.pendown() turtle.right(90)# 花蕊 turtle.fillcolor("red") turtle.begin_fill…

C语言玫瑰花

效果图&#xff0c;如果想要更改颜色&#xff0c;可以在代码最后一行system处修改。 #include <stdio.h> #include <math.h>const int max_iterations 128; const float stop_threshold 0.01f; const float grad_step 0.01f; const float clip_far 10.0f;cons…

如何买玫瑰?

代码和任务 /*copyright(c)2015 csdn学院 *All right reserved. *文件名称&#xff1a;main.c *作者&#xff1b;张如田 *完成日期&#xff1a; *版本号&#xff1a; *任务描述&#xff1a;小慧过生日&#xff0c;小明&#xff08;小明真忙&#xff09;要买鲜花送她。每枝红玫瑰…

买玫瑰

要求&#xff1a;小慧过生日&#xff0c;小明&#xff08;小明真忙&#xff09;要买鲜花送她。每枝红玫瑰5元&#xff0c;满5支送1枝&#xff0c;满20枝送5枝。小明一共有n(n>10)元钱&#xff0c;最多能买到多少&#xff1f; 样例输入&#xff1a;135 样例输出&#xff1a;3…

中软国际实训全记录——第三天

中软国际实训第三天——认识ssm与搭建ssm 1、ssm框架基本概念1.1、Spring1.2、SpringMVC1.3、MyBatis 2、建立ssm项目2.1、新建Maven项目2.2、添加项目主要目录2.3、项目内容编码2.4、使用Tomcat运行项目2.5、建立数据库的连接2.6、对数据库中数据进行查询2.7、使用控制器显示查…