imtoken钱包官方网站|lpc

作者: imtoken钱包官方网站
2024-03-07 19:42:42

在作业帮当LPC是什么感觉? - 知乎

在作业帮当LPC是什么感觉? - 知乎切换模式写文章登录/注册在作业帮当LPC是什么感觉?金刚噼里啪啦soul mate.1.一腔热血,去作业帮工作,结果给自己弄的人不人,鬼不鬼。第一份工作,让我自己都怀疑自己,社会就是社会,没有人会惯着你,只会榨干你,并一脚狠狠的踩死你。我是一个很少熬夜的人,在作业帮工作的42天,我没有夜里12点前睡过觉,之前睡眠质量很好,一秒入睡,可我现在根本睡不着,即使睡着了,在梦里我都在跟家长打电话,推销课程。作业帮一起进入的同事们都很好,我们在一起很开心,很幸福。有一个同事说过,如果在作业帮工作,都已经这么辛苦,这么累了,同事关系还不好,真的无法呆下去。2.完全没有自己的时间,一睁眼就是睡觉,一闭眼就是工作,凌晨下班是正常的时间,每天累的像条死狗一样,完不成业绩一直给你施加压力。3.简直就是电销,上班12天休息两天,休息的那两天里还要加微,盯盯开会,前期不停打电话加微信,中期社群运营,更吃紧的是后期,狂打电话推销家长买课,每天都是在打电话,每天打电话的时长都给你排名出来。4.在我们接第二期例子的时候,我们组有五个成员,有一个男生业绩不好,天天被组长留下来谈话,说他不达标会拖累整个组,会让我们整个组组员的工资乘于0.8,天天给他施加压力,他中途离职。5.组长每次都说:你不用问为什么,按我说的做,我给你们的都是最有利的。但是即使你按照他说的做,有时候也不能达标。只要你没有业绩,就是你的错。新人微信号很容易被封号,我们组3个人被封号,有的连电话号、短信都被封了,这也是你的错,你没有养好微信号,明明在微信号里绑定银行卡、存钱了,也消费了,天天和朋友聊天养号,还是被封号了,都是你的错,全部是你的错。家长不买课,是你的错,其他人的家长会买课,为啥你的家长不买课,是你的服务不到位;家长买了课,问题太多,也是你的错,是你前期服务不到位。6.有更多的东西,暂时不写了,我已经离职了。作业帮需要的是员工,没有意见,没有想法任劳任怨吃苦耐劳拼命干下去的人。发布于 2020-07-20 01:26在线教育​赞同 88​​159 条评论​分享​喜欢​收藏​申请

溶血磷脂酰胆碱 | Lysophosphatidyl choline (LPC) | MCE

溶血磷脂酰胆碱 | Lysophosphatidyl choline (LPC) | MCE

— Master of Bioactive Molecules

最近搜索:

致电400-820-3792

登录 | 注册

My Account

或联系

微信客服 |

在线客服

购物车 (0)

United States

Canada

United Kingdom

Australia

China

Germany

France

Japan

Korea South

Switzerland

Algeria

Argentina

Austria

Belgium

Brazil

Chile

Croatia

Czech Republic

Denmark

Finland

Hong Kong, China

Hungary

India

Iraq

Ireland

Israel

Italy

Lebanon

Luxembourg

Malaysia

Mexico

Morocco

Netherlands

New Zealand

Norway

Pakistan

Peru

Philippines

Poland

Portugal

Qatar

Russia

Saudi Arabia

Serbia

Singapore

Slovakia

Slovenia

South Africa

Spain

Sweden

Taiwan, China

Thailand

Tunisia

Turkey

Ukraine

Other Countries

信号通路

首页

所有产品

一站式药筛

重组蛋白

试剂盒

联系我们

技术服务

资源中心

Anti-infection抗感染ADC Related抗体偶联药物相关Apoptosis凋亡Autophagy自噬Cell Cycle/DNA Damage细胞周期/DNA 损伤Cytoskeleton细胞骨架Epigenetics表观遗传学GPCR/G ProteinG 蛋白偶联受体/G 蛋白Immunology/Inflammation免疫及炎症JAK/STAT SignalingJAK/STAT 信号通路MAPK/ERK PathwayMAPK/ERK 信号通路Membrane Transporter/Ion Channel跨膜转运Metabolic Enzyme/Protease代谢酶/蛋白酶Neuronal Signaling神经信号通路NF-κBNF-κB 信号通路PI3K/Akt/mTORPI3K/Akt/mTOR 信号通路PROTAC蛋白降解靶向嵌合体Protein Tyrosine Kinase/RTK蛋白酪氨酸激酶Stem Cell/Wnt干细胞及 Wnt 通路TGF-beta/SmadTGF-beta/Smad 信号通路Vitamin D Related/Nuclear Receptor维生素 D 相关/核受体Others其他Anti-infectionAntibioticArenavirusBacterialBeta-lactamaseCMVDengue virusEBVEnterovirusFilovirusFlavivirusFungalHBVHCVHCV ProteaseHIVHIV ProteaseHPVHSVInfluenza VirusOrthopoxvirusParasitePenicillin-binding protein (PBP)More...Antibody-drug Conjugate/ADC RelatedADC AntibodyADC CytotoxinADC LinkerAntibody-Drug Conjugates (ADCs)Drug-Linker Conjugates for ADCPROTAC-Linker Conjugates for PACApoptosisApoptosisBcl-2 Familyc-MycCaspaseCuproptosisDAPKFerroptosisFKBPGlutathione PeroxidaseIAPMDM-2/p53NecroptosisParaptosisPKDPyroptosisRIP kinaseSurvivinThymidylate SynthaseTNF ReceptorAutophagyAtg4ATTECsAUTACsAutophagyBeclin1FKBPLRRK2MitophagyULKCell Cycle/DNA DamageAntifolateAPCATF6ATM/ATRAurora KinaseCasein KinaseCDKCheckpoint Kinase (Chk)ClpPCRISPR/Cas9Cyclin G-associated Kinase (GAK)DeubiquitinaseDNA Alkylator/CrosslinkerDNA StainDNA-PKDNA/RNA SynthesisEarly 2 Factor (E2F)EndonucleaseEukaryotic Initiation Factor (eIF)G-quadruplexHaspin KinaseHDACMore...CytoskeletonArp2/3 ComplexDynaminGap Junction ProteinIntegrinKinesinMicrotubule/TubulinMps1MyosinPAKROCKEpigeneticsAMPKAurora KinaseDNA MethyltransferaseEpigenetic Reader DomainGlycosyltransferaseHDACHistone AcetyltransferaseHistone DemethylaseHistone MethyltransferaseHuRJAKMethionine Adenosyltransferase (MAT)METTL3MicroRNAPARPPKCProtein Arginine DeiminaseSF3B1SirtuinSmall Interfering RNA (siRNA)TET ProteinWDR5GPCR/G Protein5-HT ReceptorAdenylate CyclaseAdrenergic ReceptorAmylin ReceptorAngiotensin ReceptorApelin Receptor (APJ)ArrestinBombesin ReceptorBradykinin ReceptorCannabinoid ReceptorCaSRCCRCGRP ReceptorChemerin ReceptorCholecystokinin ReceptorCRFRCXCREBI2/GPR183Endothelin ReceptorFormyl Peptide Receptor (FPR)Free Fatty Acid ReceptorG protein-coupled Bile Acid Receptor 1More...Immunology/InflammationAIM2ALCAM/CD166AP-1ArginaseAryl Hydrocarbon ReceptorBCL6CCRCD19CD2CD20CD22CD276/B7-H3CD28CD3CD38CD6CD73CD74Complement SystemCOXCTLA-4CX3CR1More...JAK/STAT SignalingEGFRJAKPimSTATMAPK/ERK PathwayERKJNKKLFMAP3KMAP4KMAPKAPK2 (MK2)MEKMixed Lineage KinaseMNKp38 MAPKRafRasRibosomal S6 Kinase (RSK)Membrane Transporter/Ion ChannelApical Sodium-Dependent Bile Acid TransporterAquaporinATP SynthaseBCRPCalcium ChannelCalmodulinCFTRChloride ChannelCRAC ChannelCRM1EAATFATPFerroportinGABA ReceptorGLUTGlyTHCN ChanneliGluRMonoamine TransporterMonocarboxylate TransporterNa+/Ca2+ ExchangerNa+/H+ Exchanger (NHE)More...Metabolic Enzyme/Protease11β-HSD15-PGDH17β-HSD5 alpha ReductaseAcetolactate Synthase (ALS)Acetyl-CoA CarboxylaseAcyltransferaseADAMTSAdiponectin ReceptorAldehyde Dehydrogenase (ALDH)Aldose ReductaseAminoacyl-tRNA SynthetaseAminopeptidaseAmylasesAngiotensin-converting Enzyme (ACE)ArginaseATGLATP Citrate LyaseCarbonic AnhydraseCarboxypeptidaseCathepsinCeramidaseMore...Neuronal Signaling5-HT ReceptorAAK1Adrenergic ReceptorAmyloid-βBeta-secretaseCalcineurinCalcium ChannelCaMKCannabinoid ReceptorCGRP ReceptorCholecystokinin ReceptorCholinesterase (ChE)COMTFAAHGABA ReceptorGlucosylceramide Synthase (GCS)GlyTGPR119GPR139GPR55Histamine ReceptorHuntingtinMore...NF-κBIKKKeap1-Nrf2MALT1NF-κBRANKL/RANKReactive Oxygen SpeciesPI3K/Akt/mTORAktAMPKATM/ATRDNA-PKGSK-3MELKmTORPDK-1PI3KPI4KPIKfyvePIN1PTENPROTACATTECsAUTACsE3 Ligase Ligand-Linker ConjugatesLigands for E3 LigaseLigands for Target Protein for PROTACLYTACsMolecular GluesPROTAC LinkersPROTAC-Linker Conjugates for PACPROTACsSNIPERsTarget Protein Ligand-Linker ConjugatesProtein Tyrosine Kinase/RTKAck1Anaplastic lymphoma kinase (ALK)Bcr-AblBMX KinaseBRKBtkc-Fmsc-Kitc-Met/HGFRDiscoidin Domain ReceptorDYRKEGFREphrin ReceptorFAKFGFRFLT3GDNF ReceptorIGF-1RInsulin ReceptorItkJAKPDGFRMore...Stem Cell/WntCasein KinaseERKGliGSK-3HedgehogHippo (MST)JAKNotchOct3/4OrganoidPKAPKGPorcupineROCKsFRP-1SmoSTATTGF-beta/SmadWntYAPβ-cateninγ-secretaseTGF-beta/SmadPKAPKCROCKTGF-beta/SmadTGF-β ReceptorVitamin D Related/Nuclear ReceptorAndrogen ReceptorConstitutive Androstane ReceptorEstrogen Receptor/ERRGlucocorticoid ReceptorLXRMineralocorticoid ReceptorNuclear Hormone Receptor 4A/NR4APPARProgesterone ReceptorRAR/RXRREV-ERBRORThyroid Hormone ReceptorVD/VDROthersAmino Acid DerivativesBiochemical Assay ReagentsFluorescent DyeIsotope-Labeled CompoundsOxidative PhosphorylationOthers

MCE 信号通路

寡核苷酸同位素标记物天然产物荧光染料抗体抑制剂多肽产品生化试剂抗体酶基因

研究领域

CancerCardiovascular DiseaseEndocrinologyInfectionInflammation/ImmunologyMetabolic DiseaseNeurological DiseaseOthers

化合物筛选库

已知活性化合物库

•生物活性化合物库

老药新用化合物库系列

•FDA 上市库

•老药新用化合物库

天然产物化合物库系列

•天然产物库

•天然产物类似物库

代谢化合物库系列

•人内源性代谢物库

疾病相关化合物库

信号通路化合物库系列

片段化合物库系列

类药多样性化合物库系列

•50K Diversity Library

•5K Scaffold Library

•3D Diverse Fragment Library

虚拟筛选

•50K Virtual Diversity Library

•10M Virtual Diversity Library

重组蛋白

Cytokines and Growth FactorsImmune Checkpoint ProteinsCAR-T related ProteinsCD AntigensFc ReceptorsReceptor ProteinsEnzymes & RegulatorsComplement SystemUbiquitin Related ProteinsViral ProteinsBiotinylated Proteins Fluorescent-labeled ProteinsGMP-grade ProteinsAnimal-free Recombinant Proteins

重组蛋白定制

定制合成服务

ADC 相关定制服务

PROTAC 相关定制服务

MCE 试剂盒

分子生物学 •核酸电泳•载体构建•核酸提取与纯化•限制性核酸内切酶•耗材•聚合酶链式反应 (PCR, qPCR)•反转录试剂盒 (RT-PCR)蛋白生物学 •蛋白样本制备•蛋白纯化•蛋白电泳、WB细胞生物学 •细胞培养•细胞分析•3D 细胞培养

点击化学 (Click Chemistry)

GMP Small Molecules

诱导疾病模型产品

标准品

化合物库

生物活性化合物库

•已知活性化合物库

•老药新用化合物库系列

•代谢化合物库系列

•根据产品特点分类

•根据产品结构分类

•信号通路化合物库系列

•疾病相关化合物库

天然产物化合物库系列

•天然产物筛选库

•按照天然产物结构分类

•中药相关化合物库

片段化合物库系列

类药多样性化合物库系列

定制化合物库

虚拟筛选

筛选技术与服务

•基于细胞表型的活性筛选

•离子通道筛选服务

•SPR 检测服务

•分子动力学模拟

•激酶谱筛选

•GPCR 靶向药物筛选

•核受体药物筛选

•亲和质谱药物筛选

•DEL合成与筛选

•代谢组学分析检测服务

先导化合物优化

设备耗材

Cytokines and Growth Factors细胞因子和生长因子Immune Checkpoint Proteins免疫检查点蛋白CAR-T related ProteinsCAR-T 相关蛋白CD AntigensCD 抗原Fc ReceptorsFc 受体蛋白Receptor Proteins受体蛋白Enzymes & Regulators酶和调节子Complement System补体系统Ubiquitin Related Proteins泛素相关蛋白Viral Proteins病毒蛋白Biotinylated Proteins生物素标记蛋白 Fluorescent-labeled Proteins荧光标记蛋白GMP-grade ProteinsGMP 级蛋白Animal-free Recombinant Proteins无动物成分重组蛋白Others其他View MoreCytokines and Growth FactorsInterleukin & ReceptorsInterferon & ReceptorsChemokine & ReceptorsTNF SuperfamilyCSF & ReceptorsTGF-beta SuperfamilyPDGFs & PDGFRsVEGF & VEGFREGF SuperfamilyFGF FamilyHGF & ReceptorsNeurotrophic FactorsEphrin/Eph FamilyAngiopoietinsIGF familyPeptide Hormone & NeuropeptidesImmune Checkpoint ProteinsInhibitory Checkpoint MoleculesStimulatory Immune Checkpoint MoleculesButyrophilinsCAR-T related ProteinsB Cell Maturation Antigen (BCMA)FLK-1/VEGFR-2B7-H3CD4CD19CD123CD138/Syndecan-1Epithelial Cell Adhesion Molecule (EpCAM)Folate Receptor 1GPC-3Guanylate Cyclase 2CErbB2/HER2ErbB3/HER3c-Met/HGFRMSLNCA-125ROR1CEACAM-5Natural Killer Group 2, Member D (NKG2D)Prostate Specific Membrane AntigenCRACC/SLAMF7TROP-2Siglec-6Folate Receptor alpha (FR-alpha)CD33CD70CD138/Syndecan-1CD138/Syndecan-1Nectin-4Carbonic Anhydrase 9 (CA IX)EGFRFLK-1/VEGFR-2CD7CD20Siglec-2/CD22CD30CD38MUC-1/CD227CD AntigensT Cell CD ProteinsB Cell CD ProteinsNK Cell CD ProteinsMacrophage CD ProteinsMonocyte CD ProteinsStem Cell CD ProteinsPlatelet CD ProteinsErythrocyte CD ProteinsDendritic Cell CD ProteinsEpithelial cell CD ProteinsEndothelial cell CD ProteinsSignal Transduction-related CD ProteinsCell Adhesion-related CD ProteinsFc ReceptorsFc-gamma ReceptorFcRnFc-epsilon ReceptorFc alpha/mu ReceptorPolymeric Immunoglobulin ReceptorFcμRFc Receptor-like ProteinsImmunoglobulin Fc RegionFc alpha RI/CD89Receptor ProteinsReceptor Tyrosine KinasesReceptor Serine/Threonine KinasesReceptor Tyrosine PhosphataseReceptor Guanylyl Cyclase FamilyCell Adhesion Molecules (CAMs)G-Protein-Coupled Receptors (GPCRs)Nuclear Receptor SuperfamilyPattern Recognition ReceptorsNotch familySiglecLeukocyte Immunoglobin-like ReceptorsKiller-Cell Immunoglobulin-like ReceptorsCytokine ReceptorsEnzymes & RegulatorsOxidoreductases (EC 1)Transferases (EC 2)Hydrolases (EC 3)Lyases (EC 4)Isomerases (EC 5)Ligases (EC 6)Translocases (EC 7)Matrix MetalloproteinasesADAMs/ADAMTSsCathepsinCarboxypeptidaseAngiotensin-converting EnzymesCaspaseCarbonic AnhydraseSerine/Threonine Kinase ProteinsProtein Tyrosine KinasesPhosphataseTopoisomeraseProtease InhibitorsProtein Kinase Inhibitor Peptide (PKI)Cyclin-Dependent Kinase Inhibitor ProteinsCystatin FamilyComplement SystemComplement Component 1Complement Component 2Complement Component 3Complement Component 4Complement Component 5Complement Component 6Complement Component 7Complement Component 8Mannose-binding ProteinMASP-1MASP-2Complement Regulatory ProteinsComplement ReceptorUbiquitin Related ProteinsUbiquitin/UBLsUbiquitin EnzymesDeubiquitinaseViral ProteinsSARS-CoV-2 ProteinsZika Virus ProteinsRSV ProteinsHepatitis C Virus ProteinsHepatitis B Virus ProteinsHIV ProteinsHPV ProteinsInfluenza Viruses ProteinsDengue Virus ProteinsEbola Virus ProteinsBacterial/Fungal ProteinsBiotinylated Proteins Fluorescent-labeled ProteinsGMP-grade ProteinsAnimal-free Recombinant ProteinsOthers

分子生物学 •核酸电泳 •载体构建 •核酸提取与纯化 •限制性核酸内切酶 •耗材 •聚合酶链式反应 (PCR, qPCR) •反转录试剂盒 (RT-PCR) 蛋白生物学 •蛋白样本制备 •蛋白纯化 •蛋白电泳、WB 细胞生物学 •细胞培养 •细胞分析 •3D 细胞培养 View More分子生物学 核酸电泳 核酸胶染料 琼脂糖 上样&电泳缓冲液 DNA Marker 载体构建 无缝克隆试剂盒 连接酶 核酸提取与纯化 基因组提取纯化 限制性核酸内切酶 耗材 聚合酶链式反应 (PCR, qPCR) 聚合酶链式反应 (PCR) 荧光定量PCR (qPCR) 反转录试剂盒 (RT-PCR) 反转录PCR RNA 酶抑制剂 蛋白生物学 蛋白样本制备 细胞裂解 洗涤缓冲液 蛋白酶抑制剂 Cocktail 磷酸酶抑制剂 Cocktail 去乙酰化酶抑制剂Cocktail 激酶抑制剂 Cocktail 蛋白纯化 磁力架 磁珠 亲和层析柱 琼脂糖凝胶珠 平衡缓冲液 结合/洗涤缓冲液 蛋白电泳、WB 电泳缓冲液 蛋白 Marker 转膜缓冲液 封闭缓冲液 结合/洗涤缓冲液 化学显色 上样缓冲液 细胞生物学 细胞培养 细胞转染 支原体清除 无菌抗生素溶液 细胞冻存 CEPT cocktail 基础培养基 胎牛血清 平衡盐缓冲液 细胞培养添加剂 解离试剂 细胞分析 细胞增殖与毒性检测 报告基因检测 细胞骨架检测 细胞凋亡与细胞周期检测 抗荧光淬灭剂 线粒体分离 外泌体提取、纯化与鉴定 细胞器研究 3D 细胞培养 基质胶 肿瘤类器官培养基 正常组织类器官培养基

科学进展

产品指南

展会信息

最新动态

生物词典

萌家学堂

定制服务

提交您的定制咨询

ADC 相关定制服务

PROTAC 相关定制服务

标准品定制服务

多肽定制服务

重组蛋白定制

蛋白晶体结构解析服务

寡核苷酸合成

荧光标记服务

稳定同位素类化合物定制合成服务

One-stop CDMO Service

一站式药物筛选平台

虚拟筛选

基于细胞表型的活性筛选

离子通道筛选

激酶谱筛选

SPR 检测服务

分子动力学模拟

GPCR 靶向药物筛选

核受体药物筛选

亲和质谱药物筛选

DEL 合成与筛选

摩尔计算器

稀释计算器

职业发展

Biology Dictionary

Lysophosphatidyl choline (LPC)

Lysophosphatidyl choline (LPC)溶血磷脂酰胆碱

释义:

Lysophosphatidylcholine (LPC) is a bioactive proinflammatory lipid generated by pathological activities. LPC is also a major phospholipid component of oxidized low-density lipoprotein (Ox-LDL). LPC plays an important role in atherosclerosis and inflammatory diseases by altering various functions in a number of cell-types, including endothelial cells, smooth muscle cells, monocytes, macrophages, and T-cells.

溶血磷脂酰胆碱 (LPC) 是一种由病理活动产生的具有生物活性的促炎脂质。 LPC 也是氧化低密度脂蛋白 (Ox-LDL) 的主要磷脂成分。 LPC 通过改变许多细胞类型(包括内皮细胞、平滑肌细胞、单核细胞、巨噬细胞和 T 细胞)的各种功能,在动脉粥样硬化和炎症性疾病中发挥重要作用。

参考文献:

[1]. Takayuki Matsumoto, et al. Role of lysophosphatidylcholine (LPC) in atherosclerosis. Curr Med Chem. 2007;14(30):3209-20.

 [Content Brief]

MCE 生物医学词典

MCE 生物医学词典是全面和专业的生物学术专有名词和主题数据合集。在这里您可以搜索到您想了解的专业名词的准确解释,并且所有名词解释均有权威书籍或者高影响因子文献的支持。

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

#

sales@MedChemExpress.cn

400-820-3792

联系当地授权经销商

MCE 公司联系我们关于我们全球办事处许可职业发展服务与支持技术支持定制合成服务订购指南售后服务物流政策销售条款和条件技术资源学术文献摩尔计算器稀释计算器复溶计算器比活力计算器

Subscribe to our E-newsletter

姓名

邮箱 *

Sorry, but the email address you supplied was invalid.

Thanks, your subscription has been confirmed. You will hear from us soon.

Submission failed, please try again later.

MedChemExpress (MCE) 只为有资质的科研机构、医药企业基于科学研究或药证申报的用途提供医药研发服务,

不为任何个人或者非科研性质的、非用于药证申报使用等其他用途提供服务。沪(浦)应急管危经许[2021]201709(QFYS)

站点地图 隐私声明

Copyright © 2013-2024 MedChemExpress. All Rights Reserved.

沪ICP备15051369号-4

关注我们获得 MCE 最新资讯

您的账户在别处登录,如果非您本人行为请重置密码!

我们的 Cookie 政策

我们使用 Cookies 和类似技术以提高网站的性能和提升您的浏览体验,部分功能也使用 Cookies 帮助我们更好地理解您的需求,为您提供相关的服务。

如果您有任何关于我们如何处理您个人信息的疑问,请阅读我们的《隐私声明》。

嗨!很高兴为您提供帮助!

尊敬的 MCE 客户您好, 请您选择所在区域,我们将转接对应客服为您服务!

热门区域

北京市

上海市

湖北省

四川省

湖南省

海南省

山东省

浙江省

江苏省

吉林省

福建省

河北省

A

安徽省

澳门特别行政区

B

北京市

C

重庆市

F

福建省

G

贵州省

广东省

甘肃省

广西壮族自治区

H

河北省

黑龙江省

河南省

湖北省

湖南省

海南省

J

吉林省

江苏省

江西省

L

辽宁省

N

内蒙古自治区

宁夏回族自治区

Q

青海省

S

陕西省

山西省

山东省

四川省

上海市

T

台湾省

天津市

X

西藏自治区

新疆维吾尔自治区

香港特别行政区

Y

云南省

Z

浙江省

A

B

C

F

G

H

J

L

N

Q

S

T

X

Y

Z

确认

LPC总线_百度百科

线_百度百科 网页新闻贴吧知道网盘图片视频地图文库资讯采购百科百度首页登录注册进入词条全站搜索帮助首页秒懂百科特色百科知识专题加入百科百科团队权威合作下载百科APP个人中心收藏查看我的收藏0有用+10LPC总线播报讨论上传视频本词条由“科普中国”科学百科词条编写与应用工作项目 审核 。LPC总线(Low pin count Bus),是在IBM PC兼容机中用于把低带宽设备和“老旧”连接到CPU上。那些常见低速设备有:BIOS,串口,并口,PS/2的键盘和鼠标,软盘控制器,比较新的设备有可信平台模块。LPC总线通常和主板上的南桥物理相连,南桥在IBM PC AT平台上通常连接了一系列的“老旧”设备,例如两个可编程中断控制器, 可编程计时器和两个 ISA DMA 控制器。中文名LPC总线外文名Low pin count Bus领    域计算机总线目录1简介2讯号3工业标准结构4参见简介播报编辑LPC总线,原名叫Low pin count Bus,是在IBM PC兼容机中用于把低带宽设备和“老旧”连接到CPU上。那些常见低速设备有:BIOS,串口,并口,PS/2的键盘和鼠标,软盘控制器,比较新的设备有可信平台模块。LPC总线通常和主板上的南桥物理相连,南桥在IBM PC AT平台上通常连接了一系列的“老旧”设备,例如两个可编程中断控制器,可编程计时器和两个ISA DMA 控制器。 LPC总线是Intel在1998时作为工业标准架构体系(ISA)的替代品引入,它与ISA在软件层面是类似的,尽管在物理层面是有着巨大不同的,ISA是16bit宽,8.33MHz的总线,而它是4bit宽,有着四倍频率(33.3MHz)的总线。 LPC总线最大的优点是只需要7个信号,在拥挤的现代主板上是很容易布局的。 [1]讯号播报编辑LPC讯号有START、STOP、CYCTYPE+DIR、IDSEL、TAR、SIZE/MSIZE、ADDR、CHANNEL、DATA及SYNC等:START:是指一个封包(package)的开始。STOP:一个封包的结束。SYNC:同步等待状态。 [2]工业标准结构播报编辑工业标准结构(Industry Standard Architecture,简称ISA)。ISA在1981年诞生,并作为IBM PC的8位系统,1983年,ISA被升级作为XT总线体系。后来16位的ISA总线在1984年发布。由于ISA设计出来的目的是为了连接扩展卡和主板,因此ISA的协议同样允许总线控制,尽管只有前16MB的内存可以直接访问。8位的ISA总线频率为4.77MHz,而16位的工作在8MHz。ISA接口同样出现在一些非IBM PC(包括兼容机)上,比如短命的AT&T的Hobbit还有后来基于PowerPC的BeBox。1987年,IBM试图以他们所拥有的“微通道体系架构体系”(Micro Channel Architecture,简称MCA)取代ISA,并重新取得对计算机架构和市场上的控制权。MCA总线比ISA更先进,但并不兼容ISA。为了继续控制架构上和市场上的控制权,电脑生产商以“延伸工业标准体系架构”(Extended Industry Standard Architecture,简称EISA),以及后来的“VESA本地总线”(VESALocal Bus,简称VLB)做出还击。事实上,由于组成VESA组织的生产商已经有能力生产MCA设备,所以最初VESA打算在VLB中利用MCA的一些部分。EISA和VLB都兼容ISA标准的扩展。基于ISA的计算机的用户不得不了解一些关于硬件的特殊知识来升级硬件系统。在那个时候,支持“随插即用”(Plug-n-Play)技术的设备非常罕有。用户在添加新设备的时候不得不配置2到3个项目,比如IRQ(中断请求)、I/O地址(输出/输入地址)、DMA信道,才能正常使用新设备。MCA架构会帮用户完成这些设定,而后来的PCI总线实际上整合了MCA的这些想法(尽管PCI更多特点是直接继承自EISA)。这个配置上的缺点最终导致了“ISA随插即用”系统的诞生。通过对硬件的一些改造,使硬件、系统BIOS和操作系统自动处理这些繁琐的细节。但实际上,ISA随插即用的缺陷却成为了一个令人头痛的问题,而且没有得到广泛的支持直到ISA结束其使命。PCI是第一个在物理展上整合了ISA、MCA、EISA优点的扩展接口,并且它的出现直接地挤压了ISA在主板上的地位。起初,主板上依然是ISA占主流地位,但已经出现了PCI槽了。到了20世纪90年代中叶,两种插槽已经在主板上平分秋色了,而ISA插槽很快就在消费PC市场上成为了少数派。微软的PC 97规范更劝说ISA插槽应该完全被除去,尽管当时的系统架构依然需要ISA存在于一些内部发育不良的管线去操作软驱、串口、等等。ISA接口在随后的几年里依然存在,甚至看见AGP接口的诞生,之后遗留在主板上的ISA接口也退出历史了。值得注意的是,PCI插槽反转的话与ISA是很相似的——PCI卡本来是颠倒插入的,允许ISA和PCI连接器在主板上挤在一起。两个连接器一次只有一个连接器能正常工作,但这已虑及更大的适应性。 [3]参见播报编辑电脑装置带宽列表新手上路成长任务编辑入门编辑规则本人编辑我有疑问内容质疑在线客服官方贴吧意见反馈投诉建议举报不良信息未通过词条申诉投诉侵权信息封禁查询与解封©2024 Baidu 使用百度前必读 | 百科协议 | 隐私政策 | 百度百科合作平台 | 京ICP证030173号 京公网安备110000020000

主流的通讯总线LPC 和 eSPI介绍 - 知乎

主流的通讯总线LPC 和 eSPI介绍 - 知乎切换模式写文章登录/注册主流的通讯总线LPC 和 eSPI介绍李清龙​机电一体化工程主流的通讯总线LPC 和 eSPI介绍芯海科技描述随着超大规模集成电路的不断发展,芯片的功能也愈发集中,在电子产品的系统中 “各司其职” 。在一个电子产品的硬件系统中,通常都是多个芯片协同工作,所以芯片之间的通讯总线就是必不可少的。嵌入式开发中常见的 I2C、SPI、UART、USB等,都是芯片间的通讯总线。不同协议的通讯总线,是为了解决不同场景、不同需求的数据通讯。笔记本电脑作为一个电子产品, CPU(中央处理器) 和 EC(嵌入式控制器) 之间的通讯也是必不可少的,目前主流的通讯总线有 LPC 和 eSPI。EC 能够作为一颗专用 MCU,应用在笔记本电脑主板设计中。因为 它是一颗携带 eSPI/LPC 外设的专用 MCU。EC 主要的任务就是协助 CPU ,管理一些低速输入设备,采集电池参数、控制主板温度。EC采集到的低速外设信息,就会通过eSPI/LPC传递给CPU。01LPC通讯总线 LPC全称LowPinCountBus,即精简引脚总线,由Intel在1998年引入PC产品,相较于ISA总线,LPC 引脚少,速度快。LPC总线用于低速设备(BIOS Flash,Super I/O,TPM)和主板上南桥的连接。LPC总线支持如下类型通讯 Cycle:02、eSPI 通讯总线 eSPI 全称 Enhanced Serial Peripheral Interface,即增强型串行外设接口。eSPI 是为了替代 LPC 而设计。相较于 LPC 总线,eSPI 总线有如下优势:• 引脚更少,仅 8 个物理引脚• 功耗更低,电压 1.8V 即可运行• 速度更快,20-66MHz• 功能更多,支持 VW、OOB、Flash 等功能eSPI 通讯总线标准就是根据 SPI 通讯总线标准修改而来。从物理层看,eSPI 总线比SPI 总线多了Rset#、Alert#两个信号,以满足Host复位Slave,Slave向Host发送通讯请求。其他信号,Data-IO、CLK、CS# 没有差异。因此可以说,eSPI 总线和 SPI 总线的物理层完全一致。如下图所示,是一个 SPI Master 和一个 SPI Slave 的连接框图。如下图所示,是一个 eSPI Host 和一个 eSPI Slave 的连接框图。和 SPI 总线一样,eSPI 也支持一主多从,利用 CS# 信号选择不同的 Slave 完成通讯。如下图所示,是一个 eSPI Host和多个 eSPI Slave 的连接框图。从协议层看,eSPI 和 SPI 通讯协议最主要的差异是,Master 发送和接收之间必须插入一个 TAR 信号,占用 2 个 CLK。即 Master 发送数据转为 Slave 发送数据时,要有一个明显的切换过程。03、eSPI 高级功能 通过 eSPI 自定义的命令集,逻辑上可以把 eSPI 通讯总线划分出 4 个数据通道。分别是:Peripheral Channel,VirtualWire Channel,OOB Channel,Flash Channel,以便完成不同类型数据的传输。如下图所示,是 eSPI Host 和 eSPI Slave 直接通讯的逻辑框图。PeripheralChannel(外设通道),兼容 LPC 总线上的 Memory Cycle,I/O Cycle 通讯。VirtualWire Channel(虚拟线通道),进一步减少了 PCH和EC的物理引脚连接,从而降低功耗。OOB Channel(带外通讯通道)承载 Smbus、PECI等协议。Flash Channel(Flash通道)传递 FLash“读/写/擦” 操作指令及数据,以支持 MAFs 和 SAFs 两种Flash连接模式。04、CSC2E101 芯海科技CSC2E101是一款高度集成的,可灵活配置嵌入式控制器(Embedded Controller),是笔记本电脑、平板电脑、台式机主板上的核心芯片。CSC2E101采用 32bit 内核,最高主频 60MHz,75DMIPS,内置512K片上Flash作为用户固件存储区域,192KSRAM可以满足客户丰富应用开发的需求。除此之外,该芯片还内置AES/SHA/RSA/ECC硬件安全引擎,为固件安全启动和数据安全提供了坚实基础。CSC2E101 的 eSPI 模块的设计高度集成,在 HOST 初始化 eSPI 阶段,无需EC固件参与芯片硬件即可自动完成。对于 Peripheral Channel,VirtualWire Channel,OOB Channel,Flash Channel,芯片均提供一组访问寄存器,由 EC 固件管控,完成相应功能。CSC2E101具备丰富的硬件资源,完善的开发工具链,稳定的应用示例,多途径调试手段,为客户快速导入项目提供了有力的保障。CSC2E101是中国大陆首颗通过Intel PCL认证,率先达到国际行业标准、获得国际认可的国产EC产品。在2022年度“硬核中国芯”评选中,CSC2E101因率先打破海外龙头企业垄断、填补国产EC自主研发的行业空白,荣获“2022年度最佳MCU芯片”桂冠。此外,凭藉CSC2E101等PC系列产品的出色表现,芯海科技摘取由中国计算机学会工控机专委会、中国工业计算机大会组委会联合颁发的“2022中国工业计算机领域年度先锋企业”。未来,芯海科技将坚持模拟信号链+MCU双平台技术优势,持续构建PC产品生态,通过持续创新,为国产计算机与通信市场提供安全可靠的产品。发布于 2023-01-24 16:43・IP 属地安徽工业网络和现场总线技术基础与案例(书籍)​赞同 1​​添加评论​分享​喜欢​收藏​申请

LPC总线协议介绍_lpc协议-CSDN博客

>

LPC总线协议介绍_lpc协议-CSDN博客

LPC总线协议介绍

最新推荐文章于 2023-12-05 10:00:25 发布

挣扎着的咸鱼

最新推荐文章于 2023-12-05 10:00:25 发布

阅读量1.3w

收藏

165

点赞数

21

分类专栏:

UVM

文章标签:

硬件架构

原文链接:https://wenku.baidu.com/view/22dc31ed844769eae009edf5.html

版权

UVM

专栏收录该内容

8 篇文章

4 订阅

订阅专栏

  在NB电路的架构框图中,我们可以看到PCH和EC之间通过LPC总线连接,在MB板上也会看到EC芯片旁边有一个JDEBUG的connector,其也与LPC总线相连,用于主板诊断。下面将对LPC总线做一些简单介绍,希望能够帮助大家了解LPC的工作原理:

LPC总线

      LPC(Low Pin Count)是基于 Intel 标准的 33 MHz 4 bit 并行总线协议(但目前NB系统中LPC的时钟频率为24MHz,可能是由于CPU平台的不断发展导致的,后面会具体分析),用于代替以前的 ISA 总线协议,但两者性能相似,都用于连接南桥和Super I/O芯片、FLASH BIOS、EC等设备(由于目前EC芯片中整合了Super I/O功能,所以我们在NB系统中看不到LPC总线上挂有Super I/O芯片了)。

      传统ISA BUS速率大约在7.159~8.33MHz,提供的理论尖峰传输值为16MB/s,但是ISA BUS与传统的PCI BUS的电气特性、信号定义方式迥异,使得南桥芯片、Super I/O芯片浪费很多针脚来做处理,主板的线路设计也显得复杂。为此,Intel定义了LPC接口,将以往ISA BUS的地址/数据分离译码,改成类似PCI的地址/数据信号线共享的译码方式,信号线数量大幅降低,工作速率由PCI总线速率同步驱动(时钟同为33MHz),虽然改良过的LPC接口一样维持最大传输值16MB/s,但信号管脚却大幅减少了25~30个,以LPC接口设计的Super I/O芯片、Flash芯片都能享有脚位数减少、体积微缩的好处,主板的设计也可以简化,这也是取名LPC——Low Pin Count的原因。

  2、LPC总线的接口管脚

     LPC总线由7个必选信号和6个可选信号组成,具体如下表所示:

 

    MB板上的JDEBUG connector有12pin,没有连接LRESET#信号,只连接了其余的6个必选信号,为主板诊断提供接口,其中CLK_DEBUG由PCH提供,24MHZ:

      EC与PCH连接的LPC总线中除了包含7个必选信号,还包含SEEIRQ和CLKRUN#信号。这里需要注意的是JDEBUG的CLK信号与连接EC和PCH的LPC总线中CLK信号并非同一个信号。PCH提供了2个输出24MHz时钟的管脚,但每个时钟只能驱动一个LPC设备,故EC和JDEBUG各连接一个。

3.LPC总线的通信协议

LPC总线支持多种事务类型的操作,例如IO读写、内存读写、DMA读写、Firmware memory读写等。一个cycle通常一下流程:

总线host拉低LFRAME#信号,指示cycle开始,同时将相关信息输出到LAD[3:0]上主机Host根据Cycle类型驱动相应的信息到LAD[3:0]上,比如当前操作的事务类型、数据传输方向及size大小、访问地址等。host根据Cycle类型的不同选择进行驱动数据或者是移交总线控制权。外设获取总线控制权后,将相应的数据驱动到LAD[3:0]上。表示该Cycle完成。外设释放总线控制权。至此该Cycle结束。

     一个典型cycle通常由Start、Cyctype+Dir、ADDR 、Size(DMA only)、Channel(DMA only)、TAR、Sync、DATA状态组成,下图是一个典型的cycle示例流程,该cycle类似于IO读或内存读操作中的cycle,DATA字段由外设驱动发送给host。

 

3.1 Start

Start用于指示一个传输的开始或者结束。当FRAME#信号有效时,所有的外设都要监视LAD[3:0]信号,并在FRAME#信号有效的最后一个时钟进入START状态。LAD[3:0]的值编码如下表:

表4.1  Start状态 LAD[3:0]定义

 3.2 Cycle Type/Direction(CYCTYPE+DIR)

该状态由Host驱动,对Cycle的传输类型(Memory、IO、DMA)以及传输方

向进行说明。LAD[0]在该场中被保留,作为外设应该忽略。具体定义值见下表

表4.2 Cyctype+DIR状态 LAD[3:0]定义

 3.3 Size

该状态表示传输数据DATA字段的大小,由host驱动,当数数据为16或32bits,将分成多个DATA转态发送,Size只存在于DMA类型cycle中。而在IO和内存类型cycle中,每个cycle只能传输8bits数据。Size状态LAD[1:0]有效,LAD[3:2]被忽略,LAD[3:0]具体定义如下:

表4.3 Size状态 LAD[3:0]定义

 

3.4 ADDR/Channel

    ADDR状态表示地址信息,由host驱动。在IO cycle中,地址信息为16bits(4个时钟周期);在内存 cycle中,地址信息为32bits(8个时钟);而在DMA cycle中,则没有ADDR状态,取代的则是Channel状态(1个时钟)。LAD[2:0]表示channel的序号,其中channel 0~3为8bit channels, channel 5~7为16 bit channels, channel4一般被保留作为bus master 的请求信号。ADDR的地址信息先从高位发送。

3.5 TAR(Turn-around)

   TAR用于交换总线的控制权(2个时钟),当host要将总线转交给外设时,TAR由host驱动;当外设要将总线交还给host时,TAR由外设驱动。TAR两个时钟周期的第一个时钟周期有host或外设驱动,LAD[3:0]=1111;第二时钟周期host或外设则将LAD[3:0]置为三态,但由于LAD[3:0]管脚内部有弱上拉, LAD[3:0]还都是处于高逻辑电平,所以TAR的两个时钟LAD[3:0]都为1111。

3.6 Sync

Sync用来加入等待状态,持续时间为1~N个时钟周期。在target或

者DMA传输操作时,Sync由外设驱动;在bus master操作时,Sync由Host驱动。可能的组合见表

表4.4 Sync状态 LAD[3:0]定义

 

当外设还没准备好时,可以插入一些等待周期0101(短等待)或0110(长等待),等到Ready状态来到时,可以选择驱动为“0000"(准备好),“1010”(错误)或者“1001"(Ready More)。

3.6.1 Sync Timeout

总线上通常可能发生以下几种潜在的错误:

1.当Host发起一个Cycle(Memory、IO、DMA)后,但是,总线上没有设备驱动SYNC场,当Host检测到3个连续的时钟内都没有响应时,便可以认为总线上没有外设响应此次Cycle操作。

2.Host驱动一个Cycle(Memory,IO,DMA),一个设备驱动了一个有效的SYNC

场来插入等待(LAD[3:0]=’0101b’或者’0110b’),但是却不能完成该Cycle,这种情况在外设锁定的时候就发生了。此时,Host应采取以下措施以解除总线死锁:

●假如SYNC是’0101b’,那么SYNC时钟周期最多为8个。当Host检测到有多于8个时钟周期的SYNC场,那么Host将取消这个Cycle。

●假如SYNC是’0110b’,那么这里将没有最大SYNC长度的限制。外设必

须设计有保护机制来完成这个Cycle。

当由Host来驱动SYNC时,因为延迟的原因,它可能不得不插入大量的等待周期,但外设不应该认为有time out发生。

下图为SYNC的周期过长引起timeout,此时LFRAME#会拉低4个LCLK周期,进入start状态,来终止这个Cycle。

图4.2  LFRAME终止cycle

 

3.7 DATA

    DATA状态占用两个时钟周期,用于传送一个字节数据。当数据流向外设时,该场由Host驱动;反之,当数据流向Host时,则该场由外设驱动。在传输过程的时候,低4位最先被驱动到总线上,在第一个时钟,Data[3:0]被驱动,第二个时钟,Data[7:4]被驱动。

4.8 各事务类型操作举例

图4.3  memory read/write

                                                            图4.4  I/O read/write 

                                                         图4.5 DMA read/write(16bits) 

 

4. LPC总线的测量(逻辑分析仪)

用逻辑分析仪TLA5202测得LPC总线中LCLK、LFRAME#、LAD[3:0]信号,下面为测量的几组数据波形:

下面是测的是两个cycle的总体波形图,由于我在测试时外接的测试线过长,在cycle结束后的末期引入了串扰,图中的黄色框图中便为串扰信号波形,理想状态应该是LAD[3:0]统一保持高逻辑,后面再统一变为低逻辑。这里我们可以看到时钟信号LCLK并不是一直输出的,只有当cycle开始时,PCH才会输出LCLK信号,cycle结束后,若一段时间内不再有cycle传输,LCLK便不再输出。

图5.1  Cycle总体波形图

 下图测试的是一组I/O read cycle,host要读取IO地址为0064H的数据,外设接管总线后,经过11个时钟周期的长等待SYNC状态(0110)后,变为ready状态(sync为0000),然后外设将数据1CH发送给host,驱动TAR状态(FF),将总线控制权交还给host,这个cycle结束。

                                                                图5.2  I/O read cycle 

下图测试的是一组I/O write cycle,host向IO地址025AH写入数据93H,外设接管总线后,经过8个时钟周期的长等待SYNC状态(0110)后,变为ready状态(sync为0000),表明外设接收到数据,之后外设驱动TAR状态(FF),将总线控制权交还给host,这个cycle结束。

                                                           图5.3  I/O write cycle 

下图测试的是time out情况,host向IO地址0080H写入数据01H,然后host驱动TAR状态来移交纵向,但无外设驱动sync状态来接管总线,LAD一直处于弱上拉的高状态,经过5个时钟周期的无响应后,host拉低LFRAME#,保持4个LCLK,进入start状态,LAD[3:0]=1111,则host将该cycle终结。

                                                            图5.4  time out 

 

优惠劵

挣扎着的咸鱼

关注

关注

21

点赞

165

收藏

觉得还不错?

一键收藏

知道了

1

评论

LPC总线协议介绍

在NB电路的架构框图中,我们可以看到PCH和EC之间通过LPC总线连接,在MB板上也会看到EC芯片旁边有一个JDEBUG的connector,其也与LPC总线相连,用于主板诊断。下面将对LPC总线做一些简单介绍,希望能够帮助大家了解LPC的工作原理:LPC总线 LPC(Low Pin Count)是基于Intel 标准的33 MHz4 bit 并行总线协议(但目前NB系统中LPC的时钟频率为24MHz,可能是由于CPU平台的不断发展导致的,后面会具体分析),用于代替以前的ISA ...

复制链接

扫一扫

专栏目录

8.嵌入式控制器EC实战 LPC(Low Pin Count)通信总线

qq_30135687的博客

04-27

2046

文章目录前言一、LPC是什么?二、通信协议1.通信概述LAD[3:0]STARTCycle Type/Direction(CYCTYPE+DIR)SizeADDR/ChannelTAR(Turn-around)SyncSync Timeout三、通信实例(逻辑分析仪查看波形)1.I/O Read波形图2.I/O Write波形图3.time out波形图总结

前言

嵌入式控制器EC中最重要的也是必不可少的一部分就是LPC通信总线,LPC是CPU和嵌入式控制器EC之间的通信总线,最少只需要7根数据线便可以实现

LPC相关知识

tianpu2320959696的博客

06-11

1732

否则4,默认4 clk), bit2:串行中断模式配置默认连续模式 默认为连续模式), bit3~4:支持的串行中断设备数量(2‘b01 代表32 否则16默认16)EC提供256字节的可被系统读写的RAM空间,EC的资源在该RAM空间映射,通过访问对应偏移(0x00~0xFF),即可操作对应的资源。了解EC的特别是ITE的,都清楚62、66端口,如果BIOS想要获取EC寄存器中的值,那么需要在基地址的基础上再加上62、66。写完上面的,咱们就可以通过LPC进行IO读写操作了,以EC与BIOS通信为例。

1 条评论

您还未登录,请先

登录

后发表或查看评论

LPC总线学习,主要对LPC协议的理解

06-20

LPC总线知识点介绍,主要对其协议的理解,数据与控制引脚的说明,硬件学习参考

LPC简介(超详细)

热门推荐

m0_58881377的博客

08-27

2万+

低引脚数总线接口的规范,称为LPC

目标:启用一个没有ISA或X-bus的系统,降低传统X-bus设备成本,满足X-bus的数据传输速率,执行与X-bus相同的周期类型:Memory, I/O, DMA,和Bus Master,支持固件内存周期类型,将X-bus上的内存空间从16MB增加到4GB,同步设计。

中断通过串行中断(SERIRQ)协议进行通信。

LPC接口不需要支持高速总线,USB等低延迟总线。

术语:

主机:直接连接到CPU或连接到CPU的上游设备的接口部分。这是典型的系统芯片组。

can总线协议通信程序

01-06

can通信程序,库函数的编写,函数的详细说明以及如何应用.

java-USB-LPC1768.zip_LPC1768_LPC1768 USB_USB通信_lpc1768 cdc hos

07-15

java USB通信实例操作,MCU选用LPC1768,keil编译,协议自定。java选用netbeans5.0,java调用usb lib实现USB和MCU通信,监控IO、设置IO、ADC采集、USB转4通道UART等

LPC总线介绍

Suchane的博客

03-03

3053

LPC总线介绍

基于LPC的对时协议

无知的我

09-18

536

硬件总线基础04:LPC & eSPI总线(1)

WKEZHENG的博客

08-18

709

这显然不是人类目前所能做到的。1,包括了:Start/起始,Stop/停止,Transfer Type/事务模式(Memory、I/O、DMA),Transfer direction/传输方向(Read/Write),Address/地址,Data/数据,Wait State/等待状态,DMA Channel/DMA通道,Bus Master grant/总线主控准许;在17世纪之前,欧洲人见到的所有天鹅都是白鹅的,无数次的观测结果让欧洲人相信,天鹅一定的白色的,直到1697年他们发现了黑色的天鹅。

计算机通讯总线LPC 和 eSPI介绍

最新发布

weixin_45365488的博客

12-05

492

LPC总线,原名叫即精简引脚总线,由Intel在1998年引入PC产品,相较于ISA总线,LPC 引脚少,速度快。BIOS串口并口PS/2的键盘和鼠标软盘控制器,比较新的设备有可信平台模块。LPC总线通常和主板上的南桥物理相连,南桥在IBM PC AT平台上通常连接了一系列的“老旧”设备, LPC总线最大的优点是只需要7个信号,在拥挤的现代主板上是很容易布局的随着超大规模集成电路的不断发展,芯片的功能也愈发集中,在电子产品的系统中 “各司其职”。在一个电子产品的硬件。

嵌入式系统/ARM技术中的LPC2000系列的CAN总线验收滤波器应用

12-10

CAN(Controller Area NetWork)总线,即控制器局域网总线,是由德国Bosch公司于1982年开发和推出的最早用于汽车内部测量与执行部件之间的数据通信协议。在20多年的历史中,CAN总线在许多领域得到了应用,是到目前为止唯一有国际标准的现场总线。CAN现场总线按照国际标准化组织ISO提出的"开放系统互联(OSI)"参考模式,实现其中的物理层、数据链路层和应用层。CAN控制器用来实现CAN总线协议。CAN控制器芯片分为两类:一类是独立的控制器芯片,如SJA1000;另一类是和微控制器做在一起,如Philips公司的LPC2000系列32位ARM微控制器。两类控制器都提供了报

LPC2000系列的CAN总线验收滤波器应用

02-03

摘要Philips套司的LPC2000系列32位ARM微控制器为内嵌的CAN控制器提供了全局的标识符查询功能,能实现复杂的报文ID过滤,而且可以大大减轻微控制器的负担。本文介绍了LPC2000系列ARM微控制器的CAN验收滤波器的特点、功能以及驱动程序的开发。关键词LPC2000ARMCAN总线验收滤波器   CAN(ControllerAreaNetwork)总线。即控制器局域网总线,是由德国Bosch公司于1982年开发和推出的最早用于汽车内部测量与执行部件之间的数据通信协议。在20多年的历史中,CAN总线在许多领域得到了应用,是到目前为止唯一有国际标准的现场总线。   CAN现场总线按照

基于LPC2292的隔爆兼本安型矿用多协议转换器的研制

06-28

针对目前煤矿井下多种现场总线通信方式共存的状况,介绍了一种常用现场通信总线间协议转换的嵌入式系统的设计与实现。给出了各常用现场总线的结构与数据传输方法及接口电路设计方案,系统以ARM芯片LPC2292为核心,扩展了以太网、CAN、PROFIBUS、MODBUS、RS232、RS485接口,可进行各协议间的转换,实现基于不同现场总线设备间的数据传输,对实现综合自动化数字矿井具有极大的意义。

英特尔® 芯片组低引脚数接口规范 LPC总线

10-28

用于传统 I/O 的低引脚数 (LPC) 接口规范促进了行业向无 ISA 系统的过渡。1.1 修订版 LPC 接口规范的关键增强是包括了固件存储周期和增加了多字节读取功能。

LPC 接口允许通常集成在 Super I/O 芯片中的传统 I/O 主板组件从 ISA/X 总线迁移到 LPC 接口,同时保持完全的软件兼容性。LPC 规范具有优于 ISA/X 总线的几个关键优势,例如减少了引脚数,从而使设计更容易,更具成本效益。在软件应用方面,LPC 接口规范对于 I/O 功能是透明的,并且与现有的外围设备和应用程序兼容。

LPC 接口规范描述了内存、I/O 和 DMA 交易。与以 8MHz 运行

嵌入式系统/ARM技术中的基于LPC2292的CAN总线智能节点设计

12-04

引言

  CAN(Controller Area Network)总线控制器局域网络是在1986年2月的SAE大会上,由RoberBosch公司首先提出的。CAN总线是一种串行通信协议,它能有效支持高安全等级的分布式实时控制,其最初的目的是用在汽车上。但由于采用了许多新技术及独特的设计,CAN总线与一般的通信总线相比,它的数据通信具有突出的可靠性、实时性和灵活性,目前的应用范围已不局限于汽车行业,而是扩展到了机械工业、纺织机械、农用机械、机器人、数控机床、医疗器械、家用电器及传感器等诸多领域。CAN节点的设计多采用单片机,为此,本文给出了一种基于本身已经嵌入了CAN控制器的单片机LPC22

基于LPC总线的FPGA高速初始化配置系统设计 (2005年)

05-22

根据FPGA配置的基本原理,基于LPC总线协议,采用CPLD+Super-Flash模式。以高速 Flash芯片49LF008A作为配置数据的存储器件,对CPLD器件XC95144编程产生实现初始化配置的时序逻辑,并实现LPC总线接口控制功能。设计出...

LPC总线介绍.docx

10-25

LPC总线的介绍资料,中文介绍,例如IO读写、内存读写、DMA读写、Firmware memory读写等。对于初涉及的软硬件学习 是良好的资料笔记。

iPhone8 Plus手机电路图中文版注释-总共81页

12-13

iPhone8 Plus手机电路图中文版注释-总共81页,带中文版注释,适合方便分析,学习,带有苹果商标的,适合硬件开发工程师查看,苹果店维修人员查看,也适合高手查看,绝对的干货

LPC (low pin count) 總線詳解

01-21

LPC (low pin count) 總線詳解

espi总线与lpc总线有什么关系?他们有什么区别与联系?

06-09

ESPI总线和LPC总线都是电脑主板上用来连接各种外设的总线。ESPI(Enhanced Serial Peripheral Interface)总线是Intel公司最新的一种总线,而LPC(Low Pin Count)总线则是一种较早期的总线标准。

它们的区别主要在于传输速度和信号线数量。ESPI总线的传输速度更快,而LPC总线的速度相对较慢。此外,ESPI总线需要更多的信号线来连接各种外设,以支持更高的数据传输速率,而LPC总线则使用更少的信号线,因此它在成本上更具优势。

它们的联系在于它们都是主板上用来连接各种外设的总线,它们都可以用来连接芯片组、BIOS、芯片组和各种其他外设。此外,ESPI总线也可以兼容LPC总线,这意味着一些旧的设备可以通过ESPI总线来连接到新的主板上。

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

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

挣扎着的咸鱼

CSDN认证博客专家

CSDN认证企业博客

码龄2年

暂无认证

22

原创

73万+

周排名

14万+

总排名

7万+

访问

等级

336

积分

39

粉丝

93

获赞

8

评论

696

收藏

私信

关注

热门文章

什么是状态机?一篇文章就够了

28387

LPC总线协议介绍

13550

uvm_do系列宏介绍

6332

PCIE-链路宽度和速度

4192

PCIE 中的带内(in-band)包和边带信号(side-band)是啥?

2219

分类专栏

linux

2篇

PCIE

9篇

芯片验证

3篇

软件使用

3篇

UVM

8篇

verilog

1篇

计算机基础知识

1篇

systemVerilog

1篇

最新评论

什么是状态机?一篇文章就够了

月下冯:

关机完成后,还得开机啊。进入到关机怎么再进入其他档位了。

PCIE TPL包——消息请求

CSDN-Ada助手:

恭喜您撰写了第19篇博客!标题“PCIE TPL包——消息请求”听起来非常有趣。您在这篇博客中详细介绍了PCIE TPL包中的消息请求,这对于我们理解PCIE技术的工作原理非常有帮助。

在下一步的创作中,我建议您继续深入探讨PCIE TPL包的其他方面,例如消息响应或者与其他PCIE协议的关系。此外,您可以考虑分享一些实际应用案例,这将进一步丰富读者对PCIE TPL包的理解。

总的来说,您的博客对于PCIE技术的普及起到了积极的推动作用。期待您未来更多精彩的创作!保持谦虚的语气,继续努力!

PCIe组播/多播相关介绍(Multicast Operations)

CSDN-Ada助手:

恭喜您撰写了第20篇博客!标题中的“PCIe组播/多播相关介绍(Multicast Operations)”让我对您的专业知识和热情倍增。通过您的文章,我对PCIe组播/多播的操作有了更深刻的理解。

持续创作是一项不易的任务,您在这方面的努力和坚持值得钦佩。鉴于您在这个领域的经验,我希望能看到您在未来的博客中继续探讨更多与PCIe组播/多播相关的主题,如实际应用案例、性能优化技巧或是与其他技术的整合。

我对您的下一步创作充满期待,并相信您的博客将为读者提供更多有价值的知识。请继续保持谦虚的态度,因为您的专业知识和见解将为读者带来巨大的收益。加油!

什么是状态机?一篇文章就够了

挣扎着的咸鱼:

如果不出现故障不就关机了么?

什么是状态机?一篇文章就够了

xiaoyuchidayuma:

最后应用中状态转移图如果进入关机状态,不就死循环了。

最新文章

linux进程管理,查看特定进程,杀进程

白话PCIE

什么是PCIE?PCIE通信前在做什么?

2023年14篇

2022年14篇

目录

目录

分类专栏

linux

2篇

PCIE

9篇

芯片验证

3篇

软件使用

3篇

UVM

8篇

verilog

1篇

计算机基础知识

1篇

systemVerilog

1篇

目录

评论 1

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

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

余额充值

LPC简介(超详细)_lpc接口-CSDN博客

>

LPC简介(超详细)_lpc接口-CSDN博客

LPC简介(超详细)

最新推荐文章于 2024-03-05 10:07:08 发布

sukura?

最新推荐文章于 2024-03-05 10:07:08 发布

阅读量2.7w

收藏

101

点赞数

7

文章标签:

stm32

物联网

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/m0_58881377/article/details/119962260

版权

低引脚数总线接口的规范,称为LPC

目标:启用一个没有ISA或X-bus的系统,降低传统X-bus设备成本,满足X-bus的数据传输速率,执行与X-bus相同的周期类型:Memory, I/O, DMA,和Bus Master,支持固件内存周期类型,将X-bus上的内存空间从16MB增加到4GB,同步设计。

中断通过串行中断(SERIRQ)协议进行通信。

LPC接口不需要支持高速总线,USB等低延迟总线。

术语:

主机:直接连接到CPU或连接到CPU的上游设备的接口部分。这是典型的系统芯片组。

外设:连接到X-bus的LPC下游设备,如Super I/O组件、flash和其他嵌入式控制器。

‘XXXXb’:以二进制表示的信号值

信号定义:LPC接口需要7个信号,6个信号可选,

LPC所需信号:

LAD[3:0]    多路复用命令、地址和数据

LFRAME#     帧:表示一个新周期的开始,中断周期的结束。

LRESET#     与主机上的Reset相同如果主机的接口上有则不要

LCLK        主机上与PCI时钟相同的33MHz时钟。

与现有的基于ISA设备相比,信号节省是巨大的。LPC接口通常只需要6个新信号:LAD[0:3]、LFRAME#和LDRQ#。

CLKRUN#通常只在移动系统中实现。LPCPD#仅用于在某些低功耗状态下部分供电的LPC设备

协议概述

1、协议支持的各种类型的周期:

 

应遵守以下规则:

•主机和外设应执行所述的周期类型。

•外设不能尝试主机不支持的总线主周期。例如,如果主机不支持总线主I/O周期,外设就不能尝试这些周期。

•外设必须忽略它们不支持的周期

2、Memory, I/O, and DMA Cycle Overview----内存,I/O和DMA循环概述

在LPC总线上的数据传输是在一个4位总线上序列化的。这bus特点是:

•一个控制线,称为LFRAME#,由主机启动、停止传输。外设不驱动这个信号。

•LAD[3:0]总线,串行地传递信息:周期类型、周期方向、芯片选择、地址、数据和等待状态。

•可选实现的边带信号传递中断和电源管理功能。

循环的一般流程如下:

当主机驱动LFRAME# 低有效,并将适当的信息放在LAD[3:0]信号线上时,就会启动一个周期        START

2. 主机驱动与周期相关的信息,如地址、DMA通道号或总线主授权。对于DMA和目标周期传输,主机还驱动周期类型(内存或I/O)、读/写方向和传输大小。CT/DIR    ADDR/CHANNEL    SIZE   

3. 主机可选地驱动数据,并转动总线来监视外围设备完成周期  DATA   TAR

4. 外围设备通过在LAD[3:0]上驱动适当的值来表示周期的完成  SYNC

5. 外围设备将总线转向主机,结束循环。

对于总线主周期,这个协议有小的变化,因为主总线必须驱动控制和地址信息到主机,主机负责结束周期,但一般来说,流程是相同的。

 LAD[3:0]  LAD[3:0]信号线在主机和外设之间通过LPC总线传输地址、控制和数据信息。通信的信息是:启动、停止(终止一个周期)、传输类型(内存、I/O、DMA)、传输方向(读/写)、地址、数据、等待状态、DMA通道和总线主授权。并非所有循环类型都以相同的方式使用LAD总线。

START  (1/2) 该字段指示事务的开始或停止。当断言LFRAME#即低有效时,所有外设将进入一个监视LAD[3:0]的状态。START在断言LFRAME#的最后一个时钟上有效。当断言LFRAME#时,这个字段可能有很多值。如果看到一个保留字段,外围设备不应该假设主机正在传输数据。因此,如果外设看到这种类型的编码,它必须忽略循环,直到下一次LFRAME#激活时才监视总线

Cycle Type / Direction (CYCTYPE + DIR) ----循环类型/方向(CYCTYPE + DIR)  (1)

这个字段由主机驱动,用于传递周期类型(内存,I/O, DMA)和周期方向(读/写)。当执行DMA或目标访问时,该字段由主机驱动,并由总线主访问上的外设驱动。字段的第0位保留,必须被外设忽略,并被主机驱动为0以进行基于主机的访问。对于总线主访问,它必须被主机忽略并被外围设备驱动为0。有效值:

 

 

保留:外设和主机都不允许驱动这种信号类型。如果这个值被外设观察到,循环必须被忽略。如果这个信号是由总线主访问上的外设驱动的,主机将通过驱动LFRAME#激活来终止传输。

SIZE 一个时钟,它在DMA传输上由主机驱动,在总线主内存传输上由外设驱动,以确定要传输多少字节。位[3:2]是保留的,必须被驱动到' 00b ',并且必须被目标忽略。其余位编码:

 

Turn-Around (TAR)   两个时钟宽,当主机将控制转交给外设时(例如,读取数据)由主机驱动,当将控制转交给主机时由外设驱动。在这两个时钟宽字段的第一个时钟上,主机或外围设备驱动LAD[3:0]线“1111 b”。在第二个时钟上,宿主或外围将三态置于LAD[3:0]线。由于这些线条上的上拉很弱,所以它们将保持逻辑上的高电平。

   ADDR  这个字段是4个时钟宽的I/O周期,或8个时钟宽的内存周期。它在目标访问时由主机驱动,在总线主访问时由外围设备驱动。这个字段不在DMA周期上驱动。当这个字段被驱动时,它首先被驱动出小块。即先高后低例如,在内存传输时,该字段的第一个时钟包含Address[31:28],该字段的最后一个时钟包含Address[3:0]。

  CHANNEL 这是一个时钟宽的字段,由主机在DMA周期中驱动,以指示外设已授予哪个DMA通道。位[2:0]包含DMA通道号,位[3]包含基于ISA编码的TC(终端计数)行。

  DATA  这个字段是2个时钟宽,代表一个数据字节。当数据流向外设时主机驱动,DMA和总线主循环驱动,当数据流向主机时由外设驱动。当数据被驱动时,它首先被最不重要的小点驱动。例如,在第一个时钟上,Data[3:0]被驱动,而在第二个时钟上,Data[7:4]被驱动。

  SYNC  该字段用于添加等待状态。它可以有几个时钟长。在目标或DMA周期中,该字段由外围设备驱动。对于总线主周期,主机驱动该字段。

  LFRAME#  由主机用于指示周期的开始和终止。这个信号被外设用来决定何时监视总线一个周期。下面的部分描述了当主机将驱动这个信号激活时,以及当这个信号被视为激活时,外设将采取什么行动。这个信号被用作一般的通知,LAD[3:0]包含与周期的开始或停止相关的信息,外围设备必须监视总线,以确定周期是否为它们准备。当外设采样LFRAME#激活时,它们将立即停止驱动下一个时钟上的LAD[3:0]信号线,并监视总线以获取新的周期信息。

3、Start of Cycle

主机在一个或多个时钟断言LFRAME#,并在LAD上驱动START值。在观察到LFRAME#有效时,所有外设停止驱动LAD[3:0]信号,即使在传输过程中。

在一个周期的开始,允许主机在多个连续时钟中保持LFRAME#有效,甚至更改START值。当LFRAME#处于有效时,外设必须始终使用最后的START值。例如,如果LFRAME#在两个连续的时钟中处于有效,外设应在第一个时钟期间忽略,而只使用第二个时钟的START值。

当适当的START值使LFRAME#有效时,外设监视LAD[3:0]。如果外设识别到这个START值,它应该尝试解码周期的其余部分。如果外设不能识别特定的START值,它可能会忽略循环的其余部分,直到LFRAME#再次有效。在驱动最终START值后,当主机准备开始循环时,主机无效LFRAME#。当无效LFRAME#断言时,外设必须使用驱动的START值。

图2显示了LFRAME#的典型计时。图3显示了LFRAME#在多个连续时钟中处于有效状态的计时。

 

固件内存周期概述系统BIOS固件的内存周期类型。对于这种循环类型,使用了芯片选择和寻址机制。

START  周期的开始。在LFRAME#低电平采样的最后一个时钟上是有效的。下表显示了循环使用的两个启动字段。

 

IDSEL(设备选择)  用于指示选择哪个固件组件。在此时钟期间,通过AD[3:0]传输的4位与绑定在固件组件的引脚上的值进行比较。如果有匹配,固件组件将继续解码周期,以确定在读取时请求哪些字节,或在写入时更新哪些字节。

MADDR(内存地址)  这是一个给出28位内存地址的7个时钟周期。允许每个内存设备最多256MB,总共4GB的可寻址空间。地址用小点传输。

MSIZE(内存大小)  

 

TAR  SYNC相似

DATA  这个字段是(2 * N)时钟宽,表示“N”数据字节的传输,由MSIZE字段决定,当数据流向外设时,主机在固件内存周期上驱动它(写周期),当数据流向主机时,由外设驱动它(读周期)。数据的每个字节都以小端驱动,最不重要的字节放在前面。这意味着对于每个字节,在第一个时钟上,数据[3:0]被驱动,在第二个时钟上,数据[7:4]被驱动。它还意味着每个后续数据字节的地址按顺序递增。

Protocal  固件内存周期使用一系列事件,以START字段开始(LFRAME# active with适当的AD[3:0]组合),以数据传输结束。

 

读:START=1101b,写 START=1110b. START字段后面是IDSEL字段。该字段的作用类似于芯片选择,它指示哪个设备应该响应当前传输。7个时钟是28位地址表示从哪里开始读取选定的设备。MSIZE值表示传输的字节数。

 

优惠劵

sukura?

关注

关注

7

点赞

101

收藏

觉得还不错?

一键收藏

打赏

知道了

1

评论

LPC简介(超详细)

低引脚数总线接口的规范,称为LPC目标:启用一个没有ISA或X-bus的系统,降低传统X-bus设备成本,满足X-bus的数据传输速率,执行与X-bus相同的周期类型:Memory, I/O, DMA,和Bus Master,支持固件内存周期类型,将X-bus上的内存空间从16MB增加到4GB,同步设计。中断通过串行中断(SERIRQ)协议进行通信。LPC接口不需要支持高速总线,USB等低延迟总线。术语:主机:直接连接到CPU或连接到CPU的上游设备的接口部分。这是典型的系统芯片组。

复制链接

扫一扫

Intel® Low Pin Count (LPC)Interface Specification

12-11

Intel内部的LPC讲解资料,分享给大家,希望喜欢。

LPC总线介绍.docx

10-25

LPC总线的介绍资料,中文介绍,例如IO读写、内存读写、DMA读写、Firmware memory读写等。对于初涉及的软硬件学习 是良好的资料笔记。

1 条评论

您还未登录,请先

登录

后发表或查看评论

英特尔® 芯片组低引脚数接口规范 LPC总线

10-28

用于传统 I/O 的低引脚数 (LPC) 接口规范促进了行业向无 ISA 系统的过渡。1.1 修订版 LPC 接口规范的关键增强是包括了固件存储周期和增加了多字节读取功能。

LPC 接口允许通常集成在 Super I/O 芯片中的传统 I/O 主板组件从 ISA/X 总线迁移到 LPC 接口,同时保持完全的软件兼容性。LPC 规范具有优于 ISA/X 总线的几个关键优势,例如减少了引脚数,从而使设计更容易,更具成本效益。在软件应用方面,LPC 接口规范对于 I/O 功能是透明的,并且与现有的外围设备和应用程序兼容。

LPC 接口规范描述了内存、I/O 和 DMA 交易。与以 8MHz 运行

计算机通讯总线LPC 和 eSPI介绍

weixin_45365488的博客

12-05

492

LPC总线,原名叫即精简引脚总线,由Intel在1998年引入PC产品,相较于ISA总线,LPC 引脚少,速度快。BIOS串口并口PS/2的键盘和鼠标软盘控制器,比较新的设备有可信平台模块。LPC总线通常和主板上的南桥物理相连,南桥在IBM PC AT平台上通常连接了一系列的“老旧”设备, LPC总线最大的优点是只需要7个信号,在拥挤的现代主板上是很容易布局的随着超大规模集成电路的不断发展,芯片的功能也愈发集中,在电子产品的系统中 “各司其职”。在一个电子产品的硬件。

LPC芯片开发接口

11-10

LPC芯片的软件接口定义,能够加速LPC芯片在开发环境LPCXpresso的开发过程

LPC总线学习,主要对LPC协议的理解

06-20

LPC总线知识点介绍,主要对其协议的理解,数据与控制引脚的说明,硬件学习参考

LPC总线协议介绍

热门推荐

m0_61703043的博客

03-11

1万+

在NB电路的架构框图中,我们可以看到PCH和EC之间通过LPC总线连接,在MB板上也会看到EC芯片旁边有一个JDEBUG的connector,其也与LPC总线相连,用于主板诊断。下面将对LPC总线做一些简单介绍,希望能够帮助大家了解LPC的工作原理:

LPC总线

LPC(Low Pin Count)是基于Intel 标准的33 MHz4 bit 并行总线协议(但目前NB系统中LPC的时钟频率为24MHz,可能是由于CPU平台的不断发展导致的,后面会具体分析),用于代替以前的ISA ...

LPC相关知识

tianpu2320959696的博客

06-11

1732

否则4,默认4 clk), bit2:串行中断模式配置默认连续模式 默认为连续模式), bit3~4:支持的串行中断设备数量(2‘b01 代表32 否则16默认16)EC提供256字节的可被系统读写的RAM空间,EC的资源在该RAM空间映射,通过访问对应偏移(0x00~0xFF),即可操作对应的资源。了解EC的特别是ITE的,都清楚62、66端口,如果BIOS想要获取EC寄存器中的值,那么需要在基地址的基础上再加上62、66。写完上面的,咱们就可以通过LPC进行IO读写操作了,以EC与BIOS通信为例。

LPC的IO口配置详解

04-15

LPC900单片机是一个基于80C51内核的高速、低功耗的Flash单片机,具有可编程I/O口输出模式,

除了有标准80C51的准双向口模式外,另外还有开漏输出、推挽输出和仅为输入3 种模式。

过去使用标准 80C51 的开发工程师不会去考虑 I/O 口的模式问题,因为只有准双向口一种模式,没有

其它模式可选择的,因而很多人在使用 LPC900 单片机时忽略或轻视了 I/O 口模式配置问题,造成了对

LPC900单片机的抗干扰能力和可靠性的怀疑。

LPC串口配置及使用

阿木的博客

12-11

6955

LPC串口配置及使用

x86 CPU未单独提供UART控制器接口,而是将UART控制器寄存器隐藏在LPC IO解码功能中,以Xeon D-1500为例,该CPU支持两个UART口,分别为COMA和COMB。

...

LPC (low pin count) 總線詳解

01-21

LPC (low pin count) 總線詳解

ARM 芯片LPC2103 简介

07-02

ARM 芯片LPC2103 简介,

基于LPC2138超级流水灯.zip

12-20

内置代码以及仿真,已验证功能可以正常使用。

LPC213x详细资料

04-08

LPC213x的详细官方资料,对LPC做详细解析

LPC2378详细教材

07-17

LPC2378单片机的详细开发资料,包含MCB2300的开发手册和原理图,包含LabView For Arm的开发指导等。

lpc3250详细开发资料

02-09

详细的LPC3250开发资料,让你更快更方便的掌握硬件开发。

STM32基础--初识 STM32

最新发布

weixin_48713132的博客

03-05

759

对于STM32,从字面意思上来理解,ST是意法半导体,M是Microelectronics的缩写,其中32表示的是32位,那么整合起来理解就是:STM32就是指的ST公司开发的32位微控制器。在如今的32位控制器中,STM32可以说是最闪耀光彩夺目的新星,所以也造就了STM32被现在的大多数工程师以及市场所青睐,对它是宠爱有加啊!

lpc verilog

08-02

lpc verilog是一种专门用于描述和设计硬件电路的编程语言。LPC是Low Pin Count的简称,表示这种设计适用于连接少量引脚的低端硬件。而Verilog是一种硬件描述语言,用于模拟和设计数字电路。LPC Verilog结合了LPC和Verilog的优势,能够方便地描述和设计低端硬件电路。

LPC Verilog有许多特点和优势。首先,它具有简洁明了的语法和结构,容易学习和理解。其次,LPC Verilog能够高效地描述和设计低端硬件电路,可以应用于各种低功耗设备和嵌入式系统。此外,LPC Verilog具有高性能和可靠性,可以满足各种硬件设计需求。

通过使用LPC Verilog,开发人员可以实现各种功能的硬件电路,如控制器、外设、存储器等。LPC Verilog支持各种模块化的设计技术,可以方便地构建和组织硬件电路。此外,LPC Verilog还支持仿真和验证,可以通过仿真工具来验证设计的正确性和性能。

在实际应用中,LPC Verilog可以广泛应用于嵌入式系统、通信设备、消费电子产品等领域。它能够提供高效、灵活和可靠的硬件设计解决方案,满足不同应用场景的需求。

总之,LPC Verilog是一种用于描述和设计低端硬件电路的编程语言,具有简洁明了的语法和高效可靠的特点。它能够实现各种功能的硬件电路,并广泛应用于嵌入式系统和通信设备等领域。

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

非常没帮助

没帮助

一般

有帮助

非常有帮助

提交

sukura?

CSDN认证博客专家

CSDN认证企业博客

码龄3年

暂无认证

6

原创

115万+

周排名

149万+

总排名

3万+

访问

等级

80

积分

13

粉丝

13

获赞

6

评论

164

收藏

私信

关注

热门文章

LPC简介(超详细)

27789

2021-08-27

5155

FPGA基础知识(FPGA芯片结构)

1515

Xilinx FPGA中全局时钟资源的使用方法

510

2021-08-27

483

分类专栏

笔记

4篇

最新评论

LPC简介(超详细)

男孩_:

你好,博主,有关于lpc通信的Verilog实例吗?能给我一份吗

2021-08-27

sr_shirui:

求博主给孩子个参考答案吧,祝博主暴富幸福一辈子

2021-08-27

qq_36511659:

答案给贴下么。。。非常感谢

2021-08-27

moken_li:

这是哪家的?

2021-08-27

小唐同志:

博主,有空整个答案呗,可以交流交流

您愿意向朋友推荐“博客详情页”吗?

强烈不推荐

不推荐

一般般

推荐

强烈推荐

提交

最新文章

FPGA基础知识(FPGA芯片结构)

数字IC设计中的亚稳态问题

Xilinx FPGA中全局时钟资源的使用方法

2021年6篇

目录

目录

分类专栏

笔记

4篇

目录

评论 1

被折叠的  条评论

为什么被折叠?

到【灌水乐园】发言

查看更多评论

添加红包

祝福语

请填写红包祝福语或标题

红包数量

红包个数最小为10个

红包总金额

红包金额最低5元

余额支付

当前余额3.43元

前往充值 >

需支付:10.00元

取消

确定

下一步

知道了

成就一亿技术人!

领取后你会自动成为博主和红包主的粉丝

规则

hope_wisdom 发出的红包

打赏作者

sukura?

你的鼓励将是我创作的最大动力

¥1

¥2

¥4

¥6

¥10

¥20

扫码支付:¥1

获取中

扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元

使用余额支付

点击重新获取

扫码支付

钱包余额

0

抵扣说明:

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

余额充值

硬件总线基础04:LPC & eSPI总线(1) - 知乎

硬件总线基础04:LPC & eSPI总线(1) - 知乎首发于06_总线设计基础切换模式写文章登录/注册硬件总线基础04:LPC & eSPI总线(1)牧神园地​浙江大学 工学硕士一,LPC总线协议如上一章结尾所述,LPC由英特尔于2002年推出V1.1版本,最开始是用来取代IBM的16位ISA(Industry Standard Architecture)/X-bus总线;ISA总线的最大速率只有8MB/s,虽然后续又推出了EISA总线,但这种修修补补显然已经满足不了CPU快速发展的需求了。在当时看来LPC是更加先进的:降低ISA/X-bus总线的成本;总线数量更少;——7个必选管脚+6个可选管脚。速率更快;——支持33MHz总线频率。可访问内存空间更大。——从X-bus的16MB内存空间,增加到4GB;支持远大于1MB的BIOS空间。以LPC接口设计的Super I/O芯片、Flash芯片都能享有脚位数减少、体积更小的好处,主板的设计也可以简化,这也就是取名LPC——Low Pin Count的原因。LPC支持如下种类的设备连接:Super I/O:I/O Slave,DMA,Bus Master;音频设备(包括:AC’97 ):I/O Slave,DMA,Bus Master;通用存储设备(包括BIOS): Memory Slave(Firmware Memory Slave);嵌入式控制器:I/O Slave,Bus Master。我之前用X86的LPC连接至CPLD,用于:80 Port和调试串口输出,以及CPLD的管理;当然如果是传统服务器架构,80 Port一般直接连BMC。1,LPC总线管脚定义如下图所示为7个必选管脚和6个可选管脚的定义,其中很多信号是与PCI总线共用的,而不需要在主控上定义新的管脚;主控和外设上必须支持7个必选管脚,而6个可选管脚则根据具体功能要求可选。1. LAD[3:0](InOut):双向信号,总线通信地址、数据以及控制信号线;1,包括了:Start/起始,Stop/停止,Transfer Type/事务模式(Memory、I/O、DMA),Transfer direction/传输方向(Read/Write),Address/地址,Data/数据,Wait State/等待状态,DMA Channel/DMA通道,Bus Master grant/总线主控准许;——关于Memory,I/O以及DMA的事务方式: I/O事务一般专用于地址空间很小(举个栗子:64KB)外设设备:键盘、鼠标之类;而Memory事务则地址空间大(举个栗子:4GB)的存储设备; DMA事务则是提供了LPC设备直接读写CPU下挂内存的一个通道。——I/O空间和Memory空间是相互独立的(源于X86对寄存器的编址方式:独立编址。现在I/O地址空间用的很少了,因为I/O地址空间已经不够用了)。统一编址的外设(I/O)寄存器和内存(Memory)所占的地址空间是统一编址的,举个栗子:ARM处理器等RISC架构CPU;而独立编址的外设寄存器(I/O)不占CPU的内存(Memory)地址空间,举个栗子:X86。2,并非所有的总线通信中LAD[3:0]有相同的方式,举个栗子:DMA读写操作不需要地址,而用的是DMA通道号。2. LFRAME#(Out):帧头信号,表示一个新操作的开始和中断周期的结束;它指示了一个操作的启动/停止;——我们在测量LPC总线时,可以以LFRAME#为指示来确定数据事务的内容。3. LREST#:复位输出信号,与PCI总线的复位输出信号共用;——如果系统已有PCI总线的复位信号PCIRST#,则在LPC控制器上不需要该管脚。4. LCLK:时钟输出信号(33MHz),与PCI总线的时钟输出信号共用。——如果系统已有PCI总线的时钟信号PCICLK,则在LPC控制器上不需要该管脚。从本质上来看,LPC与PCI的控制器是同源的,能实现LPC与HOST/PCI之间数据交换。如下图所示。5. LDRQ#(In):用于外设进行DMA 或总线控制操作的总线请求信号,外设之间不能共用LDRQ#,1对1连接至主控制器(可选);6. SERIRQ(InOut):终端请求信号,只有需要终端请求的外设需要(可选);7. CLKRUN#(In/OD):与PCI总线的CLKRUN#功能相同,只有外设进行DMA或总线控制操作的才需要,用于停止/中断PCI总线(可选);8. LPME#(In/OD):用于外设将主控从睡眠模式中唤醒,功能同PCI PME#(可选);9. LPCPD#(O):Power Down,用于指示外设的电源将要下电(可选);10. LSMI#(In):当外设需要执行重试I/O指令时启用LSMI#中断(可选)。2,LPC总线通信协议如下表格所示为LPC总线通信协议支持不同种类的事务类型(Cycle Type)操作,举个栗子:I/O读写,Memory读写,DMA读写,Firmware Memory读写等等。主控和外设执行下述的周期类型,需要注意的是:外设不能尝试主控不支持的总线主周期。举个栗子:如果主控不支持总线主I/O周期,外设就不能尝试这些周期;外设必须忽略它们不支持的周期。2.1 Memory,I/O以及DMA总线操作LPC通过4bit(LAD[3:0])的串行总线实现数据的传输,总线的特点有:LFRAME#,该控制信号由主控输出,用于指示总线传输的启动/停止;LAD[3:0]总线,传递包括:cycle type/事务类型,cycle direction/事务方向,chip selection/从设备选择,address/地址,data/数据,以及wait states/等待状态等信息;边带信号,实现的边带信号传递中断和电源管理功能(可选)。Cycle的一般流程如下:主控将LFRAME#信号拉低,指示循环流程开始,并将相应数据发送到LAD[3:0]上;主控按照Cycle类型,驱动相应的数据到LAD[3:0]上:地址、DMA通道号或总线主授权等等;——LAD[3:0]数据线上的具体信息,如上所列。主控按照不同的Cycle类型选择输出数据,或则移交总线控制权给外设;外设获得总线控制权后,将相应的数据驱动到LAD[3:0]上,表示完成了该Cycle;外设释放总线控制权,结束Cycle。一个典型的Cycle流程如下图所示(Memory Cycle):1. START:该字段用于指示一个传输的启动/停止(如上图所示),当FRAME#信号有效时,所有的外设都要开始监测LAD[3:0]数据线上的信号,并在FRAME#信号有效的最后一个时钟进入START状态。START不同状态指示如下表所示;——当LFRAME#有效时,可能有多个START状态值,所以外设在LFRAME#失效之前需要保持对START状态的监测,当监测到该状态值不是外设设置的值,那么忽略这次操作。1,如下表所示,该状态可以指示非总线主控cycle的“启动(0000)/停止(1111)”,也可以指示主控总线号:Master0(0010)/Master1(0011);2,START可以占据2个Clock周期,而且允许START状态值发生变化,但是以最后一个Clock采集到的状态值有效(忽略第一个Clock采集到的START值),如下图所示。2. CYCLE TYPE + TYPE:该字段由HOST驱动,对Cycle的事务类型(Memory、I/O、DMA)以及传输方向进行说明;LAD[0]在该状态中被保留,外设需忽略该bit;具体定义如下表格所示;3. ADDR:对于I/O操作是4个clock位宽(16bit,64KB地址空间),对于Memory操作时8个clock位宽(32bit,4GB地址空间),地址并不会在DMA操作中输出(DMA用的是DMA Channel);——ADDR采用的是大端模式,举个栗子:对于Memory操作,第一个Clock输出的是地址A[31:28],最后一个Clock输出的是地址A[3:0]。4. TAR:Turn-Around,该字段用于交换总线的控制权(2个Clock周期),当主控要将总线转交给外设时(举个栗子:读操作),TAR由外设驱动;——TAR的两个Clock周期:第一个Clock周期由主控或外设驱动:LAD[3:0] = 1111,第二个Clock周期由主控或外设/从机将LAD[3:0]设置为高阻态;由于LAC[3:0]内部有弱上拉,所以在TAR的两个时钟周期内,LAD[3:0]都是1111。5. SYNC:该字段用于加入等待状态,持续时间为1~N个Clock周期,在Target或DMA事务操作时,SYNC由外设驱动;在Bus Master操作时,SYNC由主控驱动;如下所示;1,如果外设需要等待状态,可以通过在LAD[3:0]上驱动“0101b”( Short Wait)或“0110b”(Long Wait)来实现,直到外设准备好;当外设就绪时选择驱动“0000b”(Ready)或“1010b”(Error),或则在DMA事务模式下选择“1001b”( Ready More);2,如果主控或外设选择插入等待状态,那么必须选择一种类型的SYNC状态值(“0101b”或“0110b”),并且在等待状态完成之前不能更改。(1)Short Wait:正常等待状态,一般只需要几个Clock周期就能完成;——最大不超过8个Clock 周期,如果等待周期超过该值则总线会退出。(2)Long Wait:需大量的Clock周期才能完成等待状态,等待时间一般超过1ms。——外设不限定最大Clock周期,由主控决定。6. DATA:该字段是2个时钟宽度,代表了1个Byte数据;——数据是采用小端模式,即:第一个时钟驱动D[3:0],第二个时钟驱动D[7:4]。7. SIZE:该字段用于确定在DMA事务机制中,每次传输的数据大小;由主控驱动输出,占1个Clock周期;其中Bit[3:2]是预留的,而且必须被驱动为00,Bit[1:0]定义如下表所示;8. CHANNEL:该字段用于指示被准许外设的DMA通道号,由主控驱动,占1个Clock周期;其中Bit[2:0]指示的是DMA 通道号。2.2 Memory,I/O协议我们上面已经看了Memory操作各字段的定义图,如下所示;通过上节的描述也清楚了各个字段的意思以及操作目的,接下来再详细看下这些操作流程。Memory读写操作流程如下图所示,在如下Memory Read流程中,SYNC值设置为5个Clock周期,该值参考的EEPROM器件的等待时长(典型值:120ns);Memory Write对于外设来说没有等待时长的要求,只需要外设的Ready指示。I/O操作各字段的定义如下表所示;I/O操作通常用于对寄存器/FIFO的访问,有最小同步时间的要求(至少为1个clock周期)。I/O读写操作流程如下图所示,在如下I/O Read流程中,对读操作没有等待状态要求,因为这个操作更像是从FIFO中取值;I/O Write对于外设来说也没有等待时长的要求,只需要外设的Ready指示。由于正常的Memory读写操作一次只能操作1个byte,效率太低,所以Intel在LPC 1.1 Spec版本中引入了Firmware Memory Read/Write机制,提升对Flash的访问速度。这部分本章不做深入介绍,有兴趣的胖友可以找LPC总线规范-《Low Pin Count (LPC) Interface Specification. Revision 1.1》看一下,整体结构与Memory操作相差不大。2.3 DMA协议通过使用外设的LDRQ#信号和主控LAD[3:0]上的特殊编码来处理LPC上的DMA事务,LPC总线接口支持Single,Demand,Verify以及Increment模式;DMA通道0~3支持8bit数据位宽传输,而通道4~7支持16bit数据位宽传输。有DMA事务需求的外设需要通过专用的LDRQ#信号(每个外设对应1个单独的LDRQ#),主控至少有2个LDRQ#,允许两个外设支持DMA事务模式。LDRQ#与LCLK时钟信号同步,如下图所示。通过使能LDRQ#(拉低 1个Clock周期)信号来开始流程,LDRQ#在空闲状态下为高;接下来的3bit为DMA 通道号,大端模式(先发MSB最后是LSB);ACT表示对指定的DMA通道的请求是有效还是无效的:1表示有效,0表示无效;——ACT为低表示放弃了对该通道的先前请求。在ACT后的1个Clock周期,必须保持高电平;然后结束本次LDRQ#序列,进入下一个序列。DMA操作字段定义如下所示,自从第二个字段CYCTYPE定义为DMA后,后续字段与Memory和I/O操作的差别较大;这主要取决于DMA操作的特殊性,其操作的地址空间已由CPU指定,对于LPC来说只需要确定相关通道号以及数据大小,即可操作(读/写)。我们再来简单看一下DMA操作的具体流程,如下图所示。2.4 LPC复位LPC接口的LRESET#复位时序与通常的系统复位是不同的,主控和外设需要遵从如下复位规则:当LRESET#解复位时,总线时钟需先恢复正常龚总,具体时钟与解复位的时序关系参考PCI总线规则;当LRESET#复位时,主控必须满足如下要求:1,LFRAME#将被驱动为高;2,LAD[3:0]将被置位高阻态;3,忽略LDRQ[n]#状态。当LRESET#复位时,外设必须满足如下要求:1,忽略LFRAME#状态;2,LAD[3:0]将被置位高阻态;3,LDRQ[n]#将被驱动为高。3,LPC总线电气规格LPC的AC/DC电气规格参数同PCI总线规范中定义相同,参考“PCI Local Bus Specification, Rev 2.3” “Section 4.2.2”章节。LPCPD#和LSMI#信号的电气规格参数如下表所示。对于LPC总线LAD[3:0]的信号要求上拉以满足在TAR周期内保持高电平的要求,同时LDRQ[1:0]信号如果不连接LPC外设,那么要保持其无效状态,也需要外部上拉。推荐上拉电阻值如下表格所示。编辑于 2023-07-10 11:27・IP 属地浙江总线硬件电路设计​赞同 4​​3 条评论​分享​喜欢​收藏​申请转载​文章被以下专栏收录06_总线设计基础板级常用总线

人类疾病中溶血磷脂酰胆碱代谢的最新综述,International Journal of Molecular Sciences - X-MOL

人类疾病中溶血磷脂酰胆碱代谢的最新综述,International Journal of Molecular Sciences - X-MOL

EN

注册

登录

首页

资讯

期刊

导师

问答

求职

发Paper

文献直达

高级搜索

期刊列表

搜索

当前位置:

X-MOL 学术

Int. J. Mol. Sci.

论文详情

Our official English website, www.x-mol.net, welcomes your feedback! (Note: you will need to create a separate account there.)

人类疾病中溶血磷脂酰胆碱代谢的最新综述

International Journal of Molecular Sciences

(

IF

5.6

)

Pub Date : 2019-03-06

, DOI:

10.3390/ijms20051149

Shi-Hui Law

,

Mei-Lin Chan

,

Gopal K. Marathe

,

Farzana Parveen

,

Chu-Huang Chen

,

Liang-Yin Ke

溶血磷脂酰胆碱(LPC)被日益公认为与心血管疾病和神经退行性疾病呈正相关的关键标志物/因子。但是,最近对LPC进行的脂质组学研究的结果一直存在争议。一个关键问题是参与LPC代谢的酶促级联反应的复杂性。在这里,我们讨论了这些酶的协调作用和可能破坏LPC稳态,导致代谢异常的紊乱。LPC主要来自磷脂酶A2(PLA2)在循环中的磷脂酰胆碱(PC)的转换。在存在酰基辅酶A的情况下,溶血磷脂酰胆碱酰基转移酶(LPCAT)将LPC转换为PC,并在Lands循环中迅速将其回收。然而,PLA2的过表达或增强活性会增加修饰的低密度脂蛋白(LDL)和氧化的LDL中的LPC含量,这在动脉粥样硬化斑块的形成和内皮功能障碍中起重要作用。细胞内酶LPCAT不能直接从循环中去除LPC。脂溶酶(一种具有溶血磷脂酶D活性的酶)水解LPC会产生溶血磷脂酸,这与癌症高度相关。尽管理论上具有溶血磷脂酶A1活性的酶可以将LPC降解为无害的代谢产物,但尚未在循环中发现它们。总之,了解酶动力学和LPC代谢可能有助于确定与LPC相关的疾病中的新治疗靶标。细胞内酶LPCAT不能直接从循环中去除LPC。脂溶酶(一种具有溶血磷脂酶D活性的酶)水解LPC会产生溶血磷脂酸,这与癌症高度相关。尽管理论上具有溶血磷脂酶A1活性的酶可以将LPC降解为无害的代谢产物,但尚未在循环中发现它们。总之,了解酶动力学和LPC代谢可能有助于确定与LPC相关的疾病中的新治疗靶标。细胞内酶LPCAT不能直接从循环中去除LPC。脂溶酶(一种具有溶血磷脂酶D活性的酶)水解LPC会产生溶血磷脂酸,这与癌症高度相关。尽管理论上具有溶血磷脂酶A1活性的酶可以将LPC降解为无害的代谢产物,但尚未在循环中发现它们。总之,了解酶动力学和LPC代谢可能有助于确定与LPC相关的疾病中的新治疗靶标。尚未在流通中找到它们。总之,了解酶动力学和LPC代谢可能有助于确定与LPC相关的疾病中的新治疗靶标。尚未在流通中找到它们。总之,了解酶动力学和LPC代谢可能有助于确定与LPC相关的疾病中的新治疗靶标。

"点击查看英文标题和摘要"

An Updated Review of Lysophosphatidylcholine Metabolism in Human Diseases

Lysophosphatidylcholine (LPC) is increasingly recognized as a key marker/factor positively associated with cardiovascular and neurodegenerative diseases. However, findings from recent clinical lipidomic studies of LPC have been controversial. A key issue is the complexity of the enzymatic cascade involved in LPC metabolism. Here, we address the coordination of these enzymes and the derangement that may disrupt LPC homeostasis, leading to metabolic disorders. LPC is mainly derived from the turnover of phosphatidylcholine (PC) in the circulation by phospholipase A2 (PLA2). In the presence of Acyl-CoA, lysophosphatidylcholine acyltransferase (LPCAT) converts LPC to PC, which rapidly gets recycled by the Lands cycle. However, overexpression or enhanced activity of PLA2 increases the LPC content in modified low-density lipoprotein (LDL) and oxidized LDL, which play significant roles in the development of atherosclerotic plaques and endothelial dysfunction. The intracellular enzyme LPCAT cannot directly remove LPC from circulation. Hydrolysis of LPC by autotaxin, an enzyme with lysophospholipase D activity, generates lysophosphatidic acid, which is highly associated with cancers. Although enzymes with lysophospholipase A1 activity could theoretically degrade LPC into harmless metabolites, they have not been found in the circulation. In conclusion, understanding enzyme kinetics and LPC metabolism may help identify novel therapeutic targets in LPC-associated diseases.

更新日期:2019-03-06

  点击分享

  查看原文

点击收藏

取消收藏

新增笔记

公开下载

阅读更多本刊最新论文

PDF   

https://www.mdpi.com/1422-0067/20/5/1149/pdf

HTML

https://doi.org/10.3390/ijms20051149

PDF   

http://europepmc.org/articles/pmc6429061?pdf=render

HTML

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6429061

PDF   

http://pdfs.semanticscholar.org/2902/62c89fc9c4ba70f58fc42489e277dcce0c4d.pdf

全部期刊列表>>

学术期刊

行业资讯

全球导师

X-MOL问答

求职广场

网址导航

关于我们

帮助中心

客服邮箱:service@x-mol.com

官方微信:X-molTeam2

邮编:100098

地址:北京市海淀区知春路56号中航科技大厦

        

Copyright © 2014-2024 北京衮雪科技有限公司 All Rights Reserved    

京ICP备11026495号-2

    

京公网安备 11010802027423号

down

wechat

bug

bug

时域特征--线性预测系数(LPC)以及LPCC - Tingwei_chen - 博客园

时域特征--线性预测系数(LPC)以及LPCC - Tingwei_chen - 博客园

会员

周边

新闻

博问

AI培训

云市场

所有博客

当前博客

我的博客

我的园子

账号设置

简洁模式 ...

退出登录

注册

登录

Tingwei_chen

做自己的事,走自己的路

微信公众号:音频探险记

博客园

首页

新随笔

联系

订阅

管理

时域特征--线性预测系数(LPC)以及LPCC

欲知更多,请关注公众号:音频探险记

LPC

线性预测系数的基本思想:由于语音样点之间存在着相关性,那么当前点/未来点可以用过去的p个样本点进行预测,即

其中就是要求的LPC,P表示预测阶数。

好处:可以得到声道模型及其模型参数的方法,广泛用于语音识别以及语音合成中。

import librosa

import python_speech_features

import soundfile as sf

import numpy as np

def lpc(y, order):

dtype = y.dtype.type

ar_coeffs = np.zeros(order + 1, dtype=dtype)

ar_coeffs[0] = dtype(1) # 1.0

ar_coeffs_prev = np.zeros(order + 1, dtype=dtype)

ar_coeffs_prev[0] = dtype(1)

# 前向和后向的预测误差

fwd_pred_error = y[1:]

bwd_pred_error = y[:-1]

den = np.dot(fwd_pred_error, fwd_pred_error) + np.dot(bwd_pred_error, bwd_pred_error)

for i in range(order):

if den <= 0:

raise FloatingPointError("numerical error, input ill-conditioned?")

reflect_coeff = dtype(-2) * np.dot(bwd_pred_error, fwd_pred_error) / dtype(den)

ar_coeffs_prev, ar_coeffs = ar_coeffs, ar_coeffs_prev

for j in range(1, i+2):

ar_coeffs[j] = ar_coeffs_prev[j] + reflect_coeff * ar_coeffs_prev[i - j + 1]

# 前向预测误差和后向预测误差更新

fwd_pred_error_tmp = fwd_pred_error

fwd_pred_error = fwd_pred_error + reflect_coeff * bwd_pred_error

bwd_pred_error = bwd_pred_error + reflect_coeff * fwd_pred_error_tmp

q = dtype(1) - reflect_coeff ** 2

den = q * den - bwd_pred_error[-1]**2 - fwd_pred_error[0]**2

fwd_pred_error = fwd_pred_error[1:]

bwd_pred_error = bwd_pred_error[:-1]

return ar_coeffs

y, sr = sf.read('q1.wav')

frame_size = 160

num_frames = len(y) // frame_size

print(lpc(y, 32))

'''

[ 1.00000000e+00 -3.95327600e+00 8.29868847e+00 -1.27752183e+01

1.60320420e+01 -1.71512784e+01 1.59802135e+01 -1.29520778e+01

8.83717438e+00 -4.58646820e+00 8.91619704e-01 1.80827086e+00

-3.30606685e+00 3.68847432e+00 -3.13823922e+00 2.08868507e+00

-1.04485702e+00 1.47865339e-01 6.35567557e-01 -1.15391128e+00

1.35048967e+00 -1.27918423e+00 9.65718801e-01 -5.09474786e-01

5.94380366e-03 4.28867366e-01 -7.08129489e-01 8.19126446e-01

-7.55779509e-01 5.73570390e-01 -3.63595930e-01 1.78320700e-01

-4.54597679e-02]

'''

LPCC

LPCC全称线性预测倒谱系数(linear predictive cepstral coefficient, LPCC),可以在计算得到LPC后,如果如下的计算公式计算得到LPCC

LPCC是LPC系数在倒谱域的表示,计算量小易于实现,对元音的描述能力较好,对辅音的描述能力较差,抗噪性能差[1]

[1] 数字语音处理及MATLAB仿真

相应代码如下

import librosa

import python_speech_features

import soundfile as sf

import numpy as np

def lpc(y, order):

dtype = y.dtype.type

ar_coeffs = np.zeros(order + 1, dtype=dtype)

ar_coeffs[0] = dtype(1) # 1.0

ar_coeffs_prev = np.zeros(order + 1, dtype=dtype)

ar_coeffs_prev[0] = dtype(1)

# 前向和后向的预测误差

fwd_pred_error = y[1:]

bwd_pred_error = y[:-1]

den = np.dot(fwd_pred_error, fwd_pred_error) + np.dot(bwd_pred_error, bwd_pred_error)

for i in range(order):

if den <= 0:

raise FloatingPointError("numerical error, input ill-conditioned?")

reflect_coeff = dtype(-2) * np.dot(bwd_pred_error, fwd_pred_error) / dtype(den)

ar_coeffs_prev, ar_coeffs = ar_coeffs, ar_coeffs_prev

for j in range(1, i+2):

ar_coeffs[j] = ar_coeffs_prev[j] + reflect_coeff * ar_coeffs_prev[i - j + 1]

# 前向预测误差和后向预测误差更新

fwd_pred_error_tmp = fwd_pred_error

fwd_pred_error = fwd_pred_error + reflect_coeff * bwd_pred_error

bwd_pred_error = bwd_pred_error + reflect_coeff * fwd_pred_error_tmp

q = dtype(1) - reflect_coeff ** 2

den = q * den - bwd_pred_error[-1]**2 - fwd_pred_error[0]**2

fwd_pred_error = fwd_pred_error[1:]

bwd_pred_error = bwd_pred_error[:-1]

return ar_coeffs

y, sr = sf.read('q1.wav')

# 得到lpc系数

lpc_coeff = lpc(y, 32)

lpc_order = 32

# lpcc 系数个数

lpcc_order = 48

lpcc_coeff = np.zeros(lpcc_order)

lpcc_coeff[0] = lpc_coeff[0]

for m in range(1, lpc_order):

lpcc_coeff[m] = lpc_coeff[m]

for k in range(0,m):

lpcc_coeff[m] = lpc_coeff[m] + lpcc_coeff[k] * lpc_coeff[m - k] * k / m

for m in range(lpc_order, lpcc_order):

for k in range(m - lpc_order, m):

lpcc_coeff[m] = lpcc_coeff[m] + lpcc_coeff[k] * lpc_coeff[m - k] * k / m

print(lpcc_coeff)

print(lpc_coeff)

'''

[ 1.00000000e+00 -3.95327600e+00 1.61128841e+01 -5.52410036e+01

1.79819243e+02 -5.85851356e+02 1.94600697e+03 -6.60704007e+03

2.28633585e+04 -8.03469568e+04 2.85871218e+05 -1.02738713e+06

3.72307949e+06 -1.35861755e+07 4.98734770e+07 -1.84019377e+08

6.82011923e+08 -2.53758247e+09 9.47444366e+09 -3.54837702e+10

1.33263280e+11 -5.01739551e+11 1.89335516e+12 -7.15952267e+12

2.71242538e+13 -1.02940475e+14 3.91300106e+14 -1.48962409e+15

5.67857747e+15 -2.16748811e+16 8.28305613e+16 -3.16889100e+17

2.21650898e+18 -1.23415673e+19 6.99397095e+19 -3.97121614e+20

2.25665287e+21 -1.28331886e+22 7.30333576e+22 -4.15919083e+23

2.37018398e+24 -1.35153342e+25 7.71134177e+25 -4.40229745e+26

2.51457017e+27 -1.43705211e+28 8.21666908e+28 -4.70028689e+29]

'''

posted @

2021-04-05 11:45 

Tingwei_chen 

阅读(3934) 

评论(1) 

编辑 

收藏 

举报

会员力量,点亮园子希望

刷新页面返回顶部

公告

Copyright © 2024 Tingwei_chen

Powered by .NET 8.0 on Kubernetes

详解LPC - 逆枫゛ - 博客园

详解LPC - 逆枫゛ - 博客园

会员

周边

新闻

博问

AI培训

云市场

所有博客

当前博客

我的博客

我的园子

账号设置

简洁模式 ...

退出登录

注册

登录

逆枫゛

Qt学习群:1149411109 群文件提供博客源码,定期答疑、更新学习资料。

 

博客园

 ::

首页

 ::

新随笔

 ::

联系 ::

订阅

 ::

管理

公告

详解LPC

LPC是“本地过程调用(Local Procedure Call)”的缩写。所谓“本地过程调用”是与“远程过程调用”即RPC相对而言的。其实RPC是广义的,RPC可以发生在不同的主机之间,也可以发生在同一台主机上,发生在同一台主机上就是LPC。所以在Unix语境下就没有LPC这一说,即使发生在同一台主机上也称为RPC。在历史上,RPC是“开放软件基金会(OSF)”设计和提出的一种用以实现“Unix分布计算环境(Unix DCE)”的标准。实际上,微软的DCOM技术,就是建立在RPC基础上的。Win2000的RPC可以采用TCP/IP、SPX、NetBIOS、命名管道、以及“本地”作为底层的通信手段,这“本地”就是LPC。另一方面,Windows是一个带有许多微内核系统特征的操作系统(尽管它的内核不是微内核),系统中有不少“系统级”的服务进程,例如大家已经熟知的csrss、管理用户登录的“本地安全认证服务”进程LSASS等等,用户进程以及微软提供的系统工具软件经常需要调用由这些服务进程提供的服务,这里LPC就起着重要的作用。

LPC的基础是一种称为“端口(Port)”的进程间通信机制,类似于本地的(Unix域的)Socket。这种Port机制提供了面向报文传递(message passing)的进程间通信,而LPC则是建立在这个基础上的高层机制,目的是提供跨进程的过程调用。注意这里所谓“跨进程的过程调用”不同于以前所说的“跨进程操作”。前者是双方有约定、遵循一定规程的、有控制的服务提供,被调用者在向外提供一些什么服务、即提供哪些函数调用方面是自主的,而后者则可以是在不知不觉之间的被利用、被操纵。前者是良性的,而后者可以是恶性的。

“Microsoft Windows Internals”书中说LPC是“用于快速报文传递的进程间通信机制”。其实这是误导的,应该说Port才是这样的进程间通信机制,而LPC是建立在这上面的应用。然而这种说法已经被广泛接受和采纳,都把LPC和Port混淆起来了,所以本文也只好跟着说“Windows的LPC机制”,而实际上要说的则主要是Windows的Port机制。在下面的叙述中,凡说到LPC的地方往往实际上是在说Port,读者要注意区分。

端口是一种面向连接的通信机制,通信的双方需要先建立起“连接”。这种连接一般建立在用户进程之间。在建立了连接的双方之间有几种交换报文的方法:

 l 不带数据的纯报文。

 l 不大于256字节的短报文。

 l 如果是大于256字节的长报文,就要在双方之间建立两个共享内存区(Section)。双方通过共享内存区交换数据,但通过报文进行协调和同步。

大块数据之所以要通过共享内存区交换,一来是因为这样就为用于Port机制的缓冲区设置了一个上限,便于内存管理。而更重要的是提高了效率,因为否则便要在发送端把大块数据搬入内核空间,又在接收端把大块数据搬到用户空间。

Windows内核为基于端口的进程间通信机制提供了不少系统调用,包括(但并不限于):

CODE:

 l NtCreatePort()

 l NtCreateWaitablePort()

 l NtListenPort()

 l NtConnectPort()

 l NtAcceptConnectPort()

 l NtCompleteConnectPort()

 l NtRequestPort()

 l NtRequestWaiReplyPort()

 l NtReplyPort()

 l NtReplyWaitReceivePort()

 l NtReplyWaitReceivePortEx()。同上,但是带有超时控制

 l NtReadRequestData()

 l NtWriteRequestData()

 l NtQueryInformationPort()

这么多的系统调用(由此也可见LPC在Windows操作系统中的份量),当然不可能在这里一一加以介绍。本文只是从中拣几个关键而典型的作些介绍。另一方面,由于Port与Socket的相似性,对于兼容内核的开发而言应该比较容易把它嫁接到Socket机制上去。

值得一提的是,Port在Win32 API界面上是不可见的(实际上甚至LPC也不是直接可见的),而Windows的系统调用界面又不公开。这说明Port只是供微软“内部使用”的。读者后面就会看到,Port是一种既包括进程间的数据传输,又包括进程间的同步、数据量又可大可小的综合性的进程间通信机制。这样,由微软自己开发的软件、特别是一些系统工具,当然可以使用这些系统调用、也即利用Port这种功能比较强的进程间通信机制,而第三方开发的软件可就用不上了。

端口分“连接端口(connection port)”和“通信端口(communication port)”两种,各自扮演着不同的角色。连接端口用于连接的建立,通信端口才真正用于双方的通信。只有服务进程才需要有连接端口,但是通信双方都需要有通信端口。

虽然LPC一般发生在进程之间,但是实际参与通信的总是具体的线程,所以在下面的叙述中都以线程作为通信的两端。

典型的建立连接和通信的过程如下:

 l 需要建立LPC通信时,其中提供服务的一方、即服务线程首先要通过NtCreatePort()创建一个命名的连接端口、即Port对象。这个对象名应为请求服务的一方、即客户线程所知。

 l 建立了上述连接端口以后,服务线程应通过NtListenPort()等待接收来自客户线程的连接请求(服务线程被阻塞)。

 l 客户线程通过NtConnectPort()创建一个客户方的无名通信端口,并向上述命名的连接端口发出连接请求(客户线程被阻塞)。

 l 服务线程收到连接请求(因而被唤醒)以后,如果同意建立连接就通过NtAcceptConnectPort()创建一个服务方的无名通信端口、接受连接、并返回该无名通信端口的Handle。然后再通过NtCompleteConnectPort()唤醒客户线程。

 l 客户线程被唤醒,并返回所创建的无名通信端口的Handle。

 l 服务线程另创建一个新的线程,负责为客户线程提供LPC服务。该线程因企图从上述通信端口接收报文、等待来自客户端的服务请求而被阻塞。所以,新创建的线程时LPC服务线程,而原来的服务线程是端口服务进程。

 l 端口服务线程再次调用NtListenPort(),等待来自其它客户的连接请求。

 l 客户线程通过NtRequestWaiReplyPort()向对方发送报文,请求得到LPC服务,并因等待回答而被阻塞。

 l 服务端的相应线程、即LPC服务线程因接收到报文而被唤醒,并根据报文内容提供相应的LPC服务。

 l LPC服务线程通过NtReplyPort()向客户方发送回答报文(一般是计算结果)。客户线程解除阻塞。

如果回顾一下Wine进程与服务进程wineserver之间的通信,就可以明白Wine是用命名管道和Socket在模仿Windows的LPC通信,只不过那是在用户空间的模仿。另一方面,熟悉Socket通信的读者可以看到,Port与Socket是很相像的。

先看Port的创建。我们看系统调用NtCreatePort()的代码:

CODE:

NTSTATUS STDCALL

NtCreatePort (OUT PHANDLE PortHandle,

IN POBJECT_ATTRIBUTES ObjectAttributes,

IN ULONG MaxConnectInfoLength,

IN ULONG MaxDataLength,

IN ULONG MaxPoolUsage)

{

PEPORT Port;

NTSTATUS Status;

DPRINT("NtCreatePort() Name %x\n", ObjectAttributes->ObjectName->Buffer);

/* Verify parameters */

Status = LpcpVerifyCreateParameters (PortHandle, ObjectAttributes,

MaxConnectInfoLength, MaxDataLength, MaxPoolUsage);

. . . . . .

/* Ask Ob to create the object */

Status = ObCreateObject (ExGetPreviousMode(), LpcPortObjectType,

ObjectAttributes, ExGetPreviousMode(),

NULL, sizeof(EPORT), 0, 0, (PVOID*)&Port);

. . . . . .

Status = ObInsertObject ((PVOID)Port, NULL, PORT_ALL_ACCESS,

0, NULL, PortHandle);

. . . . . .

Status = LpcpInitializePort (Port, EPORT_TYPE_SERVER_RQST_PORT, NULL);

Port->MaxConnectInfoLength = PORT_MAX_DATA_LENGTH;

Port->MaxDataLength = PORT_MAX_MESSAGE_LENGTH;

Port->MaxPoolUsage = MaxPoolUsage;

ObDereferenceObject (Port);

return (Status);

}

参数ObjectAttributes、即OBJECT_ATTRIBUTES结构中有个Unicode字符串,那就是对象名,需要在调用NtCreatePort()之前加以设置,这跟创建/打开文件时的文件名设置是一样的。当然,除对象名以外,ObjectAttributes中还有别的信息,那就不是我们此刻所关心的了。其余参数的作用则不言自明。代码中的LpcpVerifyCreateParameters()对参数进行合理性检查,ObCreateObject()和ObInsertObject()就无需多说了,而LpcpInitializePort()主要是对代表着端口的EPORT数据结构进行初始化。EPORT数据结构的定义如下:

CODE:

typedef struct _EPORT

{

KSPIN_LOCK Lock;

KSEMAPHORE Semaphore;

USHORT Type;

USHORT State;

struct _EPORT *RequestPort;

struct _EPORT *OtherPort;

ULONG QueueLength;

LIST_ENTRY QueueListHead;

ULONG ConnectQueueLength;

LIST_ENTRY ConnectQueueListHead;

ULONG MaxDataLength;

ULONG MaxConnectInfoLength;

ULONG MaxPoolUsage; /* size of NP zone */

} EPORT, * PEPORT;

结构中的QueueListHead就是用来接收报文的队列。ConnectQueueListHead则是用来缓存连接请求的队列,这是因为一个Port可能会一下子接收到好几个连接请求。字段Type用来纪录端口的类型,一共有三种类型:

CODE:

#define EPORT_TYPE_SERVER_RQST_PORT (0)

#define EPORT_TYPE_SERVER_COMM_PORT (1)

#define EPORT_TYPE_CLIENT_COMM_PORT (2)

从上面的代码中可以看出,NtCreatePort()所创建的是“请求端口”,即类型为EPORT_TYPE_SERVER_RQST_PORT的端口,也就是“连接端口”。

字段state说明端口的状态和性质,例如EPORT_WAIT_FOR_CONNECT、EPORT_CONNECTED_CLIENT等等。

注意每个EPORT结构中都嵌有一个“信号量”结构Semaphore,这就是通信双方用来实现同步的手段。所以说,Port是集成了数据交换和行为同步的综合性的进程间通信机制。

还有个字段OtherPort也值得一说,这是个指针,互相指向已经建立了连接的对方端口。

LpcpInitializePort()的代码就不看了。只是要说明一下,端口对象的初始化也包括了对其“信号量”数据结构的初始化,并且信号量的初值是0,而最大值则为最大整数LONG_MAX,所以实际上没有限制。

创建了连接端口以后,服务进程就通过NtListenPort()等待连接请求,并因此而被阻塞进入睡眠。

CODE:

NTSTATUS STDCALL

NtListenPort (IN HANDLE PortHandle, IN PLPC_MESSAGE ConnectMsg)

{

NTSTATUS Status;

/* Wait forever for a connection request. */

for (;;)

{

Status = NtReplyWaitReceivePort(PortHandle, NULL, NULL, ConnectMsg);

/* Accept only LPC_CONNECTION_REQUEST requests. Drop any other message. */

if (!NT_SUCCESS(Status) ||

LPC_CONNECTION_REQUEST == ConnectMsg->MessageType)

{

DPRINT("Got message (type %x)\n", LPC_CONNECTION_REQUEST);

break;

}

DPRINT("Got message (type %x)\n", ConnectMsg->MessageType);

}

return (Status);

}

所谓“收听(Listen)”,就是在一个for循环中反复调用NtReplyWaitReceivePort(),等待接收来自客户方的报文,直至接收到报文、并且所收到报文的类型为“连接请求”、即LPC_CONNECTION_REQUEST时为止。如果接收到的报文不是连接请求就回过去再等,所以才把它放在无限for循环中。

NtReplyWaitReceivePort()本来的作用是“发送一个应答报文并等待接收”,但是这里的应答报文指针为NULL,也就是无应答报文可发,这样就成为只是等待来自客户方的请求了。另一方面,这个函数是不带超时(Timeout)的,只要没有收到客户方的请求就一直等待下去。

CODE:

[NtListenPort() > NtReplyWaitReceivePort()]

NTSTATUS STDCALL

NtReplyWaitReceivePort (IN HANDLE PortHandle, OUT PULONG PortId,

IN PLPC_MESSAGE LpcReply, OUT PLPC_MESSAGE LpcMessage)

{

return(NtReplyWaitReceivePortEx (PortHandle, PortId, LpcReply, LpcMessage, NULL));

}

NtReplyWaitReceivePort()是不带超时的,另一个系统调用NtReplyWaitReceivePortEx()则有超时功能,所以前者是通过后者实现的,只是把(最后那个)参数Timeout设成NULL。

CODE:

[NtListenPort() > NtReplyWaitReceivePort() > NtReplyWaitReceivePortEx()]

NTSTATUS STDCALL

NtReplyWaitReceivePortEx(IN HANDLE PortHandle, OUT PULONG PortId,

IN PLPC_MESSAGE LpcReply, OUT PLPC_MESSAGE LpcMessage,

IN PLARGE_INTEGER Timeout)

{

. . . . . .

if( Port->State == EPORT_DISCONNECTED )

{

/* If the port is disconnected, force the timeout to be 0

so we don't wait for new messages, because there won't be

any, only try to remove any existing messages */

Disconnected = TRUE;

to.QuadPart = 0;

Timeout = &to;

}

else Disconnected = FALSE;

Status = ObReferenceObjectByHandle(PortHandle, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, (PVOID*)&Port, NULL);

. . . . . .

/* Send the reply, only if port is connected */

if (LpcReply != NULL && !Disconnected)

{

Status = EiReplyOrRequestPort(Port->OtherPort, LpcReply, LPC_REPLY, Port);

KeReleaseSemaphore(&Port->OtherPort->Semaphore,

IO_NO_INCREMENT, 1, FALSE);

. . . . . .

}

/* Want for a message to be received */

Status = KeWaitForSingleObject(&Port->Semaphore, UserRequest,

UserMode, FALSE, Timeout);

if( Status == STATUS_TIMEOUT )

{

. . . . . .

}

. . . . . .

/* Dequeue the message */

KeAcquireSpinLock(&Port->Lock, &oldIrql);

Request = EiDequeueMessagePort(Port);

KeReleaseSpinLock(&Port->Lock, oldIrql);

if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)

{

LPC_MESSAGE Header;

PEPORT_CONNECT_REQUEST_MESSAGE CRequest;

CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;

memcpy(&Header, &Request->Message, sizeof(LPC_MESSAGE));

Header.DataSize = CRequest->ConnectDataLength;

Header.MessageSize = Header.DataSize + sizeof(LPC_MESSAGE);

Status = MmCopyToCaller(LpcMessage, &Header, sizeof(LPC_MESSAGE));

if (NT_SUCCESS(Status))

{

Status = MmCopyToCaller((PVOID)(LpcMessage + 1),

CRequest->ConnectData, CRequest->ConnectDataLength);

}

}

else

{

Status = MmCopyToCaller(LpcMessage, &Request->Message,

Request->Message.MessageSize);

}

. . . . . .

if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)

{

KeAcquireSpinLock(&Port->Lock, &oldIrql);

EiEnqueueConnectMessagePort(Port, Request);

KeReleaseSpinLock(&Port->Lock, oldIrql);

}

else

{

ExFreePool(Request);

}

/* Dereference the port */

ObDereferenceObject(Port);

return(STATUS_SUCCESS);

}

在Port机制的实现中,NtReplyWaitReceivePortEx()是个经常用到的函数。刚才我们看到的是从NtListenPort()逐层调用下来的,所以没有应答报文需要发送,直接就进入等待接收报文的阶段了,但在多数情况下是有应答报文要发送的,服务线程运行的典型情景就是“接收-处理-应答-再接收”,所以把应答和再接收合并在一起。因此,我们也应看一下在有应答报文要发送时的操作,就是代码中if (LpcReply != NULL && !Disconnected)语句里面的操作。

当然,如果端口已经处于断开状态、即Disconnected为TRUE,那就不发送应答报文了。从代码中可以看出,应答报文的发送是通过EiReplyOrRequestPort()完成的。完成以后还要向对方端口的“信号量”执行一次V操作,即增量为1的KeReleaseSemaphore()操作,如果对方线程正在睡眠等待就把它唤醒。后面这一步属于线程间同步,读者想必已经熟悉了,这里看一下EiReplyOrRequestPort()的代码:

CODE:

[NtReplyWaitReceivePort() > NtReplyWaitReceivePortEx()> EiReplyOrRequestPort()]

NTSTATUS STDCALL

EiReplyOrRequestPort (IN PEPORT Port,

IN PLPC_MESSAGE LpcReply,

IN ULONG MessageType,

IN PEPORT Sender)

{

. . . . . .

MessageReply = ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUEDMESSAGE),

TAG_LPC_MESSAGE);

MessageReply->Sender = Sender;

if (LpcReply != NULL)

{

memcpy(&MessageReply->Message, LpcReply, LpcReply->MessageSize);

}

MessageReply->Message.ClientId.UniqueProcess = PsGetCurrentProcessId();

MessageReply->Message.ClientId.UniqueThread = PsGetCurrentThreadId();

MessageReply->Message.MessageType = MessageType;

MessageReply->Message.MessageId = InterlockedIncrementUL(&LpcpNextMessageId);

KeAcquireSpinLock(&Port->Lock, &oldIrql);

EiEnqueueMessagePort(Port, MessageReply);

KeReleaseSpinLock(&Port->Lock, oldIrql);

return(STATUS_SUCCESS);

}

参数LpcReply是从上面传下来的指针,指向一个LPC_MESSAGE数据结构,这就是待发送的报文。下面是LPC_MESSAGE数据结构的格式定义:

CODE:

typedef struct _LPC_MESSAGE {

USHORT DataSize;

USHORT MessageSize;

USHORT MessageType;

USHORT VirtualRangesOffset;

CLIENT_ID ClientId;

ULONG MessageId;

ULONG SectionSize;

UCHAR Data[ANYSIZE_ARRAY];

} LPC_MESSAGE, *PLPC_MESSAGE;

实际上这只是报文的头部,后面的不定长数组Data[ANYSIZE_ARRAY]才是具体的报文。这里ANYSIZE_ARRAY定义为1,其实定义成0也可以,只是表示从这儿开始才是具体的报文内容。具体报文的数据结构可以由使用者自行定义,接收方根据头部的MessageType就可以知道收到的是什么报文。不过Port机制定义了两种特殊的报文用于建立连接的过程:

CODE:

typedef struct _EPORT_CONNECT_REQUEST_MESSAGE

{

LPC_MESSAGE MessageHeader;

PEPROCESS ConnectingProcess;

struct _SECTION_OBJECT* SendSectionObject;

LARGE_INTEGER SendSectionOffset;

ULONG SendViewSize;

ULONG ConnectDataLength;

UCHAR ConnectData[0];

} EPORT_CONNECT_REQUEST_MESSAGE;

这就是“连接请求”报文,其第一个成分是一个LPC_MESSAGE数据结构,那就是报文的头部。下面的“连接应答”报文也是一样。前面的参数LpcReply表面上是LPC_MESSAGE指针,但是实际上却可以是具体报文的指针。注意最后的ConnectData[0]表示在这个数据结构的后面还可以有不定长的数据,报文头部的DataSize就反映了这部分数据的大小。所以,报文头部的Data[ANYSIZE_ARRAY]实际上是具体报文的正身,而具体报文如“连接请求”中的ConnectData[0]则是随同具体报文发送的数据。不过这是额外的数据,因为建立连接所必需的信息已经体现在报文正身的各个字段中了。

CODE:

typedef struct _EPORT_CONNECT_REPLY_MESSAGE

{

LPC_MESSAGE MessageHeader;

PVOID SendServerViewBase;

ULONG ReceiveClientViewSize;

PVOID ReceiveClientViewBase;

ULONG MaximumMessageSize;

ULONG ConnectDataLength;

UCHAR ConnectData[0];

} EPORT_CONNECT_REPLY_MESSAGE;

最后,包括额外数据在内的报文总长度是有限的(256字节),如果是大块数据就要通过共享缓冲区发送。

再看上面EiReplyOrRequestPort()的代码。它先在内核空间分配一个QUEUEDMESSAGE数据结构作为报文的“容器”,再把需要发送的报文拷贝到这个数据结构中。注意这里的LpcReply有可能是从用户空间传下来的,相应的缓冲区也在用户空间,所以需要把它搬到内核空间的缓冲区中。然后,真正的“发送”操作其实只是把这个数据结构挂入目标端口的接收报文队列中,这是由EiEnqueueMessagePort()完成的。注意这里的LpcpNextMessageId是报文的序号,每次递增。还要说明,拷贝到QUEUEDMESSAGE数据结构中的只是报文本身,而不包括通过共享内存区传递的数据,这正是为什么要使用共享内存区的原因。

回到NtReplyWaitReceivePortEx()的代码。由于没有应答报文要发送,这里直接就通过KeWaitForSingleObject()进入了睡眠等待。当这个线程接收到了报文而被唤醒(在这里我们忽略超时的可能)时,端口的报文队列里已经有了报文,所以通过EiDequeueMessagePort()从队列中摘下一个报文的数据结构。如果这是个“连接请求”报文,就把它复制到用户提供的缓冲区中,代码中的两次调用MmCopyToCaller()就是分别复制报文的正身及其所附带的数据。其实不是“连接请求”报文也要复制,只不过此时只复制报文的正身。

然后,对于“连接请求”报文,这里还通过EiEnqueueConnectMessagePort()把它挂入端口的ConnectQueueListHead队列,这是为随后的“接受连接”操作、即系统调用NtAcceptConnectPort()留下一个参考,后面我们就会看到其作用。

不过,我们这儿讲的只是如果接收到了连接请求就要做些什么操作,但是实际上此刻还没有客户方提出连接请求,所以服务方线程只是睡眠等待。

至此,服务方已经作好了准备,就等着客户方的连接请求了。如前所述,客户方通过系统调用NtConnectPort()向命名的连接端口请求连接。注意这里连接的目标就是一个连接端口,而并不指定某个具体的进程。哪一个进程在这个连接端口上执行了NtListenPort()并因此而受到阻塞正在等待,这请求就实际上是发给那个进程(线程)的。

请求连接的一方对于将来要发送多大的数据量应该是心里有数的。如果数据量不大,那就可以作为附加信息随同报文(在同一个缓冲区中)一起发送。但是,要是数据量比较大(报文总长大于256字节),那就要通过共享内存区“发送”,因为否则的话一来传输效率低下,二来报文缓冲区的大小也不好静态地安排确定。所以,在期望的发送数据量比较大时要准备好一个共享内存区(Section)用于数据发送。这是要由请求连接的一方、即客户方做好准备,通过调用参数传给NtConnectPort()的。为此客户方要准备好两个数据结构,就是LPC_SECTION_WRITE和LPC_SECTION_READ,把有关共享内存区的信息填写在前一个数据结构中,再把指向这两个数据结构的指针作为参数传给NtConnectPort()。

这两个数据结构的定义为:

CODE:

typedef struct _LPC_SECTION_WRITE {

ULONG Length;

HANDLE SectionHandle;

ULONG SectionOffset;

ULONG ViewSize;

PVOID ViewBase;

PVOID TargetViewBase;

} LPC_SECTION_WRITE;

typedef struct _LPC_SECTION_READ {

ULONG Length;

ULONG ViewSize;

PVOID ViewBase;

} LPC_SECTION_READ;

注意客户方只提供(和映射)用于它写入(发送)的共享内存区,而反方向的共享内存区则由服务方提供(和映射)。所以LPC_SECTION_READ数据结构只是用来获取映射后的结果。

下面看NtConnectPort()的代码。

CODE:

NTSTATUS STDCALL

NtConnectPort (PHANDLE UnsafeConnectedPortHandle,

PUNICODE_STRING PortName,

PSECURITY_QUALITY_OF_SERVICE Qos,

PLPC_SECTION_WRITE UnsafeWriteMap,

PLPC_SECTION_READ UnsafeReadMap,

PULONG UnsafeMaximumMessageSize,

PVOID UnsafeConnectData,

PULONG UnsafeConnectDataLength)

{

. . . . . .

/* Copy in write map and partially validate. */

. . . . . .

/* Handle connection data. */

. . . . . .

/* Reference the named port. */

Status = ObReferenceObjectByName (PortName, 0, NULL, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, NULL, (PVOID*)&NamedPort);

. . . . . .

/* Reference the send section object. */

if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)

{

Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,

SECTION_MAP_READ | SECTION_MAP_WRITE,

MmSectionObjectType, UserMode, (PVOID*)&SectionObject, NULL);

. . . . . .

}

else

{

SectionObject = NULL;

}

/* Do the connection establishment. */

Status = EiConnectPort(&ConnectedPort, NamedPort, SectionObject, SectionOffset,

WriteMap.ViewSize, &WriteMap.ViewBase, &WriteMap.TargetViewBase,

&ReadMap.ViewSize, &ReadMap.ViewBase, &MaximumMessageSize,

ConnectData, &ConnectDataLength);

. . . . . .

/* Do some initial cleanup. */

if (SectionObject != NULL)

{

ObDereferenceObject(SectionObject);

SectionObject = NULL;

}

ObDereferenceObject(NamedPort);

NamedPort = NULL;

/* Copy the data back to the caller. */

. . . . . .

Status = ObInsertObject(ConnectedPort, NULL, PORT_ALL_ACCESS,

0, NULL, &ConnectedPortHandle);

. . . . . .

Status = MmCopyToCaller(UnsafeConnectedPortHandle,

&ConnectedPortHandle, sizeof(HANDLE));

. . . . . .

if (UnsafeWriteMap != NULL)

{

Status = MmCopyToCaller(UnsafeWriteMap,

&WriteMap, sizeof(LPC_SECTION_WRITE));

. . . . . .

}

if (UnsafeReadMap != NULL)

{

Status = MmCopyToCaller(UnsafeReadMap,

&ReadMap, sizeof(LPC_SECTION_READ));

. . . . . .

}

. . . . . .

return(STATUS_SUCCESS);

}

先看调用参数。其中UnsafeConnectedPortHandle是用来返回建立连接以后的通信端口Handle的。之所以说是“Unsafe”是为了强调这可能是在用户空间,因而可能需要把它复制到内核空间的副本ConnectedPortHandle中。其实这也并非特殊,多数系统调用都是这样的。参数PortName是个Unicode字符串,就是目标端口的对象名。另一个参数UnsafeMaximumMessageSize为允许通过本连接(如果成功的话)发送的报文长度设置了一个上限。此外,在请求建立连接的过程中也可以附带着向服务线程发送一些数据,而服务线程在接受或拒绝连接请求时也可以发回来一些数据,参数UnsafeConnectData就是指向为此而设的缓冲区,而UnsafeConnectDataLength则为数据长度。

指针UnsafeWriteMap和UnsafeReadMap就是与共享内存区有关的参数。如果所有需要传递的报文都是短报文,那么这两个指针也可以是NULL。

参数Qos就要费些口舌了。这是个指针,指向一个SECURITY_QUALITY_OF_SERVICE数据结构。QoS字面上的意义是服务质量保证,具体则与一种称为“临时身份(Impersonate)”的机制有关。Impersonate在字典上的解释是“人格化、扮演”,实际上是“身份、代表、授权”的意思。在LPC机制中,服务进程应客户进程的请求而执行某些操作。换言之,服务进程是代表着客户进程、以客户进程的名义在执行这些操作,因而服务进程在执行这些操作的过程中所具有的各种权限理应与具体的客户进程相同,这既不是服务进程本身的权限,也不是某种一成不变的权限。不妨拿日常生活中当事人与律师的关系作个对比:律师有律师的法定权限,不管当事人是谁,律师的权限都是一样的,并且一般都是高于当事人所具有的权限,例如律师可以查阅法庭的卷宗,而当事人显然不可以,所以律师并不是以当事人的身份在工作,这样才能维护社会公正。但是,LPC则与此相反,服务进程应该以客户进程的身份操作,否则就有可能被权限较低的进程利用来达到本来不能达到的目的,或者本身权限较高的客户却不能达到应该可以达到的目的。操作系统要保证的恰恰是一套等级森严的体制,而不是社会公正。所以,服务进程在为客户提供本地过程调用时就应该临时转换到客户的身份,不过这是可以选择的。显然,这与访问权限有关,因而与系统的安全机制有关。这方面一则说来话长,二则目前的ReactOS才刚开始触及安全机制的实现,所以我们以后再来专题讨论。在调用NtConnectPort()的时候,指针Qos也可以是NULL,那就表示采用默认的方式,就是服务方不采用客户的身份。

继续看NtConnectPort()其余的调用参数。如前所述,通过NtConnectPort()建立端口连接时,还可以随同连接请求发送一些数据,而对方也可以回复一些数据。这里的UnsafeConnectData就是个指针,而UnsafeConnectDataLength则是数据的长度。请求连接的进程在NtListenPort()中受阻而进入睡眠,直到对方接受(或拒绝)了连接请求时才被唤醒并且再次受调度运行。这样,当客户进程从NtConnectPort()返回时,缓冲区中的内容已经是从服务进程返回的数据。

NtConnectPort()的开头一段代码都是为了把用户空间的参数复制到内核中,这里就略去了,我们把注意力集中在实质性的操作。显然,这里的核心是EiConnectPort()。注意这里把WriteMap中ViewBase和TargetViewBase字段的地址,以及ReadMap中ViewSize和ViewBase字段的地址传了下去,这说明EiConnectPort()有可能修改这些字段的数值。

CODE:

[NtConnectPort() > EiConnectPort()]

NTSTATUS STDCALL

EiConnectPort(IN PEPORT* ConnectedPort,

IN PEPORT NamedPort,

IN PSECTION_OBJECT Section,

IN LARGE_INTEGER SectionOffset,

IN ULONG ViewSize,

OUT PVOID* ClientSendViewBase,

OUT PVOID* ServerSendViewBase,

OUT PULONG ReceiveViewSize,

OUT PVOID* ReceiveViewBase,

OUT PULONG MaximumMessageSize,

IN OUT PVOID ConnectData,

IN OUT PULONG ConnectDataLength)

{

. . . . . .

/* Create a port to represent our side of the connection */

Status = ObCreateObject (KernelMode, LpcPortObjectType, NULL,

KernelMode, NULL, sizeof(EPORT), 0, 0, (PVOID*)&OurPort);

. . . . . .

LpcpInitializePort(OurPort, EPORT_TYPE_CLIENT_COMM_PORT, NamedPort);

/* Allocate a request message. */

RequestMessage = ExAllocatePool(NonPagedPool,

sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +

RequestConnectDataLength);

. . . . . .

/* Initialize the request message. */

RequestMessage->MessageHeader.DataSize =

sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength -

sizeof(LPC_MESSAGE);

RequestMessage->MessageHeader.MessageSize =

sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength;

. . . . . .

RequestMessage->MessageHeader.SectionSize = 0;

RequestMessage->ConnectingProcess = PsGetCurrentProcess();

ObReferenceObjectByPointer(RequestMessage->ConnectingProcess,

PROCESS_VM_OPERATION, NULL, KernelMode);

RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;

RequestMessage->SendSectionOffset = SectionOffset;

RequestMessage->SendViewSize = ViewSize;

RequestMessage->ConnectDataLength = RequestConnectDataLength;

if (RequestConnectDataLength > 0)

{

memcpy(RequestMessage->ConnectData, ConnectData, RequestConnectDataLength);

}

/* Queue the message to the named port */

EiReplyOrRequestPort(NamedPort, &RequestMessage->MessageHeader,

LPC_CONNECTION_REQUEST, OurPort);

KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);

ExFreePool(RequestMessage);

/* Wait for them to accept our connection */

KeWaitForSingleObject(&OurPort->Semaphore, UserRequest, UserMode,

FALSE, NULL);

/* Dequeue the response */

KeAcquireSpinLock (&OurPort->Lock, &oldIrql);

Reply = EiDequeueMessagePort(OurPort);

KeReleaseSpinLock (&OurPort->Lock, oldIrql);

CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;

/* Do some initial cleanup. */

ObDereferenceObject(PsGetCurrentProcess());

/* Check for connection refusal. */

if (CReply->MessageHeader.MessageType == LPC_CONNECTION_REFUSED)

{

. . . . . .

return(STATUS_PORT_CONNECTION_REFUSED);

}

/* Otherwise we are connected. Copy data back to the client. */

*ServerSendViewBase = CReply->SendServerViewBase;

*ReceiveViewSize = CReply->ReceiveClientViewSize;

*ReceiveViewBase = CReply->ReceiveClientViewBase;

*MaximumMessageSize = CReply->MaximumMessageSize;

if (ConnectDataLength != NULL)

{

*ConnectDataLength = CReply->ConnectDataLength;

memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);

}

/* Create our view of the send section object. */

if (Section != NULL)

{

*ClientSendViewBase = 0;

Status = MmMapViewOfSection(Section, PsGetCurrentProcess(),

ClientSendViewBase, 0, ViewSize, &SectionOffset,

&ViewSize, ViewUnmap, 0, PAGE_READWRITE);

. . . . . .

}

/* Do the final initialization of our port. */

OurPort->State = EPORT_CONNECTED_CLIENT;

/* Cleanup. */

ExFreePool(Reply);

*ConnectedPort = OurPort;

return(STATUS_SUCCESS);

}

参数ConnectedPort的方向说是IN,看来倒应该是OUT,用来返回新创建的通信端口(见下)的Handle。参数Section是上面传下来的SECTION_OBJECT结构指针。至于其余参数的作用,读者不妨对比一下前面调用这个函数时所使用的实参。

这个函数的执行大致上可以分成四个阶段。

第一个阶段为将来(连接请求被接受以后)的通信创建一个“通信端口”,这就是ObCreateObject()和随后的LpcpInitializePort()所做的事。其结果就是代码中的指针OurPort。

第二个阶段先准备好“连接请求”报文的数据结构,包括通过参数ConnectData传递下来的附加数据,然后就通过EiReplyOrRequestPort()把报文的容器挂入目标端口的接收队列。注意这里的目标端口是个“连接端口”而不是“通信端口”。接着,还要通过KeReleaseSemaphore()对目标端口的“信号量”实行一次V操作,把正在NtListenPort()中睡眠等待的服务线程唤醒。

第三个阶段就是通过KeWaitForSingleObject()睡眠等待对方是否接受连接请求的答复了。

第四个阶段,得到了服务方线程的答复以后,客户线程从睡眠中被唤醒,通过EiDequeueMessagePort()从其通信端口的队列中获取对方的应答报文。如果对方接受连接请求的话,就把原先准备下用于发送数据的共享内存区映射到自己的用户空间,并返回映射的地址。

注意这里映射的只是供客户方写入的区间。还有,这里的指针ClientSendViewBase就是前面的&WriteMap.ViewBase。反向的区间、即供客户方读出的区间是由服务方代为映射的,实际映射的地址通过应答报文中的ReceiveClientViewBase字段返回过来,这里代码中的指针ReceiveViewBase就是前面的&ReadMap.ViewBase。应答报文中的SendServerViewBase字段是服务方读出区间的映射地址。为什么需要知道对方读出区间的映射地址地址呢?这是因为在发往对方的数据中可能会有起着指针作用的数据,对这些数据的值需要在发送出去之前根据共享内存区在对方的映射位置进行“重定位”。那为什么客户方用于读出的区间要由对方代为映射呢?客户方自己当然也可以映射,但是那样的话又得把映射的地址告知对方,那就又得再发送一个报文了。

再看服务方线程。它在NtListenPort()中被唤醒,以后就从其连接端口的接收队列中获取由客户方发来的报文。如果这不是“连接请求”报文就又回过去睡眠等待,直至接收到“连接请求”报文才从NtListenPort()返回。服务方线程在接收到连接请求以后要作出决定,并通过系统调用NtAcceptConnectPort()加以接受或拒绝。

CODE:

NTSTATUS STDCALL

NtAcceptConnectPort (PHANDLE ServerPortHandle, HANDLE NamedPortHandle,

PLPC_MESSAGE LpcMessage, BOOLEAN AcceptIt,

PLPC_SECTION_WRITE WriteMap, PLPC_SECTION_READ ReadMap)

{

. . . . . .

Size = sizeof(EPORT_CONNECT_REPLY_MESSAGE);

if (LpcMessage)

{

Size += LpcMessage->DataSize;

}

CReply = ExAllocatePool(NonPagedPool, Size);

if (CReply == NULL)

{

return(STATUS_NO_MEMORY);

}

Status = ObReferenceObjectByHandle(NamedPortHandle, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, (PVOID*)&NamedPort, NULL);

. . . . . .

/* Create a port object for our side of the connection */

if (AcceptIt)

{

Status = ObCreateObject(ExGetPreviousMode(), LpcPortObjectType, NULL,

ExGetPreviousMode(),NULL, sizeof(EPORT), 0, 0, (PVOID*)&OurPort);

if (!NT_SUCCESS(Status))

{

ExFreePool(CReply);

ObDereferenceObject(NamedPort);

return(Status);

}

Status = ObInsertObject ((PVOID)OurPort, NULL,

PORT_ALL_ACCESS, 0, NULL, ServerPortHandle);

. . . . . .

LpcpInitializePort(OurPort, EPORT_TYPE_SERVER_COMM_PORT, NamedPort);

}

/* Dequeue the connection request */

KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);

ConnectionRequest = EiDequeueConnectMessagePort(NamedPort);

KeReleaseSpinLock(&NamedPort->Lock, oldIrql);

CRequest =

(PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);

/* Prepare the reply. */

if (LpcMessage != NULL)

{

memcpy(&CReply->MessageHeader, LpcMessage, sizeof(LPC_MESSAGE));

memcpy(&CReply->ConnectData, (PVOID)(LpcMessage + 1),

LpcMessage->DataSize);

CReply->MessageHeader.MessageSize =

sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->DataSize;

CReply->MessageHeader.DataSize = CReply->MessageHeader.MessageSize -

CReply->MessageHeader.MessageSize - sizeof(LPC_MESSAGE);

CReply->ConnectDataLength = LpcMessage->DataSize;

}

else

{

CReply->MessageHeader.MessageSize =

sizeof(EPORT_CONNECT_REPLY_MESSAGE);

CReply->MessageHeader.DataSize =

sizeof(EPORT_CONNECT_REPLY_MESSAGE) - sizeof(LPC_MESSAGE);

CReply->ConnectDataLength = 0;

}

if (!AcceptIt)

{

EiReplyOrRequestPort(ConnectionRequest->Sender,

&CReply->MessageHeader,

LPC_CONNECTION_REFUSED,

NamedPort);

KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,

IO_NO_INCREMENT,

1,

FALSE);

ObDereferenceObject(ConnectionRequest->Sender);

ExFreePool(ConnectionRequest);

ExFreePool(CReply);

ObDereferenceObject(NamedPort);

return (STATUS_SUCCESS);

}

/* Prepare the connection. */

if (WriteMap != NULL)

{

PSECTION_OBJECT SectionObject;

LARGE_INTEGER SectionOffset;

Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,

SECTION_MAP_READ | SECTION_MAP_WRITE,

MmSectionObjectType, UserMode, (PVOID*)&SectionObject, NULL);

. . . . . .

SectionOffset.QuadPart = WriteMap->SectionOffset;

WriteMap->TargetViewBase = 0;

CReply->ReceiveClientViewSize = WriteMap->ViewSize;

Status = MmMapViewOfSection(SectionObject, CRequest->ConnectingProcess,

&WriteMap->TargetViewBase, 0, CReply->ReceiveClientViewSize,

&SectionOffset, &CReply->ReceiveClientViewSize,

ViewUnmap, 0, PAGE_READWRITE);

. . . . . .

WriteMap->ViewBase = 0;

Status = MmMapViewOfSection(SectionObject, PsGetCurrentProcess(),

&WriteMap->ViewBase, 0, WriteMap->ViewSize,

&SectionOffset, &WriteMap->ViewSize,

ViewUnmap, 0, PAGE_READWRITE);

. . . . . .

ObDereferenceObject(SectionObject);

}

if (ReadMap != NULL && CRequest->SendSectionObject != NULL)

{

LARGE_INTEGER SectionOffset;

SectionOffset = CRequest->SendSectionOffset;

ReadMap->ViewSize = CRequest->SendViewSize;

ReadMap->ViewBase = 0;

Status = MmMapViewOfSection(

CRequest->SendSectionObject, PsGetCurrentProcess(),

&ReadMap->ViewBase, 0, CRequest->SendViewSize,

&SectionOffset, &CRequest->SendViewSize,

ViewUnmap, 0, PAGE_READWRITE);

. . . . . .

}

/* Finish the reply. */

if (ReadMap != NULL)

{

CReply->SendServerViewBase = ReadMap->ViewBase;

}

else

{

CReply->SendServerViewBase = 0;

}

if (WriteMap != NULL)

{

CReply->ReceiveClientViewBase = WriteMap->TargetViewBase;

}

CReply->MaximumMessageSize = PORT_MAX_MESSAGE_LENGTH;

/* Connect the two ports */

OurPort->OtherPort = ConnectionRequest->Sender;

OurPort->OtherPort->OtherPort = OurPort;

EiReplyOrRequestPort(ConnectionRequest->Sender,

(PLPC_MESSAGE)CReply, LPC_REPLY, OurPort);

ExFreePool(ConnectionRequest);

ExFreePool(CReply);

ObDereferenceObject(OurPort);

ObDereferenceObject(NamedPort);

return (STATUS_SUCCESS);

}

如果接受连接请求,那么服务方也要创建一个通信端口,因为原来的连接端口是专门用来接收连接请求的。第一个参数ServerPortHandle就是用来返回新建通信端口的Handle。而NamedPortHandle当然就是连接端口的Handle,这是本次操作的目标对象。

参数AcceptIt表示是否接受连接请求。

参数WriteMap和ReadMap与NtConnectPort()中所用者相同。同样,如果预期需要发送的数据量较大的话,服务方也要为此提供一个共享内存区。

先看不接受连接请求时的情况,因为这比较简单。这就是条件语句if (!AcceptIt)里面的操作:先将一个“拒绝连接”报文、即类型为LPC_CONNECTION_REFUSED的报文、通过EiReplyOrRequestPort()挂入对方端口的报文队列,然后在对方端口的“信号量”上执行一次V操作,以唤醒正在等待的对方线程。这样就行了。

接受连接请求时的情况就比较复杂一点:

1. 先创建一个通信端口,就是类型为EPORT_TYPE_SERVER_COMM_PORT的端口。

2. 然后为应答报文LpcMessage准备好一个内核版本、就是类型为EPORT_CONNECT_REPLY_MESSAGE的数据结构Creply。

3. 处理共享内存区的映射。注意这里做了三次映射:

 l 把由服务方提供的共享内存区映射到客户进程的用户空间,这是客户方的接收区。“连接请求”报文中的ConnectingProcess提供了指向客户进程的EPROCESS数据结构的指针。

 l 把由服务方提供的共享内存区映射到服务方自己的用户空间,这是服务方进程的写入区。

 l 把由客户方提供的共享内存区映射到服务方的用户空间,这是服务方进程的读出区。

注意这里在调用MmMapViewOfSection()时所给定的地址都是0,表示听从分配。所分配的地址要通过WriteMap和ReadMap返回到用户空间,特别是替客户方进程代为映射的地址要通过应答报文发送给对方。

4. 使服务方通信端口和客户方通信端口的指针OtherPort互相指向对方,即建立连接。

5. 通过EiReplyOrRequestPort()将应答报文挂入客户方端口的报文队列,但是并不唤醒客户方线程。

在完成了NtAcceptConnectPort()以后,服务方线程还需要对新创建的通信端口执行一下另一个系统调用NtCompleteConnectPort()。目的在于唤醒客户方线程。注意此时的操作对象已经是新创建的通信端口,而不再是连接端口。

CODE:

NTSTATUS STDCALL

NtCompleteConnectPort (HANDLE hServerSideCommPort)

{

NTSTATUS Status;

PEPORT ReplyPort;

. . . . . .

/* Ask Ob to translate the port handle to EPORT */

Status = ObReferenceObjectByHandle (hServerSideCommPort, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, (PVOID*)&ReplyPort, NULL);

. . . . . .

/* Verify EPORT type is a server-side reply port; otherwise tell the caller

the port handle is not valid. */

if (ReplyPort->Type != EPORT_TYPE_SERVER_COMM_PORT)

{

ObDereferenceObject (ReplyPort);

return STATUS_INVALID_PORT_HANDLE;

}

ReplyPort->State = EPORT_CONNECTED_SERVER;

/* Wake up the client thread that issued NtConnectPort. */

KeReleaseSemaphore(&ReplyPort->OtherPort->Semaphore,

IO_NO_INCREMENT, 1, FALSE);

/* Tell Ob we are no more interested in ReplyPort */

ObDereferenceObject (ReplyPort);

return (STATUS_SUCCESS);

}

前面,在NtAcceptConnectPort()的代码中,虽然已经将应答报文挂入了客户方端口的接收队列,却并未唤醒客户方线程。现在就通过对其信号量的V操作将其唤醒。

这样,就建立起了客户方与服务方的一对通信端口的连接。以后就可以通过这个连接通信了。一般总是服务方线程先通过NtReplyWaitReceivePort()或NtReplyWaitReceivePortEx()等待对方发来报文,由于Port机制实际上只用于LPC,客户方发往服务方的一般都是服务请求报文,而服务方则根据具体的请求提供服务,然后发回应答报文、一般是返回结果。不过,也并没有规定必须是服务方等待客户方的报文,反过来也并无不可。

不管是那一方,需要向对方发送一个报文时可以通过系统调用NtRequestPort()发送。

CODE:

NTSTATUS STDCALL

NtRequestPort (IN HANDLE PortHandle, IN PLPC_MESSAGE LpcMessage)

{

. . . . . .

Status = ObReferenceObjectByHandle(PortHandle, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, (PVOID*)&Port, NULL);

. . . . . .

Status = LpcRequestPort(Port->OtherPort, LpcMessage);

ObDereferenceObject(Port);

return(Status);

}

显然,具体的操作是由LpcRequestPort()完成的。区别在于LpcRequestPort()要求使用指向EPORT数据结构的指针,而传给NtRequestPort()的是Handle,需要加以转换。Handle本质上是数组下标,所以从Handle到结构指针的转换开销并不大。

CODE:

[NtRequestPort() > LpcRequestPort()]

NTSTATUS STDCALL LpcRequestPort (IN PEPORT Port,

IN PLPC_MESSAGE LpcMessage)

{

NTSTATUS Status;

DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);

#ifdef __USE_NT_LPC__

/* Check the message's type */

if (LPC_NEW_MESSAGE == LpcMessage->MessageType)

{

LpcMessage->MessageType = LPC_DATAGRAM;

}

else if (LPC_DATAGRAM == LpcMessage->MessageType)

{

return STATUS_INVALID_PARAMETER;

}

else if (LpcMessage->MessageType > LPC_CLIENT_DIED)

{

return STATUS_INVALID_PARAMETER;

}

/* Check the range offset */

if (0 != LpcMessage->VirtualRangesOffset)

{

return STATUS_INVALID_PARAMETER;

}

#endif

Status = EiReplyOrRequestPort(Port, LpcMessage, LPC_DATAGRAM, Port);

KeReleaseSemaphore(&Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );

return(Status);

}

可见,NtRequestPort()只是发送,而并不等待对方的回应。如果需要等待回应的话可以采用另一个系统调用NtRequestWaitReplyPort()。

需要向对方发送应答报文时可以用NtReplyPort()。

CODE:

NTSTATUS STDCALL

NtReplyPort (IN HANDLE PortHandle, IN PLPC_MESSAGE LpcReply)

{

NTSTATUS Status;

PEPORT Port;

DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);

Status = ObReferenceObjectByHandle(PortHandle, PORT_ALL_ACCESS,

LpcPortObjectType, UserMode, (PVOID*)&Port, NULL);

. . . . . .

Status = EiReplyOrRequestPort(Port->OtherPort, LpcReply, LPC_REPLY, Port);

KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);

ObDereferenceObject(Port);

return(Status);

}

当然,这是纯粹的发送应答报文,如果是发送应答报文并且等待下一个请求,那就要用NtReplyWaitReceivePort(),这读者已经在前面看到了。

可见,Port是一种功能相当强、相当齐全、结构又相当完整的综合性的进程间通信机制,这样的机制理应提供给应用软件的开发者,或者在Win32 API上提供相应的库函数,或是把有关的系统调用公诸于世。但是微软却并不这么干,倒是一方面讳莫如深,一方面供自己的软件内部使用。这样,如果都来开发应用软件,那别的公司如何能与微软公平竞争呢?正因为如此,美国一直有人在呼吁甚至提起诉讼,要把操作系统和应用软件的开发分拆开来,不能让同一家公司既做操作系统又做应用软件。另一方面,这也可以解释为什么总是有这许多人热衷于探究Windows和相关产品的“Undocumented…”、“…Internals”、“Inside…”。

最后还要提一下,有些资料中还提到Windows有一种“快捷LPC(QuickLPC)”机制。这就是建立在上一篇漫谈中讲到的“事件对”基础上的LPC。早期Windows上的csrss通信太频繁了,需要有一种非常轻快的进程间通信手段,所以才有了QuickLPC。现在,一方面是csrss的功能大都移到了内核中,一方面是处理器的速度也有了量级的提高,QuickLPC就变得不那么重要了。

因为手上有个程序要用到进程间通信,打算使用LPC实现,研究了几天有些收获,

故记录下来已备查询.(有些细节没有写明,可以参阅<>,这里只写我的心得)

LPC跟socket类似,也是server-client模式

直接上代码(在vs2008下编译通过,不过要自己整理一份头文件)

Server端代码如下:

//这是一个利用结构传递短消息进行通信的例子

#include

#include

#include

#include

#pragma comment(lib,"xpntdll.lib")

int main(void)

{

//初始化Unicode字串

UNICODE_STRING portname;

RtlInitUnicodeString(&portname,L"\\NxPort");

//定义并填充结构体

OBJECT_ATTRIBUTES oa;//此结构可以看msdn

InitializeObjectAttributes(&oa,&portname,OBJ_CASE_INSENSITIVE,0,0);

int rc;

HANDLE hPort;

//api的声明和参数介绍看书

//这里说一下第3和第4个参数,这两个参数书上说

//系统会自己填充成0x104和0x148,但我填0就不能

//收到NtConnectPort发来的消息,因为不会内核调试

//只能先添上这两个值

rc = NtCreatePort(&hPort,&oa,0x104,0x148,0);

if (rc != 0)

{

printf("error 1 = %08x\n", rc);

system("pause");

return 1;

}

//定义两个结构,一个接收消息,一个发送

PORT_MESSAGE pmRecv;

PORT_MESSAGE pmSend;

//结构添0

memset(&pmSend, 0, sizeof(pmSend));

memset(&pmRecv, 0, sizeof(pmRecv));

//此函数会接收NtConnectPort发来的消息

//client端得一些信息都保存在PORT_MESSAGE

//这个结构中

printf("等待Client的请求...\n");

rc = NtListenPort(hPort,&pmRecv);

if (rc != 0)

{

printf("error 2 = %08x\n", rc);

CloseHandle(hPort);

system("pause");

return 1;

}

//将收到的消息显示到屏幕

printf("收到请求\nprocessID:%08x\nthreadID%08x\nMessageType %d\nMessageSize %d\nMessageID %x\nDataSize %d\n\n",

pmRecv.ClientId.UniqueProcess,

pmRecv.ClientId.UniqueThread,

pmRecv.MessageType,

pmRecv.MessageSize,

pmRecv.MessageId,

pmRecv.DataSize);

printf("请求内容:\n%s\n", pmRecv.Data);

//收到请求之后,server端就会调用下面两个API函数,来完成连接

//NtAcceptConnectPort会建立一个新的port来与client进行通信

//并发送一个回复给client,回复也是一个PORT_MESSAGE结构

//注意,回复的时候要填充pmSend的ClientId和MessageId

//有多个client的时候是靠这两个来区分是要回复哪个client的

//本例只能连接一个client,你可以自己完善它

//回复的内容就放到Data里面,并填充DataSize

HANDLE hAcceptPort;

pmSend.ClientId = pmRecv.ClientId;

pmSend.MessageId = pmRecv.MessageId;

pmSend.DataSize = 300;

strcpy_s((PSTR)(pmSend.Data), 300, "服务器回复");

pmSend.MessageSize = sizeof(pmSend);

rc = NtAcceptConnectPort(&hAcceptPort,0,&pmSend,TRUE,0,0);

if (rc != 0)

{

printf("error 3 = %08x\n", rc);

CloseHandle(hPort);

system("pause");

return 1;

}

rc = NtCompleteConnectPort(hAcceptPort);

if (rc != 0)

{

printf("error 4 = %08x\n", rc);

CloseHandle(hAcceptPort);

CloseHandle(hPort);

system("pause");

return 1;

}

//握手完成之后就开始循环与client通信了

while (true)

{

printf("等待客户端消息...\n\n");

//这个函数看名字知道它是回复消息并等待新的消息,

//但是上面用NtAcceptConnectPort已经回复了一次

//client接收到之后已经不在等待状态了,

//不填0会出错,你可以自己完善一下

rc = NtReplyWaitReceivePort(hAcceptPort, 0, 0,&pmRecv);

if (rc != 0)

{

printf("error 5 = %08x\n", rc);

CloseHandle(hAcceptPort);

CloseHandle(hPort);

system("pause");

return 1;

}

printf("收到客户端%d新消息:\n%s\n", pmRecv.ClientId.UniqueProcess, pmRecv.Data);

//对消息进行分类处理

//下面是所有的消息类型/* switch (pmRecv.MessageType)

{

case LPC_NEW_MESSAGE://client端发送第一个消息可以设置这个类型

case LPC_REPLY: //是server发送给client的消息,client主要处理这个

case LPC_DATAGRAM: //client发送到server,但是server不应回复

case LPC_CONNECTION_REQUEST://此消息只通过NtConnectPort发送

case LPC_REQUEST://client端发送到server的消息

printf("收到客户端消息.\n");

break;

case LPC_LOST_REPLY://这个不是太清楚

case LPC_PORT_CLOSED: //port被关闭

case LPC_CLIENT_DIED: //client端关闭

case LPC_EXCEPTION:

case LPC_DEBUG_EVENT:

case LPC_ERROR_EVENT:

default:

}*/pmSend.ClientId = pmRecv.ClientId;

pmSend.MessageId = pmRecv.MessageId;

pmSend.DataSize = 300;

strcpy_s((PSTR)pmSend.Data,300, "服务端的回复");

//上面函数用来接收消息,这个函数用来回复消息

rc = NtReplyPort(hAcceptPort,&pmSend);

if (rc != 0)

{

printf("error 6 = %08x\n", rc);

CloseHandle(hAcceptPort);

CloseHandle(hPort);

system("pause");

return 1;

}

}

return 0;

}

typedef struct _PORT_MESSAGE {

USHORT DataSize;//Data项的大小最大300

USHORT MessageSize;//可以用sizeof(PORT_MESSAGE)

USHORT MessageType;//后面有定义,代码中有解释

USHORT VirtualRangesOffset;//共享内存模式下用

CLIENT_ID ClientId;//客户端的信息

ULONG MessageId;//消息发送时系统生成的id

ULONG SectionSize;//共享内存时才会使用

UCHAR Data[300];//最大300字节

} PORT_MESSAGE, *PPORT_MESSAGE;

typedef enum _LPC_TYPE {

LPC_NEW_MESSAGE, // A new message 只在初次发送

LPC_REQUEST, // A request message 在1 和2 之间循环

LPC_REPLY, // A reply to a request message

LPC_DATAGRAM, //

LPC_LOST_REPLY, //

LPC_PORT_CLOSED, // Sent when port is deleted

LPC_CLIENT_DIED, // Messages to thread termination ports

LPC_EXCEPTION, // Messages to thread exception port

LPC_DEBUG_EVENT, // Messages to thread debug port

LPC_ERROR_EVENT, // Used by ZwRaiseHardError

LPC_CONNECTION_REQUEST // Used by 只在ZwConnectPort时发送

} LPC_TYPE;

客户端只需要两个api

NtConnectPort和NtRequestWaitReplyPort

NtRequestWaitReplyPort用法跟NtReplyWaitReceivePort类似

posted on

2015-01-06 12:57 

逆枫゛ 

阅读(417) 

评论(0) 

编辑 

收藏 

举报

会员力量,点亮园子希望

刷新页面返回顶部

Copyright @

2024 逆枫゛

Powered by .NET 8.0 on Kubernetes

Powered by:

.Text and

ASP.NET

Theme by: .NET Monster