Linux內核內存分配
Linux系統使用了一種稱為“虛擬內存”的機制。虛擬內存機制使得每個內存地址都是虛擬的,這意味著它們不會直接指向RAM中的任何地址。這樣我們訪問內存中的存儲單元時,都會進行地址轉換以匹配相應的物理內存
在Linux系統中,內核中的每個進程都表示為一個task_struct結構體實例,該結構體實例表征并描述了這個進程。在進程開始運行之前,系統會為其分配一個內存映射表,該表存放在struct mm_struct類型的變量中。在內核中,全局變量current時鐘指向當前進程,current->mm字段指向當前的進程內存映射表,struct mm_struct結構定義參見include/linux/mm_types.h
地址轉換和MMU
MMU不僅可以將虛擬地址轉換為物理地址,還可以保護內存免受未經授權的訪問。給定一個進程,需要從此進程訪問的任何頁都必須位于一個VMA中,且必須位于進程的頁表中
由于最近訪問的數據存放在緩存中,因此最近轉換的地址也存放在緩存中。數據緩存加快了數據訪問過程,TLB則加快了虛擬地址的轉換過程。TLB是內容可尋址內存,其中鍵是虛擬地址,值是物理地址,其運作過程如下圖所示
內存分配機制
下圖展示了Linux系統中不同的內存分配器。最低級別的分配器是頁分配器,它以頁為單位分配內存,然后是Slab分配器,它建立在頁分配器的基礎上,從中獲取頁并將它們拆分為較小的內存實體,kmalloc分配器依賴于Slab分配器
實現DMA支持
DMA是計算機系統的一種特性,它允許設備在沒有CPU干預的情況下訪問主系統內存,使CPU嫩鞏固專注于其他任務。它的使用示例包括網絡流量加速、音頻數據或視頻幀抓取等,它的使用并不限于特定領域。負責管理DMA事務的外圍設備是DMA控制器,它存在于大多數現代處理器和微控制器中。
DMA的工作方式如下:當驅動程序需要傳輸數據塊時,便使用源地址、目標地址和要復制的總字節數設置DMA控制器,然后DMA控制器自動將數據地址從源地址傳輸到目標地址,而不會占用CPU周期。當剩余字節數為0時,數據塊傳輸結束并通知驅動程序。
DMA引擎API
DMA控制器接口由兩部分組成:控制器和通道。控制器執行內存傳輸,通道則是客戶端驅動程序向控制器提交作業的方式
DMA控制器在Linux內核中別抽象為dma_device結構體實例,其定義如下
struct dma_device {
struct kref ref;
unsigned int chancnt;
unsigned int privatecnt;
struct list_head channels;
struct list_head global_node;
struct dma_filter filter;
dma_cap_mask_tcap_mask;
enum dma_desc_metadata_mode desc_metadata_modes;
unsigned short max_xor;
unsigned short max_pq;
enum dmaengine_alignment copy_align;
enum dmaengine_alignment xor_align;
enum dmaengine_alignment pq_align;
enum dmaengine_alignment fill_align;
#define DMA_HAS_PQ_CONTINUE (1 << 15)
int dev_id;
struct device *dev;
struct module *owner;
struct ida chan_ida;
u32 src_addr_widths;
u32 dst_addr_widths;
u32 directions;
u32 min_burst;
u32 max_burst;
u32 max_sg_burst;
bool descriptor_reuse;
enum dma_residue_granularity residue_granularity;
int (*device_alloc_chan_resources)(struct dma_chan *chan);
int (*device_router_config)(struct dma_chan *chan);
void (*device_free_chan_resources)(struct dma_chan *chan);
struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src,
unsigned int src_cnt, size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_xor_val)(
struct dma_chan *chan, dma_addr_t *src,unsigned int src_cnt,
size_t len, enum sum_check_flags *result, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_pq)(
struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src,
unsigned int src_cnt, const unsigned char *scf,
size_t len, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_pq_val)(
struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
unsigned int src_cnt, const unsigned char *scf, size_t len,
enum sum_check_flags *pqres, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_memset_sg)(
struct dma_chan *chan, struct scatterlist *sg,
unsigned int nents, int value, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan, unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
unsigned long flags, void *context);
struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_transfer_direction direction,
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
struct dma_chan *chan, struct dma_interleaved_template *xt,
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_imm_data)(
struct dma_chan *chan, dma_addr_t dst, u64 data,
unsigned long flags);
void (*device_caps)(struct dma_chan *chan,
struct dma_slave_caps *caps);
int (*device_config)(struct dma_chan *chan,
struct dma_slave_config *config);
int (*device_pause)(struct dma_chan *chan);
int (*device_resume)(struct dma_chan *chan);
int (*device_terminate_all)(struct dma_chan *chan);
void (*device_synchronize)(struct dma_chan *chan);
enum dma_status (*device_tx_status)(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate);
void (*device_issue_pending)(struct dma_chan *chan);
void (*device_release)(struct dma_device *dev);
/* debugfs support */
void (*dbg_summary_show)(struct seq_file *s, struct dma_device *dev);
struct dentry *dbg_dev_root;
};
DMA通道的結構體定義如下
struct dma_chan {
int dev_id;/* this channel is allocated if >= 0, */
/* free otherwise */
void __iomem *io;
const char *dev_str;
int irq;
void *irq_dev;
unsigned int fifo_addr;
unsigned int mode;
};
請求DMA通道
dma_request_channel()函數用于請求一個通道
struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
dma_filter_fn filter_fn,
void *filter_param);
配置DMA通道
DMA引擎框架使用struct dma_slave_config數據結構進行配置,該數據結構表示DMA通道的運行時配置,這樣客戶端就可以指定諸如DMA方向、DMA地址、總線寬度和DMA突發成都等外設的參數,struct dma_slave_config數據結構定義如下
struct dma_slave_config {
enum dma_transfer_direction direction;
phys_addr_t src_addr;
phys_addr_t dst_addr;
enum dma_slave_buswidth src_addr_width;
enum dma_slave_buswidth dst_addr_width;
u32 src_maxburst;
u32 dst_maxburst;
u32 src_port_window_size;
u32 dst_port_window_size;
bool device_fc;
void *peripheral_config;
size_t peripheral_size;
};
通過dmaengine_slave_config()函數將這種配置作用于底層硬件上
static inline int dmaengine_slave_config(struct dma_chan *chan,
struct dma_slave_config *config)
{
if (chan->device->device_config)
return chan->device->device_config(chan, config);
return -ENOSYS;
}
配置DMA傳輸
這一步用于確認DMA傳輸的方式,要進行一次DMA傳輸,就需要用到與DMA通道對應的控制器中的一些函數,這些函數名為device_prep_dma_*,例如對于內存到內存的傳輸,使用device_prep_dma_memcpy()
struct dma_async_tx_descriptor *tx;
struct dma_chan *chan = acdev->dma_chan;
dma_cookie_t cookie;
unsigned long flags = DMA_PREP_INTERRUPT;
int ret = 0;
tx = chan->device->device_prep_dma_memcpy(chan, dest, src, len, flags);
if (!tx) {
dev_err(acdev->host->dev, \"device_prep_dma_memcpy failed\\\\n\");
return -EAGAIN;
}
提交DMA傳輸
為了把事務放到驅動程序的事務待處理隊列中,可以使用dmaengine_submit()函數
static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
{
return desc->tx_submit(desc);
}
發出待處理的DMA請求并等待回調通知
啟動傳輸是DMA傳輸設置的最后一步,可以通過在通道上調用dma_async_issue_pending()來激活通道待處理隊列中的傳輸。
static inline void dma_async_issue_pending(struct dma_chan *chan)
{
chan->device->device_issue_pending(chan);
}
發表于 02-04 22:30
在現代生活中,電已經成為我們離不開的能源。而如何安全、高效地管理用電設備,成為越來越多家庭和企業的關注點。今天咱們就來聊聊一個很實用的好東西—— 廣州曼頓 手機控制斷路器 ,它不僅能幫你隨時掌控電路
發表于 02-04 14:41
?229次閱讀
在快節奏的現代生活中,手機已成為我們不可或缺的伙伴。然而,頻繁的充電操作不僅繁瑣,還可能損壞手機接口。想象一下,只需將手機放在充電板上,就能輕松完成充電,這便是無線充電技術的魅力
發表于 02-03 08:39
?407次閱讀
法國電子行業的發展道路提供了一種有別于美國的產業模式,即在保持國家戰略引導的同時,充分發揮市場活力,在開放合作中維護產業安全。
發表于 12-12 11:58
?630次閱讀
工具的好壞取決于其使用者。無論是使用一把錘子還是Fusion Compiler,唯有掌握正確的知識與技能,方能充分發揮工具潛力,達成預期目標。
發表于 08-04 15:01
?761次閱讀
在攝影的世界里,技術的革新如同璀璨星辰,不斷照亮新的創作天地。手持云臺馬達驅動作為近年來攝影器材領域的一項重要創新,正以其獨特的魅力和強大的功能,在攝影領域展現出無限的應用前景。
發表于 07-22 16:36
?583次閱讀
近日,經緯恒潤與長春富維海拉車燈有限公司(以下簡稱“富維海拉”)順利完成戰略合作協議簽約。未來,雙方將充分發揮各自在車載智能燈光領域的互補優勢和資源,共同推動創新燈光解決方案在智能汽車領域
發表于 07-15 17:08
?732次閱讀
的優勢,如高效、徹底、節能、環保等。本文將重點介紹非標超聲波清洗設備的最大優勢以及如何充分發揮其特點。一、高效清洗非標超聲波清洗設備通過高頻聲波的作用,能夠在短時
發表于 07-08 16:58
?633次閱讀
摘要:針對傳統專家系統不能進行自學習、自適應的問題,本文提出了基于種經網絡專家系統的并步電機故障診斷方法。本文將小波神經網絡和專家系統相結合,充分發揮了二者故障診斷的優點,很大程度上降低了對電機
發表于 06-16 22:09
,使得其響應速度較慢,無法充分發揮NVMe SSD的速度優勢。若想要在嵌入式系統中充分發揮NVMe協議的高速讀寫性能,一方面可以通過優化軟件執行流程,來提高傳輸性能,但嵌入式處理器的性能較低,性能提升
發表于 06-02 23:28
嵌入式物聯網生態的繁榮發展。富瀚微在視覺處理及顯示驅動芯片領域擁有深厚的技術積累,RT-Thread作為開源實時操作系統,將充分發揮其在嵌入式軟件生態中的優勢,助
發表于 05-12 11:53
?1004次閱讀
面對多樣化的市場需求,MCX 連接器充分發揮自身優勢,為不同行業量身定制適配的解決方案。展望未來,隨著科技的持續創新與進步,MCX 連接器必將繼續在各個領域發揮重要作用,以其可靠的性能為科技發展注入強勁動力,推動各行業邁向新的高度。
發表于 04-02 13:54
?714次閱讀
3月26日至3月29日,深圳國際會展中心迎來了盛大的深圳工業展。明治傳感作為土生土長的深圳企業,充分發揮東道主優勢參與其中。以【精密光電,AI傳感】為核心主題登場,展示了一系列令人矚目的創新
發表于 04-01 07:33
?860次閱讀
獲得精確的數學模型,單純采用PI 控制或模糊控制都不 會取得較好的控制效果,而采用模糊自整定PI 控制方式控制 能充分發揮模糊控制魯棒性強、動態響應好、上升時間快、 超調小的優點,又具有PI控制器的動態
發表于 03-26 14:09
低功耗原則,確保在長時間使用中維持優異的性能,延長電池壽命,滿足最終產品低功耗設計的要求。
l輕松擴展:客戶可以根據自身需求自由定義最終產品的形式,充分發揮創造力,打造個性化的使用體驗,使得用戶體驗更加豐富。
發表于 03-23 22:14
評論