# 資訊科技產業專案設計課程作業 3 ## Andes ### Linux Kernel Engineer (新竹市) :::spoiler #### 工作內容 開發 RISC-V 的 Linux 系統以協助客戶順利導入及量產,包含: 1. U-Boot 2. Linux kernel 3. OpenSBI 4. Device drivers (SPI, SD card, Ethernet) 5. Build systems (Yocto Project, OpenWrt) #### 擅長工具 : Linux、C、Git、ARM、Firmware、Drivers、USB技術 #### 需求 * Linux kernel 或 RTOS 的開發經驗 ::: #### 匹配程度 * 曾協作 open-source 的 linux device driver 專案,對於 C 語言有一定的熟練程度,但沒看完規格書 * 沒有 RTOS 相關經驗 * 沒有對 linux kernel 發過 patch ## SiFive ### System Software Engineer to Senior Staff Engineer (Linux) (新竹市) :::spoiler #### The Role: We at SiFive are proud to take a software first approach to develop tools and frameworks that achieve cutting edge performance without compromising quality for the SiFive Intelligence processor family. The SiFive Intelligence processors deliver AI acceleration for the edge and beyond. SiFive intelligence builds on RISC-V Vectors (RVV) allowing SiFive to design Core IPs that deliver performance, are optimized for power and area, but do not sacrifice flexibility or programmability. Our software stack is codesigned with the hardware and developed with scalability and quality in mind. Join us to develop revolutionary software from the ground up! SiFive is seeking an experienced System Software Engineer for our System Software group. The SiFive System Software group develops critical software components for our Core and Intelligence processors, from firmware and bare-metal to high-level OS and AI runtime code. The team is global, spanning several worldwide sites, working together as one group. We believe that engineers create most of the value in the company. Our management chain has a strong engineering and software development background. We believe in open, honest, and direct communication; mutual respect; and seek strong communicators and listeners. As a System Software Engineer, you will work with system architecture and hardware engineering teams to help design and evaluate systems, including CPUs, interconnects, firewalls, and related IP blocks. You’ll work with our software group to design software implementations that take advantage of hardware features and integrate cleanly with existing operating systems, such as Linux. You’ll write software for Linux kernel, device drivers, OpenSBI, u-boot, Yocto/OpenEmbedded. You’ll be a part of creating something big, all based around the RISC-V instruction set architecture. #### Responsibilities: - Design, develop, upstream and release system software: Linux kernel, device drivers, OpenSBI, u-boot, Yocto/OpenEmbedded (both SiFive-proprietary and public open source) - Engage with architecture, hardware engineering, and other software engineering teams to review, and refine features #### Requirements: - Above 1 years of experience developing architecture-level code or device drivers in C for multiprocessor, multithreaded open source kernels such as Linux or BSD, with upstream involvement - Proven experience with upstream development on high-level operating systems such as Linux - Strong communication, co-working, and listening skills - Experience working with hardware architecture and engineering teams - Experience debugging complex multicore systems - Experience debugging with GDB, JTAG and OpenOCD - Experience with git, Makefile, GNU toolchain and shell scripting - Experience with device drivers, virtualization, IOMMUs, power management or SoC platform security ::: #### 匹配程度 * 沒有一年以上開發經驗 * Poor communication, co-working, and listening skills ## Google ### Platform Kernel Engineer, ChromeOS (San Jose, CA, USA) :::spoiler #### Minimum qualifications: * Bachelor’s degree or equivalent practical experience. * 2 years of experience with software development coding in C, or 1 year of experience with an advanced degree. * Experience working on the Linux kernel. * Experience with debugging. #### Preferred qualifications: * Master's degree or PhD in Computer Science or related technical fields. * Experience in Rust programming. #### About the job Google's software engineers develop the next-generation technologies that change how billions of users connect, explore, and interact with information and one another. Our products need to handle information at massive scale, and extend well beyond web search. We're looking for engineers who bring fresh ideas from all areas, including information retrieval, distributed computing, large-scale system design, networking and data storage, security, artificial intelligence, natural language processing, UI design and mobile; the list goes on and is growing every day. As a software engineer, you will work on a specific project critical to Google’s needs with opportunities to switch teams and projects as you and our fast-paced business grow and evolve. We need our engineers to be versatile, display leadership qualities and be enthusiastic to take on new problems across the full-stack as we continue to push technology forward. Join us on the cutting-edge of ChromeOS development and redefine the way people interact with their devices. We're on a quest to revolutionize the ChromeOS experience, from the kernel to the user interface. Your passion and expertise will directly impact users worldwide. Imagine shaping the core operating system, building innovative tools that empower users, and pioneering technologies that push the boundaries of what's possible. With your help, we'll craft a ChromeOS that's not only faster and more secure, but also more intuitive and enjoyable. Chrome OS delivers quality computing at scale to provide universal and unfettered access to information, entertainment, and tools. Our mission is to empower anyone to create and access information freely through fast, secure, simple, and intelligent computing. The US base salary range for this full-time position is $136,000-$200,000 + bonus + equity + benefits. Our salary ranges are determined by role, level, and location. The range displayed on each job posting reflects the minimum and maximum target for new hire salaries for the position across all US locations. Within the range, individual pay is determined by work location and additional factors, including job-related skills, experience, and relevant education or training. Your recruiter can share more about the specific salary range for your preferred location during the hiring process. Please note that the compensation details listed in US role postings reflect the base salary only, and do not include bonus, equity, or benefits. Learn more about benefits at Google. #### Responsibilities Work on Linux kernel and drivers for ChromeOS. Debug system level bugs by diving into logs and crashes, uncovering the root causes of customer issues and driving solutions to enhance the user experience. Collaborate with technology teams to bring cutting-edge SoC power solutions to life, enabling peak performance and efficiency. Design innovative tools and services that pinpoint and resolve kernel and application bottlenecks. Contribute to the open-source community by upstreaming kernel patches, ensuring the stability and security of ChromeOS for all users. ::: #### 匹配程度 * 沒有兩年以上開發經驗 * 沒有 Rust 相關開發經驗 ___ ### 模擬問題 :sunglasses: 請詳盡解釋一支 helloworld.c 程式從編譯、連結、載入到執行是如何運作的? :man_climbing: 首先 helloworld.c 會先經過 preprocessing ,將 #define 中的內容進行文本替換,並處理 #include 中的標頭檔(展開為標頭檔的詳細內容),此時程式碼仍由 C 語言構成。 :man_climbing: 接著 Compiler 進行 Parsing 和 Semantic analysis 檢查 C 語法的正確性(front-end)。並產生 intermedia code 並對其最佳化(middle-end)。最後將 intermedia code 轉換為 assembly code(back-end)。 :man_climbing: 藉由組譯器將組合語言轉成 machine code。 ```graphviz digraph procedure { node[shape=box]; { rank="same"; "Source Code"->"Token"->"Syntax Tree"->"Intermedia code"->"assembly code"->"machine code(object code)"; } } ``` :man_climbing: 接著再進行 Linking,將標頭檔中宣告的函式從函式庫link 到程式中,並合並成執行檔。由 loader 將執行檔載入 memory,並初始化 global variable 和起始函式。 :man_climbing: 最後再由起始程式設定 stack pointer 並呼叫 main 函式執行 helloworld 內容。 :sunglasses: 這樣好了,假設我今天給你的檔案長這樣,你能更具體的說明剛剛的過程嗎? ```c #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; } ``` :man_climbing: 首先 preprocessor 會先展開 stdio.h 中的內容(內含 printf 的宣告)。 :man_climbing: 接著 compiler 對其進行 parsing 和語法分析生成中間碼並最佳化,最後生成 assembly code。 :man_climbing: 接著透過組譯器將 assembly code 轉成 machine code 。 :man_climbing: linker 將 printf 的定義加入程式中合併出可執行檔。 :man_climbing: loader 將執行檔載入 memory ,由 _start 初始化環境並呼叫 main function。main function 呼叫 printf 輸出 Hello, World!(其中 printf 會將字串轉成 binary form 傳遞給 I/O system call)。最後 return 後 _start 會使用 system call exit() 釋放 memory 並結束程式。 :sunglasses: 請解釋在 linux 中 user space 和 kernel space 是如何溝通的? :man_climbing: 可以透過 linux 中的 netlink library 來完成。 :sunglasses: 你可以具體說明如何運作嗎? :man_climbing: 假設我今天想要從 user program 傳 "Hello" 給 kernel module,我必須在 user 和 kernel 間建立 netlink socket。 user: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/socket.h> #include <linux/netlink.h> #include <unistd.h> #define NETLINK_USER 31 #define MAX_PAYLOAD 1024 int main(){ struct sockaddr_nl src_addr, dest_addr; struct nlmsghdr *nlh = NULL; struct iovec iov; int sock_fd; struct msghdr msg; sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER); if (sock_fd < 0) { printf("Error: Can't open socket\n"); return -1; } memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); src_addr.nl_groups = 0; bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; dest_addr.nl_groups = 0; nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; strcpy(NLMSG_DATA(nlh), "Hello"); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; sendmsg(sock_fd, &msg, 0); close(sock_fd); free(nlh); return 0; } ``` kernel: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/netlink.h> #include <linux/skbuff.h> #include <net/sock.h> #define NL_USER 31 struct sock *nl_sk = NULL; static void nl_recv(struct sk_buff *skb){ struct nlmsghdr *nlh; char *msg; nlh = (struct nlmsghdr*)skb->data; msg = (char*)nlmsg_data(nlh); pr_info("Received: %s\n", msg); } static struct netlink_kernel_cfg nl_cfg = { .input = nl_recv, }; static int __init m_init(){ nl_sk = netlink_lernel_create(&init_net, NL_USER, &nl_cfg); if(!nl_sk){ pr_err("Error creating netlink socket\n"); return -1; } return 0; } static void __exit m_exit(){ if(nl_sk){ netlink_lernel_release(nl_sk); } } module_init(m_init); module_exit(m_exit); ```