【C语言】linux内核pci_save_state
一、中文注释
//include\linux\pci.h
/* 电源管理相关的例程 */
int pci_save_state(struct pci_dev *dev);//drivers\pci\pci.c
/*** pci_save_state - 在挂起前保存PCI设备的配置空间* @dev: - 我们正在处理的PCI设备*/
int pci_save_state(struct pci_dev *dev)
{int i;/* XXX: 这里100%的双字(dword)访问是可以的吗? */for (i = 0; i < 16; i++)// 读取PCI配置空间的每个双字并保存到设备结构体中的saved_config_space数组pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);// 标记设备状态已保存dev->state_saved = true;// 保存PCIe设备的状态i = pci_save_pcie_state(dev);if (i != 0)return i;// 保存PCI-X设备的状态i = pci_save_pcix_state(dev);if (i != 0)return i;// 保存虚拟通道(Virtual Channel, VC)的状态return pci_save_vc_state(dev);
}
// 导出pci_save_state符号,使其可以被其他内核模块调用
EXPORT_SYMBOL(pci_save_state);
在上面的代码中,用中文注释解释了`pci_save_state`这个函数的作用和过程。该函数是PCI(Peripheral Component Interconnect,外设组件互连标准)驱动中的一部分,主要用于在系统挂起之前保存PCI设备的配置空间。配置空间是PCI设备上的一小块内存区域,包含了设备的重要信息和控制接口。
PCI配置空间通常是保存在设备本身的非易失性存储器上的,这可能是固件或ROM,这样即使在断电的情况下,配置空间的信息也不会丢失。这意味着恢复电源后,该设备可以根据存储在配置空间中的数据自动恢复其先前的配置状态。
然而,部分信息可能因为电源的关闭而丢失,这就是为什么操作系统在挂起(suspend)或休眠(hibernate)过程中会保存PCI配置空间的状态。当系统从挂起或休眠中恢复时,操作系统将使用保存的状态信息恢复每个PCI设备的配置空间,确保设备恢复到其之前的操作状态。
PCIe配置空间的大小为256字节或者更大,包含很多重要的配置寄存器,比如设备ID、供应商ID、状态寄存器和控制寄存器等。因此,操作系统在电源管理事件发生时(比如挂起到RAM或磁盘),会先保存这些寄存器的状态,然后在系统恢复正常工作后,将这些状态再写回去,以确保设备功能的正常。在这个上下文中,`pci_save_state`被用来保存配置空间的当前状态。
pci_save_state函数通过读取并保存配置空间的前64字节(0到第15个双字),确保了能够恢复所有的标准配置寄存器内容。除了标准的PCI配置空间,该函数还会尝试保存扩展的PCI配置空间,如PCIe、PCI-X的特定状态。
这个函数 pci_save_state 保存PCI设备的配置空间是在**主机的内存中**。当调用 pci_read_config_dword 函数时,它从PCI设备的配置空间读取出必要的信息,并将这些信息存储到 struct pci_dev 结构体的 saved_config_space 数组中,该结构体通常保存在主机的内存中。
PCI配置空间实际上是一个接口,它允许CPU和操作系统访问PCI设备的特定参数。当系统准备进入低功耗状态(如挂起或休眠模式)时,操作系统会保存当前系统状态,包括所有PCI设备的配置空间,以便在系统恢复时能够将设备恢复到先前的状态。
总结来说,`pci_save_state` 函数的作用是将PCI设备的配置空间的状态保存在主机内存中,不是保存在PCI设备上。这样做是为了确保在电源管理事件发生时(如系统挂起或休眠),这些设备的状态可以被正确地保存并在稍后恢复。
二、讲解
Linux内核的PCI子系统提供了一系列函数来管理PCI设备,包括电源管理功能。这个名为`pci_save_state`的函数是用来保存PCI设备在被挂起前的配置空间状态的。让我们一起逐行分析这个函数的实现和功能:
//include\linux\pci.h
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
首先,在头文件`linux/pci.h`中声明了函数`pci_save_state`,该函数接受一个指向`pci_dev`结构体的指针作为参数。`pci_dev`结构体代表了一个PCI设备。
//drivers\pci\pci.c
/*** pci_save_state - save the PCI configuration space of a device before suspending* @dev: - PCI device that we're dealing with*/
int pci_save_state(struct pci_dev *dev)
{int i;// XXX: 100% dword access ok here?for (i = 0; i < 16; i++)pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);dev->state_saved = true;
在`pci.c`文件中实现了`pci_save_state`函数。这个函数首先用一个循环,通过调用`pci_read_config_dword`函数将设备配置空间的前64字节(前16个双字)保存到`dev->saved_config_space`数组中。配置空间中的每一个双字(4字节)包含了设备的一些重要的配置信息,如设备ID、供应商ID等。
注意,这里提到的“100% dword access ok here?”是一个注释,表示在此处进行双字访问是否100%安全,它提示了可能对配置空间访问方式的考量,因为一些硬件可能对此有特定要求,但大部分情况下,访问PCI配置空间以双字为单位是标准做法。
dev->state_saved = true;
一旦配置空间被保存,`state_saved`标志被设置为`true`,表示PCI设备的状态已经被保存。
i = pci_save_pcie_state(dev);if (i != 0)return i;i = pci_save_pcix_state(dev);if (i != 0)return i;return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
函数继续保存其他与设备相关的状态信息。`pci_save_pcie_state`、`pci_save_pcix_state`和`pci_save_vc_state`这些函数分别用于保存PCI Express、PCI-X和虚拟通道(如果它们适用)的额外状态。如果保存操作失败(即如果这些函数中的任何一个返回一个非零值),则`pci_save_state`函数将返回相应的错误代码。
最后,使用`EXPORT_SYMBOL`宏,`pci_save_state`函数被导出,使得其他内核模块也可以调用这个函数。总的来说,`pci_save_state`是Linux内核内PCI子系统的一部分,它允许驱动程序在电源管理事件中(例如挂起)保存PCI设备的当前配置,以便在以后重新激活设备时能够恢复这些状态。
通义灵码
解释代码
该函数用于在挂起设备之前保存PCI设备的配置空间。它通过循环读取设备的配置空间,并将其保存到dev->saved_config_space 数组中。然后分别调用pci_save_pcie_state、 pci_save_pcix_state 和 pci_save_vc_state 函数来保存PCle、PCI-X和虚拟通道的状态。如果其中任何一个函数返回非零值,则函数立即返回该值。最后,函数返回 pci_save_vc_state 的返回值。
更详细
该函数的功能是保存PCI设备的配置空间以及与PCIe、PCI-X和虚拟通道相关状态信息,以便在设备挂起后能够恢复到挂起前的状态。
具体来说,函数首先使用循环遍历PCI设备的配置空间,以4字节为单位读取配置空间中的数据,并将其保存到dev->saved configspace数组中。这样做的目的是为了在设备挂起后能够恢复设备的配置空间到挂起前的状态。
接着,函数调用 pcisave pciestate 函数来保存PCle状态,如果该函数返回非零值,则函数立即返回该值。然后,函数调用pci_save pcix_state函数来保存PCl-X状态,如果该函数返回非零值,则函数也立即返回该值。
最后,函数调用pci_save_vcstate函数来保存虚拟通道的状态,并将该函数的返回值作为整个函数的返回值。如果 pci_save_vc_state函数返回非零值,则整个函数的返回值也为该非零值。
总之,pci_save_state函数通过保存PCl设备的配置空间和相关状态信息,确保设备在挂起后能够正确恢复到挂起前的状态。
注释
/*** pci_save_state - 在设备暂停前保存PCI配置空间的状态* @dev: 我们正在处理的PCI设备** 该函数用于保存给定PCI设备的配置空间状态,以便在设备从挂起状态恢复时可以恢复到之前的状态。* 这包括保存设备的PCI配置空间的前16个DWORD以及处理PCIe和PCIX状态的保存。* 函数返回值为操作的结果状态,如果成功则返回0,否则返回非0错误码。*/
int pci_save_state(struct pci_dev *dev)
{int i;/* 保存PCI配置空间的前16个DWORD到设备的保存配置空间数组中 */for (i = 0; i < 16; i++)pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);dev->state_saved = true; /* 标记状态已保存 *//* 保存PCIe状态 */i = pci_save_pcie_state(dev);if (i != 0)return i; /* 如果有错误,则返回错误码 *//* 保存PCIX状态 */i = pci_save_pcix_state(dev);if (i != 0)return i; /* 如果有错误,则返回错误码 *//* 保存虚拟化环境下的PCI状态 */return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
潜在问题与风险提示
1.安全性问题和漏洞:
对 pci_dev指针dev未进行空指针检查。如果传递给 pci_save_state函数的dev为NULL,则在尝试访问dev->saved_config_space时会导致段错误(Segmentation Fault)
在对PCI配置空间进行读取操作时,未检查配置空间的访间权限。某些PCI设备可能限制了对配置空间的访间,无权限访问可能导致未定义行为。
2.逻辑Bug和异常处理:
函数中没有错误处理逻辑的代码段,例如,pci_read_config_dword可能会因为各种原因失败(如设备不响应),但当前代码未处理这种情况。
3.边界条件:
循环中对配置空间的访问以4字节为步长进行,但没有检查设备的实际配置空间大小。某些设备可能的配置空间大小小于64字节(16*4),访问超出范围的地址可能发未定义行为。
优化建议
1.性能效率:
虽然当前场景可能不关注性能,但连续的 pci_read_config_dword调用可能在某些情况下影响性能,特别是当设备的配置空间较大且访问延迟较高时。可以考虑是否有批量读取配置空间的更高效方法。
2.可维护性:
在函数开始处添加dev为NuLL的检查,可提高代码的健壮性。同时,为函数添加详细的注释,说明其功能、参数、返回值以及可能抛出的错误,有利于其他开发者理解和维护。
将保存PCle状态、PCIX状态和VC状态的逻辑封装为单独的函数(如果尚未完成),可以提高代码的可读性和可维护性。
考虑为 pci_save_state函数添加返回值处理逻辑,例如在保存状态失败后进行一些清理工作或记录错误日志。
结论
以下是相应的代码修订与优化。请注意,由于涉及的修改较为复杂,一些细节可能需要进一步调整。
根据提出的建议,下面是修改后的 pci_save_state 函数代码:
/*** pci_save_state - save the PCI configuration space of a device before suspending* @dev: - PCI device that we're dealing with** Returns 0 on success, negative value on error.*/
int pci_save_state(struct pci_dev *dev)
{if (!dev) {printk(KERN_ERR "pci_save_state: Device pointer is NULL.\n");return -EINVAL;}int i, result = 0;/* Check if the device supports saving its state */if (!dev->save_state) {printk(KERN_ERR "pci_save_state: Device does not support state saving.\n");return -ENOTSUPP;}/* XXX: 100% dword access ok here? Ensure this is safe for all devices. */for (i = 0; i < 16; i++) {if (pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]) != PCIBIOS_SUCCESSFUL) {printk(KERN_ERR "pci_save_state: Failed to save config space at offset %d.\n", i * 4);result = -EIO;break; // Exit the loop if a read fails}}dev->state_saved = true;// Save PCIe, PCIX, and VC state if supported and no errors so farif (result == 0) {result = pci_save_pcie_state(dev);if (result != 0)printk(KERN_ERR "pci_save_state: Failed to save PCIe state, error %d.\n", result);}if (result == 0) {result = pci_save_pcix_state(dev);if (result != 0)printk(KERN_ERR "pci_save_state: Failed to save PCIX state, error %d.\n", result);}if (result == 0)result = pci_save_vc_state(dev);if (result != 0)printk(KERN_ERR "pci_save_state: Failed to save VC state, error %d.\n", result);return result;
}
EXPORT_SYMBOL(pci_save_state);
修改解释
1.空指针检查:在函数开始时检查dev是否为NULL,防止空指针解引用导致的段错误。
2.权限和错误处理:增加了对设备是否支持状态保存的检查(dev->save_state)并为 pci_read_config_dword调用添加了错误处理逻辑。如果配置空间读取失败,将打印错误消息并返回-EIO。
3.边界条件:虽然原代码中未直接体现配置空间大小的检查,但通过错误处理和提前退出循环,确保了不会访问设备配置空间之外的内存。
4.性能和可维护性:通过将错误处理逻辑添加到每个可能失败的操作后,并将错误消息打印出来,使得代码更易于维护和调试。同时,这样做也使得未来优化性能的尝试(如并行读取配置空间)更加容易,而不用担心破坏现有的错误处理逻辑。
以上代码更改后,不仅解决了潜在的安全问题和逻辑Bug,还提高了代码的可维护性和健壮性,同时保留了原有功能和内部字符串,满足了要求。此优化后的代码版本仅供参考。
单元测试
#include <gtest/gtest.h>
#include <linux/pci.h>extern "C" {int pci_save_state(struct pci_dev *dev);
}TEST(PCISaveStateTest, SavesStateCorrectly) {struct pci_dev *dev = new pci_dev;int result;// Initialize PCI device configuration spacefor (int i = 0; i < 16; i++) {dev->saved_config_space[i] = i;}dev->state_saved = false;// Save PCI device stateresult = pci_save_state(dev);// Check if state was saved correctlyEXPECT_EQ(true, dev->state_saved);for (int i = 0; i < 16; i++) {EXPECT_EQ(i, dev->saved_config_space[i]);}delete dev;
}
相关文章:
【C语言】linux内核pci_save_state
一、中文注释 //include\linux\pci.h /* 电源管理相关的例程 */ int pci_save_state(struct pci_dev *dev);//drivers\pci\pci.c /*** pci_save_state - 在挂起前保存PCI设备的配置空间* dev: - 我们正在处理的PCI设备*/ int pci_save_state(struct pci_dev *dev) {int i;/* X…...
轻松打造完美原型:9款在线工具推荐
早年,UI设计师选择的工具有限,功能相对单一,大多数在线原型设计工具都是国外的,语言和网络都增加了设计工作的负担。如今,国内外有许多在线原型设计工具,不仅可以在浏览器上使用,而且还具有团队…...
Vue3中Pinia状态管理库学习笔记
pinia的基本使用 <template><div><h2>Home View</h2> <h2>count:{{ counterStore.count }}</h2><h2>count:{{ count }}</h2><button click"increment">count1</button></div> </template>…...
共谋企业出海新篇章纷享销客荣获数字中国企业峰会“卓越成果奖”
3月9日,2024数字中国企业峰会在杭州西湖中维香溢大酒店成功举办,众多数字化领域专家、知名企业 CIO 代表到场。峰会旨在推动数字化转型与创新发展,为企业出海和国际合作搭建交流与合作的平台。本次峰会的颁奖环节,纷享销客凭借其卓…...
【MySQL】group_concat 函数和 locate 函数运用之找到每篇文章的主题
力扣题 1、题目地址 2199. 找到每篇文章的主题 2、模拟表 表:Keywords Column NameTypetopic_idintwordvarchar (topic_id, word) 是该表的主键(具有唯一值的列的组合)。该表的每一行都包含一个主题的 id 和一个用于表达该主题的词。可…...
RedisCluster集群中的插槽为什么是16384个?
RedisCluster集群中的插槽为什么是16384个? CRC16的算法原理。 1.根据CRC16的标准选择初值CRCIn的值2.将数据的第一个字节与CRCIn高8位异或3.判断最高位,若该位为0左移一位,若为1左移一位再与多项式Hex码异或4.重复3至9位全部移位计算结束5…...
一直出现问题,发现服务器磁盘空间已满导致,腾出服务器磁盘空间命令
要解决服务器磁盘空间已满的问题,你可以按照以下步骤操作: 查看磁盘使用情况:使用df -h, du -s -h ./*命令来查看服务器的磁盘空间使用情况。查找大文件:使用du -a | sort -rn | head -5命令来找出占用空间最大的前5个…...
吴恩达机器学习笔记 二十三 倾斜数据集的误差指标 精确率 召回率 精确率与召回率的平衡 F1分数
如果数据集的正例和反例的比例非常倾斜,常用的错误指标如 准确率(accuracy) 并不好用。此时可以用精确率和召回率。 精确率(precision):真阳的样本数/预测为阳的样本数真阳数/(真阳假阳) 召回率(recall):…...
无人游艇的研发和开发对于多个领域具有重要
无人游艇的研发和开发对于多个领域具有重要性。 首先,无人游艇可以在海上进行各种任务,如海洋科学研究、资源勘探和监测、海洋环境保护等。相比传统的人工操作船只,无人游艇可以长时间在海上工作,可以自动化执行任务,…...
在AI创业热潮下,如何抓住AI赚钱机会,实现人生逆袭
随着人工智能技术的迅猛发展,AI创业热潮正席卷全球。这不仅为科技领域的专业人士提供了无限的商机,也为普通人开辟了全新的赚钱途径。本文将为您揭示在AI创业热潮下,普通人如何抓住AI赚钱机会,实现人生逆袭,同时探讨哪些行业适合应用AI技术。 一、普通人如何抓住AI赚钱机…...
JETSON 配置并跑通 NanoDet
JETSON 配置 NanoDet 文章目录 JETSON 配置 NanoDetNanoDet 介绍源码环境搭建及测试配置 NanoDet 的环境环境配置过程中遇到的问题:环境配置完毕验证 NanoDet NanoDet 介绍 可以参考这个博客:NanoDet:这是个小于4M超轻量目标检测模型 源码 …...
突破编程_C++_C++11新特性(unordered_multimap)
1 概述 std::unordered_multimap 是一个哈希表实现的无序容器,它存储的元素是键值对,并且允许键的重复。这意味着同一个键可以关联多个值。在 std::unordered_multimap 中,元素的插入顺序是不确定的,并且不会因为元素的插入、删除…...
15.WEB渗透测试--Kali Linux(三)
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:14.WEB渗透测试--Kali Linux(二)-CSDN博客 Kali工具使用 3389远…...
Android-Framework pm list packages和pm install返回指定应用信息
一、环境 高通 Android 13 注:Android10 和Android13有些差异,代码位置不变,参照修改即可 二、pm简单介绍 pm工具为包管理(package manager)的简称 可以使用pm工具来执行应用的安装和查询应用宝的信息、系统权限、…...
CSS
什么是CSS? CSS是一门语言,用于控制网页表现 CSS(Cascading Style Sheet):层叠样式表 W3C标准:网页主要由三部分组成 结构:HTML表现:CSS行为:JavaScript CSS导入方式…...
算法详解——选择排序和冒泡排序
一、选择排序 选择排序算法的执行过程是这样的:首先,算法遍历整个列表以确定最小的元素,接着,这个最小的元素被置换到列表的开头,确保它被放置在其应有的有序位置上。接下来,从列表的第二个元素开始&#x…...
图论(蓝桥杯 C++ 题目 代码 注解)
目录 迪杰斯特拉模板(用来求一个点出发到其它点的最短距离): 克鲁斯卡尔模板(用来求最小生成树): 题目一(蓝桥王国): 题目二(随机数据下的最短路径&#…...
矩阵起源新一年喜报连连!
新春伊始 矩阵起源向大家分享 一连串好消息 首先,公司创始人兼CEO王龙先生获评“2023深圳创新突出贡献人物“。这一荣誉是对其在推动数据库行业技术创新和产品开发方面所做出的卓越贡献的认可。他的领导力和创新精神不仅引领我司取得了显著的成就,也为…...
牛客——紫魔法师(并查集)
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 “サーヴァント、キャスター、Medea。”--紫魔法师 给出一棵仙人掌(每条边最多被包含于一个环,无自环,无重边,保证连通),要求用最少的…...
最新WooCommerce教程指南-如何搭建B2C外贸独立站
WooCommerce是全球最受欢迎的开源电子商务平台之一。它基于WordPress建站,只需一键安装即可使用。该平台提供了丰富的功能,包括产品发布、库存管理、支付网关和运输发货等,可以帮助搭建各种类型的电子商务网站。相比其他竞争对手,…...
一文教会你SpringBoot是如何启动的
SpringBoot启动流程分析 流程图 源码剖析 运行Application.run()方法 我们在创建好一个 SpringBoot 程序之后,肯定会包含一个类:xxxApplication,我们也是通过这个类来启动我们的程序的(梦开始的地方),而…...
车载测试面试:各大车企面试题汇总
本博主可协助大家成功进军车载测试行业 TBOX 深圳 涉及过T-BOX测试吗Ota升级涉及的台架环境是什么样的?上车实测之前有没有一个仿真环境台架环境都什么零部件T-BOX了解多少Linux和shell有接触吗 单片机uds诊断是在实车上座的吗 uds在实车上插的那口 诊断仪器是哪…...
Qt散文一
Qt的事件分为普通事件和系统事件,普通事件比如用户按下键盘,系统事件比如定时器事件。事件循环的开始是从main函数的QApplication,然后调用exec()开始的,在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件…...
MySQL学习Day32——数据库备份与恢复
在任何数据库环境中,总会有不确定的意外情况发生,比如例外的停电、计算机系统中的各种软硬件故障、人为破坏、管理员误操作等是不可避免的,这些情况可能会导致数据的丢失、 服务器瘫痪等严重的后果。存在多个服务器时,会出现主从服…...
阅读基础知识
一 网络 1. 三次握手四次挥手 三次握手:为了建立长链接进行交互即建立一个会话,使用 http/https 协议 ① 客户端产生初始化序列号 Seqx ,向服务端发送建立连接的请求报文,将 SYN1 同步序列号; ② 服务端接收建立连接…...
【NestJS 编程艺术】1. NestJS设计模式深度解析:构建高效、可维护的服务端应用
在当今快速发展的软件开发领域,Node.js凭借其轻量级和高性能的特点,已经成为了构建服务端应用的首选技术之一。然而,随着应用规模的扩大,传统的Node.js框架如Express和Koa可能在架构设计和代码组织上显得力不从心。这时࿰…...
QT中connect()的参数5:Qt::DirectConnection、Qt::QueuedConnection区别
原文链接:https://blog.csdn.net/Dasis/article/details/120916993 connect用于连接QT的信号和槽,在qt编程过程中不可或缺。它其实有第5个参数,只是一般使用默认值,在满足某些特殊需求的时候可能需要手动设置。 Qt::AutoConnect…...
VXLAN学习笔记
声明:该博客内容大部分参考参考链接整理 什么是VXLAN? VXLAN(Virtual Extensible LAN)即虚拟扩展局域网,是大二层网络中广泛使用的网络虚拟化技术。在源网络设备与目的网络设备之间建立一条逻辑VXLAN隧道,采用MAC in UDP的封装方…...
全排列的不同写法(茴字的不同写法)及对应的时间开销
资源课件: CS106B-recursion-pptstanford library-timer.hstanford library-set.h 不同的方法 1------ Set<string> permutations1Rec(string remaining) {Set<string> res;if(remaining.size() 0) {res "";}else {for(int i 0; i <…...
权衡后台数据库设计中是否使用外键
目录 引言 外键简介 对比 真实后台项目中的权衡 结论 引言 在大学学习数据库课程时,我们会早早的接触到外键这一概念,同时我相信大部分人在懂了外键的概念后都会觉得外键很重要,在涉及多表一定要用,但后来在我接触到真实项目…...
济南行业网站开发/app软件开发
#-*- codeing utf-8 -*- #Time :2021/5/17 10:33 #Author :Onion #File :Convolution.py #Software :PyCharm# 卷积神经网络Demo # 步骤 # 1:定义输入变量 # 2:定义卷积核变量 # 3:定义卷积操作 # 4:运行卷积操作import tensorfl…...
长沙影楼网站建设/电商网站建设平台
引言: 一直都是从事客户端的开发工作,最近抽了点时间想了解一下服务器开发的相关知识,一番博客瞎逛之后,发现了一个不错的框架,云风大神的 skynet开源服务器框架,这不仅仅是针对于游戏服务器开发的框架&am…...
独立电商网站开发/搜索引擎营销有哪些
写篇博客,在我项目中用到了一个很重要的第三方---AsyncSocket,写下我对AsyncSocket使用心得。我的项目中是APP对硬件直接交互,APP对硬件发指令的时候不需要经过服务端,要经过采集端,此处我要感谢曾在北京天一众合java工…...
公司网站怎么做实名认证/广西seo
1、首先确定自己的iis没有问题 2、其次确定自己sqlserver没有问题 然后在iis的文件夹wwwroot里,建立一个文件 名为testSqlServer.asp,编写代码例如以下就可以 <% ole db连接 set cnn1 Server.CreateObject("ADODB.Connection") 连接串需要…...
服务性网站建设的原则/百度联盟app
一、要求 ‘销售额’:K为单位 ‘利润’: M为单位,负值用括号括起来,但是正值 ‘利润率’:带百分号,负值用括号括起来仍然时负值 二、解决方案 1、‘销售额’:m为单位 2、‘利润’&#x…...